@budibase/backend-core 2.23.10 → 2.23.12

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 (46) hide show
  1. package/dist/index.js +92 -23
  2. package/dist/index.js.map +3 -3
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +4 -4
  5. package/dist/plugins.js +2 -0
  6. package/dist/plugins.js.map +2 -2
  7. package/dist/plugins.js.meta.json +1 -1
  8. package/dist/src/auth/auth.js +0 -2
  9. package/dist/src/auth/auth.js.map +1 -1
  10. package/dist/src/environment.d.ts +1 -0
  11. package/dist/src/environment.js +2 -1
  12. package/dist/src/environment.js.map +1 -1
  13. package/dist/src/middleware/authenticated.js +0 -2
  14. package/dist/src/middleware/authenticated.js.map +1 -1
  15. package/dist/src/middleware/errorHandling.js +1 -1
  16. package/dist/src/middleware/errorHandling.js.map +1 -1
  17. package/dist/src/middleware/passport/sso/google.js +0 -1
  18. package/dist/src/middleware/passport/sso/google.js.map +1 -1
  19. package/dist/src/middleware/passport/sso/oidc.js +0 -2
  20. package/dist/src/middleware/passport/sso/oidc.js.map +1 -1
  21. package/dist/src/migrations/migrations.js +0 -1
  22. package/dist/src/migrations/migrations.js.map +1 -1
  23. package/dist/src/objectStore/objectStore.d.ts +24 -6
  24. package/dist/src/objectStore/objectStore.js +61 -14
  25. package/dist/src/objectStore/objectStore.js.map +1 -1
  26. package/dist/src/objectStore/utils.d.ts +3 -0
  27. package/dist/src/objectStore/utils.js +21 -1
  28. package/dist/src/objectStore/utils.js.map +1 -1
  29. package/dist/tests/core/utilities/index.d.ts +4 -0
  30. package/dist/tests/core/utilities/index.js +3 -1
  31. package/dist/tests/core/utilities/index.js.map +1 -1
  32. package/dist/tests/core/utilities/minio.d.ts +2 -0
  33. package/dist/tests/core/utilities/minio.js +53 -0
  34. package/dist/tests/core/utilities/minio.js.map +1 -0
  35. package/package.json +4 -4
  36. package/src/auth/auth.ts +0 -2
  37. package/src/environment.ts +2 -0
  38. package/src/middleware/authenticated.ts +0 -2
  39. package/src/middleware/errorHandling.ts +1 -1
  40. package/src/middleware/passport/sso/google.ts +0 -1
  41. package/src/middleware/passport/sso/oidc.ts +0 -2
  42. package/src/migrations/migrations.ts +0 -1
  43. package/src/objectStore/objectStore.ts +97 -24
  44. package/src/objectStore/utils.ts +26 -0
  45. package/tests/core/utilities/index.ts +3 -0
  46. package/tests/core/utilities/minio.ts +34 -0
package/dist/index.js CHANGED
@@ -54482,6 +54482,7 @@ var AutomationIOType = /* @__PURE__ */ ((AutomationIOType2) => {
54482
54482
  AutomationIOType2["ARRAY"] = "array";
54483
54483
  AutomationIOType2["JSON"] = "json";
54484
54484
  AutomationIOType2["DATE"] = "date";
54485
+ AutomationIOType2["ATTACHMENT"] = "attachment";
54485
54486
  return AutomationIOType2;
54486
54487
  })(AutomationIOType || {});
