@squidcloud/client 1.0.189 → 1.0.190

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.
package/dist/cjs/index.js CHANGED
@@ -27757,6 +27757,7 @@ __webpack_require__.d(__webpack_exports__, {
27757
27757
  SecretClient: () => (/* reexport */ SecretClient),
27758
27758
  SocketManager: () => (/* reexport */ SocketManager),
27759
27759
  Squid: () => (/* reexport */ Squid),
27760
+ StorageClient: () => (/* reexport */ StorageClient),
27760
27761
  allEnvironmentIds: () => (/* reexport */ allEnvironmentIds),
27761
27762
  deserializeQuery: () => (/* reexport */ deserializeQuery),
27762
27763
  generateId: () => (/* reexport */ generateId),
@@ -29337,7 +29338,6 @@ class ApiClient {
29337
29338
 
29338
29339
  // EXTERNAL MODULE: ../node_modules/lodash/lodash.js
29339
29340
  var lodash = __webpack_require__(8784);
29340
- var lodash_default = /*#__PURE__*/__webpack_require__.n(lodash);
29341
29341
  // EXTERNAL MODULE: ../node_modules/assertic/dist/index.js
29342
29342
  var dist = __webpack_require__(8975);
29343
29343
  // EXTERNAL MODULE: ../node_modules/rfdc/index.js
@@ -29473,17 +29473,19 @@ function isEmpty(a) {
29473
29473
  }
29474
29474
  return false;
29475
29475
  }
29476
- function omit(object, ...paths) {
29476
+ function omit(object, ...fieldsToRemove) {
29477
29477
  if (object === null || object === undefined) {
29478
29478
  return {};
29479
29479
  }
29480
- const result = {};
29481
- const omitKeys = new Set(paths);
29482
- Object.keys(object).forEach(key => {
29483
- if (!omitKeys.has(key)) {
29484
- result[key] = object[key];
29480
+ if (fieldsToRemove.length === 0) {
29481
+ return object;
29482
+ }
29483
+ const result = Object.assign({}, object);
29484
+ for (const fieldToRemove of fieldsToRemove) {
29485
+ if (result.hasOwnProperty(fieldToRemove)) {
29486
+ delete result[fieldToRemove];
29485
29487
  }
29486
- });
29488
+ }
29487
29489
  return result;
29488
29490
  }
29489
29491
  /** Creates a deep copy of the object. Copies all Date, Map, Set fields. */
@@ -29494,18 +29496,70 @@ function cloneDeep(value) {
29494
29496
  return rfdc_default()()(value);
29495
29497
  }
29496
29498
  /** Compares 2 values. 'null' and 'undefined' values are considered equal and are less than any other values. */
29497
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
29498
- function compareValues(a, b) {
29499
- if (a === b || (isNil(a) && isNil(b))) {
29499
+ function compareValues(v1, v2) {
29500
+ if (v1 === v2 || (isNil(v1) && isNil(v2))) {
29500
29501
  return 0;
29501
29502
  }
29502
- else if (isNil(a)) {
29503
+ else if (isNil(v1)) {
29503
29504
  return -1;
29504
29505
  }
29505
- else if (isNil(b)) {
29506
+ else if (isNil(v2)) {
29506
29507
  return 1;
29507
29508
  }
29508
- return a < b ? -1 : a > b ? 1 : 0;
29509
+ const v1Type = typeof v1;
29510
+ const v2Type = typeof v2;
29511
+ if (v1Type !== v2Type) {
29512
+ return v1Type < v2Type ? -1 : 1;
29513
+ }
29514
+ if (typeof v1 === 'number') {
29515
+ (0,dist.assertTruthy)(typeof v2 === 'number');
29516
+ if (isNaN(v1) && isNaN(v2))
29517
+ return 0; // Consider NaNs as equal.
29518
+ if (isNaN(v1))
29519
+ return -1; // NaN is considered less than any number.
29520
+ if (isNaN(v2))
29521
+ return 1; // Any number is considered greater than NaN.
29522
+ return v1 < v2 ? -1 : 1;
29523
+ }
29524
+ if (typeof v1 === 'boolean') {
29525
+ (0,dist.assertTruthy)(typeof v2 === 'boolean');
29526
+ return v1 < v2 ? -1 : 1;
29527
+ }
29528
+ if (typeof v1 === 'bigint') {
29529
+ (0,dist.assertTruthy)(typeof v2 === 'bigint');
29530
+ return v1 < v2 ? -1 : 1;
29531
+ }
29532
+ if (typeof v1 === 'string') {
29533
+ (0,dist.assertTruthy)(typeof v2 === 'string');
29534
+ return v1.localeCompare(v2);
29535
+ }
29536
+ if (v1 instanceof Date && v2 instanceof Date) {
29537
+ return Math.sign(v1.getTime() - v2.getTime());
29538
+ }
29539
+ return 0; // Fallback if types are not comparable.
29540
+ }
29541
+ /** Returns a new object with all top-level object fields re-mapped using `valueMapperFn`. */
29542
+ function mapValues(obj, valueMapperFn) {
29543
+ const result = {};
29544
+ const keys = Object.keys(obj);
29545
+ for (const key of keys) {
29546
+ const value = obj[key];
29547
+ result[key] = valueMapperFn(value, key, obj);
29548
+ }
29549
+ return result;
29550
+ }
29551
+ /** Groups elements of the array by key. See _.groupBy for details. */
29552
+ function groupBy(array, getKey) {
29553
+ return array.reduce((result, item) => {
29554
+ const key = getKey(item);
29555
+ if (!result[key]) {
29556
+ result[key] = [item];
29557
+ }
29558
+ else {
29559
+ result[key].push(item);
29560
+ }
29561
+ return result;
29562
+ }, {});
29509
29563
  }
29510
29564
 
29511
29565
  ;// CONCATENATED MODULE: ../internal-common/src/utils/serialization.ts
@@ -29593,14 +29647,14 @@ class ApiManager {
29593
29647
  this.clientIdService = clientIdService;
29594
29648
  this.rpcManager = rpcManager;
29595
29649
  }
29596
- callApiAndSubscribe(integrationId, endpointId, request, options) {
29650
+ callApiAndSubscribe(integrationId, endpointId, request, options, file) {
29597
29651
  const callApiRequest = {
29598
29652
  integrationId,
29599
29653
  endpointId,
29600
29654
  request,
29601
29655
  options,
29602
29656
  };
29603
- return (0,external_rxjs_.race)((0,external_rxjs_.from)(this.rpcManager.post('api/call', callApiRequest)).pipe(map(response => {
29657
+ return (0,external_rxjs_.race)((0,external_rxjs_.from)(this.rpcManager.post('api/call', callApiRequest, file ? [file] : undefined, file ? 'file' : undefined)).pipe(map(response => {
29604
29658
  const parsedPayload = response.payload ? deserializeObj(response.payload) : undefined;
29605
29659
  if (response.success) {
29606
29660
  return parsedPayload;
@@ -29672,13 +29726,23 @@ class BackendFunctionManager {
29672
29726
  this.rpcManager = rpcManager;
29673
29727
  }
29674
29728
  executeFunctionAndSubscribe(functionName, ...params) {
29729
+ const fileArr = [];
29730
+ const paramArr = [];
29731
+ params.forEach(param => {
29732
+ if (typeof File !== 'undefined' && param instanceof File) {
29733
+ fileArr.push(param);
29734
+ }
29735
+ else {
29736
+ paramArr.push(param);
29737
+ }
29738
+ });
29675
29739
  const request = {
29676
29740
  functionName,
29677
- paramsArrayStr: serializeObj(params),
29741
+ paramsArrayStr: serializeObj(paramArr),
29678
29742
  };
29679
29743
  // Append '?functionName' suffix to every POST request for visibility in the browser's 'Network' tab.
29680
29744
  const postUrl = `backend-function/execute?${encodeURIComponent(functionName)}`;
29681
- return (0,external_rxjs_.race)((0,external_rxjs_.from)(this.rpcManager.post(postUrl, request)).pipe(map(response => {
29745
+ return (0,external_rxjs_.race)((0,external_rxjs_.from)(this.rpcManager.post(postUrl, request, fileArr.length > 0 ? fileArr : [])).pipe(map(response => {
29682
29746
  if (!response.success) {
29683
29747
  throw new Error(response.payload);
29684
29748
  }
@@ -30086,6 +30150,8 @@ var IntegrationType;
30086
30150
  IntegrationType["kafka"] = "kafka";
30087
30151
  IntegrationType["confluent"] = "confluent";
30088
30152
  IntegrationType["built_in_queue"] = "built_in_queue";
30153
+ IntegrationType["s3"] = "s3";
30154
+ IntegrationType["built_in_s3"] = "built_in_s3";
30089
30155
  // Coming Soon
30090
30156
  IntegrationType["algolia"] = "algolia";
30091
30157
  IntegrationType["elastic_observability"] = "elastic_observability";
@@ -30269,15 +30335,54 @@ function isStringMatch(str, pattern, caseSensitive) {
30269
30335
  str = str.toLowerCase();
30270
30336
  pattern = pattern.toLowerCase();
30271
30337
  }
30272
- // Escape special regex characters in the pattern
30273
- const escapedPattern = pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
30274
- // Replace '%' wildcard with regex equivalent
30275
- // Note: this allows for newlines, unlike .*
30276
- const regexPattern = escapedPattern.replace(/%/g, '[\\s\\S]*');
30338
+ const regexPattern = replaceSpecialCharacters(pattern);
30277
30339
  // Create regex object and test if string matches
30278
30340
  const regex = new RegExp(`^${regexPattern}$`);
30279
30341
  return regex.test(str);
30280
30342
  }
30343
+ /**
30344
+ * Generates the regex pattern, handling special characters as follows:
30345
+ * - `_` is replaced with a `.`
30346
+ * - `%` is replaced with `[\s\S]*`.
30347
+ * - The above characters can be escaped with \, eg. `\_` is replaced with `_` and `\%` with `%`.
30348
+ * - All special characters in regex (-, /, \, ^, $, *, +, ?, ., (, ), |, [, ], {, }) get escaped with \
30349
+ *
30350
+ * Exported for testing purposes.
30351
+ * */
30352
+ function replaceSpecialCharacters(input) {
30353
+ let result = '';
30354
+ for (let i = 0; i < input.length; ++i) {
30355
+ if (input[i] === '\\') {
30356
+ if (i + 1 < input.length && ['%', '_'].includes(input[i + 1])) {
30357
+ result += input[i + 1];
30358
+ i++;
30359
+ }
30360
+ else if (i + 1 < input.length && input[i + 1] === '\\') {
30361
+ result += '\\\\';
30362
+ i++;
30363
+ }
30364
+ else {
30365
+ result += '\\';
30366
+ }
30367
+ }
30368
+ else if (input[i] === '%') {
30369
+ // Replace '%' wildcard with regex equivalent. Note: this allows for newlines, unlike .*
30370
+ result += '[\\s\\S]*';
30371
+ }
30372
+ else if (input[i] === '_') {
30373
+ result += '[\\s\\S]';
30374
+ }
30375
+ else {
30376
+ // Escape special regex characters in the pattern
30377
+ // '\' is checked above and needs to be manually escaped by the user
30378
+ if ('/-\\^$*+?.()[]{}|'.includes(input[i])) {
30379
+ result += '\\';
30380
+ }
30381
+ result += input[i];
30382
+ }
30383
+ }
30384
+ return result;
30385
+ }
30281
30386
  /**
30282
30387
  * Returns a unique identifier for the query which includes both the client id and the client request id.
30283
30388
  * @internal
@@ -30602,6 +30707,7 @@ var ClientConnectionState;
30602
30707
 
30603
30708
 
30604
30709
 
30710
+
30605
30711
 
30606
30712
 
30607
30713
  ;// CONCATENATED MODULE: ../internal-common/src/utils/assert.ts
@@ -31108,7 +31214,6 @@ class Pagination {
31108
31214
 
31109
31215
 
31110
31216
 
31111
-
31112
31217
  /** @internal */
31113
31218
  class QueryBuilderFactory {
31114
31219
  constructor(querySubscriptionManager, localQueryManager, documentReferenceFactory, documentIdentityService) {
@@ -31218,24 +31323,32 @@ class BaseQueryBuilder {
31218
31323
  * A shortcut for where(fieldName, 'like', pattern).
31219
31324
  *
31220
31325
  * @param fieldName The name of the field to query.
31221
- * @param pattern The pattern to compare against. '%' is the only allowed wildcard
31326
+ * @param pattern The pattern to compare against. '%' matches 0 or more wildcard characters. '_' matches exactly one wildcard character. '\' can be used to escape '%', '_'. or another '\'. Note that any '\' that is not followed by '%', '_', or '\' is invalid.
31222
31327
  * @param caseSensitive Whether to use case-sensitive comparison. Defaults to true.
31223
31328
  * @returns The query builder.
31224
31329
  */
31225
31330
  like(fieldName, pattern, caseSensitive) {
31331
+ this.throwIfInvalidLikePattern(pattern);
31226
31332
  return this.where(fieldName, caseSensitive ? 'like_cs' : 'like', pattern);
31227
31333
  }
31228
31334
  /**
31229
31335
  * A shortcut for where(fieldName, 'not like', pattern).
31230
31336
  *
31231
31337
  * @param fieldName The name of the field to query.
31232
- * @param pattern The pattern to compare against. '%' is the only allowed wildcard
31338
+ * @param pattern The pattern to compare against. '%' matches 0 or more wildcard characters. '_' matches exactly one wildcard character. '\' can be used to escape '%', '_'. or another '\'. Note that any '\' that is not followed by '%', '_', or '\' is invalid.
31233
31339
  * @param caseSensitive Whether to use case-sensitive comparison. Defaults to true.
31234
31340
  * @returns The query builder.
31235
31341
  */
31236
31342
  notLike(fieldName, pattern, caseSensitive) {
31343
+ this.throwIfInvalidLikePattern(pattern);
31237
31344
  return this.where(fieldName, caseSensitive ? 'not like_cs' : 'not like', pattern);
31238
31345
  }
31346
+ throwIfInvalidLikePattern(pattern) {
31347
+ const invalidBackslash = /\\(?![%_\\])/;
31348
+ if (invalidBackslash.test(pattern)) {
31349
+ throw new Error(`Invalid pattern. Cannot have any \\ which are not followed by _, % or \\`);
31350
+ }
31351
+ }
31239
31352
  }
31240
31353
  /** @internal */
31241
31354
  class DereferenceEmitter {
@@ -31368,15 +31481,16 @@ class QueryBuilder extends BaseQueryBuilder {
31368
31481
  mergeConditions() {
31369
31482
  const simpleConditions = this.query.conditions.filter(isSimpleCondition);
31370
31483
  const result = [];
31371
- const groupByFieldName = lodash.groupBy(simpleConditions || [], condition => condition.fieldName);
31484
+ const groupByFieldName = groupBy(simpleConditions || [], condition => condition.fieldName);
31372
31485
  for (const fieldNameGroup of Object.values(groupByFieldName)) {
31373
- const groupByOperator = lodash.groupBy(fieldNameGroup, operator => operator.operator);
31486
+ const groupByOperator = groupBy(fieldNameGroup, operator => operator.operator);
31374
31487
  for (const [operator, operatorGroup] of Object.entries(groupByOperator)) {
31375
31488
  if (operator === '==' || operator === '!=') {
31376
31489
  result.push(...operatorGroup);
31377
31490
  continue;
31378
31491
  }
31379
- const sorted = lodash.sortBy(operatorGroup, o => o.value);
31492
+ const sorted = [...operatorGroup];
31493
+ sorted.sort((o1, o2) => compareValues(o1.value, o2.value));
31380
31494
  if (operator === '>' || operator === '>=') {
31381
31495
  result.push(sorted[sorted.length - 1]);
31382
31496
  }
@@ -31567,7 +31681,6 @@ class Changes {
31567
31681
 
31568
31682
 
31569
31683
 
31570
-
31571
31684
  /**
31572
31685
  * A query builder that can participate in a join.
31573
31686
  * To learn more about join queries, see the
@@ -31735,13 +31848,9 @@ class DereferencedJoin {
31735
31848
  }
31736
31849
  /** @inheritDoc */
31737
31850
  snapshots(subscribe) {
31738
- return this.joinQueryBuilder.snapshots(subscribe).pipe(map(docs => {
31739
- return docs.map(doc => {
31740
- return lodash.mapValues(doc, doc1 => {
31741
- return doc1 === null || doc1 === void 0 ? void 0 : doc1.data;
31742
- });
31743
- });
31744
- }));
31851
+ return this.joinQueryBuilder
31852
+ .snapshots(subscribe)
31853
+ .pipe(map(docs => docs.map(doc => mapValues(doc, fieldDoc => fieldDoc === null || fieldDoc === void 0 ? void 0 : fieldDoc.data))));
31745
31854
  }
31746
31855
  /**
31747
31856
  * @inheritDoc
@@ -31879,7 +31988,7 @@ class GroupedJoin {
31879
31988
  return new DereferencedGroupedJoin(this);
31880
31989
  }
31881
31990
  groupData(input, rootAlias) {
31882
- const oneLevelGroup = lodash.groupBy(input, inputRow => { var _a; return (_a = inputRow[rootAlias]) === null || _a === void 0 ? void 0 : _a.squidDocId; });
31991
+ const oneLevelGroup = groupBy(input, inputRow => { var _a; return (_a = inputRow[rootAlias]) === null || _a === void 0 ? void 0 : _a.squidDocId; });
31883
31992
  return Object.values(oneLevelGroup)
31884
31993
  .filter(value => {
31885
31994
  return value[0][rootAlias] !== undefined;
@@ -32236,7 +32345,6 @@ var promise_pool_dist = __webpack_require__(3910);
32236
32345
 
32237
32346
 
32238
32347
 
32239
-
32240
32348
  function applyStringFn(initialValue, propertyMutation) {
32241
32349
  switch (propertyMutation.fn) {
32242
32350
  case 'trim':
@@ -32268,7 +32376,7 @@ function applyPropertyMutation(property, propertyMutation) {
32268
32376
  case 'applyStringFn':
32269
32377
  return applyStringFn(property, propertyMutation);
32270
32378
  case 'update':
32271
- return typeof propertyMutation.value === 'object' ? lodash.cloneDeep(propertyMutation.value) : propertyMutation.value;
32379
+ return typeof propertyMutation.value === 'object' ? cloneDeep(propertyMutation.value) : propertyMutation.value;
32272
32380
  case 'removeProperty':
32273
32381
  return undefined;
32274
32382
  default:
@@ -32351,18 +32459,6 @@ function applyUpdateMutation(doc, updateMutation) {
32351
32459
  }
32352
32460
  return result;
32353
32461
  }
32354
- /** @internal */
32355
- function convertInsertToUpdate(insertMutation) {
32356
- const result = {
32357
- type: 'update',
32358
- squidDocIdObj: insertMutation.squidDocIdObj,
32359
- properties: {},
32360
- };
32361
- for (const [key, value] of Object.entries(insertMutation.properties)) {
32362
- result.properties[key] = [{ type: 'update', value }];
32363
- }
32364
- return result;
32365
- }
32366
32462
  /**
32367
32463
  * Reduces the list of mutations such that each document will have a single mutation. If for example there are multiple
32368
32464
  * updates to the same document, those will be merged and a single update will be returned.
@@ -33172,6 +33268,9 @@ class DistributedLockManager {
33172
33268
  },
33173
33269
  };
33174
33270
  })), this.acquireLockMessagesFromServer.pipe((0,external_rxjs_.filter)(message => message.payload.clientRequestId === clientRequestId))));
33271
+ if (this.destructManager.isDestructing) {
33272
+ throw new Error('Destructing');
33273
+ }
33175
33274
  if (!result.payload.lockId) {
33176
33275
  throw new Error(`Failed to acquire lock: ${result.payload.error}`);
33177
33276
  }
@@ -33587,7 +33686,6 @@ class DocumentReferenceFactory {
33587
33686
 
33588
33687
 
33589
33688
 
33590
-
33591
33689
  class DocumentStore {
33592
33690
  constructor() {
33593
33691
  this.squidDocIdToDoc = new Map();
@@ -33635,9 +33733,7 @@ class DocumentStore {
33635
33733
  return 0;
33636
33734
  }
33637
33735
  group(sortedDocs, sortFieldNames) {
33638
- return Object.values(lodash_default().groupBy(sortedDocs, doc => {
33639
- return normalizeJsonAsString(sortFieldNames.map(fieldName => getInPath(doc, fieldName)));
33640
- }));
33736
+ return Object.values(groupBy(sortedDocs, doc => normalizeJsonAsString(sortFieldNames.map(fieldName => getInPath(doc, fieldName)))));
33641
33737
  }
33642
33738
  sortAndLimitDocs(docIdSet, query) {
33643
33739
  if (docIdSet.size === 0) {
@@ -49573,6 +49669,7 @@ const kotlinControllers = [
49573
49669
  'queue',
49574
49670
  'mutation',
49575
49671
  'application',
49672
+ 'storage',
49576
49673
  ];
49577
49674
  function getApplicationUrl(regionPrefix, appId, path) {
49578
49675
  const baseUrl = 'https://squid.cloud';
@@ -51193,7 +51290,7 @@ async function performFetchRequest({ headers, files, filesFieldName, message: bo
51193
51290
  };
51194
51291
  }
51195
51292
  catch (e) {
51196
- console.error(`Unable to perform fetch request to url: ${url}`, e);
51293
+ DebugLogger.debug(`Unable to perform fetch request to url: ${url}`, e);
51197
51294
  throw e;
51198
51295
  }
51199
51296
  }
@@ -51495,11 +51592,13 @@ class SocketManager {
51495
51592
  }))
51496
51593
  .subscribe(() => {
51497
51594
  if (this.connectionReady.value) {
51498
- DebugLogger.debug(`Client reconnected before becoming too old. Ignoring... ${this.clientIdService.getClientId()}`);
51595
+ DebugLogger.debug(this.clientIdService.getClientId(), `Client reconnected before becoming too old. Ignoring...`);
51499
51596
  return;
51500
51597
  }
51501
- DebugLogger.debug(`Client disconnected for a long period - refreshing ${this.clientIdService.getClientId()}`);
51502
- this.refreshClient();
51598
+ if (!this.destructManager.isDestructing) {
51599
+ DebugLogger.debug(this.clientIdService.getClientId(), `Client disconnected for a long period - refreshing`);
51600
+ this.refreshClient();
51601
+ }
51503
51602
  });
51504
51603
  this.observeConnectionReady()
51505
51604
  .pipe((0,external_rxjs_.filter)(Boolean))
@@ -51511,22 +51610,22 @@ class SocketManager {
51511
51610
  }
51512
51611
  refreshClient() {
51513
51612
  if (this.destructManager.isDestructing) {
51514
- DebugLogger.debug(`Client too old but is destructed. Ignoring... ${this.clientIdService.getClientId()}`);
51613
+ DebugLogger.debug(this.clientIdService.getClientId(), `Client too old but is destructed. Ignoring...`);
51515
51614
  return;
51516
51615
  }
51517
51616
  else if (this.clientIdService.isClientTooOld()) {
51518
- DebugLogger.debug(`Client is already marked as too old. Ignoring... ${this.clientIdService.getClientId()}`);
51617
+ DebugLogger.debug(this.clientIdService.getClientId(), `Client is already marked as too old. Ignoring...`);
51519
51618
  return;
51520
51619
  }
51521
- DebugLogger.debug(`Notifying client too old ${this.clientIdService.getClientId()}`);
51620
+ DebugLogger.debug(this.clientIdService.getClientId(), `Notifying client too old`);
51522
51621
  this.clientIdService.notifyClientTooOld();
51523
- DebugLogger.debug('Client too old. Reconnecting...');
51622
+ DebugLogger.debug(this.clientIdService.getClientId(), 'Client too old. Reconnecting...');
51524
51623
  this.connect();
51525
51624
  }
51526
51625
  tick() {
51527
51626
  const diff = Math.abs(Date.now() - this.lastTick.getTime());
51528
51627
  if (diff > this.clientTooOldThreshold) {
51529
- DebugLogger.debug('Tick: Client not responding for a long time. Refreshing...', this.clientIdService.getClientId());
51628
+ DebugLogger.debug(this.clientIdService.getClientId(), 'Tick: Client not responding for a long time. Refreshing...');
51530
51629
  this.refreshClient();
51531
51630
  }
51532
51631
  this.lastTick = new Date();
@@ -51551,7 +51650,9 @@ class SocketManager {
51551
51650
  }
51552
51651
  try {
51553
51652
  (0,dist.assertTruthy)(this.socket, 'Socket is undefined in sendMessageAsync');
51554
- this.socket.send(serializeObj({ message, authToken }));
51653
+ const serializedMessage = serializeObj({ message, authToken });
51654
+ DebugLogger.debug(this.clientIdService.getClientId(), 'Sending message to socket: ', serializedMessage);
51655
+ this.socket.send(serializedMessage);
51555
51656
  }
51556
51657
  catch (e) {
51557
51658
  if (!((_a = this.socket) === null || _a === void 0 ? void 0 : _a.connected)) {
@@ -51582,18 +51683,18 @@ class SocketManager {
51582
51683
  .replace('https', 'wss')
51583
51684
  .replace('http', 'ws');
51584
51685
  const clientId = this.clientIdService.getClientId();
51585
- DebugLogger.debug('Connecting to socket at:', endpoint, 'clientId:', clientId);
51686
+ DebugLogger.debug(this.clientIdService.getClientId(), 'Connecting to socket at:', endpoint);
51586
51687
  const socketUri = `${endpoint}?clientId=${clientId}`;
51587
51688
  this.socket = createWebSocketWrapper(socketUri, {
51588
51689
  timeout: 5000, // 5 seconds
51589
51690
  onmessage: (e) => this.onMessage(e.data),
51590
51691
  onopen: () => {
51591
- DebugLogger.debug(`Connection to socket established. Endpoint: ${endpoint} ${this.clientIdService.getClientId()}`);
51692
+ DebugLogger.debug(this.clientIdService.getClientId(), `Connection to socket established. Endpoint: ${endpoint}`);
51592
51693
  },
51593
51694
  onreconnect: () => {
51594
- DebugLogger.debug(`WebSocket reconnect event triggered ${clientId}`);
51695
+ DebugLogger.debug(clientId, `WebSocket reconnect event triggered`);
51595
51696
  if (this.clientIdService.getClientId() !== clientId) {
51596
- DebugLogger.debug(`WebSocket reconnect event triggered - ignored because the client id changed. Old: ${clientId}, new: ${this.clientIdService.getClientId()}`);
51697
+ DebugLogger.debug(clientId, `WebSocket reconnect event triggered - ignored because the client id changed. Old: ${this.clientIdService.getClientId()}`);
51597
51698
  return;
51598
51699
  }
51599
51700
  if (this.connectionReady.value) {
@@ -51601,9 +51702,9 @@ class SocketManager {
51601
51702
  }
51602
51703
  },
51603
51704
  onclose: () => {
51604
- DebugLogger.debug(`WebSocket onclose event triggered ${clientId}`);
51705
+ DebugLogger.debug(clientId, `WebSocket onclose event triggered`);
51605
51706
  if (this.clientIdService.getClientId() !== clientId) {
51606
- DebugLogger.debug(`WebSocket onclose event triggered - ignored because the client id changed. Old: ${clientId}, new: ${this.clientIdService.getClientId()}`);
51707
+ DebugLogger.debug(clientId, `WebSocket onclose event triggered - ignored because the client id changed. new: ${this.clientIdService.getClientId()}`);
51607
51708
  return;
51608
51709
  }
51609
51710
  if (this.connectionReady.value) {
@@ -51624,7 +51725,7 @@ class SocketManager {
51624
51725
  }
51625
51726
  onMessage(messagesStr) {
51626
51727
  if (messagesStr === 'connectionReady') {
51627
- DebugLogger.debug(`Got socket message: connectionReady ${this.clientIdService.getClientId()}`);
51728
+ DebugLogger.debug(this.clientIdService.getClientId(), `Got socket message: connectionReady`);
51628
51729
  this.onConnectionReady();
51629
51730
  return;
51630
51731
  }
@@ -51635,7 +51736,7 @@ class SocketManager {
51635
51736
  continue;
51636
51737
  }
51637
51738
  this.seenMessageIds.add(message.messageId);
51638
- DebugLogger.debug(new Date(), `Got socket message: (${this.clientIdService.getClientId()})`, JSON.stringify(message, null, 2));
51739
+ DebugLogger.debug(this.clientIdService.getClientId(), new Date(), `Got socket message`, JSON.stringify(message, null, 2));
51639
51740
  this.messageNotificationWrapper(() => {
51640
51741
  this.webSocketObserver.next(message);
51641
51742
  });
@@ -51717,6 +51818,55 @@ function omitSquidDevId(appId) {
51717
51818
  return appIdWithEnvironmentId(parsedAppId.appId, parsedAppId.environmentId);
51718
51819
  }
51719
51820
 
51821
+ ;// CONCATENATED MODULE: ./src/storage-client.ts
51822
+ class StorageClient {
51823
+ /** @internal */
51824
+ constructor(integrationId = 'built_in_storage', rpcManager) {
51825
+ this.integrationId = integrationId;
51826
+ this.rpcManager = rpcManager;
51827
+ }
51828
+ async uploadFile(pathInBucket, file, expirationInSeconds) {
51829
+ const request = {
51830
+ integrationId: this.integrationId,
51831
+ pathInBucket,
51832
+ expirationInSeconds,
51833
+ };
51834
+ await this.rpcManager.post('storage/uploadFile', request, [file]);
51835
+ }
51836
+ async getFileMetadata(pathInBucket) {
51837
+ const request = {
51838
+ integrationId: this.integrationId,
51839
+ pathInBucket,
51840
+ };
51841
+ return await this.rpcManager.post('storage/getFileMetadata', request);
51842
+ }
51843
+ async getDownloadUrl(pathInBucket, urlExpirationInSeconds) {
51844
+ const request = {
51845
+ integrationId: this.integrationId,
51846
+ pathInBucket,
51847
+ urlExpirationInSeconds,
51848
+ };
51849
+ return await this.rpcManager.post('storage/getDownloadUrl', request);
51850
+ }
51851
+ async listDirectoryContents(pathInBucket) {
51852
+ const request = {
51853
+ integrationId: this.integrationId,
51854
+ pathInBucket,
51855
+ };
51856
+ return await this.rpcManager.post('storage/listDirectoryContents', request);
51857
+ }
51858
+ async deleteFile(pathInBucket) {
51859
+ await this.deleteFiles([pathInBucket]);
51860
+ }
51861
+ async deleteFiles(pathsInBucket) {
51862
+ const request = {
51863
+ integrationId: this.integrationId,
51864
+ pathsInBucket,
51865
+ };
51866
+ await this.rpcManager.post('storage/deleteFiles', request);
51867
+ }
51868
+ }
51869
+
51720
51870
  ;// CONCATENATED MODULE: ./src/squid.ts
51721
51871
 
51722
51872
 
@@ -51749,6 +51899,7 @@ function omitSquidDevId(appId) {
51749
51899
 
51750
51900
 
51751
51901
 
51902
+
51752
51903
 
51753
51904
 
51754
51905
  /**
@@ -51923,12 +52074,13 @@ class Squid {
51923
52074
  * @param endpointId The id of the endpoint in the API integration.
51924
52075
  * @param request The request parameters to pass to the API.
51925
52076
  * @param options optional options for the API call.
52077
+ * @param file optional file to pass in as part of the API
51926
52078
  * @returns A promise that resolves with the response of the API.
51927
52079
  * @typeParam T The type of the response of the API.
51928
52080
  */
51929
- callApi(integrationId, endpointId, request = {}, options) {
52081
+ callApi(integrationId, endpointId, request = {}, options, file) {
51930
52082
  this._validateNotDestructed();
51931
- return (0,external_rxjs_.firstValueFrom)(this.apiManager.callApiAndSubscribe(integrationId, endpointId, request, options || {}));
52083
+ return (0,external_rxjs_.firstValueFrom)(this.apiManager.callApiAndSubscribe(integrationId, endpointId, request, options || {}, file));
51932
52084
  }
51933
52085
  /**
51934
52086
  * Returns a GraphQL client for the given integration. The GraphQL client can be used to execute GraphQL queries and
@@ -51955,6 +52107,10 @@ class Squid {
51955
52107
  this._validateNotDestructed();
51956
52108
  return this.apiClient;
51957
52109
  }
52110
+ storage(integrationId = 'built_in_storage') {
52111
+ this._validateNotDestructed();
52112
+ return new StorageClient(integrationId, this.rpcManager);
52113
+ }
51958
52114
  get secrets() {
51959
52115
  return this.secretClient;
51960
52116
  }
@@ -51969,6 +52125,23 @@ class Squid {
51969
52125
  this._validateNotDestructed();
51970
52126
  return this.distributedLockManager.lock(mutex);
51971
52127
  }
52128
+ /**
52129
+ * Executes the given callback while holding a lock for the given mutex. The lock will be released when the callback
52130
+ * finishes.
52131
+ * @param mutex A string that uniquely identifies the lock.
52132
+ * @param fn The callback to execute while holding the lock.
52133
+ * @returns A promise that resolves with the result of the callback. The promise will reject if failed
52134
+ * to acquire the lock.
52135
+ */
52136
+ async withLock(mutex, fn) {
52137
+ const lock = await this.acquireLock(mutex);
52138
+ try {
52139
+ return await fn(lock);
52140
+ }
52141
+ finally {
52142
+ void lock.release();
52143
+ }
52144
+ }
51972
52145
  /**
51973
52146
  * Returns a queue manager for the given topic name and integration id. Using the queue manager you can consume and
51974
52147
  * produce messages
@@ -52050,6 +52223,7 @@ Squid.squidInstancesMap = {};
52050
52223
 
52051
52224
 
52052
52225
 
52226
+
52053
52227
 
52054
52228
 
52055
52229
  })();
@@ -1,7 +1,7 @@
1
1
  import { MutationContext } from './mutation.public-context';
2
2
  import { ApiCallContext } from './api-call.public-context';
3
3
  import { QueryContext } from './query.public-context';
4
- import { AiChatbotActionType, DatabaseActionType, TopicActionType } from './bundle-data.public-types';
4
+ import { AiChatbotActionType, DatabaseActionType, StorageActionType, TopicActionType } from './bundle-data.public-types';
5
5
  import { ClientConnectionState } from './socket.public-types';
6
6
  import { DocumentData } from './document.public-types';
7
7
  import { MutationType } from './mutation.public-types';
@@ -11,7 +11,9 @@ import { NativeQueryContext } from './native-query.public-context';
11
11
  import { DistributedLockContext } from './distributed-lock.public-context';
12
12
  import { GraphqlContext } from './graphql.public-context';
13
13
  import { AiChatbotChatContext, AiChatbotMutationContext } from './ai-chatbot.public-context';
14
+ import { SecureStorageRequest } from './storage.types';
14
15
  export type SecureDatabaseAction<T extends DatabaseActionType> = T extends 'all' ? () => boolean | Promise<boolean> : T extends 'read' ? ((context: QueryContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>) : ((context: MutationContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
16
+ export type SecureStorageAction<T extends StorageActionType> = T extends 'all' ? () => boolean | Promise<boolean> : (request: SecureStorageRequest) => boolean | Promise<boolean>;
15
17
  export type SecureTopicAction<T extends TopicActionType> = T extends 'all' ? () => boolean | Promise<boolean> : T extends 'read' ? ((context: TopicReadContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>) : ((context: TopicWriteContext<T>) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
16
18
  export type SecureApiAction = ((context: ApiCallContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
17
19
  export type SecureNativeQueryAction = ((context: NativeQueryContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
@@ -1,5 +1,7 @@
1
1
  /** The different types of actions that can be performed on a database. */
2
2
  export type DatabaseActionType = 'read' | 'write' | 'update' | 'insert' | 'delete' | 'all';
3
+ /** The different types of actions that can be performed for storage. */
4
+ export type StorageActionType = 'read' | 'write' | 'update' | 'insert' | 'delete' | 'all';
3
5
  /** The different types of actions that can be performed on a topic. */
4
6
  export type TopicActionType = 'read' | 'write' | 'all';
5
7
  /** The different types of actions that can be performed on an AI chatbot. */
@@ -21,6 +21,8 @@ export declare enum IntegrationType {
21
21
  'kafka' = "kafka",
22
22
  'confluent' = "confluent",
23
23
  'built_in_queue' = "built_in_queue",
24
+ 's3' = "s3",
25
+ 'built_in_s3' = "built_in_s3",
24
26
  'algolia' = "algolia",
25
27
  'elastic_observability' = "elastic_observability",
26
28
  'elastic_search' = "elastic_search",
@@ -39,3 +39,6 @@ export interface DiscoverOpenApiSchemaRequest {
39
39
  integrationType: IntegrationType.api;
40
40
  discoveryOptions: OpenApiDiscoveryOptions;
41
41
  }
42
+ export interface DiscoverOpenApiSchemaFromFileRequest {
43
+ integrationType: IntegrationType.api;
44
+ }
@@ -0,0 +1,9 @@
1
+ import { IntegrationId } from './communication.public-types';
2
+ import { StorageActionType } from './bundle-data.public-types';
3
+ export type StorageFunctionality = 'fileUpload';
4
+ export interface SecureStorageRequest {
5
+ integrationId: IntegrationId;
6
+ pathsInBucket: Array<string>;
7
+ action: StorageActionType;
8
+ functionality: StorageFunctionality;
9
+ }
@@ -1 +1,10 @@
1
- export {};
1
+ /**
2
+ * Generates the regex pattern, handling special characters as follows:
3
+ * - `_` is replaced with a `.`
4
+ * - `%` is replaced with `[\s\S]*`.
5
+ * - The above characters can be escaped with \, eg. `\_` is replaced with `_` and `\%` with `%`.
6
+ * - All special characters in regex (-, /, \, ^, $, *, +, ?, ., (, ), |, [, ], {, }) get escaped with \
7
+ *
8
+ * Exported for testing purposes.
9
+ * */
10
+ export declare function replaceSpecialCharacters(input: string): string;
@@ -9,8 +9,12 @@ export declare function replaceKeyInRecord<K extends keyof any, T>(record: Recor
9
9
  export declare function isNil(obj: unknown): obj is null | undefined;
10
10
  export declare function isEqual(a: unknown, b: unknown): boolean;
11
11
  export declare function isEmpty(a: unknown): boolean;
12
- export declare function omit<T extends object, K extends (string | number | symbol)[]>(object: T | null | undefined, ...paths: K): Pick<T, Exclude<keyof T, K[number]>>;
12
+ export declare function omit<T extends object, K extends PropertyKey[]>(object: T | null | undefined, ...fieldsToRemove: K): Pick<T, Exclude<keyof T, K[number]>>;
13
13
  /** Creates a deep copy of the object. Copies all Date, Map, Set fields. */
14
14
  export declare function cloneDeep<T>(value: T): T;
15
15
  /** Compares 2 values. 'null' and 'undefined' values are considered equal and are less than any other values. */
16
- export declare function compareValues(a: any, b: any): number;
16
+ export declare function compareValues(v1: unknown, v2: unknown): number;
17
+ /** Returns a new object with all top-level object fields re-mapped using `valueMapperFn`. */
18
+ export declare function mapValues<ResultType extends object = Record<string, unknown>, InputType extends Record<string, unknown> = Record<string, unknown>>(obj: InputType, valueMapperFn: (value: any, key: keyof InputType, obj: InputType) => unknown): ResultType;
19
+ /** Groups elements of the array by key. See _.groupBy for details. */
20
+ export declare function groupBy<T, K extends PropertyKey>(array: T[], getKey: (item: T) => K): Record<K, T[]>;
@@ -40,3 +40,4 @@ export * from './socket.manager';
40
40
  export * from './squid-http-client';
41
41
  export * from './squid';
42
42
  export * from './types';
43
+ export * from './storage-client';
@@ -29,3 +29,4 @@ export * from '../../internal-common/src/public-types/serialized-query.public-ty
29
29
  export * from '../../internal-common/src/public-types/socket.public-types';
30
30
  export * from '../../internal-common/src/public-types/topic.public-context';
31
31
  export * from '../../internal-common/src/public-types/typescript.public-types';
32
+ export * from '../../internal-common/src/public-types/storage.types';
@@ -87,7 +87,7 @@ export declare abstract class BaseQueryBuilder<MyDocType extends DocumentData> {
87
87
  * A shortcut for where(fieldName, 'like', pattern).
88
88
  *
89
89
  * @param fieldName The name of the field to query.
90
- * @param pattern The pattern to compare against. '%' is the only allowed wildcard
90
+ * @param pattern The pattern to compare against. '%' matches 0 or more wildcard characters. '_' matches exactly one wildcard character. '\' can be used to escape '%', '_'. or another '\'. Note that any '\' that is not followed by '%', '_', or '\' is invalid.
91
91
  * @param caseSensitive Whether to use case-sensitive comparison. Defaults to true.
92
92
  * @returns The query builder.
93
93
  */
@@ -96,11 +96,12 @@ export declare abstract class BaseQueryBuilder<MyDocType extends DocumentData> {
96
96
  * A shortcut for where(fieldName, 'not like', pattern).
97
97
  *
98
98
  * @param fieldName The name of the field to query.
99
- * @param pattern The pattern to compare against. '%' is the only allowed wildcard
99
+ * @param pattern The pattern to compare against. '%' matches 0 or more wildcard characters. '_' matches exactly one wildcard character. '\' can be used to escape '%', '_'. or another '\'. Note that any '\' that is not followed by '%', '_', or '\' is invalid.
100
100
  * @param caseSensitive Whether to use case-sensitive comparison. Defaults to true.
101
101
  * @returns The query builder.
102
102
  */
103
103
  notLike(fieldName: (keyof MyDocType & FieldName) | string, pattern: string, caseSensitive?: boolean): this;
104
+ throwIfInvalidLikePattern(pattern: string): void;
104
105
  /**
105
106
  * Sets a limit to the number of results returned by the query. The maximum limit is 20,000 and the default is 1,000
106
107
  * if none is provided.
@@ -5,9 +5,10 @@ import { GraphQLClient } from './graphql-client';
5
5
  import { SecretClient } from './secret.client';
6
6
  import { TransactionId } from './types';
7
7
  import { AiClient } from './ai.types';
8
- import { ApiEndpointId, ApiKey, CallApiOptions, AppId, CollectionName, DocumentData, EnvironmentId, IntegrationId, NativeApiCallResponse, SquidDeveloperId, SquidRegion } from './public-types';
8
+ import { ApiEndpointId, ApiKey, AppId, CallApiOptions, CollectionName, DocumentData, EnvironmentId, IntegrationId, NativeApiCallResponse, SquidDeveloperId, SquidRegion } from './public-types';
9
9
  import { QueueManager } from './queue.manager';
10
10
  import { ApiClient } from './api-client';
11
+ import { StorageClient } from './storage-client';
11
12
  /** The different options that can be used to initialize a Squid instance. */
12
13
  export interface SquidOptions {
13
14
  /**
@@ -207,6 +208,7 @@ export declare class Squid {
207
208
  */
208
209
  ai(): AiClient;
209
210
  api(): ApiClient;
211
+ storage(integrationId?: IntegrationId): StorageClient;
210
212
  get secrets(): SecretClient;
211
213
  /**
212
214
  * Returns a distributed lock for the given mutex. The lock can be used to synchronize access to a shared resource.
@@ -216,6 +218,15 @@ export declare class Squid {
216
218
  * @returns A promise that resolves with the lock object. The promise will reject if failed to acquire the lock.
217
219
  */
218
220
  acquireLock(mutex: string): Promise<DistributedLock>;
221
+ /**
222
+ * Executes the given callback while holding a lock for the given mutex. The lock will be released when the callback
223
+ * finishes.
224
+ * @param mutex A string that uniquely identifies the lock.
225
+ * @param fn The callback to execute while holding the lock.
226
+ * @returns A promise that resolves with the result of the callback. The promise will reject if failed
227
+ * to acquire the lock.
228
+ */
229
+ withLock<T>(mutex: string, fn: (lock: DistributedLock) => Promise<T>): Promise<T>;
219
230
  /**
220
231
  * Returns a queue manager for the given topic name and integration id. Using the queue manager you can consume and
221
232
  * produce messages
@@ -0,0 +1,53 @@
1
+ import { BlobAndFilename } from './types';
2
+ import { IntegrationId } from '../../internal-common/src/public-types/communication.public-types';
3
+ export interface StorageFileUploadRequest {
4
+ integrationId: IntegrationId;
5
+ pathInBucket: string;
6
+ expirationInSeconds?: number;
7
+ }
8
+ export interface GetFileMetadataRequest {
9
+ integrationId: IntegrationId;
10
+ pathInBucket: string;
11
+ }
12
+ export interface GetFileMetadataResponse {
13
+ filename: string;
14
+ size: number;
15
+ lastModified: Date;
16
+ metadata: Record<string, string>;
17
+ }
18
+ export interface GetDownloadUrlRequest {
19
+ integrationId: IntegrationId;
20
+ pathInBucket: string;
21
+ urlExpirationInSeconds?: number;
22
+ }
23
+ export interface GetDownloadUrlResponse {
24
+ url: string;
25
+ }
26
+ export interface DeleteFilesRequest {
27
+ integrationId: IntegrationId;
28
+ pathsInBucket: Array<string>;
29
+ }
30
+ export interface ListDirectoryContentsRequest {
31
+ integrationId: IntegrationId;
32
+ pathInBucket: string;
33
+ }
34
+ export interface FileInDirectory {
35
+ filename: string;
36
+ absolutePathInBucket: string;
37
+ size: number;
38
+ lastModified: Date;
39
+ }
40
+ export interface ListDirectoryContentsResponse {
41
+ directories: Array<string>;
42
+ files: Array<FileInDirectory>;
43
+ }
44
+ export declare class StorageClient {
45
+ private readonly integrationId;
46
+ private readonly rpcManager;
47
+ uploadFile(pathInBucket: string, file: File | BlobAndFilename, expirationInSeconds?: number): Promise<void>;
48
+ getFileMetadata(pathInBucket: string): Promise<GetFileMetadataResponse>;
49
+ getDownloadUrl(pathInBucket: string, urlExpirationInSeconds?: number): Promise<GetDownloadUrlResponse>;
50
+ listDirectoryContents(pathInBucket: string): Promise<ListDirectoryContentsResponse>;
51
+ deleteFile(pathInBucket: string): Promise<void>;
52
+ deleteFiles(pathsInBucket: Array<string>): Promise<void>;
53
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squidcloud/client",
3
- "version": "1.0.189",
3
+ "version": "1.0.190",
4
4
  "description": "A typescript implementation of the Squid client",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/typescript-client/src/index.d.ts",