@budibase/backend-core 2.29.13 → 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 (38) hide show
  1. package/dist/index.js +2280 -2241
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +4 -4
  5. package/dist/src/db/couch/DatabaseImpl.js +2 -0
  6. package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
  7. package/dist/src/db/couch/index.d.ts +0 -1
  8. package/dist/src/db/couch/index.js +0 -1
  9. package/dist/src/db/couch/index.js.map +1 -1
  10. package/dist/src/environment.d.ts +2 -0
  11. package/dist/src/environment.js +16 -0
  12. package/dist/src/environment.js.map +1 -1
  13. package/dist/src/middleware/errorHandling.js +9 -1
  14. package/dist/src/middleware/errorHandling.js.map +1 -1
  15. package/dist/src/security/secrets.d.ts +1 -0
  16. package/dist/src/security/secrets.js +43 -0
  17. package/dist/src/security/secrets.js.map +1 -0
  18. package/dist/src/sql/sql.js +3 -14
  19. package/dist/src/sql/sql.js.map +1 -1
  20. package/dist/src/sql/utils.d.ts +3 -1
  21. package/dist/src/sql/utils.js +31 -3
  22. package/dist/src/sql/utils.js.map +1 -1
  23. package/dist/tests/core/utilities/jestUtils.d.ts +3 -3
  24. package/dist/tests/core/utilities/jestUtils.js.map +1 -1
  25. package/package.json +4 -4
  26. package/src/db/couch/DatabaseImpl.ts +3 -0
  27. package/src/db/couch/index.ts +0 -1
  28. package/src/environment.ts +17 -0
  29. package/src/middleware/errorHandling.ts +10 -1
  30. package/src/security/secrets.ts +20 -0
  31. package/src/security/tests/secrets.spec.ts +35 -0
  32. package/src/sql/sql.ts +6 -16
  33. package/src/sql/utils.ts +27 -2
  34. package/tests/core/utilities/jestUtils.ts +6 -3
  35. package/dist/src/db/constants.d.ts +0 -1
  36. package/dist/src/db/constants.js +0 -8
  37. package/dist/src/db/constants.js.map +0 -1
  38. package/src/db/constants.ts +0 -5
package/dist/index.js CHANGED
@@ -54216,9 +54216,9 @@ __export(src_exports, {
54216
54216
  sql: () => sql_exports,
54217
54217
  tenancy: () => tenancy,
54218
54218
  timers: () => timers_exports,
54219
- userUtils: () => utils_exports4,
54219
+ userUtils: () => utils_exports5,
54220
54220
  users: () => users_exports3,
54221
- utils: () => utils_exports3
54221
+ utils: () => utils_exports4
54222
54222
  });
54223
54223
  module.exports = __toCommonJS(src_exports);
54224
54224
 
@@ -54751,20 +54751,6 @@ var SWITCHABLE_TYPES = {
54751
54751
  ["number" /* NUMBER */]: ["number" /* NUMBER */, "boolean" /* BOOLEAN */]
54752
54752
  };
54753
54753
 
54754
- // ../shared-core/src/constants/rows.ts
54755
- var CONSTANT_INTERNAL_ROW_COLS = [
54756
- "_id",
54757
- "_rev",
54758
- "type",
54759
- "createdAt",
54760
- "updatedAt",
54761
- "tableId"
54762
- ];
54763
- var CONSTANT_EXTERNAL_ROW_COLS = ["_id", "_rev", "tableId"];
54764
- function isInternalColumnName(name) {
54765
- return CONSTANT_INTERNAL_ROW_COLS.includes(name);
54766
- }
54767
-
54768
54754
  // ../shared-core/src/constants/index.ts
54769
54755
  var OperatorOptions = {
54770
54756
  Equals: {
@@ -56115,6 +56101,21 @@ var environment = {
56115
56101
  BB_ADMIN_USER_PASSWORD: process.env.BB_ADMIN_USER_PASSWORD,
56116
56102
  OPENAI_API_KEY: process.env.OPENAI_API_KEY
56117
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
+ ];
56118
56119
  for (let [key, value] of Object.entries(environment)) {
56119
56120
  if (value === "0") {
56120
56121
  environment[key] = 0;
@@ -56512,1021 +56513,1650 @@ var DDInstrumentedDatabase = class {
56512
56513
  }
56513
56514
  };
56514
56515
 
56515
- // src/db/couch/DatabaseImpl.ts
56516
- var DATABASE_NOT_FOUND = "Database does not exist.";
56517
- function buildNano(couchInfo) {
56518
- return (0, import_nano.default)({
56519
- url: couchInfo.url,
56520
- requestDefaults: {
56521
- headers: {
56522
- Authorization: couchInfo.cookie
56523
- }
56524
- },
56525
- parseUrl: false
56526
- });
56527
- }
56528
- var CouchDBError = class extends Error {
56529
- constructor(message, info) {
56530
- super(message);
56531
- const statusCode = info.status || info.statusCode || 500;
56532
- this.status = statusCode;
56533
- this.statusCode = statusCode;
56534
- this.reason = info.reason;
56535
- this.name = info.name;
56536
- this.errid = info.errid;
56537
- this.description = info.description;
56538
- this.error = info.error;
56539
- }
56540
- };
56541
- function DatabaseWithConnection(dbName, connection, opts) {
56542
- if (!dbName || !connection) {
56543
- throw new Error(
56544
- "Unable to create database without database name or connection"
56545
- );
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];
56546
56728
  }
56547
- const db = new DatabaseImpl(dbName, opts, connection);
56548
- 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
+ };
56549
56737
  }
56550
- var DatabaseImpl = class _DatabaseImpl {
56551
- constructor(dbName, opts, connection) {
56552
- this.couchInfo = getCouchInfo();
56553
- this.name = dbName;
56554
- this.pouchOpts = opts || {};
56555
- if (connection) {
56556
- this.couchInfo = getCouchInfo(connection);
56557
- this.instanceNano = buildNano(this.couchInfo);
56558
- }
56559
- if (!_DatabaseImpl.nano) {
56560
- _DatabaseImpl.init();
56561
- }
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
+ };
56562
56757
  }
56563
- static init() {
56564
- const couchInfo = getCouchInfo();
56565
- _DatabaseImpl.nano = buildNano(couchInfo);
56758
+ return opts;
56759
+ }
56760
+ function addDbPrefix(db, key) {
56761
+ if (key.includes(db)) {
56762
+ return key;
56566
56763
  }
56567
- exists(docId) {
56568
- if (docId === void 0) {
56569
- return this.dbExists();
56570
- }
56571
- 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];
56572
56773
  }
56573
- async dbExists() {
56574
- const response = await directCouchUrlCall({
56575
- url: `${this.couchInfo.url}/${this.name}`,
56576
- method: "HEAD",
56577
- cookie: this.couchInfo.cookie
56578
- });
56579
- 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;
56580
56798
  }
56581
- async docExists(id) {
56582
- try {
56583
- await this.performCall((db) => () => db.head(id));
56584
- return true;
56585
- } catch {
56586
- 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
56587
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}`);
56588
56918
  }
56589
- nano() {
56590
- 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");
56591
56922
  }
56592
- getDb() {
56593
- 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");
56594
56932
  }
56595
- async checkAndCreateDb() {
56596
- let shouldCreate = !this.pouchOpts?.skip_setup;
56597
- let exists2 = await this.exists();
56598
- if (!shouldCreate && !exists2) {
56599
- throw new Error("DB does not exist");
56600
- }
56601
- if (!exists2) {
56602
- try {
56603
- await this.nano().db.create(this.name);
56604
- } catch (err) {
56605
- if (err.statusCode !== 412) {
56606
- throw new CouchDBError(err.message, err);
56607
- }
56608
- }
56609
- }
56610
- 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);
56611
56949
  }
56612
- // this function fetches the DB and handles if DB creation is needed
56613
- async performCall(call) {
56614
- const db = this.getDb();
56615
- const fnc = await call(db);
56616
- try {
56617
- return await fnc();
56618
- } catch (err) {
56619
- if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {
56620
- await this.checkAndCreateDb();
56621
- return await this.performCall(call);
56622
- }
56623
- throw new CouchDBError(`CouchDB error: ${err.message}`, err);
56624
- }
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
+ };
56625
56996
  }
56626
- async get(id) {
56627
- return this.performCall((db) => {
56628
- if (!id) {
56629
- throw new Error("Unable to get doc without a valid _id.");
56630
- }
56631
- return () => db.get(id);
56632
- });
56997
+ if (!environment_default.MINIO_ENABLED && environment_default.AWS_SESSION_TOKEN) {
56998
+ config.sessionToken = environment_default.AWS_SESSION_TOKEN;
56633
56999
  }
56634
- async getMultiple(ids, opts) {
56635
- ids = [...new Set(ids)];
56636
- const response = await this.allDocs({
56637
- keys: ids,
56638
- include_docs: true
56639
- });
56640
- const rowUnavailable = (row) => {
56641
- if (row.doc == null || "deleted" in row.value && row.value.deleted) {
56642
- return true;
56643
- }
56644
- return row.error === "not_found";
56645
- };
56646
- const rows = response.rows.filter((row) => !rowUnavailable(row));
56647
- const someMissing = rows.length !== response.rows.length;
56648
- if (!opts?.allowMissing && someMissing) {
56649
- const missing = response.rows.filter((row) => rowUnavailable(row));
56650
- const missingIds = missing.map((row) => row.key).join(", ");
56651
- 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;
56652
57005
  }
56653
- return rows.map((row) => row.doc);
56654
57006
  }
56655
- async remove(idOrDoc, rev) {
56656
- return this.performCall((db) => {
56657
- let _id;
56658
- let _rev;
56659
- if (isDocument(idOrDoc)) {
56660
- _id = idOrDoc._id;
56661
- _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 };
56662
57030
  } else {
56663
- _id = idOrDoc;
56664
- _rev = rev;
56665
- }
56666
- if (!_id || !_rev) {
56667
- throw new Error("Unable to remove doc without a valid _id and _rev.");
57031
+ throw new Error("Access denied to object store bucket." + err);
56668
57032
  }
56669
- return () => db.destroy(_id, _rev);
56670
- });
56671
- }
56672
- async post(document, opts) {
56673
- if (!document._id) {
56674
- document._id = newid();
57033
+ } else {
57034
+ throw new Error("Unable to write to object store bucket.");
56675
57035
  }
56676
- return this.put(document, opts);
56677
57036
  }
56678
- async put(document, opts) {
56679
- if (!document._id) {
56680
- throw new Error("Cannot store document without _id field.");
56681
- }
56682
- return this.performCall(async (db) => {
56683
- if (!document.createdAt) {
56684
- document.createdAt = (/* @__PURE__ */ new Date()).toISOString();
56685
- }
56686
- document.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
56687
- if (opts?.force && document._id) {
56688
- try {
56689
- const existing = await this.get(document._id);
56690
- if (existing) {
56691
- document._rev = existing._rev;
56692
- }
56693
- } catch (err) {
56694
- if (err.status !== 404) {
56695
- throw err;
56696
- }
56697
- }
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];
56698
57069
  }
56699
- return () => db.insert(document);
56700
- });
57070
+ }
57071
+ config.Metadata = metadata;
56701
57072
  }
56702
- async bulkDocs(documents) {
56703
- return this.performCall((db) => {
56704
- return () => db.bulk({ docs: documents });
56705
- });
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");
56706
57085
  }
56707
- async allDocs(params2) {
56708
- return this.performCall((db) => {
56709
- return () => db.list(params2);
56710
- });
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();
56711
57092
  }
56712
- async _sqlQuery(url, method, body2) {
56713
- url = checkSlashesInUrl(`${this.couchInfo.sqlUrl}/${url}`);
56714
- const args = {
56715
- url,
56716
- method,
56717
- 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"
56718
57102
  };
56719
- if (body2) {
56720
- args.body = body2;
56721
- }
56722
- return this.performCall(() => {
56723
- return async () => {
56724
- const response = await directCouchUrlCall(args);
56725
- const json = await response.json();
56726
- if (response.status > 300) {
56727
- throw json;
56728
- }
56729
- return json;
56730
- };
56731
- });
56732
57103
  }
56733
- async sql(sql, parameters) {
56734
- const dbName = this.name;
56735
- const url = `/${dbName}/${SQLITE_DESIGN_DOC_ID}`;
56736
- return await this._sqlQuery(url, "POST", {
56737
- query: sql,
56738
- args: parameters
56739
- });
57104
+ let contentType = type;
57105
+ if (!contentType) {
57106
+ contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
56740
57107
  }
56741
- // checks design document is accurate (cleans up tables)
56742
- // this will check the design document and remove anything from
56743
- // disk which is not supposed to be there
56744
- async sqlDiskCleanup() {
56745
- const dbName = this.name;
56746
- const url = `/${dbName}/_cleanup`;
56747
- try {
56748
- await this._sqlQuery(url, "POST");
56749
- } catch (err) {
56750
- if (err.status !== 500) {
56751
- throw err;
56752
- }
56753
- }
56754
- }
56755
- // removes a document from sqlite
56756
- async sqlPurgeDocument(docIds) {
56757
- if (!Array.isArray(docIds)) {
56758
- docIds = [docIds];
56759
- }
56760
- const dbName = this.name;
56761
- const url = `/${dbName}/_purge`;
56762
- return await this._sqlQuery(url, "POST", { docs: docIds });
56763
- }
56764
- async query(viewName, params2) {
56765
- return this.performCall((db) => {
56766
- const [database, view] = viewName.split("/");
56767
- return () => db.view(database, view, params2);
56768
- });
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;
56769
57137
  }
56770
- async destroy() {
56771
- if (environment_default.SQS_SEARCH_ENABLE && await this.exists(SQLITE_DESIGN_DOC_ID)) {
56772
- const definition = await this.get(SQLITE_DESIGN_DOC_ID);
56773
- definition.sql.tables = {};
56774
- await this.put(definition);
56775
- 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;
56776
57153
  }
56777
- try {
56778
- return await this.nano().db.destroy(this.name);
56779
- } catch (err) {
56780
- if (err.statusCode === 404) {
56781
- return;
56782
- } else {
56783
- throw new CouchDBError(err.message, err);
56784
- }
57154
+ const response = await list(params2);
57155
+ if (response.Contents) {
57156
+ objects = objects.concat(response.Contents);
56785
57157
  }
56786
- }
56787
- async compact() {
56788
- return this.performCall((db) => {
56789
- return () => db.compact();
56790
- });
56791
- }
56792
- // All below functions are in-frequently called, just utilise PouchDB
56793
- // for them as it implements them better than we can
56794
- async dump(stream3, opts) {
56795
- const pouch = getPouchDB(this.name);
56796
- return pouch.dump(stream3, opts);
56797
- }
56798
- async load(stream3) {
56799
- const pouch = getPouchDB(this.name);
56800
- return pouch.load(stream3);
56801
- }
56802
- async createIndex(opts) {
56803
- const pouch = getPouchDB(this.name);
56804
- return pouch.createIndex(opts);
56805
- }
56806
- async deleteIndex(opts) {
56807
- const pouch = getPouchDB(this.name);
56808
- return pouch.deleteIndex(opts);
56809
- }
56810
- async getIndexes() {
56811
- const pouch = getPouchDB(this.name);
56812
- return pouch.getIndexes();
56813
- }
56814
- };
56815
-
56816
- // src/db/db.ts
56817
- function getDB(dbName, opts) {
56818
- return new DDInstrumentedDatabase(new DatabaseImpl(dbName, opts));
56819
- }
56820
- async function doWithDB(dbName, cb, opts) {
56821
- const db = getDB(dbName, opts);
56822
- return await cb(db);
57158
+ isTruncated = !!response.IsTruncated;
57159
+ token = response.NextContinuationToken;
57160
+ } while (isTruncated && token);
57161
+ return objects;
56823
57162
  }
56824
- async function directCouchAllDbs(queryString) {
56825
- let couchPath = "/_all_dbs";
56826
- if (queryString) {
56827
- couchPath += `?${queryString}`;
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}`;
56828
57178
  }
56829
- return await directCouchQuery(couchPath);
56830
57179
  }