54487
54488
  var AutomationCustomIOType = /* @__PURE__ */ ((AutomationCustomIOType2) => {
@@ -54502,6 +54503,7 @@ var AutomationCustomIOType = /* @__PURE__ */ ((AutomationCustomIOType2) => {
54502
54503
  AutomationCustomIOType2["WEBHOOK_URL"] = "webhookUrl";
54503
54504
  AutomationCustomIOType2["AUTOMATION"] = "automation";
54504
54505
  AutomationCustomIOType2["AUTOMATION_FIELDS"] = "automationFields";
54506
+ AutomationCustomIOType2["MULTI_ATTACHMENTS"] = "multi_attachments";
54505
54507
  return AutomationCustomIOType2;
54506
54508
  })(AutomationCustomIOType || {});
54507
54509
  var AutomationTriggerStepId = /* @__PURE__ */ ((AutomationTriggerStepId2) => {
@@ -55611,7 +55613,8 @@ var DefaultBucketName = {
55611
55613
  APPS: "prod-budi-app-assets",
55612
55614
  TEMPLATES: "templates",
55613
55615
  GLOBAL: "global",
55614
- PLUGINS: "plugins"
55616
+ PLUGINS: "plugins",
55617
+ TEMP: "tmp-file-attachments"
55615
55618
  };
55616
55619
  var selfHosted = !!parseInt(process.env.SELF_HOSTED || "");
55617
55620
  function getAPIEncryptionKey() {
@@ -55702,6 +55705,7 @@ var environment = {
55702
55705
  TEMPLATES_BUCKET_NAME: process.env.TEMPLATES_BUCKET_NAME || DefaultBucketName.TEMPLATES,
55703
55706
  GLOBAL_BUCKET_NAME: process.env.GLOBAL_BUCKET_NAME || DefaultBucketName.GLOBAL,
55704
55707
  PLUGIN_BUCKET_NAME: process.env.PLUGIN_BUCKET_NAME || DefaultBucketName.PLUGINS,
55708
+ TEMP_BUCKET_NAME: process.env.TEMP_BUCKET_NAME || DefaultBucketName.TEMP,
55705
55709
  USE_COUCH: process.env.USE_COUCH || true,
55706
55710
  MOCK_REDIS: process.env.MOCK_REDIS,
55707
55711
  DEFAULT_LICENSE: process.env.DEFAULT_LICENSE,
@@ -56848,16 +56852,19 @@ var objectStore_exports2 = {};
56848
56852
  __export(objectStore_exports2, {
56849
56853
  ObjectStore: () => ObjectStore,
56850
56854
  ObjectStoreBuckets: () => ObjectStoreBuckets,
56855
+ bucketTTLConfig: () => bucketTTLConfig,
56851
56856
  budibaseTempDir: () => budibaseTempDir,
56852
56857
  clientLibraryCDNUrl: () => clientLibraryCDNUrl,
56853
56858
  clientLibraryPath: () => clientLibraryPath,
56854
56859
  clientLibraryUrl: () => clientLibraryUrl,
56860
+ createBucketIfNotExists: () => createBucketIfNotExists,
56855
56861
  deleteFile: () => deleteFile,
56856
56862
  deleteFiles: () => deleteFiles,
56857
56863
  deleteFolder: () => deleteFolder,
56858
56864
  downloadTarball: () => downloadTarball,
56859
56865
  downloadTarballDirect: () => downloadTarballDirect,
56860
56866
  enrichPluginURLs: () => enrichPluginURLs,
56867
+ extractBucketAndPath: () => extractBucketAndPath,
56861
56868
  getAppFileUrl: () => getAppFileUrl,
56862
56869
  getGlobalFileS3Key: () => getGlobalFileS3Key,
56863
56870
  getGlobalFileUrl: () => getGlobalFileUrl,
@@ -56867,7 +56874,6 @@ __export(objectStore_exports2, {
56867
56874
  getPresignedUrl: () => getPresignedUrl,
56868
56875
  getReadStream: () => getReadStream,
56869
56876
  listAllObjects: () => listAllObjects,
56870
- makeSureBucketExists: () => makeSureBucketExists,
56871
56877
  retrieve: () => retrieve,
56872
56878
  retrieveDirectory: () => retrieveDirectory,
56873
56879
  retrieveToTmp: () => retrieveToTmp,
@@ -56897,7 +56903,8 @@ var ObjectStoreBuckets = {
56897
56903
  APPS: environment_default.APPS_BUCKET_NAME,
56898
56904
  TEMPLATES: environment_default.TEMPLATES_BUCKET_NAME,
56899
56905
  GLOBAL: environment_default.GLOBAL_BUCKET_NAME,
56900
- PLUGINS: environment_default.PLUGIN_BUCKET_NAME
56906
+ PLUGINS: environment_default.PLUGIN_BUCKET_NAME,
56907
+ TEMP: environment_default.TEMP_BUCKET_NAME
56901
56908
  };
56902
56909
  var bbTmp = (0, import_path.join)((0, import_os.tmpdir)(), ".budibase");
56903
56910
  try {
@@ -56910,6 +56917,24 @@ try {
56910
56917
  function budibaseTempDir() {
56911
56918
  return bbTmp;
56912
56919
  }
56920
+ var bucketTTLConfig = (bucketName, days) => {
56921
+ const lifecycleRule = {
56922
+ ID: `${bucketName}-ExpireAfter${days}days`,
56923
+ Prefix: "",
56924
+ Status: "Enabled",
56925
+ Expiration: {
56926
+ Days: days
56927
+ }
56928
+ };
56929
+ const lifecycleConfiguration = {
56930
+ Rules: [lifecycleRule]
56931
+ };
56932
+ const params2 = {
56933
+ Bucket: bucketName,
56934
+ LifecycleConfiguration: lifecycleConfiguration
56935
+ };
56936
+ return params2;
56937
+ };
56913
56938
 
56914
56939
  // src/objectStore/objectStore.ts
56915
56940
  var import_uuid2 = require("uuid");
@@ -58216,18 +58241,22 @@ function isDocumentConflictError(error) {
58216
58241
  }
58217
58242
 
58218
58243
  // src/objectStore/objectStore.ts
58244
+ var import_promises = __toESM(require("fs/promises"));
58219
58245
  var sanitize = require("sanitize-s3-objectkey");
58220
58246
  var streamPipeline = (0, import_util.promisify)(import_stream.default.pipeline);
58221
58247
  var STATE = {
58222
58248
  bucketCreationPromises: {}
58223
58249
  };
58250
+ var signedFilePrefix = "/files/signed";
58224
58251
  var CONTENT_TYPE_MAP = {
58225
58252
  txt: "text/plain",
58226
58253
  html: "text/html",
58227
58254
  css: "text/css",
58228
58255
  js: "application/javascript",
58229
58256
  json: "application/json",
58230
- gz: "application/gzip"
58257
+ gz: "application/gzip",
58258
+ svg: "image/svg+xml",
58259
+ form: "multipart/form-data"
58231
58260
  };
58232
58261
  var STRING_CONTENT_TYPES = [
58233
58262
  CONTENT_TYPE_MAP.html,
@@ -58264,17 +58293,19 @@ function ObjectStore(bucket, opts = { presigning: false }) {
58264
58293
  }
58265
58294
  return new import_aws_sdk.default.S3(config);
58266
58295
  }
58267
- async function makeSureBucketExists(client, bucketName) {
58296
+ async function createBucketIfNotExists(client, bucketName) {
58268
58297
  bucketName = sanitizeBucket(bucketName);
58269
58298
  try {
58270
58299
  await client.headBucket({
58271
58300
  Bucket: bucketName
58272
58301
  }).promise();
58302
+ return { created: false, exists: true };
58273
58303
  } catch (err) {
58274
58304
  const promises = STATE.bucketCreationPromises;
58275
58305
  const doesntExist = err.statusCode === 404, noAccess = err.statusCode === 403;
58276
58306
  if (promises[bucketName]) {
58277
58307
  await promises[bucketName];
58308
+ return { created: false, exists: true };
58278
58309
  } else if (doesntExist || noAccess) {
58279
58310
  if (doesntExist) {
58280
58311
  promises[bucketName] = client.createBucket({
@@ -58282,6 +58313,9 @@ async function makeSureBucketExists(client, bucketName) {
58282
58313
  }).promise();
58283
58314
  await promises[bucketName];
58284
58315
  delete promises[bucketName];
58316
+ return { created: true, exists: false };
58317
+ } else {
58318
+ throw new Error("Access denied to object store bucket." + err);
58285
58319
  }
58286
58320
  } else {
58287
58321
  throw new Error("Unable to write to object store bucket.");
@@ -58293,12 +58327,20 @@ async function upload({
58293
58327
  filename,
58294
58328
  path: path2,
58295
58329
  type,
58296
- metadata
58330
+ metadata,
58331
+ body: body2,
58332
+ ttl
58297
58333
  }) {
58298
58334
  const extension = filename.split(".").pop();
58299
- const fileBytes = import_fs3.default.readFileSync(path2);
58335
+ const fileBytes = path2 ? (await import_promises.default.open(path2)).createReadStream() : body2;
58300
58336
  const objectStore = ObjectStore(bucketName);
58301
- await makeSureBucketExists(objectStore, bucketName);
58337
+ const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
58338
+ if (ttl && (bucketCreated.created || bucketCreated.exists)) {
58339
+ let ttlConfig = bucketTTLConfig(bucketName, ttl);
58340
+ if (objectStore.putBucketLifecycleConfiguration) {
58341
+ await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
58342
+ }
58343
+ }
58302
58344
  let contentType = type;
58303
58345
  if (!contentType) {
58304
58346
  contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
@@ -58319,9 +58361,23 @@ async function upload({
58319
58361
  }
58320
58362
  return objectStore.upload(config).promise();
58321
58363
  }
58322
- async function streamUpload(bucketName, filename, stream2, extra = {}) {
58364
+ async function streamUpload({
58365
+ bucket: bucketName,
58366
+ stream: stream2,
58367
+ filename,
58368
+ type,
58369
+ extra,
58370
+ ttl
58371
+ }) {
58372
+ const extension = filename.split(".").pop();
58323
58373
  const objectStore = ObjectStore(bucketName);
58324
- await makeSureBucketExists(objectStore, bucketName);
58374
+ const bucketCreated = await createBucketIfNotExists(objectStore, bucketName);
58375
+ if (ttl && (bucketCreated.created || bucketCreated.exists)) {
58376
+ let ttlConfig = bucketTTLConfig(bucketName, ttl);
58377
+ if (objectStore.putBucketLifecycleConfiguration) {
58378
+ await objectStore.putBucketLifecycleConfiguration(ttlConfig).promise();
58379
+ }
58380
+ }
58325
58381
  if (filename?.endsWith(".js")) {
58326
58382
  extra = {
58327
58383
  ...extra,
@@ -58333,10 +58389,15 @@ async function streamUpload(bucketName, filename, stream2, extra = {}) {
58333
58389
  ContentType: "image"
58334
58390
  };
58335
58391
  }
58392
+ let contentType = type;
58393
+ if (!contentType) {
58394
+ contentType = extension ? CONTENT_TYPE_MAP[extension.toLowerCase()] : CONTENT_TYPE_MAP.txt;
58395
+ }
58336
58396
  const params2 = {
58337
58397
  Bucket: sanitizeBucket(bucketName),
58338
58398
  Key: sanitizeKey(filename),
58339
58399
  Body: stream2,
58400
+ ContentType: contentType,
58340
58401
  ...extra
58341
58402
  };
58342
58403
  return objectStore.upload(params2).promise();
@@ -58392,7 +58453,7 @@ function getPresignedUrl(bucketName, key, durationSeconds = 3600) {
58392
58453
  const signedUrl = new URL(url);
58393
58454
  const path2 = signedUrl.pathname;
58394
58455
  const query = signedUrl.search;
58395
- return `/files/signed${path2}${query}`;
58456
+ return `${signedFilePrefix}${path2}${query}`;
58396
58457
  }
58397
58458
  }
58398
58459
  async function retrieveToTmp(bucketName, filepath) {
@@ -58438,7 +58499,7 @@ async function retrieveDirectory(bucketName, path2) {
58438
58499
  }
58439
58500
  async function deleteFile(bucketName, filepath) {
58440
58501
  const objectStore = ObjectStore(bucketName);
58441
- await makeSureBucketExists(objectStore, bucketName);
58502
+ await createBucketIfNotExists(objectStore, bucketName);
58442
58503
  const params2 = {
58443
58504
  Bucket: bucketName,
58444
58505
  Key: sanitizeKey(filepath)
@@ -58447,7 +58508,7 @@ async function deleteFile(bucketName, filepath) {
58447
58508
  }
58448
58509
  async function deleteFiles(bucketName, filepaths) {
58449
58510
  const objectStore = ObjectStore(bucketName);
58450
- await makeSureBucketExists(objectStore, bucketName);
58511
+ await createBucketIfNotExists(objectStore, bucketName);
58451
58512
  const params2 = {
58452
58513
  Bucket: bucketName,
58453
58514
  Delete: {
@@ -58492,7 +58553,13 @@ async function uploadDirectory(bucketName, localPath, bucketPath) {
58492
58553
  if (file.isDirectory()) {
58493
58554
  uploads.push(uploadDirectory(bucketName, local, path2));
58494
58555
  } else {
58495
- uploads.push(streamUpload(bucketName, path2, import_fs3.default.createReadStream(local)));
58556
+ uploads.push(
58557
+ streamUpload({
58558
+ bucket: bucketName,
58559
+ filename: path2,
58560
+ stream: import_fs3.default.createReadStream(local)
58561
+ })
58562
+ );
58496
58563
  }
58497
58564
  }
58498
58565
  await Promise.all(uploads);
@@ -58530,6 +58597,16 @@ async function getReadStream(bucketName, path2) {
58530
58597
  };
58531
58598
  return client.getObject(params2).createReadStream();
58532
58599
  }
58600
+ function extractBucketAndPath(url) {
58601
+ const baseUrl = url.split("?")[0];
58602
+ const regex = new RegExp(`^${signedFilePrefix}/(?<bucket>[^/]+)/(?<path>.+)$`);
58603
+ const match = baseUrl.match(regex);
58604
+ if (match && match.groups) {
58605
+ const { bucket, path: path2 } = match.groups;
58606
+ return { bucket, path: path2 };
58607
+ }
58608
+ return null;
58609
+ }
58533
58610
 
58534
58611
  // src/objectStore/cloudfront.ts
58535
58612
  var cfsign = __toESM(require("aws-cloudfront-sign"));
@@ -64830,7 +64907,6 @@ var getMigrationsDoc = async (db) => {
64830
64907
  if (err.status && err.status === 404) {
64831
64908
  return { _id: "migrations" /* MIGRATIONS */ };
64832
64909
  } else {
64833
- console.error(err);
64834
64910
  throw err;
64835
64911
  }
64836
64912
  }
@@ -65334,7 +65410,6 @@ async function strategyFactory(config, callbackUrl, saveUserFn) {
65334
65410
  verify
65335
65411
  );
65336
65412
  } catch (err) {
65337
- console.error(err);
65338
65413
  throw new Error(`Error constructing google authentication strategy: ${err}`);
65339
65414
  }
65340
65415
  }
@@ -65399,7 +65474,6 @@ async function strategyFactory2(config, saveUserFn) {
65399
65474
  strategy.name = "oidc";
65400
65475
  return strategy;
65401
65476
  } catch (err) {
65402
- console.error(err);
65403
65477
  throw new Error(`Error constructing OIDC authentication strategy - ${err}`);
65404
65478
  }
65405
65479
  }
@@ -65428,7 +65502,6 @@ async function fetchStrategyConfig(oidcConfig, callbackUrl) {
65428
65502
  callbackURL: callbackUrl
65429
65503
  };
65430
65504
  } catch (err) {
65431
- console.error(err);
65432
65505
  throw new Error(
65433
65506
  `Error constructing OIDC authentication configuration - ${err}`
65434
65507
  );
@@ -65774,7 +65847,6 @@ function authenticated_default(noAuthPatterns = [], opts = {
65774
65847
  } catch (err) {
65775
65848
  authenticated = false;
65776
65849
  console.error(`Auth Error: ${err.message}`);
65777
- console.error(err);
65778
65850
  clearCookie(ctx, "budibase:auth" /* Auth */);
65779
65851
  }
65780
65852
  }
@@ -65816,7 +65888,6 @@ function authenticated_default(noAuthPatterns = [], opts = {
65816
65888
  }
65817
65889
  } catch (err) {
65818
65890
  console.error(`Auth Error: ${err.message}`);
65819
- console.error(err);
65820
65891
  if (err?.name === "JsonWebTokenError") {
65821
65892
  clearCookie(ctx, "budibase:auth" /* Auth */);
65822
65893
  } else if (err?.code === "invalid_api_key" /* INVALID_API_KEY */) {
@@ -66003,7 +66074,7 @@ async function errorHandling(ctx, next) {
66003
66074
  if (status >= 400 && status < 500) {
66004
66075
  console.warn(err);
66005
66076
  } else {
66006
- console.error(err);
66077
+ console.error("Got 400 response code", err);
66007
66078
  }
66008
66079
  let error = {
66009
66080
  message: err.message,
@@ -66106,7 +66177,6 @@ async function refreshOIDCAccessToken(chosenConfig, refreshToken) {
66106
66177
  }
66107
66178
  strategy = await oidc_exports.strategyFactory(enrichedConfig, ssoSaveUserNoOp);
66108
66179
  } catch (err) {
66109
- console.error(err);
66110
66180
  throw new Error("Could not refresh OAuth Token");
66111
66181
  }
66112
66182
  refresh.use(strategy, {
@@ -66134,7 +66204,6 @@ async function refreshGoogleAccessToken(config, refreshToken) {
66134
66204
  ssoSaveUserNoOp
66135
66205
  );
66136
66206
  } catch (err) {
66137
- console.error(err);
66138
66207
  throw new Error(
66139
66208
  `Error constructing OIDC refresh strategy: message=${err.message}`
66140
66209
  );