roboto-js 1.7.4 → 1.8.1

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.
@@ -292,6 +292,343 @@ export default class RbtObject {
292
292
  throw e;
293
293
  }
294
294
  }
295
+
296
+ /**
297
+ * Grants access to this object for specific users and/or user groups.
298
+ * Updates the IAC (Identity and Access Control) permissions.
299
+ *
300
+ * @param {Object} options - Access grant options
301
+ * @param {string[]} [options.userIds=[]] - Array of user IDs to grant read access
302
+ * @param {string[]} [options.groupIds=[]] - Array of user group IDs to grant read access
303
+ * @param {boolean} [options.write=false] - If true, grants write access instead of read access
304
+ * @param {boolean} [options.replace=false] - If true, replaces existing grants; if false, merges with existing
305
+ * @param {boolean} [options.save=true] - If true, automatically saves the object after updating permissions
306
+ * @returns {Promise<RbtObject>} - Returns this object (saved if options.save is true)
307
+ *
308
+ * @example
309
+ * // Grant read access to specific users
310
+ * await myObject.grantAccess({
311
+ * userIds: ['user123', 'user456']
312
+ * });
313
+ *
314
+ * @example
315
+ * // Grant read access to user groups
316
+ * await myObject.grantAccess({
317
+ * groupIds: ['grpRngAccount', 'grpAdmins']
318
+ * });
319
+ *
320
+ * @example
321
+ * // Grant write access to users and groups
322
+ * await myObject.grantAccess({
323
+ * userIds: ['user123'],
324
+ * groupIds: ['grpAdmins'],
325
+ * write: true
326
+ * });
327
+ *
328
+ * @example
329
+ * // Replace existing permissions instead of merging
330
+ * await myObject.grantAccess({
331
+ * userIds: ['user123'],
332
+ * replace: true
333
+ * });
334
+ *
335
+ * @example
336
+ * // Update permissions without auto-saving
337
+ * await myObject.grantAccess({
338
+ * userIds: ['user123'],
339
+ * save: false
340
+ * });
341
+ * // ... make other changes ...
342
+ * await myObject.save();
343
+ */
344
+ async grantAccess(options = {}) {
345
+ const {
346
+ userIds = [],
347
+ groupIds = [],
348
+ write = false,
349
+ replace = false,
350
+ save = true
351
+ } = options;
352
+
353
+ // Validate inputs
354
+ if (!Array.isArray(userIds)) {
355
+ throw new Error('userIds must be an array');
356
+ }
357
+ if (!Array.isArray(groupIds)) {
358
+ throw new Error('groupIds must be an array');
359
+ }
360
+
361
+ // Get current IAC settings
362
+ const iac = this.get('iac') || {};
363
+
364
+ // Determine which grant type to update (read or write)
365
+ const grantType = write ? 'writeGrants' : 'readGrants';
366
+
367
+ // Initialize grants if they don't exist
368
+ if (!iac[grantType]) {
369
+ iac[grantType] = {};
370
+ }
371
+
372
+ // Handle users
373
+ if (userIds.length > 0) {
374
+ if (replace) {
375
+ // Replace existing users
376
+ iac[grantType].users = [...userIds];
377
+ } else {
378
+ // Merge with existing users (avoiding duplicates)
379
+ const existingUsers = iac[grantType].users || [];
380
+ const mergedUsers = [...new Set([...existingUsers, ...userIds])];
381
+ iac[grantType].users = mergedUsers;
382
+ }
383
+ }
384
+
385
+ // Handle user groups
386
+ if (groupIds.length > 0) {
387
+ if (replace) {
388
+ // Replace existing groups
389
+ iac[grantType].userGroups = [...groupIds];
390
+ } else {
391
+ // Merge with existing groups (avoiding duplicates)
392
+ const existingGroups = iac[grantType].userGroups || [];
393
+ const mergedGroups = [...new Set([...existingGroups, ...groupIds])];
394
+ iac[grantType].userGroups = mergedGroups;
395
+ }
396
+ }
397
+
398
+ // Update the object
399
+ this.set('iac', iac);
400
+
401
+ // Save if requested
402
+ if (save) {
403
+ return await this.save();
404
+ }
405
+ return this;
406
+ }
407
+
408
+ /**
409
+ * Publishes this object to make it publicly accessible (or unpublishes it).
410
+ * Adds or removes 'public_user' from the IAC read permissions.
411
+ *
412
+ * @param {Object} options - Publishing options
413
+ * @param {boolean} [options.publish=true] - If true, publishes the object; if false, unpublishes it
414
+ * @param {boolean} [options.save=true] - If true, automatically saves the object after updating permissions
415
+ * @returns {Promise<RbtObject>} - Returns this object (saved if options.save is true)
416
+ *
417
+ * @example
418
+ * // Publish an object (make it public)
419
+ * await myObject.publishObject();
420
+ *
421
+ * @example
422
+ * // Unpublish an object (make it private)
423
+ * await myObject.publishObject({ publish: false });
424
+ *
425
+ * @example
426
+ * // Publish without auto-saving
427
+ * await myObject.publishObject({ save: false });
428
+ * // ... make other changes ...
429
+ * await myObject.save();
430
+ */
431
+ async publishObject(options = {}) {
432
+ const {
433
+ publish = true,
434
+ save = true
435
+ } = options;
436
+
437
+ // Get current IAC settings
438
+ const iac = this.get('iac') || {};
439
+
440
+ // Initialize readGrants if it doesn't exist
441
+ if (!iac.readGrants) {
442
+ iac.readGrants = {};
443
+ }
444
+
445
+ // Initialize users array if it doesn't exist
446
+ if (!Array.isArray(iac.readGrants.users)) {
447
+ iac.readGrants.users = [];
448
+ }
449
+ if (publish) {
450
+ // Add public_user if not already present
451
+ if (!iac.readGrants.users.includes('public_user')) {
452
+ iac.readGrants.users.push('public_user');
453
+ }
454
+ } else {
455
+ // Remove public_user
456
+ iac.readGrants.users = iac.readGrants.users.filter(userId => userId !== 'public_user');
457
+ }
458
+
459
+ // Update the object
460
+ this.set('iac', iac);
461
+
462
+ // Save if requested
463
+ if (save) {
464
+ return await this.save();
465
+ }
466
+ return this;
467
+ }
468
+
469
+ /**
470
+ * Unpublishes this object to remove public access.
471
+ * Removes 'public_user' from the IAC read permissions.
472
+ * This is an alias for publishObject({ publish: false }) for better code clarity.
473
+ *
474
+ * @param {Object} options - Unpublishing options
475
+ * @param {boolean} [options.save=true] - If true, automatically saves the object after updating permissions
476
+ * @returns {Promise<RbtObject>} - Returns this object (saved if options.save is true)
477
+ *
478
+ * @example
479
+ * // Unpublish an object (remove public access)
480
+ * await myObject.unpublishObject();
481
+ *
482
+ * @example
483
+ * // Unpublish without auto-saving
484
+ * await myObject.unpublishObject({ save: false });
485
+ * // ... make other changes ...
486
+ * await myObject.save();
487
+ */
488
+ async unpublishObject(options = {}) {
489
+ return await this.publishObject({
490
+ publish: false,
491
+ save: options.save !== undefined ? options.save : true
492
+ });
493
+ }
494
+
495
+ /**
496
+ * Revokes access from specific users and/or user groups.
497
+ *
498
+ * @param {Object} options - Access revocation options
499
+ * @param {string[]} [options.userIds=[]] - Array of user IDs to remove from read or write access
500
+ * @param {string[]} [options.groupIds=[]] - Array of group IDs to remove from read or write access
501
+ * @param {boolean} [options.write=false] - If true, removes write access; if false, removes read access
502
+ * @param {boolean} [options.save=true] - If true, automatically saves the object after updating permissions
503
+ * @returns {Promise<RbtObject>} - Returns this object (saved if options.save is true)
504
+ *
505
+ * @example
506
+ * // Revoke read access from specific users
507
+ * await myObject.revokeAccess({
508
+ * userIds: ['user_123', 'user_456']
509
+ * });
510
+ *
511
+ * @example
512
+ * // Revoke write access from specific groups
513
+ * await myObject.revokeAccess({
514
+ * groupIds: ['grpEditors'],
515
+ * write: true
516
+ * });
517
+ *
518
+ * @example
519
+ * // Revoke access from users and groups
520
+ * await myObject.revokeAccess({
521
+ * userIds: ['user_123'],
522
+ * groupIds: ['grpViewers']
523
+ * });
524
+ *
525
+ * @example
526
+ * // Revoke without auto-saving
527
+ * await myObject.revokeAccess({
528
+ * userIds: ['user_123'],
529
+ * save: false
530
+ * });
531
+ */
532
+ async revokeAccess(options = {}) {
533
+ const {
534
+ userIds = [],
535
+ groupIds = [],
536
+ write = false,
537
+ save = true
538
+ } = options;
539
+
540
+ // Validate inputs
541
+ if (!Array.isArray(userIds)) {
542
+ throw new Error('userIds must be an array');
543
+ }
544
+ if (!Array.isArray(groupIds)) {
545
+ throw new Error('groupIds must be an array');
546
+ }
547
+
548
+ // Get current IAC settings
549
+ const iac = this.get('iac') || {};
550
+
551
+ // Determine which grant type to update (read or write)
552
+ const grantType = write ? 'writeGrants' : 'readGrants';
553
+
554
+ // Initialize grants if they don't exist
555
+ if (!iac[grantType]) {
556
+ iac[grantType] = {};
557
+ }
558
+
559
+ // Remove specified users
560
+ if (userIds.length > 0 && Array.isArray(iac[grantType].users)) {
561
+ iac[grantType].users = iac[grantType].users.filter(userId => !userIds.includes(userId));
562
+ }
563
+
564
+ // Remove specified groups
565
+ if (groupIds.length > 0 && Array.isArray(iac[grantType].userGroups)) {
566
+ iac[grantType].userGroups = iac[grantType].userGroups.filter(groupId => !groupIds.includes(groupId));
567
+ }
568
+
569
+ // Update the object
570
+ this.set('iac', iac);
571
+
572
+ // Save if requested
573
+ if (save) {
574
+ return await this.save();
575
+ }
576
+ return this;
577
+ }
578
+
579
+ /**
580
+ * Checks if this object is currently published (publicly accessible).
581
+ *
582
+ * @returns {boolean} - True if 'public_user' is in the read grants, false otherwise
583
+ *
584
+ * @example
585
+ * if (myObject.isPublished()) {
586
+ * console.log('Object is public');
587
+ * }
588
+ */
589
+ isPublished() {
590
+ const iac = this.get('iac');
591
+ if (!iac || !iac.readGrants || !Array.isArray(iac.readGrants.users)) {
592
+ return false;
593
+ }
594
+ return iac.readGrants.users.includes('public_user');
595
+ }
596
+
597
+ /**
598
+ * Gets the current sharing permissions for this object.
599
+ *
600
+ * @returns {Object} - Object containing read and write grants
601
+ * @returns {Object} returns.readGrants - Read access grants
602
+ * @returns {string[]} returns.readGrants.users - Array of user IDs with read access
603
+ * @returns {string[]} returns.readGrants.userGroups - Array of group IDs with read access
604
+ * @returns {string[]} returns.readGrants.organizations - Array of organization IDs with read access
605
+ * @returns {Object} returns.writeGrants - Write access grants
606
+ * @returns {string[]} returns.writeGrants.users - Array of user IDs with write access
607
+ * @returns {string[]} returns.writeGrants.userGroups - Array of group IDs with write access
608
+ * @returns {string[]} returns.writeGrants.organizations - Array of organization IDs with write access
609
+ *
610
+ * @example
611
+ * const permissions = myObject.getSharing();
612
+ * console.log('Read users:', permissions.readGrants.users);
613
+ * console.log('Read groups:', permissions.readGrants.userGroups);
614
+ */
615
+ getSharing() {
616
+ const iac = this.get('iac') || {};
617
+ return {
618
+ readGrants: {
619
+ users: iac.readGrants?.users || [],
620
+ userGroups: iac.readGrants?.userGroups || [],
621
+ organizations: iac.readGrants?.organizations || [],
622
+ userSegments: iac.readGrants?.userSegments || []
623
+ },
624
+ writeGrants: {
625
+ users: iac.writeGrants?.users || [],
626
+ userGroups: iac.writeGrants?.userGroups || [],
627
+ organizations: iac.writeGrants?.organizations || [],
628
+ userSegments: iac.writeGrants?.userSegments || []
629
+ }
630
+ };
631
+ }
295
632
  async delete() {
296
633
  if (!this._internalData.type) {
297
634
  throw new Error('Cannot delete object without type');
package/dist/rbt_api.js CHANGED
@@ -1,4 +1,8 @@
1
+ var _excluded = ["enableRealtime"],
2
+ _excluded2 = ["enableRealtime"];
1
3
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
5
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
2
6
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
7
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
8
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
@@ -1119,6 +1123,10 @@ var RbtApi = /*#__PURE__*/function () {
1119
1123
  * - limit: An object to control the pagination of results. It includes:
1120
1124
  * - offset: The starting point from where to fetch the results.
1121
1125
  * - results: The maximum number of results to return.
1126
+ * - requestAttrs: An array of attribute paths to include in the response (e.g., ['id', 'configs.title', 'configs.description']).
1127
+ * If not provided, all attributes are returned.
1128
+ * - excludeAttrs: An array of attribute paths to exclude from the response (e.g., ['details.log', 'internalData']).
1129
+ * Excludes the specified paths and all their subpaths.
1122
1130
  * - resolveReferences: An array of attribute names whose references should be resolved in the returned objects.
1123
1131
  * - timeout: A numerical value in milliseconds to set a maximum time limit for the query execution.
1124
1132
  *
@@ -1127,6 +1135,8 @@ var RbtApi = /*#__PURE__*/function () {
1127
1135
  * where: 'email="tom@pospa.com"',
1128
1136
  * orderBy: { column: 'timeCreated', direction: 'DESC' },
1129
1137
  * limit: { offset: 0, results: 50 },
1138
+ * requestAttrs: ['id', 'configs.title'],
1139
+ * excludeAttrs: ['details.log'],
1130
1140
  * resolveReferences: ['translatableContent']
1131
1141
  * });
1132
1142
  *
@@ -1140,6 +1150,8 @@ var RbtApi = /*#__PURE__*/function () {
1140
1150
  var _this6 = this;
1141
1151
  var params,
1142
1152
  paramsKey,
1153
+ validParams,
1154
+ invalidParams,
1143
1155
  defaultOrderBy,
1144
1156
  defaultLimit,
1145
1157
  mergedParams,
@@ -1155,6 +1167,21 @@ var RbtApi = /*#__PURE__*/function () {
1155
1167
  params = _args20.length > 1 && _args20[1] !== undefined ? _args20[1] : {};
1156
1168
  _context20.p = 1;
1157
1169
  //console.log('RBTAPI.query INIT', type, params);
1170
+ // Validate parameters - reject invalid parameter names
1171
+ validParams = ['type', 'where', 'orderBy', 'limit', 'resolveReferences', 'requestAttrs', 'excludeAttrs', 'timeout', 'enableRealtime'];
1172
+ invalidParams = Object.keys(params).filter(function (key) {
1173
+ return !validParams.includes(key);
1174
+ });
1175
+ if (!(invalidParams.length > 0)) {
1176
+ _context20.n = 2;
1177
+ break;
1178
+ }
1179
+ throw new Error("Invalid query parameter(s): ".concat(invalidParams.join(', '), ". Valid parameters are: ").concat(validParams.join(', ')));
1180
+ case 2:
1181
+ // Warn if enableRealtime is passed to query() - it should only be used by load()
1182
+ if (params.enableRealtime) {
1183
+ console.warn('[roboto-js] enableRealtime should not be passed to query(), only to load(). This parameter will be ignored.');
1184
+ }
1158
1185
  params.type = type;
1159
1186
 
1160
1187
  // Default ordering and pagination
@@ -1175,11 +1202,11 @@ var RbtApi = /*#__PURE__*/function () {
1175
1202
  paramsKey = JSON.stringify(mergedParams);
1176
1203
  cacheEntry = this.requestCache[paramsKey];
1177
1204
  if (!(cacheEntry && currentTime - cacheEntry.time < 10000)) {
1178
- _context20.n = 2;
1205
+ _context20.n = 3;
1179
1206
  break;
1180
1207
  }
1181
1208
  return _context20.a(2, cacheEntry.val);
1182
- case 2:
1209
+ case 3:
1183
1210
  // Create the response promise
1184
1211
  responsePromise = this.axios.post('/object_service/queryObjects', [mergedParams]); // Cache the promise of processing data, not just the raw response
1185
1212
  processingPromise = responsePromise.then(function (response) {
@@ -1195,18 +1222,18 @@ var RbtApi = /*#__PURE__*/function () {
1195
1222
  };
1196
1223
 
1197
1224
  // Await the processing promise for this call to get processed data
1198
- _context20.n = 3;
1225
+ _context20.n = 4;
1199
1226
  return processingPromise;
1200
- case 3:
1201
- return _context20.a(2, _context20.v);
1202
1227
  case 4:
1203
- _context20.p = 4;
1228
+ return _context20.a(2, _context20.v);
1229
+ case 5:
1230
+ _context20.p = 5;
1204
1231
  _t15 = _context20.v;
1205
1232
  delete this.requestCache[paramsKey]; // Ensure cache cleanup on error
1206
1233
  //console.log('RBTAPI.query ERROR', paramsKey, e);
1207
1234
  return _context20.a(2, this._handleError(_t15));
1208
1235
  }
1209
- }, _callee20, this, [[1, 4]]);
1236
+ }, _callee20, this, [[1, 5]]);
1210
1237
  }));