56831
- async function directCouchFind(dbName, opts) {
56832
- const json = await directCouchQuery(`${dbName}/_find`, "POST", opts);
56833
- return { rows: json.docs, bookmark: json.bookmark };
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;
56834
57187
  }
56835
-
56836
- // src/context/mainContext.ts
56837
- var TEST_APP_ID = null;
56838
- function getGlobalDBName(tenantId) {
56839
- if (!tenantId) {
56840
- tenantId = getTenantId();
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
+ );
56841
57217
  }
56842
- return baseGlobalDBName(tenantId);
57218
+ await Promise.all(writePromises);
57219
+ return writePath;
56843
57220
  }
56844
- function getAuditLogDBName(tenantId) {
56845
- if (!tenantId) {
56846
- tenantId = getTenantId();
56847
- }
56848
- if (tenantId === DEFAULT_TENANT_ID) {
56849
- return StaticDatabases.AUDIT_LOGS.name;
56850
- } else {
56851
- return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}`;
56852
- }
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();
56853
57229
  }
56854
- function getScimDBName(tenantId) {
56855
- if (!tenantId) {
56856
- tenantId = getTenantId();
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();
57240
+ }
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;
56857
57252
  }
56858
- if (tenantId === DEFAULT_TENANT_ID) {
56859
- return StaticDatabases.SCIM_LOGS.name;
56860
- } else {
56861
- return `${tenantId}${SEPARATOR}${StaticDatabases.SCIM_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);
56862
57265
  }
56863
57266
  }
56864
- function baseGlobalDBName(tenantId) {
56865
- if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
56866
- return StaticDatabases.GLOBAL.name;
56867
- } else {
56868
- 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
+ }
56869
57285
  }
57286
+ await Promise.all(uploads);
57287
+ return files;
56870
57288
  }
56871
- function getPlatformURL() {
56872
- return environment_default.PLATFORM_URL;
56873
- }
56874
- function isMultiTenant() {
56875
- return !!environment_default.MULTI_TENANCY;
56876
- }
56877
- function isTenantIdSet() {
56878
- const context = Context.get();
56879
- return !!context?.tenantId;
56880
- }
56881
- function isTenancyEnabled() {
56882
- return environment_default.MULTI_TENANCY;
56883
- }
56884
- function getTenantIDFromAppID(appId) {
56885
- if (!appId) {
56886
- return void 0;
56887
- }
56888
- if (!isMultiTenant()) {
56889
- 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}`);
56890
57294
  }
56891
- const split = appId.split(SEPARATOR);
56892
- const hasDev = split[1] === "dev" /* DEV */;
56893
- if (hasDev && split.length === 3 || !hasDev && split.length === 2) {
56894
- 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}`);
56895
57303
  }
56896
- if (hasDev) {
56897
- return split[2];
56898
- } else {
56899
- 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);
56900
57308
  }
57309
+ return tmpPath;
56901
57310
  }
56902
- function updateContext(updates) {
56903
- 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
+ };
56904
57329
  try {
56905
- context = Context.get();
57330
+ return await client.headObject(params2).promise();
56906
57331
  } catch (err) {
56907
- context = {};
57332
+ throw new Error("Unable to retrieve metadata from object");
56908
57333
  }
56909
- context = {
56910
- ...context,
56911
- ...updates
56912
- };
56913
- return context;
56914
57334
  }
56915
- async function newContext(updates, task) {
56916
- guardMigration();
56917
- let context = updateContext(updates);
56918
- return Context.run(context, task);
56919
- }
56920
- async function doInAutomationContext(params2) {
56921
- await ensureSnippetContext();
56922
- return newContext(
56923
- {
56924
- tenantId: getTenantIDFromAppID(params2.appId),
56925
- appId: params2.appId,
56926
- automationId: params2.automationId
56927
- },
56928
- params2.task
56929
- );
56930
- }
56931
- async function doInContext(appId, task) {
56932
- const tenantId = getTenantIDFromAppID(appId);
56933
- return newContext(
56934
- {
56935
- tenantId,
56936
- appId
56937
- },
56938
- task
57335
+ function extractBucketAndPath(url) {
57336
+ const baseUrl = url.split("?")[0];
57337
+ const regex = new RegExp(
57338
+ `^${SIGNED_FILE_PREFIX}/(?<bucket>[^/]+)/(?<path>.+)$`
56939
57339
  );
56940
- }
56941
- async function doInTenant(tenantId, task) {
56942
- if (!environment_default.MULTI_TENANCY) {
56943
- 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 };
56944
57344
  }
56945
- const updates = tenantId ? { tenantId } : {};
56946
- return newContext(updates, task);
56947
- }
56948
- async function doInAppContext(appId, task) {
56949
- return _doInAppContext(appId, task);
57345
+ return null;
56950
57346
  }
56951
- async function _doInAppContext(appId, task, extraContextSettings) {
56952
- if (!appId) {
56953
- 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");
56954
57354
  }
56955
- const tenantId = getTenantIDFromAppID(appId);
56956
- const updates = { appId, ...extraContextSettings };
56957
- if (tenantId) {
56958
- updates.tenantId = tenantId;
57355
+ if (PRIVATE_KEY) {
57356
+ return PRIVATE_KEY;
56959
57357
  }
56960
- 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;
56961
57362
  }
56962
- async function doInIdentityContext(identity, task) {
56963
- if (!identity) {
56964
- throw new Error("identity is required");
56965
- }
56966
- const context = {
56967
- 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
56968
57369
  };
56969
- if (identity.tenantId) {
56970
- 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 = "";
56971
57379
  }
56972
- 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`;
56973
57387
  }
56974
- function guardMigration() {
56975
- const context = Context.get();
56976
- if (context?.isMigrating) {
56977
- throw new Error(
56978
- "The context cannot be changed, a migration is currently running"
56979
- );
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);
56980
57397
  }
56981
57398
  }
56982
- async function doInAppMigrationContext(appId, task) {
56983
- return _doInAppContext(appId, task, {
56984
- isMigrating: true
56985
- });
56986
- }
56987
- function getIdentity() {
57399
+ function clientLibraryUrl(appId, version) {
57400
+ let tenantId, qsParams;
56988
57401
  try {
56989
- const context = Context.get();
56990
- return context?.identity;
56991
- } catch (e) {
56992
- }
56993
- }
56994
- function getTenantId() {
56995
- if (!isMultiTenant()) {
56996
- return DEFAULT_TENANT_ID;
57402
+ tenantId = getTenantId();
57403
+ } finally {
57404
+ qsParams = {
57405
+ appId,
57406
+ version
57407
+ };
56997
57408
  }
56998
- const context = Context.get();
56999
- const tenantId = context?.tenantId;
57000
- if (!tenantId) {
57001
- throw new Error("Tenant id not found");
57409
+ if (tenantId && tenantId !== DEFAULT_TENANT_ID) {
57410
+ qsParams.tenantId = tenantId;
57002
57411
  }
57003
- return tenantId;
57004
- }
57005
- function getAutomationId() {
57006
- const context = Context.get();
57007
- return context?.automationId;
57412
+ return `/api/assets/client?${import_querystring.default.encode(qsParams)}`;
57008
57413
  }
57009
- function getAppId() {
57010
- const context = Context.get();
57011
- const foundId = context?.appId;
57012
- if (!foundId && environment_default.isTest() && TEST_APP_ID) {
57013
- return TEST_APP_ID;
57414
+ function getAppFileUrl(s3Key) {
57415
+ if (environment_default.CLOUDFRONT_CDN) {
57416
+ return getPresignedUrl2(s3Key);
57014
57417
  } else {
57015
- return foundId;
57418
+ return getPresignedUrl(environment_default.APPS_BUCKET_NAME, s3Key);
57016
57419
  }
57017
57420
  }
57018
- var getProdAppId = () => {
57019
- const appId = getAppId();
57020
- if (!appId) {
57021
- throw new Error("Could not get appId");
57022
- }
57023
- return getProdAppID2(appId);
57024
- };
57025
- function doInEnvironmentContext(values2, task) {
57026
- if (!values2) {
57027
- throw new Error("Must supply environment variables.");
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);
57028
57432
  }
57029
- const updates = {
57030
- environmentVariables: values2
57031
- };
57032
- return newContext(updates, task);
57433
+ };
57434
+ var getGlobalFileS3Key = (type, name) => {
57435
+ let file = `${type}/${name}`;
57436
+ if (environment_default.MULTI_TENANCY) {
57437
+ const tenantId = getTenantId();
57438
+ file = `${tenantId}/${file}`;
57439
+ }
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
+ });
57033
57453
  }
57034
- function doInScimContext(task) {
57035
- const updates = {
57036
- isScim: true
57037
- };
57038
- return newContext(updates, task);
57454
+ function getPluginJSUrl(plugin) {
57455
+ const s3Key = getPluginJSKey(plugin);
57456
+ return getPluginUrl(s3Key);
57039
57457
  }
57040
- async function ensureSnippetContext(enabled2 = !environment_default.isTest()) {
57041
- const ctx = getCurrentContext();
57042
- if (!ctx || ctx.snippets) {
57458
+ function getPluginIconUrl(plugin) {
57459
+ const s3Key = getPluginIconKey(plugin);
57460
+ if (!s3Key) {
57043
57461
  return;
57044
57462
  }
57045
- let snippets;
57046
- const db = getAppDB();
57047
- if (db && enabled2) {
57048
- const app = await db.get("app_metadata" /* APP_METADATA */);
57049
- snippets = app.snippets;
57050
- }
57051
- ctx.snippets = snippets || [];
57463
+ return getPluginUrl(s3Key);
57052
57464
  }
57053
- function getEnvironmentVariables() {
57054
- const context = Context.get();
57055
- if (!context.environmentVariables) {
57056
- return null;
57465
+ function getPluginUrl(s3Key) {
57466
+ if (environment_default.CLOUDFRONT_CDN) {
57467
+ return getPresignedUrl2(s3Key);
57057
57468
  } else {
57058
- return context.environmentVariables;
57469
+ return getPresignedUrl(environment_default.PLUGIN_BUCKET_NAME, s3Key);
57059
57470
  }
57060
57471
  }
57061
- function getGlobalDB() {
57062
- const context = Context.get();
57063
- if (!context || environment_default.MULTI_TENANCY && !context.tenantId) {
57064
- throw new Error("Global DB not found");
57065
- }
57066
- return getDB(baseGlobalDBName(context?.tenantId));
57472
+ function getPluginJSKey(plugin) {
57473
+ return getPluginS3Key(plugin, "plugin.min.js");
57067
57474
  }
57068
- function getAuditLogsDB() {
57069
- if (!getTenantId()) {
57070
- 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;
57071
57479
  }
57072
- return getDB(getAuditLogDBName());
57480
+ return getPluginS3Key(plugin, iconFileName);
57073
57481
  }
57074
- function getAppDB(opts) {
57075
- const appId = getAppId();
57076
- if (!appId) {
57077
- throw new Error("Unable to retrieve app DB - no app ID.");
57078
- }
57079
- return getDB(appId, opts);
57482
+ function getPluginS3Key(plugin, fileName) {
57483
+ const s3Key = getPluginS3Dir(plugin.name);
57484
+ return `${s3Key}/${fileName}`;
57080
57485
  }
57081
- function getProdAppDB(opts) {
57082
- const appId = getAppId();
57083
- if (!appId) {
57084
- 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}`;
57085
57491
  }
57086
- return getDB(getProdAppID2(appId), opts);
57087
- }
57088
- function getDevAppDB(opts) {
57089
- const appId = getAppId();
57090
- if (!appId) {
57091
- throw new Error("Unable to retrieve dev DB - no app ID.");
57492
+ if (environment_default.CLOUDFRONT_CDN) {
57493
+ s3Key = `plugins/${s3Key}`;
57092
57494
  }
57093
- return getDB(getDevelopmentAppID(appId), opts);
57495
+ return s3Key;
57094
57496
  }
57095
- function isScim() {
57096
- const context = Context.get();
57097
- const scimCall = context?.isScim;
57098
- 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);
57099
57504
  }
57100
- function getCurrentContext() {
57101
- try {
57102
- return Context.get();
57103
- } 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
+ });
57104
57512
  return void 0;
57105
57513
  }
