roboto-js 1.7.0 → 1.7.4
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 +1 -0
- package/dist/cjs/cookie_storage_adaptor.cjs +429 -0
- package/dist/cjs/index.cjs +57 -5
- package/dist/cjs/rbt_api.cjs +548 -463
- package/dist/cookie_storage_adaptor.js +415 -0
- package/dist/esm/cookie_storage_adaptor.js +226 -0
- package/dist/esm/index.js +37 -5
- package/dist/esm/rbt_api.js +50 -22
- package/dist/index.js +573 -0
- package/dist/rbt_api.js +2029 -0
- package/dist/rbt_file.js +223 -0
- package/dist/rbt_metrics_api.js +200 -0
- package/dist/rbt_object.js +665 -0
- package/dist/rbt_user.js +235 -0
- package/package.json +1 -1
- package/src/cookie_storage_adaptor.js +246 -0
- package/src/index.js +41 -5
- package/src/rbt_api.js +51 -20
package/dist/rbt_user.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
2
|
+
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
|
|
3
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
4
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
5
|
+
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
|
|
6
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
7
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
8
|
+
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
|
|
9
|
+
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
|
|
10
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
11
|
+
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); }
|
|
12
|
+
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; }
|
|
13
|
+
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; }
|
|
14
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
15
|
+
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
|
|
16
|
+
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
|
|
17
|
+
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
|
|
18
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
|
|
19
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
20
|
+
import _ from 'lodash';
|
|
21
|
+
var RbtUser = /*#__PURE__*/function () {
|
|
22
|
+
function RbtUser(record, axiosInstance) {
|
|
23
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
24
|
+
_classCallCheck(this, RbtUser);
|
|
25
|
+
this._axios = axiosInstance;
|
|
26
|
+
this._internalData = record;
|
|
27
|
+
this.id = record.id;
|
|
28
|
+
this.id_revision = record.id_revision;
|
|
29
|
+
this.rpcMeta = {
|
|
30
|
+
changes: [],
|
|
31
|
+
isNew: options.isNew || false
|
|
32
|
+
};
|
|
33
|
+
if (record.data) {
|
|
34
|
+
this._data = this._deepUnpackJson(record.data);
|
|
35
|
+
} else {
|
|
36
|
+
this._data = record.dataJson ? this._deepUnpackJson(record.dataJson) : {};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return _createClass(RbtUser, [{
|
|
40
|
+
key: "get",
|
|
41
|
+
value: function get(path) {
|
|
42
|
+
return _.get(this._data, path);
|
|
43
|
+
}
|
|
44
|
+
}, {
|
|
45
|
+
key: "getData",
|
|
46
|
+
value: function getData() {
|
|
47
|
+
return _objectSpread({}, this._data);
|
|
48
|
+
}
|
|
49
|
+
}, {
|
|
50
|
+
key: "_addChange",
|
|
51
|
+
value: function _addChange(path) {
|
|
52
|
+
// Ensure no duplicate paths
|
|
53
|
+
if (!this.rpcMeta.changes.includes(path)) {
|
|
54
|
+
this.rpcMeta.changes.push(path);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, {
|
|
58
|
+
key: "set",
|
|
59
|
+
value: function set(path, value) {
|
|
60
|
+
var currentValue = _.get(this._data, path);
|
|
61
|
+
if (!_.isEqual(currentValue, value)) {
|
|
62
|
+
_.set(this._data, path, value);
|
|
63
|
+
this._addChange(path);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}, {
|
|
67
|
+
key: "setData",
|
|
68
|
+
value: function setData(newData) {
|
|
69
|
+
var _this = this;
|
|
70
|
+
if (_typeof(newData) !== 'object' || newData === null) {
|
|
71
|
+
throw new Error('setData expects an object');
|
|
72
|
+
}
|
|
73
|
+
Object.keys(newData).forEach(function (key) {
|
|
74
|
+
if (!_.isEqual(_.get(_this._data, key), newData[key])) {
|
|
75
|
+
_.set(_this._data, key, newData[key]);
|
|
76
|
+
_this._addChange(key);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//
|
|
82
|
+
// For Arrays
|
|
83
|
+
//
|
|
84
|
+
}, {
|
|
85
|
+
key: "setAppend",
|
|
86
|
+
value: function setAppend(key, value) {
|
|
87
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
88
|
+
var existingValue = this.get(key) || []; // Get the existing value or default to an empty array
|
|
89
|
+
if (!Array.isArray(existingValue)) {
|
|
90
|
+
existingValue = []; // Ensure existingValue is an array if not already
|
|
91
|
+
}
|
|
92
|
+
var valuesToAdd = Array.isArray(value) ? value : [value]; // Convert value to an array if it's not one
|
|
93
|
+
|
|
94
|
+
// Combine existingValue and valuesToAdd, filtering out duplicates
|
|
95
|
+
var mergedValues = Array.from(new Set([].concat(_toConsumableArray(existingValue), _toConsumableArray(valuesToAdd))));
|
|
96
|
+
this.set(key, mergedValues, options); // Set the updated array back to the user data
|
|
97
|
+
}
|
|
98
|
+
}, {
|
|
99
|
+
key: "setRemove",
|
|
100
|
+
value: function setRemove(key, value) {
|
|
101
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
102
|
+
var existingValue = this.get(key) || []; // Get the existing value or default to an empty array
|
|
103
|
+
if (!Array.isArray(existingValue)) {
|
|
104
|
+
return; // If it's not an array, there's nothing to remove, so exit early
|
|
105
|
+
}
|
|
106
|
+
var valuesToRemove = Array.isArray(value) ? value : [value]; // Convert value to an array if it's not one
|
|
107
|
+
|
|
108
|
+
// Filter out the values to remove from the existing value array
|
|
109
|
+
var filteredValues = existingValue.filter(function (item) {
|
|
110
|
+
return !valuesToRemove.includes(item);
|
|
111
|
+
});
|
|
112
|
+
this.set(key, filteredValues); // Set the updated array back to the user data
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//
|
|
116
|
+
//
|
|
117
|
+
//
|
|
118
|
+
}, {
|
|
119
|
+
key: "toRecord",
|
|
120
|
+
value: function toRecord() {
|
|
121
|
+
return _objectSpread(_objectSpread({}, this._internalData), {}, {
|
|
122
|
+
dataJson: JSON.stringify(this._data),
|
|
123
|
+
rpcMeta: this.rpcMeta
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}, {
|
|
127
|
+
key: "clone",
|
|
128
|
+
value: function clone() {
|
|
129
|
+
// Create a deep copy of the current object's data
|
|
130
|
+
var clonedData = _.cloneDeep(this._internalData);
|
|
131
|
+
|
|
132
|
+
// Reset unique identifiers to ensure a new ID is generated upon saving
|
|
133
|
+
delete clonedData.id;
|
|
134
|
+
delete clonedData.id_revision;
|
|
135
|
+
|
|
136
|
+
// Create a new instance of RbtUser with the cloned data
|
|
137
|
+
var clonedObject = new RbtUser(clonedData, this._axios, {
|
|
138
|
+
isNew: true
|
|
139
|
+
});
|
|
140
|
+
return clonedObject;
|
|
141
|
+
}
|
|
142
|
+
}, {
|
|
143
|
+
key: "save",
|
|
144
|
+
value: function () {
|
|
145
|
+
var _save = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
146
|
+
var record, response, _t;
|
|
147
|
+
return _regenerator().w(function (_context) {
|
|
148
|
+
while (1) switch (_context.p = _context.n) {
|
|
149
|
+
case 0:
|
|
150
|
+
_context.p = 0;
|
|
151
|
+
debugger;
|
|
152
|
+
record = this.toRecord();
|
|
153
|
+
record.type = '<@iac.user>';
|
|
154
|
+
_context.n = 1;
|
|
155
|
+
return this._axios.post('/user_service/saveUser', [record]);
|
|
156
|
+
case 1:
|
|
157
|
+
response = _context.v;
|
|
158
|
+
if (!(response.data.ok === false)) {
|
|
159
|
+
_context.n = 2;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
throw new Error(response.data.message);
|
|
163
|
+
case 2:
|
|
164
|
+
this._internalData = response.data;
|
|
165
|
+
this.id = response.data.id;
|
|
166
|
+
this.id_revision = response.data.id_revision;
|
|
167
|
+
this.type = response.data.type;
|
|
168
|
+
this.rpcMeta.isNew = false;
|
|
169
|
+
return _context.a(2, this);
|
|
170
|
+
case 3:
|
|
171
|
+
_context.p = 3;
|
|
172
|
+
_t = _context.v;
|
|
173
|
+
console.log('RbtUser.save.error:', _t);
|
|
174
|
+
//console.log(e.response.data);
|
|
175
|
+
throw _t;
|
|
176
|
+
case 4:
|
|
177
|
+
return _context.a(2);
|
|
178
|
+
}
|
|
179
|
+
}, _callee, this, [[0, 3]]);
|
|
180
|
+
}));
|
|
181
|
+
function save() {
|
|
182
|
+
return _save.apply(this, arguments);
|
|
183
|
+
}
|
|
184
|
+
return save;
|
|
185
|
+
}()
|
|
186
|
+
}, {
|
|
187
|
+
key: "_deepUnpackJson",
|
|
188
|
+
value: function _deepUnpackJson(value) {
|
|
189
|
+
if (typeof value === 'string') {
|
|
190
|
+
try {
|
|
191
|
+
// Only parse as JSON if it's not a large number
|
|
192
|
+
// https://chatgpt.com/c/6745902c-edf4-800c-ab52-31bf27dde2bd
|
|
193
|
+
//
|
|
194
|
+
if (!/^\d{16,}$/.test(value)) {
|
|
195
|
+
var parsed = JSON.parse(value);
|
|
196
|
+
// Recursively parse if the result is a string, object, or array
|
|
197
|
+
return this._deepUnpackJson(parsed);
|
|
198
|
+
}
|
|
199
|
+
} catch (e) {
|
|
200
|
+
return value; // Return the original string if parsing fails
|
|
201
|
+
}
|
|
202
|
+
} else if (value !== null && _typeof(value) === 'object') {
|
|
203
|
+
// If it's an object (including arrays), recursively parse each value
|
|
204
|
+
for (var key in value) {
|
|
205
|
+
value[key] = this._deepUnpackJson(value[key]);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
//async delete() {
|
|
212
|
+
// if (!this._internalData.type) {
|
|
213
|
+
// throw new Error('Cannot delete object without type');
|
|
214
|
+
// }
|
|
215
|
+
//
|
|
216
|
+
// try {
|
|
217
|
+
// const record = this.toRecord();
|
|
218
|
+
// const response = await this._axios.post('/object_service/deleteObject', [record]);
|
|
219
|
+
//
|
|
220
|
+
// if (response.data.ok === false) {
|
|
221
|
+
// throw new Error(response.data.message);
|
|
222
|
+
// }
|
|
223
|
+
//
|
|
224
|
+
// this._internalData = response.data;
|
|
225
|
+
// return this;
|
|
226
|
+
//
|
|
227
|
+
// } catch (e) {
|
|
228
|
+
// console.log('RbtUser.delete.error:');
|
|
229
|
+
// console.log(e.response.data);
|
|
230
|
+
// throw e;
|
|
231
|
+
// }
|
|
232
|
+
//}
|
|
233
|
+
}]);
|
|
234
|
+
}();
|
|
235
|
+
export { RbtUser as default };
|
package/package.json
CHANGED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cookie-based storage adaptor for roboto-js
|
|
3
|
+
* Provides a localStorage-compatible interface using cookies
|
|
4
|
+
* This enables server-side access to authentication tokens
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export default class CookieStorageAdaptor {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.options = {
|
|
10
|
+
// Security settings
|
|
11
|
+
secure: options.secure ?? (typeof window !== 'undefined' && window.location.protocol === 'https:'),
|
|
12
|
+
sameSite: options.sameSite ?? 'Lax',
|
|
13
|
+
httpOnly: false, // Must be false so client-side JS can access
|
|
14
|
+
|
|
15
|
+
// Cookie settings
|
|
16
|
+
path: options.path ?? '/',
|
|
17
|
+
maxAge: options.maxAge ?? 24 * 60 * 60, // 24 hours default
|
|
18
|
+
domain: options.domain ?? undefined, // Let browser determine domain
|
|
19
|
+
|
|
20
|
+
// Prefix for roboto cookies to avoid conflicts
|
|
21
|
+
prefix: options.prefix ?? 'rbt_',
|
|
22
|
+
|
|
23
|
+
// Keys that should be stored without prefix for server-side access
|
|
24
|
+
serverAccessKeys: options.serverAccessKeys ?? ['authtoken', 'accessKey', 'apikey'],
|
|
25
|
+
|
|
26
|
+
...options
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log('[CookieStorageAdaptor] Initialized with options:', {
|
|
30
|
+
secure: this.options.secure,
|
|
31
|
+
sameSite: this.options.sameSite,
|
|
32
|
+
path: this.options.path,
|
|
33
|
+
maxAge: this.options.maxAge,
|
|
34
|
+
domain: this.options.domain,
|
|
35
|
+
prefix: this.options.prefix,
|
|
36
|
+
serverAccessKeys: this.options.serverAccessKeys
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get item from cookies (localStorage-compatible interface)
|
|
42
|
+
*/
|
|
43
|
+
async getItem(key) {
|
|
44
|
+
if (typeof document === 'undefined') {
|
|
45
|
+
console.log(`[CookieStorageAdaptor] getItem(${key}): document undefined, returning null`)
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check if this key should be stored without prefix for server access
|
|
50
|
+
const usePrefix = !this.options.serverAccessKeys.includes(key)
|
|
51
|
+
const cookieName = usePrefix ? this.options.prefix + key : key
|
|
52
|
+
const name = cookieName + '='
|
|
53
|
+
const decodedCookie = decodeURIComponent(document.cookie)
|
|
54
|
+
const cookies = decodedCookie.split(';')
|
|
55
|
+
|
|
56
|
+
console.log(`[CookieStorageAdaptor] getItem(${key}): looking for cookie "${cookieName}" ${usePrefix ? '(prefixed)' : '(server-accessible)'}`)
|
|
57
|
+
console.log(`[CookieStorageAdaptor] Available cookies:`, cookies.map(c => c.trim().split('=')[0]).join(', '))
|
|
58
|
+
|
|
59
|
+
for (let cookie of cookies) {
|
|
60
|
+
cookie = cookie.trim()
|
|
61
|
+
if (cookie.indexOf(name) === 0) {
|
|
62
|
+
const rawValue = cookie.substring(name.length, cookie.length)
|
|
63
|
+
console.log(`[CookieStorageAdaptor] Found cookie "${cookieName}" with raw value:`, rawValue)
|
|
64
|
+
|
|
65
|
+
// Handle JSON values (like rbtUser)
|
|
66
|
+
try {
|
|
67
|
+
const parsedValue = JSON.parse(rawValue)
|
|
68
|
+
console.log(`[CookieStorageAdaptor] getItem(${key}): returning parsed JSON:`, parsedValue)
|
|
69
|
+
return parsedValue
|
|
70
|
+
} catch {
|
|
71
|
+
console.log(`[CookieStorageAdaptor] getItem(${key}): returning string value:`, rawValue)
|
|
72
|
+
return rawValue
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(`[CookieStorageAdaptor] getItem(${key}): cookie "${cookieName}" not found, returning null`)
|
|
78
|
+
return null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Set item in cookies (localStorage-compatible interface)
|
|
83
|
+
*/
|
|
84
|
+
async setItem(key, value) {
|
|
85
|
+
if (typeof document === 'undefined') {
|
|
86
|
+
console.log(`[CookieStorageAdaptor] setItem(${key}): document undefined, skipping`)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check if this key should be stored without prefix for server access
|
|
91
|
+
const usePrefix = !this.options.serverAccessKeys.includes(key)
|
|
92
|
+
const cookieName = usePrefix ? this.options.prefix + key : key
|
|
93
|
+
|
|
94
|
+
// Stringify objects/arrays like localStorage does
|
|
95
|
+
const cookieValue = typeof value === 'object' ? JSON.stringify(value) : String(value)
|
|
96
|
+
|
|
97
|
+
console.log(`[CookieStorageAdaptor] setItem(${key}): storing as "${cookieName}" ${usePrefix ? '(prefixed)' : '(server-accessible)'}`)
|
|
98
|
+
console.log(`[CookieStorageAdaptor] Original value:`, value)
|
|
99
|
+
console.log(`[CookieStorageAdaptor] Cookie value:`, cookieValue)
|
|
100
|
+
|
|
101
|
+
// Build cookie string with security options
|
|
102
|
+
const secureFlag = this.options.secure ? '; Secure' : ''
|
|
103
|
+
const domainFlag = this.options.domain ? `; Domain=${this.options.domain}` : ''
|
|
104
|
+
const httpOnlyFlag = this.options.httpOnly ? '; HttpOnly' : ''
|
|
105
|
+
|
|
106
|
+
const cookieString = `${cookieName}=${encodeURIComponent(cookieValue)}; path=${this.options.path}; max-age=${this.options.maxAge}; SameSite=${this.options.sameSite}${secureFlag}${domainFlag}${httpOnlyFlag}`
|
|
107
|
+
|
|
108
|
+
console.log(`[CookieStorageAdaptor] Full cookie string:`, cookieString)
|
|
109
|
+
|
|
110
|
+
document.cookie = cookieString
|
|
111
|
+
|
|
112
|
+
// Verify the cookie was set by immediately reading it back
|
|
113
|
+
const verification = await this.getItem(key)
|
|
114
|
+
if (verification !== null) {
|
|
115
|
+
console.log(`[CookieStorageAdaptor] ✅ Successfully set and verified cookie: ${cookieName}`)
|
|
116
|
+
} else {
|
|
117
|
+
console.error(`[CookieStorageAdaptor] ❌ Failed to set cookie: ${cookieName}`)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Remove item from cookies (localStorage-compatible interface)
|
|
123
|
+
*/
|
|
124
|
+
async removeItem(key) {
|
|
125
|
+
if (typeof document === 'undefined') {
|
|
126
|
+
console.log(`[CookieStorageAdaptor] removeItem(${key}): document undefined, skipping`)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check if this key should be stored without prefix for server access
|
|
131
|
+
const usePrefix = !this.options.serverAccessKeys.includes(key)
|
|
132
|
+
const cookieName = usePrefix ? this.options.prefix + key : key
|
|
133
|
+
|
|
134
|
+
console.log(`[CookieStorageAdaptor] removeItem(${key}): removing cookie "${cookieName}" ${usePrefix ? '(prefixed)' : '(server-accessible)'}`)
|
|
135
|
+
|
|
136
|
+
// Check if cookie exists before removal
|
|
137
|
+
const existingValue = await this.getItem(key)
|
|
138
|
+
if (existingValue !== null) {
|
|
139
|
+
console.log(`[CookieStorageAdaptor] Cookie "${cookieName}" exists, removing...`)
|
|
140
|
+
} else {
|
|
141
|
+
console.log(`[CookieStorageAdaptor] Cookie "${cookieName}" doesn't exist, removal not needed`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const secureFlag = this.options.secure ? '; Secure' : ''
|
|
145
|
+
const domainFlag = this.options.domain ? `; Domain=${this.options.domain}` : ''
|
|
146
|
+
|
|
147
|
+
const removalString = `${cookieName}=; path=${this.options.path}; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=${this.options.sameSite}${secureFlag}${domainFlag}`
|
|
148
|
+
console.log(`[CookieStorageAdaptor] Removal cookie string:`, removalString)
|
|
149
|
+
|
|
150
|
+
document.cookie = removalString
|
|
151
|
+
|
|
152
|
+
// Verify the cookie was removed
|
|
153
|
+
const verification = await this.getItem(key)
|
|
154
|
+
if (verification === null) {
|
|
155
|
+
console.log(`[CookieStorageAdaptor] ✅ Successfully removed cookie: ${cookieName}`)
|
|
156
|
+
} else {
|
|
157
|
+
console.error(`[CookieStorageAdaptor] ❌ Failed to remove cookie: ${cookieName}, still has value:`, verification)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Clear all roboto cookies
|
|
163
|
+
*/
|
|
164
|
+
async clear() {
|
|
165
|
+
if (typeof document === 'undefined') return
|
|
166
|
+
|
|
167
|
+
// Get all cookies and remove ones with our prefix or server access keys
|
|
168
|
+
const cookies = document.cookie.split(';')
|
|
169
|
+
const prefix = this.options.prefix
|
|
170
|
+
|
|
171
|
+
for (let cookie of cookies) {
|
|
172
|
+
const cookieName = cookie.split('=')[0].trim()
|
|
173
|
+
|
|
174
|
+
// Remove prefixed cookies
|
|
175
|
+
if (cookieName.startsWith(prefix)) {
|
|
176
|
+
const key = cookieName.substring(prefix.length)
|
|
177
|
+
await this.removeItem(key)
|
|
178
|
+
}
|
|
179
|
+
// Remove server access keys (non-prefixed)
|
|
180
|
+
else if (this.options.serverAccessKeys.includes(cookieName)) {
|
|
181
|
+
await this.removeItem(cookieName)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get all keys (for debugging/compatibility)
|
|
188
|
+
*/
|
|
189
|
+
async keys() {
|
|
190
|
+
if (typeof document === 'undefined') return []
|
|
191
|
+
|
|
192
|
+
const cookies = document.cookie.split(';')
|
|
193
|
+
const prefix = this.options.prefix
|
|
194
|
+
const keys = []
|
|
195
|
+
|
|
196
|
+
for (let cookie of cookies) {
|
|
197
|
+
const cookieName = cookie.split('=')[0].trim()
|
|
198
|
+
|
|
199
|
+
// Add prefixed cookies
|
|
200
|
+
if (cookieName.startsWith(prefix)) {
|
|
201
|
+
keys.push(cookieName.substring(prefix.length))
|
|
202
|
+
}
|
|
203
|
+
// Add server access keys (non-prefixed)
|
|
204
|
+
else if (this.options.serverAccessKeys.includes(cookieName)) {
|
|
205
|
+
keys.push(cookieName)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return keys
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Debug method to log all current cookies and adapter state
|
|
214
|
+
*/
|
|
215
|
+
debugState() {
|
|
216
|
+
if (typeof document === 'undefined') {
|
|
217
|
+
console.log('[CookieStorageAdaptor] DEBUG: document undefined (server-side)')
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
console.log('[CookieStorageAdaptor] DEBUG STATE:')
|
|
222
|
+
console.log('- Options:', this.options)
|
|
223
|
+
console.log('- All cookies:', document.cookie)
|
|
224
|
+
|
|
225
|
+
const cookies = document.cookie.split(';')
|
|
226
|
+
const robotoKeys = []
|
|
227
|
+
const serverKeys = []
|
|
228
|
+
const otherKeys = []
|
|
229
|
+
|
|
230
|
+
for (let cookie of cookies) {
|
|
231
|
+
const cookieName = cookie.split('=')[0].trim()
|
|
232
|
+
if (cookieName.startsWith(this.options.prefix)) {
|
|
233
|
+
robotoKeys.push(cookieName)
|
|
234
|
+
} else if (this.options.serverAccessKeys.includes(cookieName)) {
|
|
235
|
+
serverKeys.push(cookieName)
|
|
236
|
+
} else if (cookieName) {
|
|
237
|
+
otherKeys.push(cookieName)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
console.log('- Roboto prefixed cookies:', robotoKeys)
|
|
242
|
+
console.log('- Server access cookies:', serverKeys)
|
|
243
|
+
console.log('- Other cookies:', otherKeys)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
}
|
package/src/index.js
CHANGED
|
@@ -3,11 +3,13 @@ import RbtApi from './rbt_api.js';
|
|
|
3
3
|
import RbtObject from './rbt_object.js';
|
|
4
4
|
import RbtFile from './rbt_file.js';
|
|
5
5
|
import RbtMetricsApi from './rbt_metrics_api.js';
|
|
6
|
+
import CookieStorageAdaptor from './cookie_storage_adaptor.js';
|
|
6
7
|
|
|
7
8
|
export {
|
|
8
9
|
RbtApi,
|
|
9
10
|
RbtObject,
|
|
10
|
-
RbtFile
|
|
11
|
+
RbtFile,
|
|
12
|
+
CookieStorageAdaptor
|
|
11
13
|
//User,
|
|
12
14
|
//Site
|
|
13
15
|
};
|
|
@@ -15,10 +17,10 @@ export {
|
|
|
15
17
|
export default class Roboto{
|
|
16
18
|
|
|
17
19
|
getVersion(){
|
|
18
|
-
return '1.
|
|
20
|
+
return '1.7.3';
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
constructor({ host, accessKey, localStorageAdaptor, disableWebSocket = false, metricsHost }, proxyReq = null) {
|
|
23
|
+
constructor({ host, accessKey, localStorageAdaptor, disableWebSocket = false, metricsHost, useCookies = true }, proxyReq = null) {
|
|
22
24
|
|
|
23
25
|
if (Roboto.instance && !proxyReq) {
|
|
24
26
|
// if on client, there can only be one instance
|
|
@@ -28,10 +30,30 @@ export default class Roboto{
|
|
|
28
30
|
|
|
29
31
|
const isBrowser = typeof window !== "undefined";
|
|
30
32
|
this.data = {};
|
|
33
|
+
|
|
34
|
+
// Auto-configure storage adaptor
|
|
35
|
+
let storageAdaptor = localStorageAdaptor;
|
|
36
|
+
if (!storageAdaptor && isBrowser && useCookies) {
|
|
37
|
+
// Use cookies by default in browser for better server-side compatibility
|
|
38
|
+
storageAdaptor = new CookieStorageAdaptor({
|
|
39
|
+
secure: window.location.protocol === 'https:',
|
|
40
|
+
sameSite: 'Lax',
|
|
41
|
+
maxAge: 24 * 60 * 60 // 24 hours
|
|
42
|
+
});
|
|
43
|
+
console.log('[Roboto] Using CookieStorageAdaptor for authentication tokens');
|
|
44
|
+
|
|
45
|
+
// Set accessKey for server-side authentication (handled automatically by adapter)
|
|
46
|
+
if (accessKey) {
|
|
47
|
+
storageAdaptor.setItem('accessKey', accessKey).catch(e =>
|
|
48
|
+
console.warn('[Roboto] Failed to set accessKey cookie:', e)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
this.config = {
|
|
32
54
|
accessKey: accessKey, // Use passed accessKey
|
|
33
55
|
baseUrl: `https://${host}`, // Use passed host
|
|
34
|
-
localStorageAdaptor:
|
|
56
|
+
localStorageAdaptor: storageAdaptor
|
|
35
57
|
};
|
|
36
58
|
|
|
37
59
|
// DEVELOPMENT
|
|
@@ -58,6 +80,12 @@ export default class Roboto{
|
|
|
58
80
|
this.api = new RbtApi(this.config);
|
|
59
81
|
if (isBrowser) {
|
|
60
82
|
this.api.initLocalDb();
|
|
83
|
+
|
|
84
|
+
// Add global debug method for cookie storage adapter
|
|
85
|
+
if (this.config.localStorageAdaptor && this.config.localStorageAdaptor.debugState) {
|
|
86
|
+
window.debugRobotoCookies = () => this.config.localStorageAdaptor.debugState();
|
|
87
|
+
console.log('[Roboto] Added global debug method: window.debugRobotoCookies()');
|
|
88
|
+
}
|
|
61
89
|
}
|
|
62
90
|
|
|
63
91
|
// METRICS API instance (separate host or same)
|
|
@@ -155,7 +183,15 @@ export default class Roboto{
|
|
|
155
183
|
return this.api.loginWithOauth(params);
|
|
156
184
|
}
|
|
157
185
|
async logout(){
|
|
158
|
-
|
|
186
|
+
const result = await this.api.logout();
|
|
187
|
+
|
|
188
|
+
// Clear accessKey and authtoken using standard localStorage interface
|
|
189
|
+
if (this.config.localStorageAdaptor) {
|
|
190
|
+
await this.config.localStorageAdaptor.removeItem('accessKey');
|
|
191
|
+
await this.config.localStorageAdaptor.removeItem('authtoken');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return result;
|
|
159
195
|
}
|
|
160
196
|
async refreshAuthToken(){
|
|
161
197
|
return this.api.refreshAuthToken(this.config.authtoken);
|
package/src/rbt_api.js
CHANGED
|
@@ -43,26 +43,9 @@ export default class RbtApi {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
//
|
|
47
|
-
if
|
|
48
|
-
|
|
49
|
-
const token = localStorage.getItem('authtoken');
|
|
50
|
-
if (token) {
|
|
51
|
-
this.authtoken = token;
|
|
52
|
-
this.axios.defaults.headers.common['authtoken'] = token;
|
|
53
|
-
}
|
|
54
|
-
} catch {}
|
|
55
|
-
try {
|
|
56
|
-
const cachedUser = localStorage.getItem('rbtUser');
|
|
57
|
-
if (cachedUser) {
|
|
58
|
-
const parsed = JSON.parse(cachedUser);
|
|
59
|
-
if (parsed && parsed.id) {
|
|
60
|
-
this.currentUser = new RbtUser({ id: parsed.id }, this.axios);
|
|
61
|
-
this.currentUser.setData(parsed);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
} catch {}
|
|
65
|
-
}
|
|
46
|
+
// Asynchronous browser hydration: set auth header and in-memory user
|
|
47
|
+
// Use storage adaptor if available, otherwise fallback to localStorage
|
|
48
|
+
this._initializeFromStorage().catch(e => console.warn('[RbtApi] Storage initialization failed:', e));
|
|
66
49
|
this.localDb = null;
|
|
67
50
|
this.iac_session = null;
|
|
68
51
|
this.appServiceHost = baseUrl;
|
|
@@ -77,6 +60,52 @@ export default class RbtApi {
|
|
|
77
60
|
|
|
78
61
|
}
|
|
79
62
|
|
|
63
|
+
// Initialize authtoken and user from storage (cookies or localStorage)
|
|
64
|
+
async _initializeFromStorage() {
|
|
65
|
+
if (!this.localStorageAdaptor) return;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
// Try to get authtoken from storage adaptor (prefixed: rbt_authtoken)
|
|
69
|
+
let token = await this.localStorageAdaptor.getItem('authtoken');
|
|
70
|
+
|
|
71
|
+
// If not found in prefixed storage, try raw cookie (like accessKey)
|
|
72
|
+
if (!token && typeof document !== 'undefined') {
|
|
73
|
+
// Try to get from raw cookie
|
|
74
|
+
const cookies = document.cookie.split(';');
|
|
75
|
+
for (let cookie of cookies) {
|
|
76
|
+
const [name, value] = cookie.trim().split('=');
|
|
77
|
+
if (name === 'authtoken') {
|
|
78
|
+
token = decodeURIComponent(value);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (token) {
|
|
85
|
+
this.authtoken = token;
|
|
86
|
+
this.axios.defaults.headers.common['authtoken'] = token;
|
|
87
|
+
console.log('[RbtApi] Loaded authtoken from storage adaptor');
|
|
88
|
+
}
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.warn('[RbtApi] Failed to load authtoken from storage adaptor:', e);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Try to get user from storage adaptor
|
|
95
|
+
const cachedUser = await this.localStorageAdaptor.getItem('rbtUser');
|
|
96
|
+
if (cachedUser) {
|
|
97
|
+
const parsed = typeof cachedUser === 'string' ? JSON.parse(cachedUser) : cachedUser;
|
|
98
|
+
if (parsed && parsed.id) {
|
|
99
|
+
this.currentUser = new RbtUser({ id: parsed.id }, this.axios);
|
|
100
|
+
this.currentUser.setData(parsed);
|
|
101
|
+
console.log('[RbtApi] Loaded user from storage adaptor');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} catch (e) {
|
|
105
|
+
console.warn('[RbtApi] Failed to load user from storage adaptor:', e);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
80
109
|
getWebSocketClient() {
|
|
81
110
|
// Reuse existing WebSocket if it's OPEN or CONNECTING (to prevent race condition)
|
|
82
111
|
if (this.websocketClient &&
|
|
@@ -277,6 +306,8 @@ export default class RbtApi {
|
|
|
277
306
|
if (this.iac_session?.user) {
|
|
278
307
|
await this.localStorageAdaptor.setItem('rbtUser', JSON.stringify(this.iac_session.user));
|
|
279
308
|
}
|
|
309
|
+
|
|
310
|
+
// authtoken is automatically stored for server-side access by the adapter
|
|
280
311
|
}
|
|
281
312
|
|
|
282
313
|
return response.data;
|