1211
1238
  function query(_x11) {
1212
1239
  return _query.apply(this, arguments);
@@ -1272,6 +1299,8 @@ var RbtApi = /*#__PURE__*/function () {
1272
1299
  hitLogKey,
1273
1300
  loadedObjects,
1274
1301
  bulkMissLogKey,
1302
+ enableRealtime,
1303
+ queryParams,
1275
1304
  _iterator4,
1276
1305
  _step4,
1277
1306
  obj,
@@ -1359,7 +1388,10 @@ var RbtApi = /*#__PURE__*/function () {
1359
1388
  });
1360
1389
  this._loggedCacheEvents.add(bulkMissLogKey);
1361
1390
  }
1362
- mergedParams = _objectSpread(_objectSpread({}, params), {}, {
1391
+
1392
+ // Remove load-specific params that shouldn't be passed to query
1393
+ enableRealtime = params.enableRealtime, queryParams = _objectWithoutProperties(params, _excluded);
1394
+ mergedParams = _objectSpread(_objectSpread({}, queryParams), {}, {
1363
1395
  where: "id IN (\"".concat(missingIds.join("\",\""), "\")")
1364
1396
  });
1365
1397
  _context22.n = 2;
@@ -1464,12 +1496,14 @@ var RbtApi = /*#__PURE__*/function () {
1464
1496
 
1465
1497
  // Create the loading promise and store it to prevent duplicate requests
1466
1498
  loadPromise = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee21() {
1467
- var res, _obj2, _setLogKey;
1499
+ var _enableRealtime, _queryParams, res, _obj2, _setLogKey;
1468
1500
  return _regenerator().w(function (_context21) {
1469
1501
  while (1) switch (_context21.p = _context21.n) {
1470
1502
  case 0:
1471
1503
  _context21.p = 0;
1472
- mergedParams = _objectSpread(_objectSpread({}, params), {}, {
1504
+ // Remove load-specific params that shouldn't be passed to query
1505
+ _enableRealtime = params.enableRealtime, _queryParams = _objectWithoutProperties(params, _excluded2);
1506
+ mergedParams = _objectSpread(_objectSpread({}, _queryParams), {}, {
1473
1507
  where: "id=\"".concat(ids, "\"")
1474
1508
  });
1475
1509
  _context21.n = 1;