roboto-js 1.6.9 → 1.6.10
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.cjs +8 -1
- package/dist/cjs/rbt_api.cjs +32 -52
- package/dist/cjs/rbt_object.cjs +102 -32
- package/dist/esm/index.js +5 -1
- package/dist/esm/rbt_api.js +24 -59
- package/dist/esm/rbt_object.js +77 -34
- package/package.json +1 -1
- package/src/index.js +5 -1
- package/src/rbt_api.js +29 -60
- package/src/rbt_object.js +77 -36
package/dist/cjs/index.cjs
CHANGED
|
@@ -39,7 +39,9 @@ var Roboto = exports["default"] = /*#__PURE__*/function () {
|
|
|
39
39
|
function Roboto(_ref) {
|
|
40
40
|
var host = _ref.host,
|
|
41
41
|
accessKey = _ref.accessKey,
|
|
42
|
-
localStorageAdaptor = _ref.localStorageAdaptor
|
|
42
|
+
localStorageAdaptor = _ref.localStorageAdaptor,
|
|
43
|
+
_ref$disableWebSocket = _ref.disableWebSocket,
|
|
44
|
+
disableWebSocket = _ref$disableWebSocket === void 0 ? false : _ref$disableWebSocket;
|
|
43
45
|
var proxyReq = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
44
46
|
_classCallCheck(this, Roboto);
|
|
45
47
|
if (Roboto.instance && !proxyReq) {
|
|
@@ -83,6 +85,11 @@ var Roboto = exports["default"] = /*#__PURE__*/function () {
|
|
|
83
85
|
Roboto.instance = this;
|
|
84
86
|
}
|
|
85
87
|
_createClass(Roboto, [{
|
|
88
|
+
key: "getVersion",
|
|
89
|
+
value: function getVersion() {
|
|
90
|
+
return '1.6.9';
|
|
91
|
+
}
|
|
92
|
+
}, {
|
|
86
93
|
key: "setSiteEnv",
|
|
87
94
|
value: function setSiteEnv(siteEnv) {
|
|
88
95
|
this.api.setSiteEnv(siteEnv);
|
package/dist/cjs/rbt_api.cjs
CHANGED
|
@@ -35,12 +35,14 @@ var RbtApi = exports["default"] = /*#__PURE__*/function () {
|
|
|
35
35
|
_ref$localStorageAdap = _ref.localStorageAdaptor,
|
|
36
36
|
localStorageAdaptor = _ref$localStorageAdap === void 0 ? null : _ref$localStorageAdap;
|
|
37
37
|
_classCallCheck(this, RbtApi);
|
|
38
|
+
this.websocketClient = null;
|
|
38
39
|
this.axios = _axios["default"].create({
|
|
39
40
|
baseURL: baseUrl,
|
|
40
41
|
headers: {
|
|
41
42
|
'accesskey': accesskey
|
|
42
43
|
}
|
|
43
44
|
});
|
|
45
|
+
this.axios.__rbtApiInstance = this;
|
|
44
46
|
if (localStorageAdaptor) {
|
|
45
47
|
// must implement getItem, setItem interface
|
|
46
48
|
this.localStorageAdaptor = localStorageAdaptor;
|
|
@@ -68,6 +70,25 @@ var RbtApi = exports["default"] = /*#__PURE__*/function () {
|
|
|
68
70
|
this.initApiKey(apikey);
|
|
69
71
|
}
|
|
70
72
|
_createClass(RbtApi, [{
|
|
73
|
+
key: "getWebSocketClient",
|
|
74
|
+
value: function getWebSocketClient() {
|
|
75
|
+
if (this.websocketClient) return this.websocketClient;
|
|
76
|
+
var baseUrl = this.axios.defaults.baseURL;
|
|
77
|
+
var wsProtocol = baseUrl.startsWith('https') ? 'wss://' : 'ws://';
|
|
78
|
+
var wsUrl = baseUrl.replace(/^https?:\/\//, wsProtocol);
|
|
79
|
+
this.websocketClient = new WebSocket("".concat(wsUrl, "/realtime"));
|
|
80
|
+
this.websocketClient.onopen = function () {
|
|
81
|
+
console.log('[RbtApi] WebSocket connected.');
|
|
82
|
+
};
|
|
83
|
+
this.websocketClient.onclose = function () {
|
|
84
|
+
console.warn('[RbtApi] WebSocket closed.');
|
|
85
|
+
};
|
|
86
|
+
this.websocketClient.onerror = function (err) {
|
|
87
|
+
console.error('[RbtApi] WebSocket error:', err.message || err);
|
|
88
|
+
};
|
|
89
|
+
return this.websocketClient;
|
|
90
|
+
}
|
|
91
|
+
}, {
|
|
71
92
|
key: "initAuthToken",
|
|
72
93
|
value: function () {
|
|
73
94
|
var _initAuthToken = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(authtoken) {
|
|
@@ -792,28 +813,27 @@ var RbtApi = exports["default"] = /*#__PURE__*/function () {
|
|
|
792
813
|
case 0:
|
|
793
814
|
dataHash = _args17.length > 1 && _args17[1] !== undefined ? _args17[1] : {};
|
|
794
815
|
_context17.prev = 1;
|
|
795
|
-
|
|
796
|
-
_context17.next = 5;
|
|
816
|
+
_context17.next = 4;
|
|
797
817
|
return this.axios.post('/object_service/createObject', [type, dataHash]);
|
|
798
|
-
case
|
|
818
|
+
case 4:
|
|
799
819
|
response = _context17.sent;
|
|
800
820
|
record = response.data;
|
|
801
821
|
if (dataHash) {
|
|
802
822
|
record.data = dataHash;
|
|
803
823
|
}
|
|
804
|
-
debugger;
|
|
805
824
|
return _context17.abrupt("return", new _rbt_object["default"](record, this.axios, {
|
|
806
|
-
isNew: true
|
|
825
|
+
isNew: true,
|
|
826
|
+
websocketClient: this.websocketClient
|
|
807
827
|
}));
|
|
808
|
-
case
|
|
809
|
-
_context17.prev =
|
|
828
|
+
case 10:
|
|
829
|
+
_context17.prev = 10;
|
|
810
830
|
_context17.t0 = _context17["catch"](1);
|
|
811
831
|
return _context17.abrupt("return", this._handleError(_context17.t0));
|
|
812
|
-
case
|
|
832
|
+
case 13:
|
|
813
833
|
case "end":
|
|
814
834
|
return _context17.stop();
|
|
815
835
|
}
|
|
816
|
-
}, _callee17, this, [[1,
|
|
836
|
+
}, _callee17, this, [[1, 10]]);
|
|
817
837
|
}));
|
|
818
838
|
function create(_x12) {
|
|
819
839
|
return _create.apply(this, arguments);
|
|
@@ -848,48 +868,6 @@ var RbtApi = exports["default"] = /*#__PURE__*/function () {
|
|
|
848
868
|
*
|
|
849
869
|
* Note: A default orderBy is applied if none is provided, ordering items by 'timeCreated' in descending order.
|
|
850
870
|
*/
|
|
851
|
-
// async query(type, params = {}) {
|
|
852
|
-
// try {
|
|
853
|
-
// console.log('RBTAPI.query INIT', type, params);
|
|
854
|
-
// params.type = type;
|
|
855
|
-
// // Default ordering and pagination
|
|
856
|
-
// const defaultOrderBy = { orderBy: { column: 'timeCreated', direction: 'DESC' } };
|
|
857
|
-
// const defaultLimit = { limit: { offset: 0, results: 50 } };
|
|
858
|
-
//
|
|
859
|
-
// // Merge defaults with provided params
|
|
860
|
-
// const mergedParams = { ...defaultOrderBy, ...defaultLimit, ...params };
|
|
861
|
-
// // Check cache for an existing request
|
|
862
|
-
// const currentTime = Date.now();
|
|
863
|
-
// const paramsKey = JSON.stringify(mergedParams);
|
|
864
|
-
// const cacheEntry = this.requestCache[paramsKey];
|
|
865
|
-
// if (cacheEntry && (currentTime - cacheEntry.time) < 10000) { // 10000 ms = 10 seconds
|
|
866
|
-
// console.log('RBTAPI.query CACHED', type, paramsKey);
|
|
867
|
-
// return cacheEntry.val;
|
|
868
|
-
// }
|
|
869
|
-
// // Create the response promise and store it in the cache
|
|
870
|
-
// const responsePromise = this.axios.post('/object_service/queryObjects', [mergedParams]);
|
|
871
|
-
// // Store the promise along with the current time in the cache
|
|
872
|
-
// this.requestCache[paramsKey] = { val: responsePromise, time: currentTime };
|
|
873
|
-
// // Await the response from the API
|
|
874
|
-
// const response = await responsePromise;
|
|
875
|
-
// if (response.data.ok === false) {
|
|
876
|
-
// return this._handleError(response);
|
|
877
|
-
// }
|
|
878
|
-
// // Process items into RbtObject instances
|
|
879
|
-
// if (Array.isArray(response.data.items)) {
|
|
880
|
-
// response.data.items = response.data.items.map(record => {
|
|
881
|
-
// return new RbtObject(record, this.axios, { isNew: true });
|
|
882
|
-
// });
|
|
883
|
-
// }
|
|
884
|
-
// console.log('RBTAPI.query RESPONSE', type, paramsKey, response.data.items);
|
|
885
|
-
// return response.data.items;
|
|
886
|
-
// } catch (e) {
|
|
887
|
-
// delete this.requestCache[paramsKey]; // Ensure cache cleanup on error
|
|
888
|
-
// console.log('RBTAPI.query ERROR', paramsKey, e);
|
|
889
|
-
// return this._handleError(e);
|
|
890
|
-
//
|
|
891
|
-
// }
|
|
892
|
-
// }
|
|
893
871
|
)
|
|
894
872
|
}, {
|
|
895
873
|
key: "query",
|
|
@@ -983,7 +961,9 @@ var RbtApi = exports["default"] = /*#__PURE__*/function () {
|
|
|
983
961
|
if (Array.isArray(response.data.items)) {
|
|
984
962
|
//console.log('RBTAPI.query RESPONSE PRE', response.data.items);
|
|
985
963
|
response.data.items = response.data.items.map(function (record) {
|
|
986
|
-
return new _rbt_object["default"](record, _this3.axios
|
|
964
|
+
return new _rbt_object["default"](record, _this3.axios, {
|
|
965
|
+
websocketClient: _this3.websocketClient
|
|
966
|
+
});
|
|
987
967
|
});
|
|
988
968
|
}
|
|
989
969
|
|
package/dist/cjs/rbt_object.cjs
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports["default"] = void 0;
|
|
7
7
|
var _lodash = _interopRequireDefault(require("lodash"));
|
|
8
8
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
9
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
|
9
10
|
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; }
|
|
10
11
|
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); } }
|
|
11
12
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
@@ -42,6 +43,15 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
|
|
|
42
43
|
} else {
|
|
43
44
|
this._data = record.dataJson ? this._deepUnpackJson(record.dataJson) : {};
|
|
44
45
|
}
|
|
46
|
+
if (options.websocketClient && this.id) {
|
|
47
|
+
this._realtime = true;
|
|
48
|
+
this._ws = options.websocketClient;
|
|
49
|
+
this._subscribeToRealtime(this._ws);
|
|
50
|
+
}
|
|
51
|
+
this._eventHandlers = {
|
|
52
|
+
change: [],
|
|
53
|
+
save: []
|
|
54
|
+
};
|
|
45
55
|
}
|
|
46
56
|
_createClass(RbtObject, [{
|
|
47
57
|
key: "get",
|
|
@@ -116,6 +126,7 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
|
|
|
116
126
|
} else if (!_lodash["default"].isEqual(currentValue, value)) {
|
|
117
127
|
_lodash["default"].set(this._data, path, value); // Set the value directly at the deep path
|
|
118
128
|
this._addChange(path);
|
|
129
|
+
this._broadcastChange(path, value);
|
|
119
130
|
}
|
|
120
131
|
}
|
|
121
132
|
}
|
|
@@ -229,38 +240,7 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
|
|
|
229
240
|
return _setRemove.apply(this, arguments);
|
|
230
241
|
}
|
|
231
242
|
return setRemove;
|
|
232
|
-
}()
|
|
233
|
-
// const currentValue = _.get(this._data, path);
|
|
234
|
-
//
|
|
235
|
-
// // Check if merge is required
|
|
236
|
-
// if (options.merge) {
|
|
237
|
-
// // Merge the value if merge option is true
|
|
238
|
-
// const mergedValue = _.merge({}, currentValue, value);
|
|
239
|
-
// if (!_.isEqual(currentValue, mergedValue)) {
|
|
240
|
-
// _.set(this._data, path, mergedValue);
|
|
241
|
-
// this._addChange(path);
|
|
242
|
-
// }
|
|
243
|
-
// } else {
|
|
244
|
-
// // Set the value directly if no merge option or merge option is false
|
|
245
|
-
// if (!_.isEqual(currentValue, value)) {
|
|
246
|
-
// _.set(this._data, path, value);
|
|
247
|
-
// this._addChange(path);
|
|
248
|
-
// }
|
|
249
|
-
// }
|
|
250
|
-
// }
|
|
251
|
-
//
|
|
252
|
-
// setData(newData) {
|
|
253
|
-
// if (typeof newData !== 'object' || newData === null) {
|
|
254
|
-
// throw new Error('setData expects an object');
|
|
255
|
-
// }
|
|
256
|
-
//
|
|
257
|
-
// Object.keys(newData).forEach(key => {
|
|
258
|
-
// if (!_.isEqual(_.get(this._data, key), newData[key])) {
|
|
259
|
-
// _.set(this._data, key, newData[key]);
|
|
260
|
-
// this._addChange(key);
|
|
261
|
-
// }
|
|
262
|
-
// });
|
|
263
|
-
// }
|
|
243
|
+
}()
|
|
264
244
|
}, {
|
|
265
245
|
key: "getMetaData",
|
|
266
246
|
value: function getMetaData() {
|
|
@@ -459,6 +439,96 @@ var RbtObject = exports["default"] = /*#__PURE__*/function () {
|
|
|
459
439
|
}
|
|
460
440
|
return value;
|
|
461
441
|
}
|
|
442
|
+
|
|
443
|
+
//
|
|
444
|
+
// Realtime WebSocket
|
|
445
|
+
//
|
|
446
|
+
//
|
|
447
|
+
}, {
|
|
448
|
+
key: "_initRealtime",
|
|
449
|
+
value: function _initRealtime() {
|
|
450
|
+
var _this$_axios;
|
|
451
|
+
if (this._realtime || !this._axios) return;
|
|
452
|
+
|
|
453
|
+
// Lazily pull WebSocket from parent API (injected via axios instance)
|
|
454
|
+
var api = (_this$_axios = this._axios) === null || _this$_axios === void 0 ? void 0 : _this$_axios.__rbtApiInstance;
|
|
455
|
+
if (!api || typeof api.getWebSocketClient !== 'function') return;
|
|
456
|
+
var ws = api.getWebSocketClient();
|
|
457
|
+
if (!ws || this._realtime) return;
|
|
458
|
+
this._ws = ws;
|
|
459
|
+
this._realtime = true;
|
|
460
|
+
this._subscribeToRealtime(ws);
|
|
461
|
+
}
|
|
462
|
+
}, {
|
|
463
|
+
key: "_subscribeToRealtime",
|
|
464
|
+
value: function _subscribeToRealtime(ws) {
|
|
465
|
+
var _this3 = this;
|
|
466
|
+
if (ws.readyState === 1) {
|
|
467
|
+
ws.send(JSON.stringify({
|
|
468
|
+
type: 'subscribe',
|
|
469
|
+
objectId: this.id
|
|
470
|
+
}));
|
|
471
|
+
} else {
|
|
472
|
+
ws.addEventListener('open', function () {
|
|
473
|
+
ws.send(JSON.stringify({
|
|
474
|
+
type: 'subscribe',
|
|
475
|
+
objectId: _this3.id
|
|
476
|
+
}));
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
ws.addEventListener('message', function (event) {
|
|
480
|
+
var msg = JSON.parse(event.data);
|
|
481
|
+
if (msg.objectId !== _this3.id) return;
|
|
482
|
+
if (msg.type === 'update') {
|
|
483
|
+
_lodash["default"].set(_this3._data, msg.delta.path, msg.delta.value);
|
|
484
|
+
_this3._trigger('change', msg.delta);
|
|
485
|
+
} else if (msg.type === 'save') {
|
|
486
|
+
_this3._trigger('save', msg.revision || {});
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}, {
|
|
491
|
+
key: "onRealtimeChange",
|
|
492
|
+
value: function onRealtimeChange(cb) {
|
|
493
|
+
this._eventHandlers.change.push(cb);
|
|
494
|
+
this._initRealtime(); // lazy connect
|
|
495
|
+
}
|
|
496
|
+
}, {
|
|
497
|
+
key: "onRealtimeSave",
|
|
498
|
+
value: function onRealtimeSave(cb) {
|
|
499
|
+
this._eventHandlers.save.push(cb);
|
|
500
|
+
this._initRealtime(); // lazy connect
|
|
501
|
+
}
|
|
502
|
+
}, {
|
|
503
|
+
key: "_trigger",
|
|
504
|
+
value: function _trigger(type, data) {
|
|
505
|
+
var _iterator = _createForOfIteratorHelper(this._eventHandlers[type] || []),
|
|
506
|
+
_step;
|
|
507
|
+
try {
|
|
508
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
509
|
+
var fn = _step.value;
|
|
510
|
+
fn(data);
|
|
511
|
+
}
|
|
512
|
+
} catch (err) {
|
|
513
|
+
_iterator.e(err);
|
|
514
|
+
} finally {
|
|
515
|
+
_iterator.f();
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}, {
|
|
519
|
+
key: "_broadcastChange",
|
|
520
|
+
value: function _broadcastChange(path, value) {
|
|
521
|
+
if (this._realtime && this._ws && this._ws.readyState === 1) {
|
|
522
|
+
this._ws.send(JSON.stringify({
|
|
523
|
+
type: 'update',
|
|
524
|
+
objectId: this.id,
|
|
525
|
+
delta: {
|
|
526
|
+
path: path,
|
|
527
|
+
value: value
|
|
528
|
+
}
|
|
529
|
+
}));
|
|
530
|
+
}
|
|
531
|
+
}
|
|
462
532
|
}]);
|
|
463
533
|
return RbtObject;
|
|
464
534
|
}();
|
package/dist/esm/index.js
CHANGED
|
@@ -6,10 +6,14 @@ export { RbtApi, RbtObject, RbtFile
|
|
|
6
6
|
//Site
|
|
7
7
|
};
|
|
8
8
|
export default class Roboto {
|
|
9
|
+
getVersion() {
|
|
10
|
+
return '1.6.9';
|
|
11
|
+
}
|
|
9
12
|
constructor({
|
|
10
13
|
host,
|
|
11
14
|
accessKey,
|
|
12
|
-
localStorageAdaptor
|
|
15
|
+
localStorageAdaptor,
|
|
16
|
+
disableWebSocket = false
|
|
13
17
|
}, proxyReq = null) {
|
|
14
18
|
if (Roboto.instance && !proxyReq) {
|
|
15
19
|
// if on client, there can only be one instance
|
package/dist/esm/rbt_api.js
CHANGED
|
@@ -13,12 +13,14 @@ export default class RbtApi {
|
|
|
13
13
|
apikey = null,
|
|
14
14
|
localStorageAdaptor = null
|
|
15
15
|
}) {
|
|
16
|
+
this.websocketClient = null;
|
|
16
17
|
this.axios = axios.create({
|
|
17
18
|
baseURL: baseUrl,
|
|
18
19
|
headers: {
|
|
19
20
|
'accesskey': accesskey
|
|
20
21
|
}
|
|
21
22
|
});
|
|
23
|
+
this.axios.__rbtApiInstance = this;
|
|
22
24
|
if (localStorageAdaptor) {
|
|
23
25
|
// must implement getItem, setItem interface
|
|
24
26
|
this.localStorageAdaptor = localStorageAdaptor;
|
|
@@ -39,6 +41,23 @@ export default class RbtApi {
|
|
|
39
41
|
this.initAuthToken(authtoken);
|
|
40
42
|
this.initApiKey(apikey);
|
|
41
43
|
}
|
|
44
|
+
getWebSocketClient() {
|
|
45
|
+
if (this.websocketClient) return this.websocketClient;
|
|
46
|
+
const baseUrl = this.axios.defaults.baseURL;
|
|
47
|
+
const wsProtocol = baseUrl.startsWith('https') ? 'wss://' : 'ws://';
|
|
48
|
+
const wsUrl = baseUrl.replace(/^https?:\/\//, wsProtocol);
|
|
49
|
+
this.websocketClient = new WebSocket(`${wsUrl}/realtime`);
|
|
50
|
+
this.websocketClient.onopen = () => {
|
|
51
|
+
console.log('[RbtApi] WebSocket connected.');
|
|
52
|
+
};
|
|
53
|
+
this.websocketClient.onclose = () => {
|
|
54
|
+
console.warn('[RbtApi] WebSocket closed.');
|
|
55
|
+
};
|
|
56
|
+
this.websocketClient.onerror = err => {
|
|
57
|
+
console.error('[RbtApi] WebSocket error:', err.message || err);
|
|
58
|
+
};
|
|
59
|
+
return this.websocketClient;
|
|
60
|
+
}
|
|
42
61
|
async initAuthToken(authtoken) {
|
|
43
62
|
if (!authtoken && this.localStorageAdaptor) {
|
|
44
63
|
authtoken = await this.localStorageAdaptor.getItem('authtoken');
|
|
@@ -373,15 +392,14 @@ export default class RbtApi {
|
|
|
373
392
|
*/
|
|
374
393
|
async create(type, dataHash = {}) {
|
|
375
394
|
try {
|
|
376
|
-
debugger;
|
|
377
395
|
const response = await this.axios.post('/object_service/createObject', [type, dataHash]);
|
|
378
396
|
const record = response.data;
|
|
379
397
|
if (dataHash) {
|
|
380
398
|
record.data = dataHash;
|
|
381
399
|
}
|
|
382
|
-
debugger;
|
|
383
400
|
return new RbtObject(record, this.axios, {
|
|
384
|
-
isNew: true
|
|
401
|
+
isNew: true,
|
|
402
|
+
websocketClient: this.websocketClient
|
|
385
403
|
});
|
|
386
404
|
} catch (e) {
|
|
387
405
|
return this._handleError(e);
|
|
@@ -416,61 +434,6 @@ export default class RbtApi {
|
|
|
416
434
|
*
|
|
417
435
|
* Note: A default orderBy is applied if none is provided, ordering items by 'timeCreated' in descending order.
|
|
418
436
|
*/
|
|
419
|
-
// async query(type, params = {}) {
|
|
420
|
-
|
|
421
|
-
// try {
|
|
422
|
-
|
|
423
|
-
// console.log('RBTAPI.query INIT', type, params);
|
|
424
|
-
// params.type = type;
|
|
425
|
-
|
|
426
|
-
// // Default ordering and pagination
|
|
427
|
-
// const defaultOrderBy = { orderBy: { column: 'timeCreated', direction: 'DESC' } };
|
|
428
|
-
// const defaultLimit = { limit: { offset: 0, results: 50 } };
|
|
429
|
-
//
|
|
430
|
-
// // Merge defaults with provided params
|
|
431
|
-
// const mergedParams = { ...defaultOrderBy, ...defaultLimit, ...params };
|
|
432
|
-
|
|
433
|
-
// // Check cache for an existing request
|
|
434
|
-
// const currentTime = Date.now();
|
|
435
|
-
// const paramsKey = JSON.stringify(mergedParams);
|
|
436
|
-
// const cacheEntry = this.requestCache[paramsKey];
|
|
437
|
-
// if (cacheEntry && (currentTime - cacheEntry.time) < 10000) { // 10000 ms = 10 seconds
|
|
438
|
-
// console.log('RBTAPI.query CACHED', type, paramsKey);
|
|
439
|
-
// return cacheEntry.val;
|
|
440
|
-
// }
|
|
441
|
-
|
|
442
|
-
// // Create the response promise and store it in the cache
|
|
443
|
-
// const responsePromise = this.axios.post('/object_service/queryObjects', [mergedParams]);
|
|
444
|
-
|
|
445
|
-
// // Store the promise along with the current time in the cache
|
|
446
|
-
// this.requestCache[paramsKey] = { val: responsePromise, time: currentTime };
|
|
447
|
-
|
|
448
|
-
// // Await the response from the API
|
|
449
|
-
// const response = await responsePromise;
|
|
450
|
-
|
|
451
|
-
// if (response.data.ok === false) {
|
|
452
|
-
// return this._handleError(response);
|
|
453
|
-
// }
|
|
454
|
-
|
|
455
|
-
// // Process items into RbtObject instances
|
|
456
|
-
// if (Array.isArray(response.data.items)) {
|
|
457
|
-
// response.data.items = response.data.items.map(record => {
|
|
458
|
-
// return new RbtObject(record, this.axios, { isNew: true });
|
|
459
|
-
// });
|
|
460
|
-
// }
|
|
461
|
-
|
|
462
|
-
// console.log('RBTAPI.query RESPONSE', type, paramsKey, response.data.items);
|
|
463
|
-
// return response.data.items;
|
|
464
|
-
|
|
465
|
-
// } catch (e) {
|
|
466
|
-
|
|
467
|
-
// delete this.requestCache[paramsKey]; // Ensure cache cleanup on error
|
|
468
|
-
// console.log('RBTAPI.query ERROR', paramsKey, e);
|
|
469
|
-
// return this._handleError(e);
|
|
470
|
-
//
|
|
471
|
-
// }
|
|
472
|
-
|
|
473
|
-
// }
|
|
474
437
|
|
|
475
438
|
async query(type, params = {}) {
|
|
476
439
|
let paramsKey;
|
|
@@ -540,7 +503,9 @@ export default class RbtApi {
|
|
|
540
503
|
if (Array.isArray(response.data.items)) {
|
|
541
504
|
//console.log('RBTAPI.query RESPONSE PRE', response.data.items);
|
|
542
505
|
response.data.items = response.data.items.map(record => {
|
|
543
|
-
return new RbtObject(record, this.axios
|
|
506
|
+
return new RbtObject(record, this.axios, {
|
|
507
|
+
websocketClient: this.websocketClient
|
|
508
|
+
});
|
|
544
509
|
});
|
|
545
510
|
}
|
|
546
511
|
|
package/dist/esm/rbt_object.js
CHANGED
|
@@ -15,6 +15,15 @@ export default class RbtObject {
|
|
|
15
15
|
} else {
|
|
16
16
|
this._data = record.dataJson ? this._deepUnpackJson(record.dataJson) : {};
|
|
17
17
|
}
|
|
18
|
+
if (options.websocketClient && this.id) {
|
|
19
|
+
this._realtime = true;
|
|
20
|
+
this._ws = options.websocketClient;
|
|
21
|
+
this._subscribeToRealtime(this._ws);
|
|
22
|
+
}
|
|
23
|
+
this._eventHandlers = {
|
|
24
|
+
change: [],
|
|
25
|
+
save: []
|
|
26
|
+
};
|
|
18
27
|
}
|
|
19
28
|
get(path) {
|
|
20
29
|
return _.get(this._data, path);
|
|
@@ -80,6 +89,7 @@ export default class RbtObject {
|
|
|
80
89
|
} else if (!_.isEqual(currentValue, value)) {
|
|
81
90
|
_.set(this._data, path, value); // Set the value directly at the deep path
|
|
82
91
|
this._addChange(path);
|
|
92
|
+
this._broadcastChange(path, value);
|
|
83
93
|
}
|
|
84
94
|
}
|
|
85
95
|
}
|
|
@@ -145,40 +155,6 @@ export default class RbtObject {
|
|
|
145
155
|
const filteredValues = existingValue.filter(item => !valuesToRemove.includes(item));
|
|
146
156
|
this.set(key, filteredValues); // Set the updated array back to the user data
|
|
147
157
|
}
|
|
148
|
-
|
|
149
|
-
// set(path, value, options = {}) {
|
|
150
|
-
// const currentValue = _.get(this._data, path);
|
|
151
|
-
//
|
|
152
|
-
// // Check if merge is required
|
|
153
|
-
// if (options.merge) {
|
|
154
|
-
// // Merge the value if merge option is true
|
|
155
|
-
// const mergedValue = _.merge({}, currentValue, value);
|
|
156
|
-
// if (!_.isEqual(currentValue, mergedValue)) {
|
|
157
|
-
// _.set(this._data, path, mergedValue);
|
|
158
|
-
// this._addChange(path);
|
|
159
|
-
// }
|
|
160
|
-
// } else {
|
|
161
|
-
// // Set the value directly if no merge option or merge option is false
|
|
162
|
-
// if (!_.isEqual(currentValue, value)) {
|
|
163
|
-
// _.set(this._data, path, value);
|
|
164
|
-
// this._addChange(path);
|
|
165
|
-
// }
|
|
166
|
-
// }
|
|
167
|
-
// }
|
|
168
|
-
//
|
|
169
|
-
// setData(newData) {
|
|
170
|
-
// if (typeof newData !== 'object' || newData === null) {
|
|
171
|
-
// throw new Error('setData expects an object');
|
|
172
|
-
// }
|
|
173
|
-
//
|
|
174
|
-
// Object.keys(newData).forEach(key => {
|
|
175
|
-
// if (!_.isEqual(_.get(this._data, key), newData[key])) {
|
|
176
|
-
// _.set(this._data, key, newData[key]);
|
|
177
|
-
// this._addChange(key);
|
|
178
|
-
// }
|
|
179
|
-
// });
|
|
180
|
-
// }
|
|
181
|
-
|
|
182
158
|
getMetaData() {
|
|
183
159
|
let meta = {
|
|
184
160
|
timeCreated: this._internalData.timeCreated,
|
|
@@ -313,4 +289,71 @@ export default class RbtObject {
|
|
|
313
289
|
}
|
|
314
290
|
return value;
|
|
315
291
|
}
|
|
292
|
+
|
|
293
|
+
//
|
|
294
|
+
// Realtime WebSocket
|
|
295
|
+
//
|
|
296
|
+
//
|
|
297
|
+
_initRealtime() {
|
|
298
|
+
if (this._realtime || !this._axios) return;
|
|
299
|
+
|
|
300
|
+
// Lazily pull WebSocket from parent API (injected via axios instance)
|
|
301
|
+
const api = this._axios?.__rbtApiInstance;
|
|
302
|
+
if (!api || typeof api.getWebSocketClient !== 'function') return;
|
|
303
|
+
const ws = api.getWebSocketClient();
|
|
304
|
+
if (!ws || this._realtime) return;
|
|
305
|
+
this._ws = ws;
|
|
306
|
+
this._realtime = true;
|
|
307
|
+
this._subscribeToRealtime(ws);
|
|
308
|
+
}
|
|
309
|
+
_subscribeToRealtime(ws) {
|
|
310
|
+
if (ws.readyState === 1) {
|
|
311
|
+
ws.send(JSON.stringify({
|
|
312
|
+
type: 'subscribe',
|
|
313
|
+
objectId: this.id
|
|
314
|
+
}));
|
|
315
|
+
} else {
|
|
316
|
+
ws.addEventListener('open', () => {
|
|
317
|
+
ws.send(JSON.stringify({
|
|
318
|
+
type: 'subscribe',
|
|
319
|
+
objectId: this.id
|
|
320
|
+
}));
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
ws.addEventListener('message', event => {
|
|
324
|
+
const msg = JSON.parse(event.data);
|
|
325
|
+
if (msg.objectId !== this.id) return;
|
|
326
|
+
if (msg.type === 'update') {
|
|
327
|
+
_.set(this._data, msg.delta.path, msg.delta.value);
|
|
328
|
+
this._trigger('change', msg.delta);
|
|
329
|
+
} else if (msg.type === 'save') {
|
|
330
|
+
this._trigger('save', msg.revision || {});
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
onRealtimeChange(cb) {
|
|
335
|
+
this._eventHandlers.change.push(cb);
|
|
336
|
+
this._initRealtime(); // lazy connect
|
|
337
|
+
}
|
|
338
|
+
onRealtimeSave(cb) {
|
|
339
|
+
this._eventHandlers.save.push(cb);
|
|
340
|
+
this._initRealtime(); // lazy connect
|
|
341
|
+
}
|
|
342
|
+
_trigger(type, data) {
|
|
343
|
+
for (const fn of this._eventHandlers[type] || []) {
|
|
344
|
+
fn(data);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
_broadcastChange(path, value) {
|
|
348
|
+
if (this._realtime && this._ws && this._ws.readyState === 1) {
|
|
349
|
+
this._ws.send(JSON.stringify({
|
|
350
|
+
type: 'update',
|
|
351
|
+
objectId: this.id,
|
|
352
|
+
delta: {
|
|
353
|
+
path,
|
|
354
|
+
value
|
|
355
|
+
}
|
|
356
|
+
}));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
316
359
|
}
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -13,7 +13,11 @@ export {
|
|
|
13
13
|
|
|
14
14
|
export default class Roboto{
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
getVersion(){
|
|
17
|
+
return '1.6.9';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
constructor({ host, accessKey, localStorageAdaptor, disableWebSocket = false }, proxyReq = null) {
|
|
17
21
|
|
|
18
22
|
if (Roboto.instance && !proxyReq) {
|
|
19
23
|
// if on client, there can only be one instance
|
package/src/rbt_api.js
CHANGED
|
@@ -10,12 +10,15 @@ export default class RbtApi {
|
|
|
10
10
|
|
|
11
11
|
constructor({ baseUrl, accesskey, authtoken=null, apikey=null, localStorageAdaptor=null }) {
|
|
12
12
|
|
|
13
|
+
this.websocketClient = null;
|
|
14
|
+
|
|
13
15
|
this.axios = axios.create({
|
|
14
16
|
baseURL: baseUrl,
|
|
15
17
|
headers: {
|
|
16
18
|
'accesskey': accesskey
|
|
17
19
|
}
|
|
18
20
|
});
|
|
21
|
+
this.axios.__rbtApiInstance = this;
|
|
19
22
|
|
|
20
23
|
if(localStorageAdaptor){
|
|
21
24
|
// must implement getItem, setItem interface
|
|
@@ -37,9 +40,33 @@ export default class RbtApi {
|
|
|
37
40
|
// Use the storageAdaptor to get the authToken, if available
|
|
38
41
|
this.initAuthToken(authtoken);
|
|
39
42
|
this.initApiKey(apikey);
|
|
43
|
+
|
|
40
44
|
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
getWebSocketClient() {
|
|
48
|
+
if (this.websocketClient) return this.websocketClient;
|
|
49
|
+
|
|
50
|
+
const baseUrl = this.axios.defaults.baseURL;
|
|
51
|
+
const wsProtocol = baseUrl.startsWith('https') ? 'wss://' : 'ws://';
|
|
52
|
+
const wsUrl = baseUrl.replace(/^https?:\/\//, wsProtocol);
|
|
53
|
+
this.websocketClient = new WebSocket(`${wsUrl}/realtime`);
|
|
54
|
+
|
|
55
|
+
this.websocketClient.onopen = () => {
|
|
56
|
+
console.log('[RbtApi] WebSocket connected.');
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
this.websocketClient.onclose = () => {
|
|
60
|
+
console.warn('[RbtApi] WebSocket closed.');
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
this.websocketClient.onerror = (err) => {
|
|
64
|
+
console.error('[RbtApi] WebSocket error:', err.message || err);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return this.websocketClient;
|
|
68
|
+
}
|
|
69
|
+
|
|
43
70
|
async initAuthToken(authtoken) {
|
|
44
71
|
|
|
45
72
|
if(!authtoken && this.localStorageAdaptor){
|
|
@@ -470,15 +497,13 @@ export default class RbtApi {
|
|
|
470
497
|
*/
|
|
471
498
|
async create(type, dataHash={}) {
|
|
472
499
|
try {
|
|
473
|
-
debugger;
|
|
474
500
|
const response = await this.axios.post('/object_service/createObject', [type, dataHash]);
|
|
475
501
|
const record = response.data;
|
|
476
502
|
|
|
477
503
|
if(dataHash){
|
|
478
504
|
record.data = dataHash;
|
|
479
505
|
}
|
|
480
|
-
|
|
481
|
-
return new RbtObject(record, this.axios, { isNew: true });
|
|
506
|
+
return new RbtObject(record, this.axios, { isNew: true, websocketClient: this.websocketClient });
|
|
482
507
|
} catch (e) {
|
|
483
508
|
return this._handleError(e);
|
|
484
509
|
}
|
|
@@ -512,62 +537,6 @@ export default class RbtApi {
|
|
|
512
537
|
*
|
|
513
538
|
* Note: A default orderBy is applied if none is provided, ordering items by 'timeCreated' in descending order.
|
|
514
539
|
*/
|
|
515
|
-
// async query(type, params = {}) {
|
|
516
|
-
|
|
517
|
-
// try {
|
|
518
|
-
|
|
519
|
-
// console.log('RBTAPI.query INIT', type, params);
|
|
520
|
-
// params.type = type;
|
|
521
|
-
|
|
522
|
-
// // Default ordering and pagination
|
|
523
|
-
// const defaultOrderBy = { orderBy: { column: 'timeCreated', direction: 'DESC' } };
|
|
524
|
-
// const defaultLimit = { limit: { offset: 0, results: 50 } };
|
|
525
|
-
//
|
|
526
|
-
// // Merge defaults with provided params
|
|
527
|
-
// const mergedParams = { ...defaultOrderBy, ...defaultLimit, ...params };
|
|
528
|
-
|
|
529
|
-
// // Check cache for an existing request
|
|
530
|
-
// const currentTime = Date.now();
|
|
531
|
-
// const paramsKey = JSON.stringify(mergedParams);
|
|
532
|
-
// const cacheEntry = this.requestCache[paramsKey];
|
|
533
|
-
// if (cacheEntry && (currentTime - cacheEntry.time) < 10000) { // 10000 ms = 10 seconds
|
|
534
|
-
// console.log('RBTAPI.query CACHED', type, paramsKey);
|
|
535
|
-
// return cacheEntry.val;
|
|
536
|
-
// }
|
|
537
|
-
|
|
538
|
-
// // Create the response promise and store it in the cache
|
|
539
|
-
// const responsePromise = this.axios.post('/object_service/queryObjects', [mergedParams]);
|
|
540
|
-
|
|
541
|
-
// // Store the promise along with the current time in the cache
|
|
542
|
-
// this.requestCache[paramsKey] = { val: responsePromise, time: currentTime };
|
|
543
|
-
|
|
544
|
-
// // Await the response from the API
|
|
545
|
-
// const response = await responsePromise;
|
|
546
|
-
|
|
547
|
-
// if (response.data.ok === false) {
|
|
548
|
-
// return this._handleError(response);
|
|
549
|
-
// }
|
|
550
|
-
|
|
551
|
-
// // Process items into RbtObject instances
|
|
552
|
-
// if (Array.isArray(response.data.items)) {
|
|
553
|
-
// response.data.items = response.data.items.map(record => {
|
|
554
|
-
// return new RbtObject(record, this.axios, { isNew: true });
|
|
555
|
-
// });
|
|
556
|
-
// }
|
|
557
|
-
|
|
558
|
-
// console.log('RBTAPI.query RESPONSE', type, paramsKey, response.data.items);
|
|
559
|
-
// return response.data.items;
|
|
560
|
-
|
|
561
|
-
// } catch (e) {
|
|
562
|
-
|
|
563
|
-
// delete this.requestCache[paramsKey]; // Ensure cache cleanup on error
|
|
564
|
-
// console.log('RBTAPI.query ERROR', paramsKey, e);
|
|
565
|
-
// return this._handleError(e);
|
|
566
|
-
//
|
|
567
|
-
// }
|
|
568
|
-
|
|
569
|
-
// }
|
|
570
|
-
|
|
571
540
|
|
|
572
541
|
async query(type, params = {}) {
|
|
573
542
|
|
|
@@ -623,7 +592,7 @@ export default class RbtApi {
|
|
|
623
592
|
if (Array.isArray(response.data.items)) {
|
|
624
593
|
//console.log('RBTAPI.query RESPONSE PRE', response.data.items);
|
|
625
594
|
response.data.items = response.data.items.map(record => {
|
|
626
|
-
return new RbtObject(record, this.axios);
|
|
595
|
+
return new RbtObject(record, this.axios, { websocketClient: this.websocketClient });
|
|
627
596
|
});
|
|
628
597
|
}
|
|
629
598
|
|
package/src/rbt_object.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
|
|
3
|
-
export default class RbtObject
|
|
3
|
+
export default class RbtObject{
|
|
4
4
|
|
|
5
5
|
constructor(record, axiosInstance, options = {}) {
|
|
6
6
|
this._axios = axiosInstance;
|
|
@@ -19,6 +19,15 @@ export default class RbtObject {
|
|
|
19
19
|
this._data = record.dataJson ? this._deepUnpackJson(record.dataJson) : {};
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
if (options.websocketClient && this.id) {
|
|
23
|
+
this._realtime = true;
|
|
24
|
+
this._ws = options.websocketClient;
|
|
25
|
+
this._subscribeToRealtime(this._ws);
|
|
26
|
+
}
|
|
27
|
+
this._eventHandlers = {
|
|
28
|
+
change: [],
|
|
29
|
+
save: []
|
|
30
|
+
};
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
get(path) {
|
|
@@ -86,6 +95,7 @@ export default class RbtObject {
|
|
|
86
95
|
} else if (!_.isEqual(currentValue, value)) {
|
|
87
96
|
_.set(this._data, path, value); // Set the value directly at the deep path
|
|
88
97
|
this._addChange(path);
|
|
98
|
+
this._broadcastChange(path, value);
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
101
|
}
|
|
@@ -161,41 +171,6 @@ export default class RbtObject {
|
|
|
161
171
|
|
|
162
172
|
}
|
|
163
173
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
// set(path, value, options = {}) {
|
|
167
|
-
// const currentValue = _.get(this._data, path);
|
|
168
|
-
//
|
|
169
|
-
// // Check if merge is required
|
|
170
|
-
// if (options.merge) {
|
|
171
|
-
// // Merge the value if merge option is true
|
|
172
|
-
// const mergedValue = _.merge({}, currentValue, value);
|
|
173
|
-
// if (!_.isEqual(currentValue, mergedValue)) {
|
|
174
|
-
// _.set(this._data, path, mergedValue);
|
|
175
|
-
// this._addChange(path);
|
|
176
|
-
// }
|
|
177
|
-
// } else {
|
|
178
|
-
// // Set the value directly if no merge option or merge option is false
|
|
179
|
-
// if (!_.isEqual(currentValue, value)) {
|
|
180
|
-
// _.set(this._data, path, value);
|
|
181
|
-
// this._addChange(path);
|
|
182
|
-
// }
|
|
183
|
-
// }
|
|
184
|
-
// }
|
|
185
|
-
//
|
|
186
|
-
// setData(newData) {
|
|
187
|
-
// if (typeof newData !== 'object' || newData === null) {
|
|
188
|
-
// throw new Error('setData expects an object');
|
|
189
|
-
// }
|
|
190
|
-
//
|
|
191
|
-
// Object.keys(newData).forEach(key => {
|
|
192
|
-
// if (!_.isEqual(_.get(this._data, key), newData[key])) {
|
|
193
|
-
// _.set(this._data, key, newData[key]);
|
|
194
|
-
// this._addChange(key);
|
|
195
|
-
// }
|
|
196
|
-
// });
|
|
197
|
-
// }
|
|
198
|
-
|
|
199
174
|
getMetaData() {
|
|
200
175
|
|
|
201
176
|
let meta = {
|
|
@@ -355,6 +330,72 @@ export default class RbtObject {
|
|
|
355
330
|
|
|
356
331
|
|
|
357
332
|
|
|
333
|
+
//
|
|
334
|
+
// Realtime WebSocket
|
|
335
|
+
//
|
|
336
|
+
//
|
|
337
|
+
_initRealtime() {
|
|
338
|
+
if (this._realtime || !this._axios) return;
|
|
339
|
+
|
|
340
|
+
// Lazily pull WebSocket from parent API (injected via axios instance)
|
|
341
|
+
const api = this._axios?.__rbtApiInstance;
|
|
342
|
+
if (!api || typeof api.getWebSocketClient !== 'function') return;
|
|
343
|
+
|
|
344
|
+
const ws = api.getWebSocketClient();
|
|
345
|
+
if (!ws || this._realtime) return;
|
|
346
|
+
|
|
347
|
+
this._ws = ws;
|
|
348
|
+
this._realtime = true;
|
|
349
|
+
this._subscribeToRealtime(ws);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
_subscribeToRealtime(ws) {
|
|
353
|
+
if (ws.readyState === 1) {
|
|
354
|
+
ws.send(JSON.stringify({ type: 'subscribe', objectId: this.id }));
|
|
355
|
+
} else {
|
|
356
|
+
ws.addEventListener('open', () => {
|
|
357
|
+
ws.send(JSON.stringify({ type: 'subscribe', objectId: this.id }));
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
ws.addEventListener('message', (event) => {
|
|
362
|
+
const msg = JSON.parse(event.data);
|
|
363
|
+
if (msg.objectId !== this.id) return;
|
|
364
|
+
|
|
365
|
+
if (msg.type === 'update') {
|
|
366
|
+
_.set(this._data, msg.delta.path, msg.delta.value);
|
|
367
|
+
this._trigger('change', msg.delta);
|
|
368
|
+
} else if (msg.type === 'save') {
|
|
369
|
+
this._trigger('save', msg.revision || {});
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
onRealtimeChange(cb) {
|
|
375
|
+
this._eventHandlers.change.push(cb);
|
|
376
|
+
this._initRealtime(); // lazy connect
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
onRealtimeSave(cb) {
|
|
380
|
+
this._eventHandlers.save.push(cb);
|
|
381
|
+
this._initRealtime(); // lazy connect
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
_trigger(type, data) {
|
|
385
|
+
for (const fn of this._eventHandlers[type] || []) {
|
|
386
|
+
fn(data);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
_broadcastChange(path, value) {
|
|
391
|
+
if (this._realtime && this._ws && this._ws.readyState === 1) {
|
|
392
|
+
this._ws.send(JSON.stringify({
|
|
393
|
+
type: 'update',
|
|
394
|
+
objectId: this.id,
|
|
395
|
+
delta: { path, value }
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
}
|
|
358
399
|
|
|
359
400
|
|
|
360
401
|
}
|