roboto-js 1.9.3 → 1.9.5

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/.last-build CHANGED
@@ -1 +1 @@
1
- 2025-11-14T13:39:56.113Z
1
+ 2025-12-08T03:12:14.784Z
@@ -35,6 +35,9 @@ var _rbt_metrics_api = _interopRequireDefault(require("./rbt_metrics_api.cjs"));
35
35
  var _cookie_storage_adaptor = _interopRequireDefault(require("./cookie_storage_adaptor.cjs"));
36
36
  var _version = require("./version.cjs");
37
37
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
38
+ 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; }
39
+ 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; }
40
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
38
41
  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); }
39
42
  function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
40
43
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
@@ -240,6 +243,53 @@ var Roboto = exports["default"] = /*#__PURE__*/function () {
240
243
  value: function recordToInstance(recordHash) {
241
244
  return new _rbt_object["default"](recordHash, this.api.axios);
242
245
  }
246
+
247
+ /**
248
+ * Wraps raw API response data as RbtObject(s)
249
+ * Use this when receiving raw JSON from custom API endpoints (e.g., /api/tasks/*)
250
+ * that return database objects instead of using roboto's built-in query methods.
251
+ *
252
+ * @param {Object|Array|null} data - Raw response data (single object or array)
253
+ * @returns {RbtObject|Array<RbtObject>|null} - Wrapped RbtObject(s) or original value if null/already wrapped
254
+ *
255
+ * @example
256
+ * // Wrapping a single object
257
+ * const response = await fetch('/api/tasks/boards/123');
258
+ * const data = await response.cjson();
259
+ * const board = roboto.wrapAsRbtObjects(data.board);
260
+ * board.set('title', 'New Title'); // Now you can use RbtObject methods
261
+ *
262
+ * @example
263
+ * // Wrapping an array
264
+ * const response = await fetch('/api/tasks/boards');
265
+ * const data = await response.cjson();
266
+ * const boards = roboto.wrapAsRbtObjects(data.boards);
267
+ * boards.forEach(board => console.log(board.get('title')));
268
+ */
269
+ }, {
270
+ key: "wrapAsRbtObjects",
271
+ value: function wrapAsRbtObjects(data) {
272
+ var _this2 = this;
273
+ if (!data) return data;
274
+
275
+ // If it's already an RbtObject, return as-is (idempotent)
276
+ if (typeof data.get === 'function') {
277
+ return data;
278
+ }
279
+
280
+ // If it's an array, wrap each item
281
+ if (Array.isArray(data)) {
282
+ return data.map(function (item) {
283
+ if (typeof (item === null || item === void 0 ? void 0 : item.get) === 'function') {
284
+ return item;
285
+ }
286
+ return new _rbt_object["default"](item, _this2.api.axios);
287
+ });
288
+ }
289
+
290
+ // Single object - wrap it
291
+ return new _rbt_object["default"](data, this.api.axios);
292
+ }
243
293
  }, {
244
294
  key: "_stripHttpsForDomains",
245
295
  value: function _stripHttpsForDomains(baseUrl, domains) {
@@ -650,18 +700,78 @@ var Roboto = exports["default"] = /*#__PURE__*/function () {
650
700
  return _pollTaskProgress.apply(this, arguments);
651
701
  }
652
702
  return pollTaskProgress;
653
- }() //
703
+ }()
704
+ /**
705
+ * Helper to detect if an object looks like a doctree object
706
+ * @private
707
+ */
708
+ }, {
709
+ key: "_isDoctreeObject",
710
+ value: function _isDoctreeObject(obj) {
711
+ if (!obj || _typeof(obj) !== 'object') return false;
712
+ // Check for standard doctree fields
713
+ return obj.hasOwnProperty('id') && obj.hasOwnProperty('type') && obj.hasOwnProperty('timeCreated');
714
+ }
715
+
716
+ /**
717
+ * Auto-wraps response data if it contains doctree objects
718
+ * @private
719
+ */
720
+ }, {
721
+ key: "_autoWrapResponse",
722
+ value: function _autoWrapResponse(data) {
723
+ if (!data) return data;
724
+
725
+ // If response has an 'items' array (common pattern), wrap those
726
+ if (data.items && Array.isArray(data.items)) {
727
+ if (data.items.length > 0 && this._isDoctreeObject(data.items[0])) {
728
+ return _objectSpread(_objectSpread({}, data), {}, {
729
+ items: this.wrapAsRbtObjects(data.items)
730
+ });
731
+ }
732
+ }
733
+
734
+ // If response has a single object property that looks like doctree
735
+ // Check common property names: board, ticket, task, note, etc.
736
+ for (var _i = 0, _Object$keys = Object.keys(data); _i < _Object$keys.length; _i++) {
737
+ var key = _Object$keys[_i];
738
+ if (this._isDoctreeObject(data[key])) {
739
+ return _objectSpread(_objectSpread({}, data), {}, _defineProperty({}, key, this.wrapAsRbtObjects(data[key])));
740
+ }
741
+ // Check if it's an array of doctree objects
742
+ if (Array.isArray(data[key]) && data[key].length > 0 && this._isDoctreeObject(data[key][0])) {
743
+ return _objectSpread(_objectSpread({}, data), {}, _defineProperty({}, key, this.wrapAsRbtObjects(data[key])));
744
+ }
745
+ }
746
+
747
+ // If the root data itself is a doctree object or array of them
748
+ if (this._isDoctreeObject(data)) {
749
+ return this.wrapAsRbtObjects(data);
750
+ }
751
+ if (Array.isArray(data) && data.length > 0 && this._isDoctreeObject(data[0])) {
752
+ return this.wrapAsRbtObjects(data);
753
+ }
754
+ return data;
755
+ }
756
+
757
+ //
654
758
  // Get/Post to endpoint with Roboto authtoken
759
+ // Automatically wraps doctree objects in responses as RbtObjects
655
760
  //
656
761
  }, {
657
762
  key: "get",
658
763
  value: function () {
659
764
  var _get = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee20(endpoint, params) {
765
+ var result;
660
766
  return _regeneratorRuntime().wrap(function _callee20$(_context20) {
661
767
  while (1) switch (_context20.prev = _context20.next) {
662
768
  case 0:
663
- return _context20.abrupt("return", this.api.get(endpoint, params));
664
- case 1:
769
+ _context20.next = 2;
770
+ return this.api.get(endpoint, params);
771
+ case 2:
772
+ result = _context20.sent;
773
+ return _context20.abrupt("return", this._autoWrapResponse(result));
774
+ case 4:
665
775
  case "end":
666
776
  return _context20.stop();
667
777
  }
@@ -676,11 +786,16 @@ var Roboto = exports["default"] = /*#__PURE__*/function () {
676
786
  key: "post",
677
787
  value: function () {
678
788
  var _post = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(endpoint, data) {
789
+ var result;
679
790
  return _regeneratorRuntime().wrap(function _callee21$(_context21) {
680
791
  while (1) switch (_context21.prev = _context21.next) {
681
792
  case 0:
682
- return _context21.abrupt("return", this.api.post(endpoint, data));
683
- case 1:
793
+ _context21.next = 2;
794
+ return this.api.post(endpoint, data);
795
+ case 2:
796
+ result = _context21.sent;
797
+ return _context21.abrupt("return", this._autoWrapResponse(result));
798
+ case 4:
684
799
  case "end":
685
800
  return _context21.stop();
686
801
  }
@@ -481,6 +481,7 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
481
481
  replace,
482
482
  _options$save,
483
483
  save,
484
+ currentIac,
484
485
  iac,
485
486
  grantType,
486
487
  existingUsers,
@@ -505,8 +506,9 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
505
506
  }
506
507
  throw new Error('groupIds must be an array');
507
508
  case 6:
508
- // Get current IAC settings
509
- iac = this.get('iac') || {}; // Determine which grant type to update (read or write)
509
+ // Get current IAC settings and create a deep clone to ensure change detection
510
+ currentIac = this.get('iac') || {};
511
+ iac = _lodash["default"].cloneDeep(currentIac); // Determine which grant type to update (read or write)
510
512
  grantType = write ? 'writeGrants' : 'readGrants'; // Initialize grants if they don't exist
511
513
  if (!iac[grantType]) {
512
514
  iac[grantType] = {};
@@ -543,16 +545,16 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
543
545
 
544
546
  // Save if requested
545
547
  if (!save) {
546
- _context4.next = 16;
548
+ _context4.next = 17;
547
549
  break;
548
550
  }
549
- _context4.next = 15;
551
+ _context4.next = 16;
550
552
  return this.save();
551
- case 15:
552
- return _context4.abrupt("return", _context4.sent);
553
553
  case 16:
554
- return _context4.abrupt("return", this);
554
+ return _context4.abrupt("return", _context4.sent);
555
555
  case 17:
556
+ return _context4.abrupt("return", this);
557
+ case 18:
556
558
  case "end":
557
559
  return _context4.stop();
558
560
  }
@@ -750,6 +752,7 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
750
752
  write,
751
753
  _options$save3,
752
754
  save,
755
+ currentIac,
753
756
  iac,
754
757
  grantType,
755
758
  _args7 = arguments;
@@ -770,8 +773,9 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
770
773
  }
771
774
  throw new Error('groupIds must be an array');
772
775
  case 6:
773
- // Get current IAC settings
774
- iac = this.get('iac') || {}; // Determine which grant type to update (read or write)
776
+ // Get current IAC settings and create a deep clone to ensure change detection
777
+ currentIac = this.get('iac') || {};
778
+ iac = _lodash["default"].cloneDeep(currentIac); // Determine which grant type to update (read or write)
775
779
  grantType = write ? 'writeGrants' : 'readGrants'; // Initialize grants if they don't exist
776
780
  if (!iac[grantType]) {
777
781
  iac[grantType] = {};
@@ -796,16 +800,16 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
796
800
 
797
801
  // Save if requested
798
802
  if (!save) {
799
- _context7.next = 16;
803
+ _context7.next = 17;
800
804
  break;
801
805
  }
802
- _context7.next = 15;
806
+ _context7.next = 16;
803
807
  return this.save();
804
- case 15:
805
- return _context7.abrupt("return", _context7.sent);
806
808
  case 16:
807
- return _context7.abrupt("return", this);
809
+ return _context7.abrupt("return", _context7.sent);
808
810
  case 17:
811
+ return _context7.abrupt("return", this);
812
+ case 18:
809
813
  case "end":
810
814
  return _context7.stop();
811
815
  }
@@ -6,5 +6,5 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.version = void 0;
7
7
  // Auto-generated version file
8
8
  // DO NOT EDIT - This file is automatically updated from package.cjson
9
- // Version: 1.9.3
10
- var version = exports.version = '1.9.3';
9
+ // Version: 1.9.5
10
+ var version = exports.version = '1.9.5';
package/dist/esm/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ 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; }
2
+ 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; }
3
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
1
4
  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); }
2
5
  function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
3
6
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
@@ -213,6 +216,53 @@ var Roboto = /*#__PURE__*/function () {
213
216
  value: function recordToInstance(recordHash) {
214
217
  return new RbtObject(recordHash, this.api.axios);
215
218
  }
219
+
220
+ /**
221
+ * Wraps raw API response data as RbtObject(s)
222
+ * Use this when receiving raw JSON from custom API endpoints (e.g., /api/tasks/*)
223
+ * that return database objects instead of using roboto's built-in query methods.
224
+ *
225
+ * @param {Object|Array|null} data - Raw response data (single object or array)
226
+ * @returns {RbtObject|Array<RbtObject>|null} - Wrapped RbtObject(s) or original value if null/already wrapped
227
+ *
228
+ * @example
229
+ * // Wrapping a single object
230
+ * const response = await fetch('/api/tasks/boards/123');
231
+ * const data = await response.json();
232
+ * const board = roboto.wrapAsRbtObjects(data.board);
233
+ * board.set('title', 'New Title'); // Now you can use RbtObject methods
234
+ *
235
+ * @example
236
+ * // Wrapping an array
237
+ * const response = await fetch('/api/tasks/boards');
238
+ * const data = await response.json();
239
+ * const boards = roboto.wrapAsRbtObjects(data.boards);
240
+ * boards.forEach(board => console.log(board.get('title')));
241
+ */
242
+ }, {
243
+ key: "wrapAsRbtObjects",
244
+ value: function wrapAsRbtObjects(data) {
245
+ var _this2 = this;
246
+ if (!data) return data;
247
+
248
+ // If it's already an RbtObject, return as-is (idempotent)
249
+ if (typeof data.get === 'function') {
250
+ return data;
251
+ }
252
+
253
+ // If it's an array, wrap each item
254
+ if (Array.isArray(data)) {
255
+ return data.map(function (item) {
256
+ if (typeof (item === null || item === void 0 ? void 0 : item.get) === 'function') {
257
+ return item;
258
+ }
259
+ return new RbtObject(item, _this2.api.axios);
260
+ });
261
+ }
262
+
263
+ // Single object - wrap it
264
+ return new RbtObject(data, this.api.axios);
265
+ }
216
266
  }, {
217
267
  key: "_stripHttpsForDomains",
218
268
  value: function _stripHttpsForDomains(baseUrl, domains) {
@@ -623,18 +673,78 @@ var Roboto = /*#__PURE__*/function () {
623
673
  return _pollTaskProgress.apply(this, arguments);
624
674
  }
625
675
  return pollTaskProgress;
626
- }() //
676
+ }()
677
+ /**
678
+ * Helper to detect if an object looks like a doctree object
679
+ * @private
680
+ */
681
+ }, {
682
+ key: "_isDoctreeObject",
683
+ value: function _isDoctreeObject(obj) {
684
+ if (!obj || _typeof(obj) !== 'object') return false;
685
+ // Check for standard doctree fields
686
+ return obj.hasOwnProperty('id') && obj.hasOwnProperty('type') && obj.hasOwnProperty('timeCreated');
687
+ }
688
+
689
+ /**
690
+ * Auto-wraps response data if it contains doctree objects
691
+ * @private
692
+ */
693
+ }, {
694
+ key: "_autoWrapResponse",
695
+ value: function _autoWrapResponse(data) {
696
+ if (!data) return data;
697
+
698
+ // If response has an 'items' array (common pattern), wrap those
699
+ if (data.items && Array.isArray(data.items)) {
700
+ if (data.items.length > 0 && this._isDoctreeObject(data.items[0])) {
701
+ return _objectSpread(_objectSpread({}, data), {}, {
702
+ items: this.wrapAsRbtObjects(data.items)
703
+ });
704
+ }
705
+ }
706
+
707
+ // If response has a single object property that looks like doctree
708
+ // Check common property names: board, ticket, task, note, etc.
709
+ for (var _i = 0, _Object$keys = Object.keys(data); _i < _Object$keys.length; _i++) {
710
+ var key = _Object$keys[_i];
711
+ if (this._isDoctreeObject(data[key])) {
712
+ return _objectSpread(_objectSpread({}, data), {}, _defineProperty({}, key, this.wrapAsRbtObjects(data[key])));
713
+ }
714
+ // Check if it's an array of doctree objects
715
+ if (Array.isArray(data[key]) && data[key].length > 0 && this._isDoctreeObject(data[key][0])) {
716
+ return _objectSpread(_objectSpread({}, data), {}, _defineProperty({}, key, this.wrapAsRbtObjects(data[key])));
717
+ }
718
+ }
719
+
720
+ // If the root data itself is a doctree object or array of them
721
+ if (this._isDoctreeObject(data)) {
722
+ return this.wrapAsRbtObjects(data);
723
+ }
724
+ if (Array.isArray(data) && data.length > 0 && this._isDoctreeObject(data[0])) {
725
+ return this.wrapAsRbtObjects(data);
726
+ }
727
+ return data;
728
+ }
729
+
730
+ //
627
731
  // Get/Post to endpoint with Roboto authtoken
732
+ // Automatically wraps doctree objects in responses as RbtObjects
628
733
  //
629
734
  }, {
630
735
  key: "get",
631
736
  value: function () {
632
737
  var _get = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee20(endpoint, params) {
738
+ var result;
633
739
  return _regeneratorRuntime().wrap(function _callee20$(_context20) {
634
740
  while (1) switch (_context20.prev = _context20.next) {
635
741
  case 0:
636
- return _context20.abrupt("return", this.api.get(endpoint, params));
637
- case 1:
742
+ _context20.next = 2;
743
+ return this.api.get(endpoint, params);
744
+ case 2:
745
+ result = _context20.sent;
746
+ return _context20.abrupt("return", this._autoWrapResponse(result));
747
+ case 4:
638
748
  case "end":
639
749
  return _context20.stop();
640
750
  }
@@ -649,11 +759,16 @@ var Roboto = /*#__PURE__*/function () {
649
759
  key: "post",
650
760
  value: function () {
651
761
  var _post = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(endpoint, data) {
762
+ var result;
652
763
  return _regeneratorRuntime().wrap(function _callee21$(_context21) {
653
764
  while (1) switch (_context21.prev = _context21.next) {
654
765
  case 0:
655
- return _context21.abrupt("return", this.api.post(endpoint, data));
656
- case 1:
766
+ _context21.next = 2;
767
+ return this.api.post(endpoint, data);
768
+ case 2:
769
+ result = _context21.sent;
770
+ return _context21.abrupt("return", this._autoWrapResponse(result));
771
+ case 4:
657
772
  case "end":
658
773
  return _context21.stop();
659
774
  }
@@ -474,6 +474,7 @@ var RbtObject = /*#__PURE__*/function () {
474
474
  replace,
475
475
  _options$save,
476
476
  save,
477
+ currentIac,
477
478
  iac,
478
479
  grantType,
479
480
  existingUsers,
@@ -498,8 +499,9 @@ var RbtObject = /*#__PURE__*/function () {
498
499
  }
499
500
  throw new Error('groupIds must be an array');
500
501
  case 6:
501
- // Get current IAC settings
502
- iac = this.get('iac') || {}; // Determine which grant type to update (read or write)
502
+ // Get current IAC settings and create a deep clone to ensure change detection
503
+ currentIac = this.get('iac') || {};
504
+ iac = _.cloneDeep(currentIac); // Determine which grant type to update (read or write)
503
505
  grantType = write ? 'writeGrants' : 'readGrants'; // Initialize grants if they don't exist
504
506
  if (!iac[grantType]) {
505
507
  iac[grantType] = {};
@@ -536,16 +538,16 @@ var RbtObject = /*#__PURE__*/function () {
536
538
 
537
539
  // Save if requested
538
540
  if (!save) {
539
- _context4.next = 16;
541
+ _context4.next = 17;
540
542
  break;
541
543
  }
542
- _context4.next = 15;
544
+ _context4.next = 16;
543
545
  return this.save();
544
- case 15:
545
- return _context4.abrupt("return", _context4.sent);
546
546
  case 16:
547
- return _context4.abrupt("return", this);
547
+ return _context4.abrupt("return", _context4.sent);
548
548
  case 17:
549
+ return _context4.abrupt("return", this);
550
+ case 18:
549
551
  case "end":
550
552
  return _context4.stop();
551
553
  }
@@ -743,6 +745,7 @@ var RbtObject = /*#__PURE__*/function () {
743
745
  write,
744
746
  _options$save3,
745
747
  save,
748
+ currentIac,
746
749
  iac,
747
750
  grantType,
748
751
  _args7 = arguments;
@@ -763,8 +766,9 @@ var RbtObject = /*#__PURE__*/function () {
763
766
  }
764
767
  throw new Error('groupIds must be an array');
765
768
  case 6:
766
- // Get current IAC settings
767
- iac = this.get('iac') || {}; // Determine which grant type to update (read or write)
769
+ // Get current IAC settings and create a deep clone to ensure change detection
770
+ currentIac = this.get('iac') || {};
771
+ iac = _.cloneDeep(currentIac); // Determine which grant type to update (read or write)
768
772
  grantType = write ? 'writeGrants' : 'readGrants'; // Initialize grants if they don't exist
769
773
  if (!iac[grantType]) {
770
774
  iac[grantType] = {};
@@ -789,16 +793,16 @@ var RbtObject = /*#__PURE__*/function () {
789
793
 
790
794
  // Save if requested
791
795
  if (!save) {
792
- _context7.next = 16;
796
+ _context7.next = 17;
793
797
  break;
794
798
  }
795
- _context7.next = 15;
799
+ _context7.next = 16;
796
800
  return this.save();
797
- case 15:
798
- return _context7.abrupt("return", _context7.sent);
799
801
  case 16:
800
- return _context7.abrupt("return", this);
802
+ return _context7.abrupt("return", _context7.sent);
801
803
  case 17:
804
+ return _context7.abrupt("return", this);
805
+ case 18:
802
806
  case "end":
803
807
  return _context7.stop();
804
808
  }
@@ -1,4 +1,4 @@
1
1
  // Auto-generated version file
2
2
  // DO NOT EDIT - This file is automatically updated from package.json
3
- // Version: 1.9.3
4
- export var version = '1.9.3';
3
+ // Version: 1.9.5
4
+ export var version = '1.9.5';
package/dist/index.js CHANGED
@@ -13,11 +13,7 @@ import RbtObject from './rbt_object.js';
13
13
  import RbtFile from './rbt_file.js';
14
14
  import RbtMetricsApi from './rbt_metrics_api.js';
15
15
  import CookieStorageAdaptor from './cookie_storage_adaptor.js';
16
- import { createRequire } from 'module';
17
-
18
- // Import package.json to get version automatically
19
- var require = createRequire(import.meta.url);
20
- var packageJson = require('../package.json');
16
+ import { version } from './version.js';
21
17
  export { RbtApi, RbtObject, RbtFile, CookieStorageAdaptor
22
18
  //User,
23
19
  //Site
@@ -104,7 +100,8 @@ var Roboto = /*#__PURE__*/function () {
104
100
  // Use passed accessKey
105
101
  baseUrl: "https://".concat(host),
106
102
  // Use passed host
107
- localStorageAdaptor: storageAdaptor
103
+ localStorageAdaptor: storageAdaptor,
104
+ withCredentials: useCookies && isBrowser // Enabled by default in browser (disable with useCookies: false)
108
105
  };
109
106
 
110
107
  // Add apikey and authtoken if provided directly
@@ -174,7 +171,7 @@ var Roboto = /*#__PURE__*/function () {
174
171
  return _createClass(Roboto, [{
175
172
  key: "getVersion",
176
173
  value: function getVersion() {
177
- return packageJson.version;
174
+ return version;
178
175
  }
179
176
  }, {
180
177
  key: "setSiteEnv",
package/dist/rbt_api.js CHANGED
@@ -38,13 +38,16 @@ var RbtApi = /*#__PURE__*/function () {
38
38
  _ref$apikey = _ref.apikey,
39
39
  apikey = _ref$apikey === void 0 ? null : _ref$apikey,
40
40
  _ref$localStorageAdap = _ref.localStorageAdaptor,
41
- localStorageAdaptor = _ref$localStorageAdap === void 0 ? null : _ref$localStorageAdap;
41
+ localStorageAdaptor = _ref$localStorageAdap === void 0 ? null : _ref$localStorageAdap,
42
+ _ref$withCredentials = _ref.withCredentials,
43
+ withCredentials = _ref$withCredentials === void 0 ? true : _ref$withCredentials;
42
44
  _classCallCheck(this, RbtApi);
43
45
  console.log('[RbtApi] constructor received:', {
44
46
  baseUrl: baseUrl,
45
47
  accesskey: accesskey,
46
48
  authtoken: authtoken,
47
- apikey: apikey
49
+ apikey: apikey,
50
+ withCredentials: withCredentials
48
51
  });
49
52
  this.websocketClient = null;
50
53
 
@@ -61,7 +64,7 @@ var RbtApi = /*#__PURE__*/function () {
61
64
  headers: {
62
65
  'accesskey': accesskey
63
66
  },
64
- withCredentials: true // Enable sending cookies in cross-origin requests
67
+ withCredentials: withCredentials // Send cookies by default (can be disabled with useCookies: false)
65
68
  });
66
69
  this.axios.__rbtApiInstance = this;
67
70
  if (localStorageAdaptor) {
@@ -473,6 +473,7 @@ var RbtObject = /*#__PURE__*/function () {
473
473
  replace,
474
474
  _options$save,
475
475
  save,
476
+ currentIac,
476
477
  iac,
477
478
  grantType,
478
479
  existingUsers,
@@ -497,8 +498,9 @@ var RbtObject = /*#__PURE__*/function () {
497
498
  }
498
499
  throw new Error('groupIds must be an array');
499
500
  case 2:
500
- // Get current IAC settings
501
- iac = this.get('iac') || {}; // Determine which grant type to update (read or write)
501
+ // Get current IAC settings and create a deep clone to ensure change detection
502
+ currentIac = this.get('iac') || {};
503
+ iac = _.cloneDeep(currentIac); // Determine which grant type to update (read or write)
502
504
  grantType = write ? 'writeGrants' : 'readGrants'; // Initialize grants if they don't exist
503
505
  if (!iac[grantType]) {
504
506
  iac[grantType] = {};
@@ -733,6 +735,7 @@ var RbtObject = /*#__PURE__*/function () {
733
735
  write,
734
736
  _options$save3,
735
737
  save,
738
+ currentIac,
736
739
  iac,
737
740
  grantType,
738
741
  _args7 = arguments;
@@ -753,8 +756,9 @@ var RbtObject = /*#__PURE__*/function () {
753
756
  }
754
757
  throw new Error('groupIds must be an array');
755
758
  case 2:
756
- // Get current IAC settings
757
- iac = this.get('iac') || {}; // Determine which grant type to update (read or write)
759
+ // Get current IAC settings and create a deep clone to ensure change detection
760
+ currentIac = this.get('iac') || {};
761
+ iac = _.cloneDeep(currentIac); // Determine which grant type to update (read or write)
758
762
  grantType = write ? 'writeGrants' : 'readGrants'; // Initialize grants if they don't exist
759
763
  if (!iac[grantType]) {
760
764
  iac[grantType] = {};
@@ -0,0 +1,4 @@
1
+ // Auto-generated version file
2
+ // DO NOT EDIT - This file is automatically updated from package.json
3
+ // Version: 1.9.4
4
+ export var version = '1.9.4';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roboto-js",
3
- "version": "1.9.3",
3
+ "version": "1.9.5",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "dist/cjs/index.cjs",
package/src/index.js CHANGED
@@ -205,6 +205,50 @@ export default class Roboto{
205
205
 
206
206
  }
207
207
 
208
+ /**
209
+ * Wraps raw API response data as RbtObject(s)
210
+ * Use this when receiving raw JSON from custom API endpoints (e.g., /api/tasks/*)
211
+ * that return database objects instead of using roboto's built-in query methods.
212
+ *
213
+ * @param {Object|Array|null} data - Raw response data (single object or array)
214
+ * @returns {RbtObject|Array<RbtObject>|null} - Wrapped RbtObject(s) or original value if null/already wrapped
215
+ *
216
+ * @example
217
+ * // Wrapping a single object
218
+ * const response = await fetch('/api/tasks/boards/123');
219
+ * const data = await response.json();
220
+ * const board = roboto.wrapAsRbtObjects(data.board);
221
+ * board.set('title', 'New Title'); // Now you can use RbtObject methods
222
+ *
223
+ * @example
224
+ * // Wrapping an array
225
+ * const response = await fetch('/api/tasks/boards');
226
+ * const data = await response.json();
227
+ * const boards = roboto.wrapAsRbtObjects(data.boards);
228
+ * boards.forEach(board => console.log(board.get('title')));
229
+ */
230
+ wrapAsRbtObjects(data) {
231
+ if (!data) return data;
232
+
233
+ // If it's already an RbtObject, return as-is (idempotent)
234
+ if (typeof data.get === 'function') {
235
+ return data;
236
+ }
237
+
238
+ // If it's an array, wrap each item
239
+ if (Array.isArray(data)) {
240
+ return data.map(item => {
241
+ if (typeof item?.get === 'function') {
242
+ return item;
243
+ }
244
+ return new RbtObject(item, this.api.axios);
245
+ });
246
+ }
247
+
248
+ // Single object - wrap it
249
+ return new RbtObject(data, this.api.axios);
250
+ }
251
+
208
252
  _stripHttpsForDomains(baseUrl, domains) {
209
253
  return baseUrl.replace(new RegExp(`^https://(${domains.map(domain => domain.replace(/\./g, '\\.')).join('|')})`), 'http://$1');
210
254
  }
@@ -306,15 +350,76 @@ export default class Roboto{
306
350
  return this.api.pollTaskProgress(params);
307
351
  }
308
352
 
353
+ /**
354
+ * Helper to detect if an object looks like a doctree object
355
+ * @private
356
+ */
357
+ _isDoctreeObject(obj) {
358
+ if (!obj || typeof obj !== 'object') return false;
359
+ // Check for standard doctree fields
360
+ return obj.hasOwnProperty('id') &&
361
+ obj.hasOwnProperty('type') &&
362
+ obj.hasOwnProperty('timeCreated');
363
+ }
364
+
365
+ /**
366
+ * Auto-wraps response data if it contains doctree objects
367
+ * @private
368
+ */
369
+ _autoWrapResponse(data) {
370
+ if (!data) return data;
371
+
372
+ // If response has an 'items' array (common pattern), wrap those
373
+ if (data.items && Array.isArray(data.items)) {
374
+ if (data.items.length > 0 && this._isDoctreeObject(data.items[0])) {
375
+ return {
376
+ ...data,
377
+ items: this.wrapAsRbtObjects(data.items)
378
+ };
379
+ }
380
+ }
381
+
382
+ // If response has a single object property that looks like doctree
383
+ // Check common property names: board, ticket, task, note, etc.
384
+ for (const key of Object.keys(data)) {
385
+ if (this._isDoctreeObject(data[key])) {
386
+ return {
387
+ ...data,
388
+ [key]: this.wrapAsRbtObjects(data[key])
389
+ };
390
+ }
391
+ // Check if it's an array of doctree objects
392
+ if (Array.isArray(data[key]) && data[key].length > 0 && this._isDoctreeObject(data[key][0])) {
393
+ return {
394
+ ...data,
395
+ [key]: this.wrapAsRbtObjects(data[key])
396
+ };
397
+ }
398
+ }
399
+
400
+ // If the root data itself is a doctree object or array of them
401
+ if (this._isDoctreeObject(data)) {
402
+ return this.wrapAsRbtObjects(data);
403
+ }
404
+ if (Array.isArray(data) && data.length > 0 && this._isDoctreeObject(data[0])) {
405
+ return this.wrapAsRbtObjects(data);
406
+ }
407
+
408
+ return data;
409
+ }
410
+
309
411
  //
310
412
  // Get/Post to endpoint with Roboto authtoken
413
+ // Automatically wraps doctree objects in responses as RbtObjects
311
414
  //
312
415
  async get(endpoint, params){
313
- return this.api.get(endpoint, params);
416
+ const result = await this.api.get(endpoint, params);
417
+ return this._autoWrapResponse(result);
314
418
  }
315
419
 
316
420
  async post(endpoint, data){
317
- return this.api.post(endpoint, data);
421
+ const result = await this.api.post(endpoint, data);
422
+ return this._autoWrapResponse(result);
318
423
  }
319
424
 
320
425
 
package/src/rbt_object.js CHANGED
@@ -374,8 +374,9 @@ export default class RbtObject{
374
374
  throw new Error('groupIds must be an array');
375
375
  }
376
376
 
377
- // Get current IAC settings
378
- const iac = this.get('iac') || {};
377
+ // Get current IAC settings and create a deep clone to ensure change detection
378
+ const currentIac = this.get('iac') || {};
379
+ const iac = _.cloneDeep(currentIac);
379
380
 
380
381
  // Determine which grant type to update (read or write)
381
382
  const grantType = write ? 'writeGrants' : 'readGrants';
@@ -565,8 +566,9 @@ export default class RbtObject{
565
566
  throw new Error('groupIds must be an array');
566
567
  }
567
568
 
568
- // Get current IAC settings
569
- const iac = this.get('iac') || {};
569
+ // Get current IAC settings and create a deep clone to ensure change detection
570
+ const currentIac = this.get('iac') || {};
571
+ const iac = _.cloneDeep(currentIac);
570
572
 
571
573
  // Determine which grant type to update (read or write)
572
574
  const grantType = write ? 'writeGrants' : 'readGrants';
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // Auto-generated version file
2
2
  // DO NOT EDIT - This file is automatically updated from package.json
3
- // Version: 1.9.3
4
- export const version = '1.9.3';
3
+ // Version: 1.9.5
4
+ export const version = '1.9.5';