57106
- }
57107
-
57108
- // src/redis/init.ts
57109
- var init_exports = {};
57110
- __export(init_exports, {
57111
- getAppClient: () => getAppClient,
57112
- getCacheClient: () => getCacheClient,
57113
- getDocWritethroughClient: () => getDocWritethroughClient,
57114
- getInviteClient: () => getInviteClient,
57115
- getLockClient: () => getLockClient,
57116
- getPasswordResetClient: () => getPasswordResetClient,
57117
- getSessionClient: () => getSessionClient,
57118
- getSocketClient: () => getSocketClient,
57119
- getUserClient: () => getUserClient,
57120
- getWritethroughClient: () => getWritethroughClient,
57121
- init: () => init3,
57122
- shutdown: () => shutdown
57123
- });
57124
-
57125
- // src/redis/redis.ts
57126
- var import_ioredis = __toESM(require("ioredis"));
57127
-
57128
- // src/redis/utils.ts
57129
- var utils_exports2 = {};
57130
- __export(utils_exports2, {
57131
- Databases: () => Databases,
57132
- SEPARATOR: () => SEPARATOR2,
57133
- SelectableDatabase: () => SelectableDatabase,
57134
- addDbPrefix: () => addDbPrefix,
57135
- getRedisConnectionDetails: () => getRedisConnectionDetails,
57136
- getRedisOptions: () => getRedisOptions,
57137
- removeDbPrefix: () => removeDbPrefix
57138
- });
57139
- var SLOT_REFRESH_MS = 2e3;
57140
- var CONNECT_TIMEOUT_MS = 1e4;
57141
- var SEPARATOR2 = "-";
57142
- var Databases = /* @__PURE__ */ ((Databases2) => {
57143
- Databases2["PW_RESETS"] = "pwReset";
57144
- Databases2["VERIFICATIONS"] = "verification";
57145
- Databases2["INVITATIONS"] = "invitation";
57146
- Databases2["DEV_LOCKS"] = "devLocks";
57147
- Databases2["DEBOUNCE"] = "debounce";
57148
- Databases2["SESSIONS"] = "session";
57149
- Databases2["USER_CACHE"] = "users";
57150
- Databases2["FLAGS"] = "flags";
57151
- Databases2["APP_METADATA"] = "appMetadata";
57152
- Databases2["QUERY_VARS"] = "queryVars";
57153
- Databases2["LICENSES"] = "license";
57154
- Databases2["GENERIC_CACHE"] = "data_cache";
57155
- Databases2["WRITE_THROUGH"] = "writeThrough";
57156
- Databases2["LOCKS"] = "locks";
57157
- Databases2["SOCKET_IO"] = "socket_io";
57158
- Databases2["BPM_EVENTS"] = "bpmEvents";
57159
- Databases2["DOC_WRITE_THROUGH"] = "docWriteThrough";
57160
- return Databases2;
57161
- })(Databases || {});
57162
- var SelectableDatabase = /* @__PURE__ */ ((SelectableDatabase2) => {
57163
- SelectableDatabase2[SelectableDatabase2["DEFAULT"] = 0] = "DEFAULT";
57164
- SelectableDatabase2[SelectableDatabase2["SOCKET_IO"] = 1] = "SOCKET_IO";
57165
- SelectableDatabase2[SelectableDatabase2["RATE_LIMITING"] = 2] = "RATE_LIMITING";
57166
- SelectableDatabase2[SelectableDatabase2["UNUSED_2"] = 3] = "UNUSED_2";
57167
- SelectableDatabase2[SelectableDatabase2["UNUSED_3"] = 4] = "UNUSED_3";
57168
- SelectableDatabase2[SelectableDatabase2["UNUSED_4"] = 5] = "UNUSED_4";
57169
- SelectableDatabase2[SelectableDatabase2["UNUSED_5"] = 6] = "UNUSED_5";
57170
- SelectableDatabase2[SelectableDatabase2["UNUSED_6"] = 7] = "UNUSED_6";
57171
- SelectableDatabase2[SelectableDatabase2["UNUSED_7"] = 8] = "UNUSED_7";
57172
- SelectableDatabase2[SelectableDatabase2["UNUSED_8"] = 9] = "UNUSED_8";
57173
- SelectableDatabase2[SelectableDatabase2["UNUSED_9"] = 10] = "UNUSED_9";
57174
- SelectableDatabase2[SelectableDatabase2["UNUSED_10"] = 11] = "UNUSED_10";
57175
- SelectableDatabase2[SelectableDatabase2["UNUSED_11"] = 12] = "UNUSED_11";
57176
- SelectableDatabase2[SelectableDatabase2["UNUSED_12"] = 13] = "UNUSED_12";
57177
- SelectableDatabase2[SelectableDatabase2["UNUSED_13"] = 14] = "UNUSED_13";
57178
- SelectableDatabase2[SelectableDatabase2["UNUSED_14"] = 15] = "UNUSED_14";
57179
- return SelectableDatabase2;
57180
- })(SelectableDatabase || {});
57181
- function getRedisConnectionDetails() {
57182
- let password = environment_default.REDIS_PASSWORD;
57183
- let url = environment_default.REDIS_URL.split("//");
57184
- url = url.length > 1 ? url[1] : url[0];
57185
- url = url.split("@");
57186
- if (url.length > 1) {
57187
- password = url[0].split(":")[1];
57188
- url = url[1];
57189
- } else {
57190
- 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
+ }
57191
57529
  }
57192
- const [host, port] = url.split(":");
57193
- const portNumber = parseInt(port);
57194
- return {
57195
- host,
57196
- password,
57197
- // assume default port for redis if invalid found
57198
- port: isNaN(portNumber) ? 6379 : portNumber
57199
- };
57530
+ if (size % 2 === 0) {
57531
+ return { size: `${size / 2}${unit}`, totalHistoryFiles: 1 };
57532
+ }
57533
+ return { size: `1${unit}`, totalHistoryFiles: size - 1 };
57200
57534
  }
57201
- function getRedisOptions() {
57202
- const { host, password, port } = getRedisConnectionDetails();
57203
- let redisOpts = {
57204
- connectTimeout: CONNECT_TIMEOUT_MS,
57205
- port,
57206
- host,
57207
- password
57208
- };
57209
- let opts = redisOpts;
57210
- if (environment_default.REDIS_CLUSTERED) {
57211
- opts = {
57212
- connectTimeout: CONNECT_TIMEOUT_MS,
57213
- redisOptions: {
57214
- ...redisOpts,
57215
- tls: {}
57216
- },
57217
- slotsRefreshTimeout: SLOT_REFRESH_MS,
57218
- dnsLookup: (address, callback) => callback(null, address)
57219
- };
57220
- }
57221
- 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;
57222
57547
  }
57223
- function addDbPrefix(db, key) {
57224
- if (key.includes(db)) {
57225
- 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
+ }
57226
57557
  }
57227
- return `${db}${SEPARATOR2}${key}`;
57558
+ streams.push(import_fs4.default.readFileSync(getFullPath(logsFileName)));
57559
+ const combinedContent = Buffer.concat(streams);
57560
+ return combinedContent;
57228
57561
  }
57229
- function removeDbPrefix(key) {
57230
- let parts = key.split(SEPARATOR2);
57231
- if (parts.length >= 2) {
57232
- parts.shift();
57233
- return parts.join(SEPARATOR2);
57234
- } else {
57235
- 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
+ });
57236
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
+ };
57237
57721
  }
57722
+ var logger = pinoInstance;
57238
57723
 
57239
- // src/logging/index.ts
57240
- var logging_exports = {};
57241
- __export(logging_exports, {
57242
- correlation: () => correlation_exports,
57243
- logAlert: () => logAlert,
57244
- logAlertWithInfo: () => logAlertWithInfo,
57245
- logWarn: () => logWarn,
57246
- logger: () => logger,
57247
- system: () => system_exports
57248
- });
57249
-
57250
- // src/logging/correlation/correlation.ts
57251
- var correlation_exports = {};
57252
- __export(correlation_exports, {
57253
- getId: () => getId,
57254
- setHeader: () => setHeader
57255
- });
57256
- var correlator = require("correlation-id");
57257
- var setHeader = (headers) => {
57258
- const correlationId = correlator.getId();
57259
- 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)) {
57260
57731
  return;
57261
57732
  }
57262
- headers["x-budibase-correlation-id" /* CORRELATION_ID */] = correlationId;
57263
- };
57264
- function getId() {
57265
- 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);
57266
57741
  }
57267
57742
 
57268
- // src/logging/pino/logger.ts
57269
- var import_pino = __toESM(require("pino"));
57270
- var import_pino_pretty = __toESM(require("pino-pretty"));
57271
- var import_dd_trace2 = __toESM(require("dd-trace"));
57272
- var import_ext = require("dd-trace/ext");
57273
-
57274
- // src/logging/system.ts
57275
- var system_exports = {};
57276
- __export(system_exports, {
57277
- getLogReadStream: () => getLogReadStream,
57278
- getSingleFileMaxSizeInfo: () => getSingleFileMaxSizeInfo,
57279
- localFileDestination: () => localFileDestination
57280
- });
57281
- var import_fs4 = __toESM(require("fs"));
57282
- var import_path3 = __toESM(require("path"));
57283
- var rfs = __toESM(require("rotating-file-stream"));
57284
-
57285
- // src/objectStore/index.ts
57286
- var objectStore_exports2 = {};
57287
- __export(objectStore_exports2, {
57288
- ObjectStore: () => ObjectStore,
57289
- ObjectStoreBuckets: () => ObjectStoreBuckets,
57290
- SIGNED_FILE_PREFIX: () => SIGNED_FILE_PREFIX,
57291
- bucketTTLConfig: () => bucketTTLConfig,
57292
- budibaseTempDir: () => budibaseTempDir,
57293
- clientLibraryCDNUrl: () => clientLibraryCDNUrl,
57294
- clientLibraryPath: () => clientLibraryPath,
57295
- clientLibraryUrl: () => clientLibraryUrl,
57296
- createBucketIfNotExists: () => createBucketIfNotExists,
57297
- deleteFile: () => deleteFile,
57298
- deleteFiles: () => deleteFiles,
57299
- deleteFolder: () => deleteFolder,
57300
- downloadTarball: () => downloadTarball,
57301
- downloadTarballDirect: () => downloadTarballDirect,
57302
- enrichPluginURLs: () => enrichPluginURLs,
57303
- extractBucketAndPath: () => extractBucketAndPath,
57304
- getAppFileUrl: () => getAppFileUrl,
57305
- getGlobalFileS3Key: () => getGlobalFileS3Key,
57306
- getGlobalFileUrl: () => getGlobalFileUrl,
57307
- getObjectMetadata: () => getObjectMetadata,
57308
- getPluginIconKey: () => getPluginIconKey,
57309
- getPluginJSKey: () => getPluginJSKey,
57310
- getPluginS3Dir: () => getPluginS3Dir,
57311
- getPresignedUrl: () => getPresignedUrl,
57312
- getReadStream: () => getReadStream,
57313
- listAllObjects: () => listAllObjects,
57314
- processAutomationAttachment: () => processAutomationAttachment,
57315
- processObjectStoreAttachment: () => processObjectStoreAttachment,
57316
- retrieve: () => retrieve,
57317
- retrieveDirectory: () => retrieveDirectory,
57318
- retrieveToTmp: () => retrieveToTmp,
57319
- sanitizeBucket: () => sanitizeBucket,
57320
- sanitizeKey: () => sanitizeKey,
57321
- streamUpload: () => streamUpload,
57322
- upload: () => upload,
57323
- uploadDirectory: () => uploadDirectory
57743
+ // src/timers/index.ts
57744
+ var timers_exports = {};
57745
+ __export(timers_exports, {
57746
+ cleanup: () => cleanup,
57747
+ clear: () => clear,
57748
+ set: () => set
57324
57749
  });
57325
57750
 
57326
- // src/objectStore/objectStore.ts
57327
- var import_aws_sdk = __toESM(require("aws-sdk"));
57328
- var import_stream2 = __toESM(require("stream"));
57329
- var import_node_fetch3 = __toESM(require("node-fetch"));
57330
- var import_tar_fs = __toESM(require("tar-fs"));
57331
- var import_zlib = __toESM(require("zlib"));
57332
- var import_util = require("util");
57333
- var import_path2 = require("path");
57334
- var import_fs3 = __toESM(require("fs"));
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
+ }
57335
57771
 
57336
- // src/objectStore/utils.ts
57337
- var import_path = __toESM(require("path"));
57338
- var import_os = require("os");
57339
- var import_fs2 = __toESM(require("fs"));
57340
- var import_stream = __toESM(require("stream"));
57341
- var ObjectStoreBuckets = {
57342
- BACKUPS: environment_default.BACKUPS_BUCKET_NAME,
57343
- APPS: environment_default.APPS_BUCKET_NAME,
57344
- TEMPLATES: environment_default.TEMPLATES_BUCKET_NAME,
57345
- GLOBAL: environment_default.GLOBAL_BUCKET_NAME,
57346
- PLUGINS: environment_default.PLUGIN_BUCKET_NAME,
57347
- TEMP: environment_default.TEMP_BUCKET_NAME
57348
- };
57349
- var bbTmp = (0, import_path.join)((0, import_os.tmpdir)(), ".budibase");
57350
- try {
57351
- import_fs2.default.mkdirSync(bbTmp);
57352
- } catch (e) {
57353
- if (e.code !== "EEXIST") {
57354
- throw e;
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);
57355
58013
  }
57356
- }
57357
- function budibaseTempDir() {
57358
- return bbTmp;
57359
- }
57360
- var bucketTTLConfig = (bucketName, days) => {
57361
- const lifecycleRule = {
57362
- ID: `${bucketName}-ExpireAfter${days}days`,
57363
- Prefix: "",
57364
- Status: "Enabled",
57365
- Expiration: {
57366
- Days: days
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`);
57367
58030
  }
57368
- };
57369
- const lifecycleConfiguration = {
57370
- Rules: [lifecycleRule]
57371
- };
57372
- return {
57373
- Bucket: bucketName,
57374
- LifecycleConfiguration: lifecycleConfiguration
57375
- };
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
+ }
57376
58042
  };
57377
- async function processUrlAttachment(attachment) {
57378
- const response = await fetch(attachment.url);
57379
- if (!response.ok || !response.body) {
57380
- throw new Error(`Unexpected response ${response.statusText}`);
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();
58097
+ });
58098
+ async function getUserClient() {
58099
+ if (!userClient) {
58100
+ await init3();
57381
58101
  }
57382
- const fallbackFilename = import_path.default.basename(new URL(attachment.url).pathname);
57383
- if (!response.body) {
57384
- throw new Error("No response received for attachment");
58102
+ return userClient;
58103
+ }
58104
+ async function getSessionClient() {
58105
+ if (!sessionClient) {
58106
+ await init3();
57385
58107
  }
57386
- return {
57387
- filename: attachment.filename || fallbackFilename,
57388
- content: import_stream.default.Readable.fromWeb(response.body)
57389
- };
58108
+ return sessionClient;
57390
58109
  }
57391
- async function processObjectStoreAttachment(attachment) {
57392
- const result = extractBucketAndPath(attachment.url);
57393
- if (result === null) {
57394
- throw new Error("Invalid signed URL");
58110
+ async function getAppClient() {
58111
+ if (!appClient) {
58112
+ await init3();
57395
58113
  }
57396
- const { bucket, path: objectPath } = result;
57397
- const readStream = await getReadStream(bucket, objectPath);
57398
- const fallbackFilename = import_path.default.basename(objectPath);
57399
- return {
57400
- bucket,
57401
- path: objectPath,
57402
- filename: attachment.filename || fallbackFilename,
57403
- content: readStream
57404
- };
58114
+ return appClient;
57405
58115
  }
57406
- async function processAutomationAttachment(attachment) {
57407
- const isFullyFormedUrl = attachment.url?.startsWith("http://") || attachment.url?.startsWith("https://");
57408
- if (isFullyFormedUrl) {
57409
- return await processUrlAttachment(attachment);
57410
- } else {
57411
- return await processObjectStoreAttachment(attachment);
58116
+ async function getCacheClient() {
58117
+ if (!cacheClient) {
58118
+ await init3();
57412
58119
  }
58120
+ return cacheClient;
58121
+ }
58122
+ async function getWritethroughClient() {
58123
+ if (!writethroughClient) {
58124
+ await init3();
58125
+ }
58126
+ return writethroughClient;
58127
+ }
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();
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;
57413
58157
  }
57414
-
57415
- // src/objectStore/objectStore.ts
57416
- var import_uuid2 = require("uuid");
57417
-
57418
- // src/db/index.ts
57419
- var db_exports = {};
57420
- __export(db_exports, {
57421
- APP_DEV: () => APP_DEV,
57422
- APP_DEV_PREFIX: () => APP_DEV_PREFIX2,
57423
- APP_PREFIX: () => APP_PREFIX2,
57424
- AutomationViewMode: () => AutomationViewMode,
57425
- BUDIBASE_DATASOURCE_TYPE: () => BUDIBASE_DATASOURCE_TYPE,
57426
- CONSTANT_EXTERNAL_ROW_COLS: () => CONSTANT_EXTERNAL_ROW_COLS,
57427
- CONSTANT_INTERNAL_ROW_COLS: () => CONSTANT_INTERNAL_ROW_COLS,
57428
- DEFAULT_BB_DATASOURCE_ID: () => DEFAULT_BB_DATASOURCE_ID,
57429
- DEFAULT_EMPLOYEE_TABLE_ID: () => DEFAULT_EMPLOYEE_TABLE_ID,
57430
- DEFAULT_EXPENSES_TABLE_ID: () => DEFAULT_EXPENSES_TABLE_ID,
57431
- DEFAULT_INVENTORY_TABLE_ID: () => DEFAULT_INVENTORY_TABLE_ID,
57432
- DEFAULT_JOBS_TABLE_ID: () => DEFAULT_JOBS_TABLE_ID,
57433
- DatabaseImpl: () => DatabaseImpl,
57434
- DatabaseWithConnection: () => DatabaseWithConnection,
57435
- DeprecatedViews: () => DeprecatedViews,
57436
- DocumentType: () => DocumentType,
57437
- InternalTable: () => InternalTable,
57438
- QueryBuilder: () => QueryBuilder,
57439
- Replication: () => Replication_default,
57440
- SEPARATOR: () => SEPARATOR,
57441
- SQLITE_DESIGN_DOC_ID: () => SQLITE_DESIGN_DOC_ID,
57442
- SQS_DATASOURCE_INTERNAL: () => SQS_DATASOURCE_INTERNAL,
57443
- StaticDatabases: () => StaticDatabases,
57444
- UNICODE_MAX: () => UNICODE_MAX,
57445
- ViewName: () => ViewName,
57446
- baseGlobalDBName: () => baseGlobalDBName,
57447
- checkErrorCode: () => checkErrorCode,
57448
- closePouchDB: () => closePouchDB,
57449
- createApiKeyView: () => createApiKeyView,
57450
- createNewUserEmailView: () => createNewUserEmailView,
57451
- createPlatformAccountEmailView: () => createPlatformAccountEmailView,
57452
- createPlatformUserView: () => createPlatformUserView,
57453
- createUserAppView: () => createUserAppView,
57454
- createView: () => createView,
57455
- dbExists: () => dbExists,
57456
- directCouchAllDbs: () => directCouchAllDbs,
57457
- directCouchCall: () => directCouchCall,
57458
- directCouchFind: () => directCouchFind,
57459
- directCouchQuery: () => directCouchQuery,
57460
- directCouchUrlCall: () => directCouchUrlCall,
57461
- doWithDB: () => doWithDB,
57462
- extractAppUUID: () => extractAppUUID,
57463
- fullSearch: () => fullSearch,
57464
- generateAppID: () => generateAppID,
57465
- generateAppUserID: () => generateAppUserID,
57466
- generateDevInfoID: () => generateDevInfoID,
57467
- generateGlobalUserID: () => generateGlobalUserID,
57468
- generatePluginID: () => generatePluginID,
57469
- generateRoleID: () => generateRoleID,
57470
- generateRowID: () => generateRowID,
57471
- generateTableID: () => generateTableID,
57472
- generateTemplateID: () => generateTemplateID,
57473
- generateUserMetadataID: () => generateUserMetadataID,
57474
- generateWorkspaceID: () => generateWorkspaceID,
57475
- getAllApps: () => getAllApps,
57476
- getAllDbs: () => getAllDbs,
57477
- getAppsByIDs: () => getAppsByIDs,
57478
- getCouchInfo: () => getCouchInfo,
57479
- getDB: () => getDB,
57480
- getDevAppID: () => getDevAppID2,
57481
- getDevAppIDs: () => getDevAppIDs,
57482
- getDevelopmentAppID: () => getDevelopmentAppID,
57483
- getDocParams: () => getDocParams,
57484
- getGlobalDBName: () => getGlobalDBName,
57485
- getGlobalIDFromUserMetadataID: () => getGlobalIDFromUserMetadataID,
57486
- getGlobalUserParams: () => getGlobalUserParams,
57487
- getPluginParams: () => getPluginParams,
57488
- getPouch: () => getPouch,
57489
- getPouchDB: () => getPouchDB,
57490
- getProdAppID: () => getProdAppID2,
57491
- getProdAppIDs: () => getProdAppIDs,
57492
- getQueryIndex: () => getQueryIndex,
57493
- getRoleParams: () => getRoleParams,
57494
- getRowParams: () => getRowParams,
57495
- getStartEndKeyURL: () => getStartEndKeyURL,
57496
- getTemplateParams: () => getTemplateParams,
57497
- getUrlInfo: () => getUrlInfo,
57498
- getUserMetadataParams: () => getUserMetadataParams,
57499
- getUsersByAppParams: () => getUsersByAppParams,
57500
- getWorkspaceParams: () => getWorkspaceParams,
57501
- init: () => init,
57502
- isDatasourceId: () => isDatasourceId,
57503
- isDevApp: () => isDevApp,
57504
- isDevAppID: () => isDevAppID,
57505
- isDocumentConflictError: () => isDocumentConflictError,
57506
- isGlobalUserID: () => isGlobalUserID,
57507
- isInternalColumnName: () => isInternalColumnName,
57508
- isProdAppID: () => isProdAppID,
57509
- isSameAppID: () => isSameAppID,
57510
- isTableId: () => isTableId,
57511
- paginatedSearch: () => paginatedSearch,
57512
- pagination: () => pagination,
57513
- prefixRoleID: () => prefixRoleID,
57514
- queryGlobalView: () => queryGlobalView,
57515
- queryGlobalViewRaw: () => queryGlobalViewRaw,
57516
- queryPlatformView: () => queryPlatformView,
57517
- queryView: () => queryView,
57518
- queryViewRaw: () => queryViewRaw,
57519
- removeKeyNumbering: () => removeKeyNumbering2,
57520
- searchIndexes: () => searchIndexes_exports
57521
- });
57522
58158
 
57523
58159
  // src/cache/appMetadata.ts
57524
- var appMetadata_exports = {};
57525
- __export(appMetadata_exports, {
57526
- AppState: () => AppState,
57527
- getAppMetadata: () => getAppMetadata,
57528
- invalidateAppMetadata: () => invalidateAppMetadata
57529
- });
57530
58160
  var AppState = /* @__PURE__ */ ((AppState2) => {
57531
58161
  AppState2["INVALID"] = "invalid";
57532
58162
  return AppState2;
@@ -58118,7 +58748,7 @@ var Replication = class {
58118
58748
  var Replication_default = Replication;
58119
58749
 
58120
58750
  // src/db/lucene.ts
58121
- var import_node_fetch2 = __toESM(require("node-fetch"));
58751
+ var import_node_fetch3 = __toESM(require("node-fetch"));
58122
58752
  var removeKeyNumbering2 = filters_exports.removeKeyNumbering;
58123
58753
  function isEmpty(value) {
58124
58754
  return value == null || value === "";
@@ -58573,7 +59203,7 @@ var QueryBuilder = class _QueryBuilder {
58573
59203
  }
58574
59204
  };
58575
59205
  async function runQuery2(url, body2, cookie) {
58576
- const response = await (0, import_node_fetch2.default)(url, {
59206
+ const response = await (0, import_node_fetch3.default)(url, {
58577
59207
  body: JSON.stringify(body2),
58578
59208
  method: "POST",
58579
59209
  headers: {
@@ -58633,1323 +59263,833 @@ async function paginatedSearch(dbName, index2, query, params2) {
58633
59263
  if (limit2 == null || isNaN(limit2) || limit2 < 0) {
58634
59264
  limit2 = 50;
58635
59265
  }
58636
- limit2 = Math.min(limit2, QueryBuilder.maxLimit);
58637
- const search2 = new QueryBuilder(dbName, index2, query);
58638
- if (params2.version) {
58639
- search2.setVersion(params2.version);
58640
- }
58641
- if (params2.tableId) {
58642
- search2.setTable(params2.tableId);
58643
- }
58644
- if (params2.sort) {
58645
- search2.setSort(params2.sort).setSortOrder(params2.sortOrder).setSortType(params2.sortType);
58646
- }
58647
- if (params2.indexer) {
58648
- search2.setIndexBuilder(params2.indexer);
58649
- }
58650
- if (params2.disableEscaping) {
58651
- search2.disableEscaping();
58652
- }
58653
- const searchResults = await search2.setBookmark(params2.bookmark).setLimit(limit2).run();
58654
- search2.setBookmark(searchResults.bookmark).setLimit(1);
58655
- if (params2.tableId) {
58656
- search2.setTable(params2.tableId);
58657
- }
58658
- const nextResults = await search2.run();
58659
- return {
58660
- ...searchResults,
58661
- hasNextPage: nextResults.rows && nextResults.rows.length > 0
58662
- };
58663
- }
58664
- async function fullSearch(dbName, index2, query, params2) {
58665
- let limit2 = params2.limit;
58666
- if (limit2 == null || isNaN(limit2) || limit2 < 0) {
58667
- limit2 = 1e3;
58668
- }
58669
- params2.limit = Math.min(limit2, 1e3);
58670
- const rows = await recursiveSearch(dbName, index2, query, params2);
58671
- return { rows };
58672
- }
58673
-
58674
- // src/db/searchIndexes/index.ts
58675
- var searchIndexes_exports = {};
58676
- __export(searchIndexes_exports, {
58677
- createUserIndex: () => createUserIndex
58678
- });
58679
-
58680
- // src/db/searchIndexes/searchIndexes.ts
58681
- async function createUserIndex() {
58682
- const db = getGlobalDB();
58683
- let designDoc;
58684
- try {
58685
- designDoc = await db.get("_design/database");
58686
- } catch (err) {
58687
- if (err.status === 404) {
58688
- designDoc = { _id: "_design/database" };
58689
- }
58690
- }
58691
- const fn = function(user) {
58692
- if (user._id && !user._id.startsWith("us_")) {
58693
- return;
58694
- }
58695
- const ignoredFields = [
58696
- "_id",
58697
- "_rev",
58698
- "password",
58699
- "account",
58700
- "license",
58701
- "budibaseAccess",
58702
- "accountPortalAccess",
58703
- "csrfToken"
58704
- ];
58705
- function idx(input, prev) {
58706
- for (let key of Object.keys(input)) {
58707
- if (ignoredFields.includes(key)) {
58708
- continue;
58709
- }
58710
- let idxKey = prev != null ? `${prev}.${key}` : key;
58711
- if (typeof input[key] === "string") {
58712
- index(idxKey, input[key].toLowerCase(), { facet: true });
58713
- } else if (typeof input[key] !== "object") {
58714
- index(idxKey, input[key], { facet: true });
58715
- } else {
58716
- idx(input[key], idxKey);
58717
- }
58718
- }
58719
- }
58720
- idx(user);
58721
- };
58722
- designDoc.indexes = {
58723
- ["user" /* USER */]: {
58724
- index: fn.toString(),
58725
- analyzer: {
58726
- default: "keyword",
58727
- name: "perfield"
58728
- }
58729
- }
58730
- };
58731
- await db.put(designDoc);
58732
- }
58733
-
58734
- // src/db/errors.ts
58735
- function checkErrorCode(error, code) {
58736
- const stringCode = code.toString();
58737
- if (typeof error === "object") {
58738
- return error.status === code || error.message?.includes(stringCode);
58739
- } else if (typeof error === "number") {
58740
- return error === code;
58741
- } else if (typeof error === "string") {
58742
- return error.includes(stringCode);
58743
- }
58744
- }
58745
- function isDocumentConflictError(error) {
58746
- return checkErrorCode(error, 409);
58747
- }
58748
-
58749
- // src/objectStore/objectStore.ts
58750
- var import_promises = __toESM(require("fs/promises"));
58751
- var sanitize = require("sanitize-s3-objectkey");
58752
- var streamPipeline = (0, import_util.promisify)(import_stream2.default.pipeline);
58753
- var STATE = {
58754
- bucketCreationPromises: {}
58755
- };
58756
- var SIGNED_FILE_PREFIX = "/files/signed";
58757
- var CONTENT_TYPE_MAP = {
58758
- txt: "text/plain",
58759
- html: "text/html",
58760
- css: "text/css",
58761
- js: "application/javascript",
58762
- json: "application/json",
58763
- gz: "application/gzip",
58764
- svg: "image/svg+xml",
58765
- form: "multipart/form-data"
58766
- };
58767
- var STRING_CONTENT_TYPES = [
58768
- CONTENT_TYPE_MAP.html,
58769
- CONTENT_TYPE_MAP.css,
58770
- CONTENT_TYPE_MAP.js,
58771
- CONTENT_TYPE_MAP.json
58772
- ];
58773
- function sanitizeKey(input) {
58774
- return sanitize(sanitizeBucket(input)).replace(/\\/g, "/");
58775
- }
58776
- function sanitizeBucket(input) {
58777
- return input.replace(new RegExp(APP_DEV_PREFIX2, "g"), APP_PREFIX2);
58778
- }
58779
- function ObjectStore(bucket, opts = { presigning: false }) {
58780
- const config = {
58781
- s3ForcePathStyle: true,
58782
- signatureVersion: "v4",
58783
- apiVersion: "2006-03-01",
58784
- accessKeyId: environment_default.MINIO_ACCESS_KEY,
58785
- secretAccessKey: environment_default.MINIO_SECRET_KEY,
58786
- region: environment_default.AWS_REGION
58787
- };
58788
- if (bucket) {
58789
- config.params = {
58790
- Bucket: sanitizeBucket(bucket)
58791
- };
58792
- }
58793
- if (!environment_default.MINIO_ENABLED && environment_default.AWS_SESSION_TOKEN) {
58794
- config.sessionToken = environment_default.AWS_SESSION_TOKEN;
58795
- }
58796
- if (environment_default.MINIO_URL) {
58797
- if (opts.presigning && environment_default.MINIO_ENABLED) {
58798
- config.endpoint = "minio-service";
58799
- } else {
58800
- config.endpoint = environment_default.MINIO_URL;
58801
- }
58802
- }
58803
- return new import_aws_sdk.default.S3(config);
58804
- }
58805
- async function createBucketIfNotExists(client, bucketName) {
58806
- bucketName = sanitizeBucket(bucketName);
58807
- try {
58808
- await client.headBucket({
58809
- Bucket: bucketName
58810
- }).promise();
58811
- return { created: false, exists: true };
58812
- } catch (err) {
58813
- const promises = STATE.bucketCreationPromises;
58814
- const doesntExist = err.statusCode === 404, noAccess = err.statusCode === 403;
58815
- if (promises[bucketName]) {
58816
- await promises[bucketName];
58817
- return { created: false, exists: true };
58818
- } else if (doesntExist || noAccess) {
58819
- if (doesntExist) {
58820
- promises[bucketName] = client.createBucket({
58821
- Bucket: bucketName
58822
- }).promise();
58823
- await promises[bucketName];
58824
- delete promises[bucketName];
58825
- return { created: true, exists: false };
58826
- } else {
58827
- throw new Error("Access denied to object store bucket." + err);
58828
- }
58829
- } else {
58830
- throw new Error("Unable to write to object store bucket.");
58831
- }
58832
- }
58833
- }
58834
- async function upload({
58835
- bucket: bucketName,
58836
- filename,
58837
- path: path3,
58838
- type,
58839
- metadata,
58840
- body: body2,
58841
- ttl
58842
- }) {
58843
- const extension = filename.split(".").pop();
58844
- const fileBytes = path3 ? (await import_promises.default.open(path3)).createReadStream() : body2;
58845
- const objectStore = ObjectStore(bucketName);
58846
- const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
58847
- if (ttl && bucketCreated.created) {
58848
- let ttlConfig = bucketTTLConfig(bucketName, ttl);
58849
- await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
58850
- }
58851
- let contentType = type;
58852
- if (!contentType) {
58853
- contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
59266
+ limit2 = Math.min(limit2, QueryBuilder.maxLimit);
59267
+ const search2 = new QueryBuilder(dbName, index2, query);
59268
+ if (params2.version) {
59269
+ search2.setVersion(params2.version);
58854
59270
  }
58855
- const config = {
58856
- // windows file paths need to be converted to forward slashes for s3
58857
- Key: sanitizeKey(filename),
58858
- Body: fileBytes,
58859
- ContentType: contentType
58860
- };
58861
- if (metadata && typeof metadata === "object") {
58862
- for (let key of Object.keys(metadata)) {
58863
- if (!metadata[key] || typeof metadata[key] !== "string") {
58864
- delete metadata[key];
58865
- }
58866
- }
58867
- config.Metadata = metadata;
59271
+ if (params2.tableId) {
59272
+ search2.setTable(params2.tableId);
58868
59273
  }
58869
- return objectStore.upload(config).promise();
58870
- }
58871
- async function streamUpload({
58872
- bucket: bucketName,
58873
- stream: stream3,
58874
- filename,
58875
- type,
58876
- extra,
58877
- ttl
58878
- }) {
58879
- if (!stream3) {
58880
- throw new Error("Stream to upload is invalid/undefined");
59274
+ if (params2.sort) {
59275
+ search2.setSort(params2.sort).setSortOrder(params2.sortOrder).setSortType(params2.sortType);
58881
59276
  }
58882
- const extension = filename.split(".").pop();
58883
- const objectStore = ObjectStore(bucketName);
58884
- const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
58885
- if (ttl && bucketCreated.created) {
58886
- let ttlConfig = bucketTTLConfig(bucketName, ttl);
58887
- await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
59277
+ if (params2.indexer) {
59278
+ search2.setIndexBuilder(params2.indexer);
58888
59279
  }
58889
- if (filename?.endsWith(".js")) {
58890
- extra = {
58891
- ...extra,
58892
- ContentType: "application/javascript"
58893
- };
58894
- } else if (filename?.endsWith(".svg")) {
58895
- extra = {
58896
- ...extra,
58897
- ContentType: "image"
58898
- };
59280
+ if (params2.disableEscaping) {
59281
+ search2.disableEscaping();
58899
59282
  }
58900
- let contentType = type;
58901
- if (!contentType) {
58902
- contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
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);
58903
59287
  }
58904
- const bucket = sanitizeBucket(bucketName), objKey = sanitizeKey(filename);
58905
- const params2 = {
58906
- Bucket: bucket,
58907
- Key: objKey,
58908
- Body: stream3,
58909
- ContentType: contentType,
58910
- ...extra
58911
- };
58912
- const details = await objectStore.upload(params2).promise();
58913
- const headDetails = await objectStore.headObject({
58914
- Bucket: bucket,
58915
- Key: objKey
58916
- }).promise();
59288
+ const nextResults = await search2.run();
58917
59289
  return {
58918
- ...details,
58919
- ContentLength: headDetails.ContentLength
59290
+ ...searchResults,
59291
+ hasNextPage: nextResults.rows && nextResults.rows.length > 0
58920
59292
  };
58921
59293
  }
58922
- async function retrieve(bucketName, filepath) {
58923
- const objectStore = ObjectStore(bucketName);
58924
- const params2 = {
58925
- Bucket: sanitizeBucket(bucketName),
58926
- Key: sanitizeKey(filepath)
58927
- };
58928
- const response = await objectStore.getObject(params2).promise();
58929
- if (STRING_CONTENT_TYPES.includes(response.ContentType)) {
58930
- return response.Body.toString("utf8");
58931
- } else {
58932
- 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;
58933
59298
  }
59299
+ params2.limit = Math.min(limit2, 1e3);
59300
+ const rows = await recursiveSearch(dbName, index2, query, params2);
59301
+ return { rows };
58934
59302
  }
58935
- async function listAllObjects(bucketName, path3) {
58936
- const objectStore = ObjectStore(bucketName);
58937
- const list = (params2 = {}) => {
58938
- return objectStore.listObjectsV2({
58939
- ...params2,
58940
- Bucket: sanitizeBucket(bucketName),
58941
- Prefix: sanitizeKey(path3)
58942
- }).promise();
58943
- };
58944
- let isTruncated = false, token, objects = [];
58945
- do {
58946
- let params2 = {};
58947
- if (token) {
58948
- params2.ContinuationToken = token;
58949
- }
58950
- const response = await list(params2);
58951
- if (response.Contents) {
58952
- 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" };
58953
59319
  }
58954
- isTruncated = !!response.IsTruncated;
58955
- token = response.NextContinuationToken;
58956
- } while (isTruncated && token);
58957
- return objects;
58958
- }
58959
- function getPresignedUrl(bucketName, key, durationSeconds = 3600) {
58960
- const objectStore = ObjectStore(bucketName, { presigning: true });
58961
- const params2 = {
58962
- Bucket: sanitizeBucket(bucketName),
58963
- Key: sanitizeKey(key),
58964
- Expires: durationSeconds
58965
- };
58966
- const url = objectStore.getSignedUrl("getObject", params2);
58967
- if (!environment_default.MINIO_ENABLED) {
58968
- return url;
58969
- } else {
58970
- const signedUrl = new URL(url);
58971
- const path3 = signedUrl.pathname;
58972
- const query = signedUrl.search;
58973
- return `${SIGNED_FILE_PREFIX}${path3}${query}`;
58974
59320
  }
58975
- }
58976
- async function retrieveToTmp(bucketName, filepath) {
58977
- bucketName = sanitizeBucket(bucketName);
58978
- filepath = sanitizeKey(filepath);
58979
- const data = await retrieve(bucketName, filepath);
58980
- const outputPath = (0, import_path2.join)(budibaseTempDir(), (0, import_uuid2.v4)());
58981
- import_fs3.default.writeFileSync(outputPath, data);
58982
- return outputPath;
58983
- }
58984
- async function retrieveDirectory(bucketName, path3) {
58985
- let writePath = (0, import_path2.join)(budibaseTempDir(), (0, import_uuid2.v4)());
58986
- import_fs3.default.mkdirSync(writePath);
58987
- const objects = await listAllObjects(bucketName, path3);
58988
- let streams = await Promise.all(
58989
- objects.map((obj) => getReadStream(bucketName, obj.Key))
58990
- );
58991
- let count = 0;
58992
- const writePromises = [];
58993
- for (let obj of objects) {
58994
- const filename = obj.Key;
58995
- const stream3 = streams[count++];
58996
- const possiblePath = filename.split("/");
58997
- const dirs = possiblePath.slice(0, possiblePath.length - 1);
58998
- const possibleDir = (0, import_path2.join)(writePath, ...dirs);
58999
- if (possiblePath.length > 1 && !import_fs3.default.existsSync(possibleDir)) {
59000
- import_fs3.default.mkdirSync(possibleDir, { recursive: true });
59321
+ const fn = function(user) {
59322
+ if (user._id && !user._id.startsWith("us_")) {
59323
+ return;
59001
59324
  }
59002
- const writeStream = import_fs3.default.createWriteStream((0, import_path2.join)(writePath, ...possiblePath), {
59003
- mode: 420
59004
- });
59005
- stream3.pipe(writeStream);
59006
- writePromises.push(
59007
- new Promise((resolve, reject) => {
59008
- stream3.on("finish", resolve);
59009
- stream3.on("error", reject);
59010
- writeStream.on("error", reject);
59011
- })
59012
- );
59013
- }
59014
- await Promise.all(writePromises);
59015
- return writePath;
59016
- }
59017
- async function deleteFile(bucketName, filepath) {
59018
- const objectStore = ObjectStore(bucketName);
59019
- await createBucketIfNotExists(objectStore, bucketName);
59020
- const params2 = {
59021
- Bucket: bucketName,
59022
- Key: sanitizeKey(filepath)
59023
- };
59024
- return objectStore.deleteObject(params2).promise();
59025
- }
59026
- async function deleteFiles(bucketName, filepaths) {
59027
- const objectStore = ObjectStore(bucketName);
59028
- await createBucketIfNotExists(objectStore, bucketName);
59029
- const params2 = {
59030
- Bucket: bucketName,
59031
- Delete: {
59032
- 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
+ }
59033
59349
  }
59350
+ idx(user);
59034
59351
  };
59035
- return objectStore.deleteObjects(params2).promise();
59036
- }
59037
- async function deleteFolder(bucketName, folder) {
59038
- bucketName = sanitizeBucket(bucketName);
59039
- folder = sanitizeKey(folder);
59040
- const client = ObjectStore(bucketName);
59041
- const listParams = {
59042
- Bucket: bucketName,
59043
- Prefix: folder
59044
- };
59045
- const existingObjectsResponse = await client.listObjects(listParams).promise();
59046
- if (existingObjectsResponse.Contents?.length === 0) {
59047
- return;
59048
- }
59049
- const deleteParams = {
59050
- Bucket: bucketName,
59051
- Delete: {
59052
- Objects: []
59352
+ designDoc.indexes = {
59353
+ ["user" /* USER */]: {
59354
+ index: fn.toString(),
59355
+ analyzer: {
59356
+ default: "keyword",
59357
+ name: "perfield"
59358
+ }
59053
59359
  }
59054
59360
  };
59055
- existingObjectsResponse.Contents?.forEach((content) => {
59056
- deleteParams.Delete.Objects.push({ Key: content.Key });
59057
- });
59058
- const deleteResponse = await client.deleteObjects(deleteParams).promise();
59059
- if (deleteResponse.Deleted?.length === 1e3) {
59060
- return deleteFolder(bucketName, folder);
59061
- }
59361
+ await db.put(designDoc);
59062
59362
  }
59063
- async function uploadDirectory(bucketName, localPath, bucketPath) {
59064
- bucketName = sanitizeBucket(bucketName);
59065
- let uploads = [];
59066
- const files = import_fs3.default.readdirSync(localPath, { withFileTypes: true });
59067
- for (let file of files) {
59068
- const path3 = sanitizeKey((0, import_path2.join)(bucketPath, file.name));
59069
- const local = (0, import_path2.join)(localPath, file.name);
59070
- if (file.isDirectory()) {
59071
- uploads.push(uploadDirectory(bucketName, local, path3));
59072
- } else {
59073
- uploads.push(
59074
- streamUpload({
59075
- bucket: bucketName,
59076
- filename: path3,
59077
- stream: import_fs3.default.createReadStream(local)
59078
- })
59079
- );
59080
- }
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);
59081
59373
  }
59082
- await Promise.all(uploads);
59083
- return files;
59084
59374
  }
59085
- async function downloadTarballDirect(url, path3, headers = {}) {
59086
- path3 = sanitizeKey(path3);
59087
- const response = await (0, import_node_fetch3.default)(url, { headers });
59088
- if (!response.ok) {
59089
- throw new Error(`unexpected response ${response.statusText}`);
59090
- }
59091
- await streamPipeline(response.body, import_zlib.default.createUnzip(), import_tar_fs.default.extract(path3));
59375
+ function isDocumentConflictError(error) {
59376
+ return checkErrorCode(error, 409);
59092
59377
  }
59093
- async function downloadTarball(url, bucketName, path3) {
59094
- bucketName = sanitizeBucket(bucketName);
59095
- path3 = sanitizeKey(path3);
59096
- const response = await (0, import_node_fetch3.default)(url);
59097
- if (!response.ok) {
59098
- 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;
59099
59394
  }
59100
- const tmpPath = (0, import_path2.join)(budibaseTempDir(), path3);
59101
- await streamPipeline(response.body, import_zlib.default.createUnzip(), import_tar_fs.default.extract(tmpPath));
59102
- if (!environment_default.isTest() && environment_default.SELF_HOSTED) {
59103
- await uploadDirectory(bucketName, tmpPath, path3);
59395
+ let native;
59396
+ if (sql.toNative) {
59397
+ native = sql.toNative();
59104
59398
  }
59105
- return tmpPath;
59106
- }
59107
- async function getReadStream(bucketName, path3) {
59108
- bucketName = sanitizeBucket(bucketName);
59109
- path3 = sanitizeKey(path3);
59110
- const client = ObjectStore(bucketName);
59111
- const params2 = {
59112
- Bucket: bucketName,
59113
- Key: path3
59399
+ return {
59400
+ sql: native?.sql || sql.sql,
59401
+ bindings: native?.bindings || sql.bindings
59114
59402
  };
59115
- return client.getObject(params2).createReadStream();
59116
59403
  }
59117
- async function getObjectMetadata(bucket, path3) {
59118
- bucket = sanitizeBucket(bucket);
59119
- path3 = sanitizeKey(path3);
59120
- const client = ObjectStore(bucket);
59121
- const params2 = {
59122
- Bucket: bucket,
59123
- Key: path3
59124
- };
59125
- try {
59126
- return await client.headObject(params2).promise();
59127
- } catch (err) {
59128
- 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;
59129
59411
  }
59412
+ return false;
59130
59413
  }
59131
- function extractBucketAndPath(url) {
59132
- const baseUrl = url.split("?")[0];
59133
- const regex = new RegExp(
59134
- `^${SIGNED_FILE_PREFIX}/(?<bucket>[^/]+)/(?<path>.+)$`
59135
- );
59136
- const match = baseUrl.match(regex);
59137
- if (match && match.groups) {
59138
- const { bucket, path: path3 } = match.groups;
59139
- return { bucket, path: path3 };
59414
+ function buildExternalTableId(datasourceId, tableName) {
59415
+ if (tableName.includes(" ")) {
59416
+ tableName = encodeURIComponent(tableName);
59140
59417
  }
59141
- return null;
59418
+ return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`;
59142
59419
  }
59143
-
59144
- // src/objectStore/cloudfront.ts
59145
- var cfsign = __toESM(require("aws-cloudfront-sign"));
59146
- var PRIVATE_KEY;
59147
- function getPrivateKey() {
59148
- if (!environment_default.CLOUDFRONT_PRIVATE_KEY_64) {
59149
- 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);
59150
59426
  }
59151
- if (PRIVATE_KEY) {
59152
- return PRIVATE_KEY;
59427
+ if (!datasourceId || !tableName) {
59428
+ throw new Error("Unable to get datasource/table name from table ID");
59153
59429
  }
59154
- PRIVATE_KEY = Buffer.from(environment_default.CLOUDFRONT_PRIVATE_KEY_64, "base64").toString(
59155
- "utf-8"
59156
- );
59157
- return PRIVATE_KEY;
59430
+ return { datasourceId, tableName };
59158
59431
  }
59159
- var getCloudfrontSignParams = () => {
59160
- return {
59161
- keypairId: environment_default.CLOUDFRONT_PUBLIC_KEY_ID,
59162
- privateKeyString: getPrivateKey(),
59163
- expireTime: (/* @__PURE__ */ new Date()).getTime() + 1e3 * 60 * 60 * 24
59164
- // 1 day
59165
- };
59166
- };
59167
- var getPresignedUrl2 = (s3Key) => {
59168
- const url = getUrl(s3Key);
59169
- return cfsign.getSignedUrl(url, getCloudfrontSignParams());
59170
- };
59171
- var getUrl = (s3Key) => {
59172
- let prefix = "/";
59173
- if (s3Key.startsWith("/")) {
59174
- prefix = "";
59432
+ function generateRowIdField(keyProps = []) {
59433
+ if (!Array.isArray(keyProps)) {
59434
+ keyProps = [keyProps];
59175
59435
  }
59176
- return `${environment_default.CLOUDFRONT_CDN}${prefix}${s3Key}`;
59177
- };
59178
-
59179
- // src/objectStore/buckets/app.ts
59180
- var import_querystring = __toESM(require("querystring"));
59181
- function clientLibraryPath(appId) {
59182
- return `${sanitizeKey(appId)}/budibase-client.js`;
59183
- }
59184
- function clientLibraryCDNUrl(appId, version) {
59185
- let file = clientLibraryPath(appId);
59186
- if (environment_default.CLOUDFRONT_CDN) {
59187
- if (version) {
59188
- file += `?v=${version}`;
59436
+ for (let index2 in keyProps) {
59437
+ if (keyProps[index2] instanceof Buffer) {
59438
+ keyProps[index2] = keyProps[index2].toString();
59189
59439
  }
59190
- return getUrl(file);
59191
- } else {
59192
- return getPresignedUrl(environment_default.APPS_BUCKET_NAME, file);
59193
- }
59194
- }
59195
- function clientLibraryUrl(appId, version) {
59196
- let tenantId, qsParams;
59197
- try {
59198
- tenantId = getTenantId();
59199
- } finally {
59200
- qsParams = {
59201
- appId,
59202
- version
59203
- };
59204
- }
59205
- if (tenantId && tenantId !== DEFAULT_TENANT_ID) {
59206
- qsParams.tenantId = tenantId;
59207
59440
  }
59208
- return `/api/assets/client?${import_querystring.default.encode(qsParams)}`;
59441
+ return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"));
59209
59442
  }
59210
- function getAppFileUrl(s3Key) {
59211
- if (environment_default.CLOUDFRONT_CDN) {
59212
- return getPresignedUrl2(s3Key);
59213
- } else {
59214
- return getPresignedUrl(environment_default.APPS_BUCKET_NAME, s3Key);
59215
- }
59443
+ function isRowId(field) {
59444
+ return Array.isArray(field) || typeof field === "string" && field.match(ROW_ID_REGEX) != null;
59216
59445
  }
59217
-
59218
- // src/objectStore/buckets/global.ts
59219
- var getGlobalFileUrl = (type, name, etag) => {
59220
- let file = getGlobalFileS3Key(type, name);
59221
- if (environment_default.CLOUDFRONT_CDN) {
59222
- if (etag) {
59223
- file = `${file}?etag=${etag}`;
59224
- }
59225
- return getPresignedUrl2(file);
59226
- } else {
59227
- return getPresignedUrl(environment_default.GLOBAL_BUCKET_NAME, file);
59446
+ function convertRowId(field) {
59447
+ if (Array.isArray(field)) {
59448
+ return field[0];
59228
59449
  }
59229
- };
59230
- var getGlobalFileS3Key = (type, name) => {
59231
- let file = `${type}/${name}`;
59232
- if (environment_default.MULTI_TENANCY) {
59233
- const tenantId = getTenantId();
59234
- file = `${tenantId}/${file}`;
59450
+ if (typeof field === "string" && field.match(ROW_ID_REGEX) != null) {
59451
+ return field.substring(1, field.length - 1);
59235
59452
  }
59236
- return file;
59237
- };
59238
-
59239
- // src/objectStore/buckets/plugins.ts
59240
- function enrichPluginURLs(plugins) {
59241
- if (!plugins || !plugins.length) {
59453
+ return field;
59454
+ }
59455
+ function breakRowIdField(_id) {
59456
+ if (!_id) {
59242
59457
  return [];
59243
59458
  }
59244
- return plugins.map((plugin) => {
59245
- const jsUrl = getPluginJSUrl(plugin);
59246
- const iconUrl = getPluginIconUrl(plugin);
59247
- return { ...plugin, jsUrl, iconUrl };
59248
- });
59249
- }
59250
- function getPluginJSUrl(plugin) {
59251
- const s3Key = getPluginJSKey(plugin);
59252
- 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
+ }
59253
59467
  }
59254
- function getPluginIconUrl(plugin) {
59255
- const s3Key = getPluginIconKey(plugin);
59256
- if (!s3Key) {
59257
- return;
59468
+ function isInvalidISODateString(str) {
59469
+ const trimmedValue = str.trim();
59470
+ if (!ISO_DATE_REGEX.test(trimmedValue)) {
59471
+ return false;
59258
59472
  }
59259
- return getPluginUrl(s3Key);
59473
+ let d = new Date(trimmedValue);
59474
+ return isNaN(d.getTime());
59260
59475
  }
59261
- function getPluginUrl(s3Key) {
59262
- if (environment_default.CLOUDFRONT_CDN) {
59263
- return getPresignedUrl2(s3Key);
59264
- } else {
59265
- 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;
59266
59484
  }
59485
+ return d.toISOString() === trimmedValue;
59267
59486
  }
59268
- function getPluginJSKey(plugin) {
59269
- return getPluginS3Key(plugin, "plugin.min.js");
59487
+ function isValidFilter(value) {
59488
+ return value != null && value !== "";
59270
59489
  }
59271
- function getPluginIconKey(plugin) {
59272
- const iconFileName = plugin.iconUrl ? "icon.svg" : plugin.iconFileName;
59273
- if (!iconFileName) {
59490
+ function sqlLog(client, query, values2) {
59491
+ if (!environment_default.SQL_LOGGING_ENABLE) {
59274
59492
  return;
59275
59493
  }
59276
- 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);
59277
59499
  }
59278
- function getPluginS3Key(plugin, fileName) {
59279
- const s3Key = getPluginS3Dir(plugin.name);
59280
- 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
+ });
59281
59513
  }
59282
- function getPluginS3Dir(pluginName) {
59283
- let s3Key = `${pluginName}`;
59284
- if (environment_default.MULTI_TENANCY) {
59285
- const tenantId = getTenantId();
59286
- 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;
59287
59525
  }
59288
- if (environment_default.CLOUDFRONT_CDN) {
59289
- 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
+ );
59290
59532
  }
59291
- return s3Key;
59292
- }
59293
-
59294
- // src/logging/system.ts
59295
- var logsFileName = `budibase.log`;
59296
- var budibaseLogsHistoryFileName = "budibase-logs-history.txt";
59297
- var logsPath = import_path3.default.join(budibaseTempDir(), "systemlogs");
59298
- function getFullPath(fileName) {
59299
- return import_path3.default.join(logsPath, fileName);
59533
+ const db = new DatabaseImpl(dbName, opts, connection);
59534
+ return new DDInstrumentedDatabase(db);
59300
59535
  }
59301
- function getSingleFileMaxSizeInfo(totalMaxSize) {
59302
- const regex = /(\d+)([A-Za-z])/;
59303
- const match = totalMaxSize?.match(regex);
59304
- if (!match) {
59305
- console.warn(`totalMaxSize does not have a valid value`, {
59306
- totalMaxSize
59307
- });
59308
- 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
+ }
59309
59548
  }
59310
- const size = +match[1];
59311
- const unit = match[2];
59312
- if (size === 1) {
59313
- switch (unit) {
59314
- case "B":
59315
- return { size: `${size}B`, totalHistoryFiles: 1 };
59316
- case "K":
59317
- return { size: `${size * 1e3 / 2}B`, totalHistoryFiles: 1 };
59318
- case "M":
59319
- return { size: `${size * 1e3 / 2}K`, totalHistoryFiles: 1 };
59320
- case "G":
59321
- return { size: `${size * 1e3 / 2}M`, totalHistoryFiles: 1 };
59322
- default:
59323
- 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();
59324
59556
  }
59557
+ return this.docExists(docId);
59325
59558
  }
59326
- if (size % 2 === 0) {
59327
- 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;
59328
59566
  }
59329
- return { size: `1${unit}`, totalHistoryFiles: size - 1 };
59330
- }
59331
- function localFileDestination() {
59332
- const fileInfo = getSingleFileMaxSizeInfo(environment_default.ROLLING_LOG_MAX_SIZE);
59333
- const outFile = rfs.createStream(logsFileName, {
59334
- // As we have a rolling size, we want to half the max size
59335
- size: fileInfo?.size,
59336
- path: logsPath,
59337
- maxFiles: fileInfo?.totalHistoryFiles || 1,
59338
- immutable: true,
59339
- history: budibaseLogsHistoryFileName,
59340
- initialRotation: false
59341
- });
59342
- return outFile;
59343
- }
59344
- function getLogReadStream() {
59345
- const streams = [];
59346
- const historyFile = getFullPath(budibaseLogsHistoryFileName);
59347
- if (import_fs4.default.existsSync(historyFile)) {
59348
- const fileContent = import_fs4.default.readFileSync(historyFile, "utf-8");
59349
- const historyFiles = fileContent.split("\n");
59350
- for (const historyFile2 of historyFiles.filter((x) => x)) {
59351
- 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;
59352
59573
  }
59353
59574
  }
59354
- streams.push(import_fs4.default.readFileSync(getFullPath(logsFileName)));
59355
- const combinedContent = Buffer.concat(streams);
59356
- return combinedContent;
59357
- }
59358
-
59359
- // src/logging/pino/logger.ts
59360
- function isPlainObject(obj) {
59361
- return typeof obj === "object" && obj !== null && !(obj instanceof Error);
59362
- }
59363
- function isError(obj) {
59364
- return obj instanceof Error;
59365
- }
59366
- function isMessage(obj) {
59367
- return typeof obj === "string";
59368
- }
59369
- var pinoInstance;
59370
- if (!environment_default.DISABLE_PINO_LOGGER) {
59371
- const level = environment_default.LOG_LEVEL;
59372
- const pinoOptions = {
59373
- level,
59374
- formatters: {
59375
- level: (level2) => {
59376
- return { level: level2.toUpperCase() };
59377
- },
59378
- bindings: () => {
59379
- if (environment_default.SELF_HOSTED) {
59380
- return {
59381
- service: environment_default.SERVICE_NAME
59382
- };
59383
- } else {
59384
- 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);
59385
59593
  }
59386
59594
  }
59387
- },
59388
- timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`
59389
- };
59390
- const destinations = [];
59391
- destinations.push(
59392
- environment_default.isDev() ? {
59393
- stream: (0, import_pino_pretty.default)({ singleLine: true }),
59394
- level
59395
- } : { stream: process.stdout, level }
59396
- );
59397
- if (environment_default.SELF_HOSTED) {
59398
- destinations.push({
59399
- stream: localFileDestination(),
59400
- 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
59401
59625
  });
59402
- }
59403
- pinoInstance = destinations.length ? (0, import_pino.default)(pinoOptions, import_pino.default.multistream(destinations)) : (0, import_pino.default)(pinoOptions);
59404
- const getLogParams2 = (args) => {
59405
- let error = void 0;
59406
- let objects = [];
59407
- let message = "";
59408
- args.forEach((arg) => {
59409
- if (isMessage(arg)) {
59410
- message = `${message} ${arg}`.trimStart();
59626
+ const rowUnavailable = (row) => {
59627
+ if (row.doc == null || "deleted" in row.value && row.value.deleted) {
59628
+ return true;
59411
59629
  }
59412
- if (isPlainObject(arg)) {
59413
- objects.push(arg);
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;
59414
59651
  }
59415
- if (isError(arg)) {
59416
- error = arg;
59652
+ if (!_id || !_rev) {
59653
+ throw new Error("Unable to remove doc without a valid _id and _rev.");
59417
59654
  }
59655
+ return () => db.destroy(_id, _rev);
59418
59656
  });
59419
- const identity = getIdentity3();
59420
- let contextObject = {};
59421
- contextObject = {
59422
- tenantId: getTenantId2(),
59423
- appId: getAppId2(),
59424
- automationId: getAutomationId2(),
59425
- identityId: identity?._id,
59426
- identityType: identity?.type,
59427
- correlationId: getId()
59428
- };
59429
- const span = import_dd_trace2.default.scope().active();
59430
- if (span) {
59431
- import_dd_trace2.default.inject(span.context(), import_ext.formats.LOG, contextObject);
59657
+ }
59658
+ async post(document, opts) {
59659
+ if (!document._id) {
59660
+ document._id = newid();
59432
59661
  }
59433
- const mergingObject = {
59434
- err: error,
59435
- pid: process.pid,
59436
- ...contextObject
59437
- };
59438
- if (objects.length) {
59439
- const data = {};
59440
- let dataIndex = 0;
59441
- for (let i = 0; i < objects.length; i++) {
59442
- const object = objects[i];
59443
- const logKey = object._logKey;
59444
- if (logKey) {
59445
- delete object._logKey;
59446
- mergingObject[logKey] = object;
59447
- } else {
59448
- data[dataIndex] = object;
59449
- dataIndex++;
59450
- }
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();
59451
59671
  }
59452
- if (Object.keys(data).length) {
59453
- mergingObject.data = data;
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
+ }
59454
59684
  }
59685
+ return () => db.insert(document);
59686
+ });
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
59704
+ };
59705
+ if (body2) {
59706
+ args.body = body2;
59455
59707
  }
59456
- return [mergingObject, message];
59457
- };
59458
- console.log = (...arg) => {
59459
- const [obj, msg] = getLogParams2(arg);
59460
- pinoInstance?.info(obj, msg);
59461
- };
59462
- console.info = (...arg) => {
59463
- const [obj, msg] = getLogParams2(arg);
59464
- pinoInstance?.info(obj, msg);
59465
- };
59466
- console.warn = (...arg) => {
59467
- const [obj, msg] = getLogParams2(arg);
59468
- pinoInstance?.warn(obj, msg);
59469
- };
59470
- console.error = (...arg) => {
59471
- const [obj, msg] = getLogParams2(arg);
59472
- pinoInstance?.error(obj, msg);
59473
- };
59474
- console.trace = (...arg) => {
59475
- const [obj, msg] = getLogParams2(arg);
59476
- if (!obj.err) {
59477
- obj.err = new Error();
59478
- }
59479
- pinoInstance?.trace(obj, msg);
59480
- };
59481
- console.debug = (...arg) => {
59482
- const [obj, msg] = getLogParams2(arg);
59483
- pinoInstance?.debug(obj, msg);
59484
- };
59485
- const getTenantId2 = () => {
59486
- let tenantId;
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;
59714
+ }
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`;
59487
59734
  try {
59488
- tenantId = getTenantId();
59489
- } catch (e) {
59735
+ await this._sqlQuery(url, "POST");
59736
+ } catch (err) {
59737
+ if (err.status !== 500) {
59738
+ throw err;
59739
+ }
59490
59740
  }
59491
- return tenantId;
59492
- };
59493
- const getAppId2 = () => {
59494
- let appId;
59495
- try {
59496
- appId = getAppId();
59497
- } catch (e) {
59741
+ }
59742
+ // removes a document from sqlite
59743
+ async sqlPurgeDocument(docIds) {
59744
+ if (!Array.isArray(docIds)) {
59745
+ docIds = [docIds];
59498
59746
  }
59499
- return appId;
59500
- };
59501
- const getAutomationId2 = () => {
59502
- let appId;
59503
- try {
59504
- appId = getAutomationId();
59505
- } 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();
59506
59763
  }
59507
- return appId;
59508
- };
59509
- const getIdentity3 = () => {
59510
- let identity;
59511
59764
  try {
59512
- identity = getIdentity();
59513
- } 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
+ }
59514
59772
  }
59515
- return identity;
59516
- };
59517
- }
59518
- var logger = pinoInstance;
59519
-
59520
- // src/logging/alerts.ts
59521
- var NonErrors = ["AccountError"];
59522
- function isSuppressed(e) {
59523
- return e && e["suppressAlert"];
59524
- }
59525
- function logAlert(message, e) {
59526
- if (e && NonErrors.includes(e.name) && isSuppressed(e)) {
59527
- return;
59528
59773
  }
59529
- console.error(`bb-alert: ${message}`, e);
59530
- }
59531
- function logAlertWithInfo(message, db, id, error) {
59532
- message = `${message} - db: ${db} - doc: ${id} - error: `;
59533
- logAlert(message, error);
59534
- }
59535
- function logWarn(message, e) {
59536
- console.warn(`bb-warn: ${message}`, e);
59537
- }
59538
-
59539
- // src/timers/index.ts
59540
- var timers_exports = {};
59541
- __export(timers_exports, {
59542
- cleanup: () => cleanup,
59543
- clear: () => clear,
59544
- set: () => set
59545
- });
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
+ };
59546
59802
 
59547
- // src/timers/timers.ts
59548
- var intervals = [];
59549
- function set(callback, period) {
59550
- const interval = setInterval(callback, period);
59551
- intervals.push(interval);
59552
- return interval;
59803
+ // src/db/db.ts
59804
+ function getDB(dbName, opts) {
59805
+ return new DDInstrumentedDatabase(new DatabaseImpl(dbName, opts));
59553
59806
  }
59554
- function clear(interval) {
59555
- const idx = intervals.indexOf(interval);
59556
- if (idx !== -1) {
59557
- intervals.splice(idx, 1);
59558
- }
59559
- clearInterval(interval);
59807
+ async function doWithDB(dbName, cb, opts) {
59808
+ const db = getDB(dbName, opts);
59809
+ return await cb(db);
59560
59810
  }
59561
- function cleanup() {
59562
- for (let interval of intervals) {
59563
- clearInterval(interval);
59811
+ async function directCouchAllDbs(queryString) {
59812
+ let couchPath = "/_all_dbs";
59813
+ if (queryString) {
59814
+ couchPath += `?${queryString}`;
59564
59815
  }
59565
- 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 };
59566
59821
  }
59567
59822
 
59568
- // src/redis/redis.ts
59569
- var MockRedis;
59570
- if (environment_default.MOCK_REDIS) {
59571
- try {
59572
- MockRedis = require("ioredis-mock");
59573
- } catch (err) {
59574
- 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();
59575
59828
  }
59829
+ return baseGlobalDBName(tenantId);
59576
59830
  }
59577
- var RETRY_PERIOD_MS = 2e3;
59578
- var STARTUP_TIMEOUT_MS = 5e3;
59579
- var CLUSTERED = environment_default.REDIS_CLUSTERED;
59580
- var DEFAULT_SELECT_DB = 0 /* DEFAULT */;
59581
- var CLOSED = false;
59582
- var CLIENTS = {};
59583
- var CONNECTED = false;
59584
- if (environment_default.MOCK_REDIS) {
59585
- CONNECTED = true;
59586
- }
59587
- function pickClient(selectDb) {
59588
- return CLIENTS[selectDb];
59589
- }
59590
- function connectionError(timeout2, err) {
59591
- if (CLOSED) {
59592
- return;
59831
+ function getAuditLogDBName(tenantId) {
59832
+ if (!tenantId) {
59833
+ tenantId = getTenantId();
59593
59834
  }
59594
- CLOSED = true;
59595
- clearTimeout(timeout2);
59596
- CONNECTED = false;
59597
- logAlert("Redis connection failed", err);
59598
- setTimeout(() => {
59599
- init2();
59600
- }, RETRY_PERIOD_MS);
59601
- }
59602
- function init2(selectDb = DEFAULT_SELECT_DB) {
59603
- const RedisCore = environment_default.MOCK_REDIS && MockRedis ? MockRedis : import_ioredis.default;
59604
- let timeout2;
59605
- CLOSED = false;
59606
- let client = pickClient(selectDb);
59607
- if (client && CONNECTED) {
59608
- return;
59835
+ if (tenantId === DEFAULT_TENANT_ID) {
59836
+ return StaticDatabases.AUDIT_LOGS.name;
59837
+ } else {
59838
+ return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}`;
59609
59839
  }
59610
- if (environment_default.MOCK_REDIS) {
59611
- CLIENTS[selectDb] = new RedisCore(getRedisOptions());
59840
+ }
59841
+ function getScimDBName(tenantId) {
59842
+ if (!tenantId) {
59843
+ tenantId = getTenantId();
59612
59844
  }
59613
- timeout2 = setTimeout(() => {
59614
- if (!CONNECTED) {
59615
- connectionError(timeout2, "Did not successfully connect in timeout");
59616
- }
59617
- }, STARTUP_TIMEOUT_MS);
59618
- if (client) {
59619
- client.disconnect();
59845
+ if (tenantId === DEFAULT_TENANT_ID) {
59846
+ return StaticDatabases.SCIM_LOGS.name;
59847
+ } else {
59848
+ return `${tenantId}${SEPARATOR}${StaticDatabases.SCIM_LOGS.name}`;
59620
59849
  }
59621
- const { host, port } = getRedisConnectionDetails();
59622
- const opts = getRedisOptions();
59623
- if (CLUSTERED) {
59624
- client = new RedisCore.Cluster([{ host, port }], opts);
59850
+ }
59851
+ function baseGlobalDBName(tenantId) {
59852
+ if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
59853
+ return StaticDatabases.GLOBAL.name;
59625
59854
  } else {
59626
- client = new RedisCore(opts);
59855
+ return `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}`;
59627
59856
  }
59628
- client.on("end", (err) => {
59629
- if (environment_default.isTest()) {
59630
- return;
59631
- }
59632
- connectionError(timeout2, err);
59633
- });
59634
- client.on("error", (err) => {
59635
- connectionError(timeout2, err);
59636
- });
59637
- client.on("connect", () => {
59638
- console.log(`Connected to Redis DB: ${selectDb}`);
59639
- clearTimeout(timeout2);
59640
- CONNECTED = true;
59641
- });
59642
- CLIENTS[selectDb] = client;
59643
59857
  }
59644
- function waitForConnection(selectDb = DEFAULT_SELECT_DB) {
59645
- return new Promise((resolve) => {
59646
- if (pickClient(selectDb) == null) {
59647
- init2();
59648
- } else if (CONNECTED) {
59649
- resolve("");
59650
- return;
59651
- }
59652
- const interval = set(() => {
59653
- if (CONNECTED) {
59654
- clear(interval);
59655
- resolve("");
59656
- }
59657
- }, 500);
59658
- });
59858
+ function getPlatformURL() {
59859
+ return environment_default.PLATFORM_URL;
59659
59860
  }
59660
- function promisifyStream(stream3, client) {
59661
- return new Promise((resolve, reject) => {
59662
- const outputKeys = /* @__PURE__ */ new Set();
59663
- stream3.on("data", (keys2) => {
59664
- keys2.forEach((key) => {
59665
- outputKeys.add(key);
59666
- });
59667
- });
59668
- stream3.on("error", (err) => {
59669
- reject(err);
59670
- });
59671
- stream3.on("end", async () => {
59672
- const keysArray = Array.from(outputKeys);
59673
- try {
59674
- let getPromises = [];
59675
- for (let key of keysArray) {
59676
- getPromises.push(client.get(key));
59677
- }
59678
- const jsonArray = await Promise.all(getPromises);
59679
- resolve(
59680
- keysArray.map((key) => ({
59681
- key: removeDbPrefix(key),
59682
- value: JSON.parse(jsonArray.shift())
59683
- }))
59684
- );
59685
- } catch (err) {
59686
- reject(err);
59687
- }
59688
- });
59689
- });
59861
+ function isMultiTenant() {
59862
+ return !!environment_default.MULTI_TENANCY;
59690
59863
  }
59691
- var RedisWrapper = class {
59692
- constructor(db, selectDb = null) {
59693
- this._db = db;
59694
- this._select = selectDb || DEFAULT_SELECT_DB;
59695
- }
59696
- getClient() {
59697
- return pickClient(this._select);
59698
- }
59699
- async init() {
59700
- CLOSED = false;
59701
- init2(this._select);
59702
- await waitForConnection(this._select);
59703
- if (this._select && !environment_default.isTest()) {
59704
- this.getClient().select(this._select);
59705
- }
59706
- return this;
59707
- }
59708
- async finish() {
59709
- CLOSED = true;
59710
- this.getClient().disconnect();
59711
- }
59712
- async scan(key = "") {
59713
- const db = this._db;
59714
- key = `${db}${SEPARATOR2}${key}`;
59715
- let stream3;
59716
- if (CLUSTERED) {
59717
- let node = this.getClient().nodes("master");
59718
- stream3 = node[0].scanStream({ match: key + "*", count: 100 });
59719
- } else {
59720
- stream3 = this.getClient().scanStream({
59721
- match: key + "*",
59722
- count: 100
59723
- });
59724
- }
59725
- return promisifyStream(stream3, this.getClient());
59726
- }
59727
- async keys(pattern) {
59728
- const db = this._db;
59729
- return this.getClient().keys(addDbPrefix(db, pattern));
59730
- }
59731
- async exists(key) {
59732
- const db = this._db;
59733
- 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;
59734
59874
  }
59735
- async get(key) {
59736
- const db = this._db;
59737
- const response = await this.getClient().get(addDbPrefix(db, key));
59738
- if (response != null && response.key) {
59739
- response.key = key;
59740
- }
59741
- try {
59742
- return JSON.parse(response);
59743
- } catch (err) {
59744
- return response;
59745
- }
59875
+ if (!isMultiTenant()) {
59876
+ return DEFAULT_TENANT_ID;
59746
59877
  }
59747
- async bulkGet(keys2) {
59748
- const db = this._db;
59749
- if (keys2.length === 0) {
59750
- return {};
59751
- }
59752
- const prefixedKeys = keys2.map((key) => addDbPrefix(db, key));
59753
- let response = await this.getClient().mget(prefixedKeys);
59754
- if (Array.isArray(response)) {
59755
- let final = {};
59756
- let count = 0;
59757
- for (let result of response) {
59758
- if (result) {
59759
- let parsed;
59760
- try {
59761
- parsed = JSON.parse(result);
59762
- } catch (err) {
59763
- parsed = result;
59764
- }
59765
- final[keys2[count]] = parsed;
59766
- }
59767
- count++;
59768
- }
59769
- return final;
59770
- } else {
59771
- throw new Error(`Invalid response: ${response}`);
59772
- }
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;
59773
59882
  }
59774
- async store(key, value, expirySeconds = null) {
59775
- const db = this._db;
59776
- if (typeof value === "object") {
59777
- value = JSON.stringify(value);
59778
- }
59779
- const prefixedKey = addDbPrefix(db, key);
59780
- await this.getClient().set(prefixedKey, value);
59781
- if (expirySeconds) {
59782
- await this.getClient().expire(prefixedKey, expirySeconds);
59783
- }
59883
+ if (hasDev) {
59884
+ return split[2];
59885
+ } else {
59886
+ return split[1];
59784
59887
  }
59785
- async bulkStore(data, expirySeconds = null) {
59786
- const client = this.getClient();
59787
- const dataToStore = Object.entries(data).reduce((acc, [key, value]) => {
59788
- acc[addDbPrefix(this._db, key)] = typeof value === "object" ? JSON.stringify(value) : value;
59789
- return acc;
59790
- }, {});
59791
- const pipeline = client.pipeline();
59792
- pipeline.mset(dataToStore);
59793
- if (expirySeconds !== null) {
59794
- for (const key of Object.keys(dataToStore)) {
59795
- pipeline.expire(key, expirySeconds);
59796
- }
59797
- }
59798
- await pipeline.exec();
59888
+ }
59889
+ function updateContext(updates) {
59890
+ let context;
59891
+ try {
59892
+ context = Context.get();
59893
+ } catch (err) {
59894
+ context = {};
59799
59895
  }
59800
- async getTTL(key) {
59801
- const db = this._db;
59802
- const prefixedKey = addDbPrefix(db, key);
59803
- 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;
59804
59931
  }
59805
- async setExpiry(key, expirySeconds) {
59806
- const db = this._db;
59807
- const prefixedKey = addDbPrefix(db, key);
59808
- 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");
59809
59941
  }
59810
- async delete(key) {
59811
- const db = this._db;
59812
- await this.getClient().del(addDbPrefix(db, key));
59942
+ const tenantId = getTenantIDFromAppID(appId);
59943
+ const updates = { appId, ...extraContextSettings };
59944
+ if (tenantId) {
59945
+ updates.tenantId = tenantId;
59813
59946
  }
59814
- async bulkDelete(keys2) {
59815
- const db = this._db;
59816
- 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");
59817
59952
  }
59818
- async clear() {
59819
- let items = await this.scan();
59820
- 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;
59821
59958
  }
59822
- async increment(key) {
59823
- const result = await this.getClient().incr(addDbPrefix(this._db, key));
59824
- if (isNaN(result)) {
59825
- throw new Error(`Redis ${key} does not contain a number`);
59826
- }
59827
- 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
+ );
59828
59967
  }
59829
- async deleteIfValue(key, value) {
59830
- const client = this.getClient();
59831
- const luaScript = `
59832
- if redis.call('GET', KEYS[1]) == ARGV[1] then
59833
- redis.call('DEL', KEYS[1])
59834
- end
59835
- `;
59836
- 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) {
59837
59979
  }
59838
- };
59839
- var redis_default = RedisWrapper;
59840
-
59841
- // src/redis/init.ts
59842
- var userClient;
59843
- var sessionClient;
59844
- var appClient;
59845
- var cacheClient;
59846
- var writethroughClient;
59847
- var lockClient;
59848
- var socketClient;
59849
- var inviteClient;
59850
- var passwordResetClient;
59851
- var docWritethroughClient;
59852
- async function init3() {
59853
- userClient = await new redis_default("users" /* USER_CACHE */).init();
59854
- sessionClient = await new redis_default("session" /* SESSIONS */).init();
59855
- appClient = await new redis_default("appMetadata" /* APP_METADATA */).init();
59856
- cacheClient = await new redis_default("data_cache" /* GENERIC_CACHE */).init();
59857
- lockClient = await new redis_default("locks" /* LOCKS */).init();
59858
- writethroughClient = await new redis_default("writeThrough" /* WRITE_THROUGH */).init();
59859
- inviteClient = await new redis_default("invitation" /* INVITATIONS */).init();
59860
- passwordResetClient = await new redis_default("pwReset" /* PW_RESETS */).init();
59861
- socketClient = await new redis_default(
59862
- "socket_io" /* SOCKET_IO */,
59863
- 1 /* SOCKET_IO */
59864
- ).init();
59865
- docWritethroughClient = await new redis_default(
59866
- "docWriteThrough" /* DOC_WRITE_THROUGH */
59867
- ).init();
59868
59980
  }
59869
- async function shutdown() {
59870
- if (userClient)
59871
- await userClient.finish();
59872
- if (sessionClient)
59873
- await sessionClient.finish();
59874
- if (appClient)
59875
- await appClient.finish();
59876
- if (cacheClient)
59877
- await cacheClient.finish();
59878
- if (writethroughClient)
59879
- await writethroughClient.finish();
59880
- if (lockClient)
59881
- await lockClient.finish();
59882
- if (inviteClient)
59883
- await inviteClient.finish();
59884
- if (passwordResetClient)
59885
- await passwordResetClient.finish();
59886
- if (socketClient)
59887
- await socketClient.finish();
59888
- if (docWritethroughClient)
59889
- 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;
59890
59991
  }
59891
- process.on("exit", async () => {
59892
- await shutdown();
59893
- });
59894
- async function getUserClient() {
59895
- if (!userClient) {
59896
- 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;
59897
60003
  }
59898
- return userClient;
59899
60004
  }
59900
- async function getSessionClient() {
59901
- if (!sessionClient) {
59902
- await init3();
60005
+ var getProdAppId = () => {
60006
+ const appId = getAppId();
60007
+ if (!appId) {
60008
+ throw new Error("Could not get appId");
59903
60009
  }
59904
- 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);
59905
60020
  }
59906
- async function getAppClient() {
59907
- if (!appClient) {
59908
- 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;
59909
60031
  }
59910
- 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 || [];
59911
60039
  }
59912
- async function getCacheClient() {
59913
- if (!cacheClient) {
59914
- await init3();
60040
+ function getEnvironmentVariables() {
60041
+ const context = Context.get();
60042
+ if (!context.environmentVariables) {
60043
+ return null;
60044
+ } else {
60045
+ return context.environmentVariables;
59915
60046
  }
59916
- return cacheClient;
59917
60047
  }
59918
- async function getWritethroughClient() {
59919
- if (!writethroughClient) {
59920
- 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");
59921
60052
  }
59922
- return writethroughClient;
60053
+ return getDB(baseGlobalDBName(context?.tenantId));
59923
60054
  }
59924
- async function getLockClient() {
59925
- if (!lockClient) {
59926
- await init3();
60055
+ function getAuditLogsDB() {
60056
+ if (!getTenantId()) {
60057
+ throw new Error("No tenant ID found - cannot open audit log DB");
59927
60058
  }
59928
- return lockClient;
60059
+ return getDB(getAuditLogDBName());
59929
60060
  }
59930
- async function getSocketClient() {
59931
- if (!socketClient) {
59932
- 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.");
59933
60065
  }
59934
- return socketClient;
60066
+ return getDB(appId, opts);
59935
60067
  }
59936
- async function getInviteClient() {
59937
- if (!inviteClient) {
59938
- 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.");
59939
60072
  }
59940
- return inviteClient;
60073
+ return getDB(getProdAppID2(appId), opts);
59941
60074
  }
59942
- async function getPasswordResetClient() {
59943
- if (!passwordResetClient) {
59944
- 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.");
59945
60079
  }
59946
- return passwordResetClient;
60080
+ return getDB(getDevelopmentAppID(appId), opts);
59947
60081
  }
59948
- async function getDocWritethroughClient() {
59949
- if (!writethroughClient) {
59950
- 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;
59951
60092
  }
59952
- return writethroughClient;
59953
60093
  }
59954
60094
 
59955
60095
  // src/cache/base/index.ts
@@ -60352,8 +60492,8 @@ __export(redlockImpl_exports, {
60352
60492
  var import_redlock = __toESM(require("redlock"));
60353
60493
 
60354
60494
  // src/utils/index.ts
60355
- var utils_exports3 = {};
60356
- __export(utils_exports3, {
60495
+ var utils_exports4 = {};
60496
+ __export(utils_exports4, {
60357
60497
  Duration: () => Duration,
60358
60498
  DurationType: () => DurationType,
60359
60499
  clearCookie: () => clearCookie,
@@ -60926,8 +61066,8 @@ __export(users_exports3, {
60926
61066
  });
60927
61067
 
60928
61068
  // src/users/utils.ts
60929
- var utils_exports4 = {};
60930
- __export(utils_exports4, {
61069
+ var utils_exports5 = {};
61070
+ __export(utils_exports5, {
60931
61071
  getAccountHolderFromUserIds: () => getAccountHolderFromUserIds,
60932
61072
  hasAdminPermissions: () => hasAdminPermissions2,
60933
61073
  hasAppBuilderPermissions: () => hasAppBuilderPermissions2,
@@ -66617,6 +66757,23 @@ var correlation = (ctx, next) => {
66617
66757
  };
66618
66758
  var middleware_default2 = correlation;
66619
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
+
66620
66777
  // src/middleware/errorHandling.ts
66621
66778
  async function errorHandling(ctx, next) {
66622
66779
  try {
@@ -66635,6 +66792,13 @@ async function errorHandling(ctx, next) {
66635
66792
  validationErrors: err.validation,
66636
66793
  error: getPublicError(err)
66637
66794
  };
66795
+ if (stringContainsSecret(JSON.stringify(error))) {
66796
+ error = {
66797
+ message: "Unexpected error",
66798
+ status,
66799
+ error: "Unexpected error"
66800
+ };
66801
+ }
66638
66802
  if (environment_default.isTest() && ctx.headers["x-budibase-include-stacktrace"]) {
66639
66803
  error.stack = err.stack;
66640
66804
  }
@@ -67122,123 +67286,8 @@ __export(sql_exports, {
67122
67286
  Sql: () => sql_default,
67123
67287
  SqlTable: () => sqlTable_default,
67124
67288
  designDoc: () => designDoc_exports,
67125
- utils: () => utils_exports5
67126
- });
67127
-
67128
- // src/sql/utils.ts
67129
- var utils_exports5 = {};
67130
- __export(utils_exports5, {
67131
- breakExternalTableId: () => breakExternalTableId,
67132
- breakRowIdField: () => breakRowIdField,
67133
- buildExternalTableId: () => buildExternalTableId,
67134
- convertRowId: () => convertRowId,
67135
- generateRowIdField: () => generateRowIdField,
67136
- getNativeSql: () => getNativeSql,
67137
- isExternalTable: () => isExternalTable,
67138
- isExternalTableID: () => isExternalTableID,
67139
- isInternalTableID: () => isInternalTableID,
67140
- isIsoDateString: () => isIsoDateString,
67141
- isRowId: () => isRowId,
67142
- isValidFilter: () => isValidFilter
67289
+ utils: () => utils_exports3
67143
67290
  });
67144
- var DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`;
67145
- var ROW_ID_REGEX = /^\[.*]$/g;
67146
- var ENCODED_SPACE = encodeURIComponent(" ");
67147
- function isExternalTableID(tableId) {
67148
- return tableId.startsWith("datasource" /* DATASOURCE */ + SEPARATOR);
67149
- }
67150
- function isInternalTableID(tableId) {
67151
- return !isExternalTableID(tableId);
67152
- }
67153
- function getNativeSql(query) {
67154
- let sql = query.toSQL();
67155
- if (Array.isArray(sql)) {
67156
- return sql;
67157
- }
67158
- let native;
67159
- if (sql.toNative) {
67160
- native = sql.toNative();
67161
- }
67162
- return {
67163
- sql: native?.sql || sql.sql,
67164
- bindings: native?.bindings || sql.bindings
67165
- };
67166
- }
67167
- function isExternalTable(table) {
67168
- if (table?.sourceId && table.sourceId.includes("datasource" /* DATASOURCE */ + SEPARATOR) && table?.sourceId !== DEFAULT_BB_DATASOURCE_ID) {
67169
- return true;
67170
- } else if (table?.sourceType === "external" /* EXTERNAL */) {
67171
- return true;
67172
- } else if (table?._id && isExternalTableID(table._id)) {
67173
- return true;
67174
- }
67175
- return false;
67176
- }
67177
- function buildExternalTableId(datasourceId, tableName) {
67178
- if (tableName.includes(" ")) {
67179
- tableName = encodeURIComponent(tableName);
67180
- }
67181
- return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`;
67182
- }
67183
- function breakExternalTableId(tableId) {
67184
- const parts = tableId.split(DOUBLE_SEPARATOR);
67185
- let datasourceId = parts.shift();
67186
- let tableName = parts.join(DOUBLE_SEPARATOR);
67187
- if (tableName.includes(ENCODED_SPACE)) {
67188
- tableName = decodeURIComponent(tableName);
67189
- }
67190
- if (!datasourceId || !tableName) {
67191
- throw new Error("Unable to get datasource/table name from table ID");
67192
- }
67193
- return { datasourceId, tableName };
67194
- }
67195
- function generateRowIdField(keyProps = []) {
67196
- if (!Array.isArray(keyProps)) {
67197
- keyProps = [keyProps];
67198
- }
67199
- for (let index2 in keyProps) {
67200
- if (keyProps[index2] instanceof Buffer) {
67201
- keyProps[index2] = keyProps[index2].toString();
67202
- }
67203
- }
67204
- return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"));
67205
- }
67206
- function isRowId(field) {
67207
- return Array.isArray(field) || typeof field === "string" && field.match(ROW_ID_REGEX) != null;
67208
- }
67209
- function convertRowId(field) {
67210
- if (Array.isArray(field)) {
67211
- return field[0];
67212
- }
67213
- if (typeof field === "string" && field.match(ROW_ID_REGEX) != null) {
67214
- return field.substring(1, field.length - 1);
67215
- }
67216
- return field;
67217
- }
67218
- function breakRowIdField(_id) {
67219
- if (!_id) {
67220
- return [];
67221
- }
67222
- const id = typeof _id === "string" ? _id : _id._id;
67223
- const decoded = decodeURIComponent(id).replace(/'/g, '"');
67224
- try {
67225
- const parsed = JSON.parse(decoded);
67226
- return Array.isArray(parsed) ? parsed : [parsed];
67227
- } catch (err) {
67228
- return [_id];
67229
- }
67230
- }
67231
- function isIsoDateString(str) {
67232
- const trimmedValue = str.trim();
67233
- if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(trimmedValue)) {
67234
- return false;
67235
- }
67236
- let d = new Date(trimmedValue);
67237
- return d.toISOString() === trimmedValue;
67238
- }
67239
- function isValidFilter(value) {
67240
- return value != null && value !== "";
67241
- }
67242
67291
 
67243
67292
  // src/sql/sql.ts
67244
67293
  var import_knex2 = require("knex");
@@ -67513,8 +67562,6 @@ var sqlTable_default = SqlTableQueryBuilder;
67513
67562
  // src/sql/sql.ts
67514
67563
  var envLimit = environment_default.SQL_MAX_ROWS ? parseInt(environment_default.SQL_MAX_ROWS) : null;
67515
67564
  var BASE_LIMIT = envLimit || 5e3;
67516
- var MIN_ISO_DATE = "0000-00-00T00:00:00.000Z";
67517
- var MAX_ISO_DATE = "9999-00-00T00:00:00.000Z";
67518
67565
  function likeKey(client, key) {
67519
67566
  let start2, end2;
67520
67567
  switch (client) {
@@ -67547,10 +67594,10 @@ function parse(input) {
67547
67594
  if (typeof input !== "string") {
67548
67595
  return input;
67549
67596
  }
67550
- if (input === MAX_ISO_DATE || input === MIN_ISO_DATE) {
67597
+ if (isInvalidISODateString(input)) {
67551
67598
  return null;
67552
67599
  }
67553
- if (isIsoDateString(input)) {
67600
+ if (isValidISODateString(input)) {
67554
67601
  return new Date(input.trim());
67555
67602
  }
67556
67603
  return input;
@@ -68238,15 +68285,7 @@ var SqlQueryBuilder = class extends sqlTable_default {
68238
68285
  return JsonTypes.includes(field.type) && !helpers_exports.schema.isDeprecatedSingleUserColumn(field);
68239
68286
  }
68240
68287
  log(query, values2) {
68241
- if (!environment_default.SQL_LOGGING_ENABLE) {
68242
- return;
68243
- }
68244
- const sqlClient = this.getSqlClient();
68245
- let string = `[SQL] [${sqlClient.toUpperCase()}] query="${query}"`;
68246
- if (values2) {
68247
- string += ` values="${values2.join(", ")}"`;
68248
- }
68249
- console.log(string);
68288
+ sqlLog(this.getSqlClient(), query, values2);
68250
68289
  }
68251
68290
  };
68252
68291
  var sql_default = SqlQueryBuilder;