roboto-js 3.0.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/dist/cjs/index.cjs +185 -111
- package/dist/cjs/rbt_api.cjs +645 -446
- package/dist/cjs/rbt_object.cjs +65 -21
- package/dist/cjs/version.cjs +2 -2
- package/dist/esm/index.js +185 -111
- package/dist/esm/rbt_api.js +646 -446
- package/dist/esm/rbt_object.js +65 -21
- package/dist/esm/version.js +2 -2
- package/package.json +1 -1
- package/src/index.js +13 -5
- package/src/rbt_api.js +125 -59
- package/src/rbt_object.js +46 -0
- package/src/version.js +2 -2
package/dist/esm/rbt_object.js
CHANGED
|
@@ -351,11 +351,47 @@ var RbtObject = /*#__PURE__*/function () {
|
|
|
351
351
|
});
|
|
352
352
|
return clonedObject;
|
|
353
353
|
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Rebuild read_ids/write_ids record meta from iac grant arrays.
|
|
357
|
+
* Keeps denormalized columns in sync with dataJson.iac for delta saves.
|
|
358
|
+
*/
|
|
359
|
+
}, {
|
|
360
|
+
key: "_syncIacRecordMeta",
|
|
361
|
+
value: function _syncIacRecordMeta() {
|
|
362
|
+
var iac = _.get(this._data, 'iac');
|
|
363
|
+
if (!iac) return;
|
|
364
|
+
var readIds = new Set();
|
|
365
|
+
var writeIds = new Set();
|
|
366
|
+
if (this.type === '<@iac.user>') {
|
|
367
|
+
writeIds.add(this.id);
|
|
368
|
+
readIds.add(this.id);
|
|
369
|
+
}
|
|
370
|
+
if (iac.creator) {
|
|
371
|
+
writeIds.add(iac.creator);
|
|
372
|
+
readIds.add(iac.creator);
|
|
373
|
+
}
|
|
374
|
+
var collect = function collect(grants, target) {
|
|
375
|
+
if (!grants) return;
|
|
376
|
+
for (var _i = 0, _arr = ['users', 'userGroups', 'organizations', 'userSegments']; _i < _arr.length; _i++) {
|
|
377
|
+
var key = _arr[_i];
|
|
378
|
+
if (Array.isArray(grants[key])) {
|
|
379
|
+
grants[key].forEach(function (id) {
|
|
380
|
+
return target.add(id);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
collect(iac.readGrants, readIds);
|
|
386
|
+
collect(iac.writeGrants, writeIds);
|
|
387
|
+
this._internalData.read_ids = Array.from(readIds).join(',');
|
|
388
|
+
this._internalData.write_ids = Array.from(writeIds).join(',');
|
|
389
|
+
}
|
|
354
390
|
}, {
|
|
355
391
|
key: "save",
|
|
356
392
|
value: function () {
|
|
357
393
|
var _save = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
|
|
358
|
-
var _response$data, _response$data2, record, response;
|
|
394
|
+
var _response$data, _response$data2, iacGrantChange, record, response;
|
|
359
395
|
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
|
360
396
|
while (1) switch (_context3.prev = _context3.next) {
|
|
361
397
|
case 0:
|
|
@@ -366,28 +402,34 @@ var RbtObject = /*#__PURE__*/function () {
|
|
|
366
402
|
throw new Error('Cannot save object without type');
|
|
367
403
|
case 2:
|
|
368
404
|
_context3.prev = 2;
|
|
405
|
+
iacGrantChange = (this.rpcMeta.changes || []).some(function (path) {
|
|
406
|
+
return path.startsWith('iac.readGrants') || path.startsWith('iac.writeGrants');
|
|
407
|
+
});
|
|
408
|
+
if (iacGrantChange) {
|
|
409
|
+
this._syncIacRecordMeta();
|
|
410
|
+
}
|
|
369
411
|
if (this.rpcMeta.isNew) {
|
|
370
412
|
record = this.toRecord();
|
|
371
413
|
} else {
|
|
372
414
|
record = this.toDeltaRecord();
|
|
373
415
|
}
|
|
374
|
-
_context3.next =
|
|
416
|
+
_context3.next = 8;
|
|
375
417
|
return this._axios.post('/object_service/saveObject', [record]);
|
|
376
|
-
case
|
|
418
|
+
case 8:
|
|
377
419
|
response = _context3.sent;
|
|
378
420
|
if (!(response.data.ok === false)) {
|
|
379
|
-
_context3.next =
|
|
421
|
+
_context3.next = 11;
|
|
380
422
|
break;
|
|
381
423
|
}
|
|
382
424
|
throw new Error(response.data.message);
|
|
383
|
-
case
|
|
425
|
+
case 11:
|
|
384
426
|
if (!(((_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.result) == 'NO_CHANGES')) {
|
|
385
|
-
_context3.next =
|
|
427
|
+
_context3.next = 14;
|
|
386
428
|
break;
|
|
387
429
|
}
|
|
388
430
|
this.rpcMeta.isNew = false;
|
|
389
431
|
return _context3.abrupt("return", this);
|
|
390
|
-
case
|
|
432
|
+
case 14:
|
|
391
433
|
if ((_response$data2 = response.data) !== null && _response$data2 !== void 0 && _response$data2.newData) {
|
|
392
434
|
// apply new incoming data
|
|
393
435
|
this.setData(response.newData);
|
|
@@ -397,17 +439,17 @@ var RbtObject = /*#__PURE__*/function () {
|
|
|
397
439
|
this.type = response.data.type;
|
|
398
440
|
this.rpcMeta.isNew = false;
|
|
399
441
|
return _context3.abrupt("return", this);
|
|
400
|
-
case
|
|
401
|
-
_context3.prev =
|
|
442
|
+
case 22:
|
|
443
|
+
_context3.prev = 22;
|
|
402
444
|
_context3.t0 = _context3["catch"](2);
|
|
403
445
|
this._error = _context3.t0;
|
|
404
446
|
//console.log(e.response.data);
|
|
405
447
|
throw _context3.t0;
|
|
406
|
-
case
|
|
448
|
+
case 26:
|
|
407
449
|
case "end":
|
|
408
450
|
return _context3.stop();
|
|
409
451
|
}
|
|
410
|
-
}, _callee3, this, [[2,
|
|
452
|
+
}, _callee3, this, [[2, 22]]);
|
|
411
453
|
}));
|
|
412
454
|
function save() {
|
|
413
455
|
return _save.apply(this, arguments);
|
|
@@ -524,19 +566,20 @@ var RbtObject = /*#__PURE__*/function () {
|
|
|
524
566
|
this.set(groupsPath, _toConsumableArray(new Set([].concat(_toConsumableArray(existingGroups), _toConsumableArray(groupIds)))));
|
|
525
567
|
}
|
|
526
568
|
}
|
|
569
|
+
this._syncIacRecordMeta();
|
|
527
570
|
|
|
528
571
|
// Save if requested
|
|
529
572
|
if (!save) {
|
|
530
|
-
_context4.next =
|
|
573
|
+
_context4.next = 16;
|
|
531
574
|
break;
|
|
532
575
|
}
|
|
533
|
-
_context4.next =
|
|
576
|
+
_context4.next = 15;
|
|
534
577
|
return this.save();
|
|
535
|
-
case 14:
|
|
536
|
-
return _context4.abrupt("return", _context4.sent);
|
|
537
578
|
case 15:
|
|
538
|
-
return _context4.abrupt("return",
|
|
579
|
+
return _context4.abrupt("return", _context4.sent);
|
|
539
580
|
case 16:
|
|
581
|
+
return _context4.abrupt("return", this);
|
|
582
|
+
case 17:
|
|
540
583
|
case "end":
|
|
541
584
|
return _context4.stop();
|
|
542
585
|
}
|
|
@@ -769,19 +812,20 @@ var RbtObject = /*#__PURE__*/function () {
|
|
|
769
812
|
return !groupIds.includes(id);
|
|
770
813
|
}));
|
|
771
814
|
}
|
|
815
|
+
this._syncIacRecordMeta();
|
|
772
816
|
|
|
773
817
|
// Save if requested
|
|
774
818
|
if (!save) {
|
|
775
|
-
_context7.next =
|
|
819
|
+
_context7.next = 16;
|
|
776
820
|
break;
|
|
777
821
|
}
|
|
778
|
-
_context7.next =
|
|
822
|
+
_context7.next = 15;
|
|
779
823
|
return this.save();
|
|
780
|
-
case 14:
|
|
781
|
-
return _context7.abrupt("return", _context7.sent);
|
|
782
824
|
case 15:
|
|
783
|
-
return _context7.abrupt("return",
|
|
825
|
+
return _context7.abrupt("return", _context7.sent);
|
|
784
826
|
case 16:
|
|
827
|
+
return _context7.abrupt("return", this);
|
|
828
|
+
case 17:
|
|
785
829
|
case "end":
|
|
786
830
|
return _context7.stop();
|
|
787
831
|
}
|
package/dist/esm/version.js
CHANGED
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -298,10 +298,18 @@ export default class Roboto{
|
|
|
298
298
|
async confirmUserEmail(params){
|
|
299
299
|
return this.api.confirmUserEmail(params);
|
|
300
300
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
301
|
+
async sendResetEmailViaFlows(email) {
|
|
302
|
+
return this.api.sendResetEmailViaFlows(email);
|
|
303
|
+
}
|
|
304
|
+
async sendRegistrationVerificationEmail(email) {
|
|
305
|
+
return this.api.sendRegistrationVerificationEmail(email);
|
|
306
|
+
}
|
|
307
|
+
async resendRegistrationCode(email) {
|
|
308
|
+
return this.api.resendRegistrationCode(email);
|
|
309
|
+
}
|
|
310
|
+
async completePasswordReset(params) {
|
|
311
|
+
return this.api.completePasswordReset(params);
|
|
312
|
+
}
|
|
305
313
|
async loadCurrentOrganization(forceReload = false){
|
|
306
314
|
return this.api.loadCurrentOrganization(forceReload);
|
|
307
315
|
}
|
|
@@ -315,7 +323,7 @@ export default class Roboto{
|
|
|
315
323
|
return this.api.getCurrentOrganization();
|
|
316
324
|
}
|
|
317
325
|
get currentOrganization(){
|
|
318
|
-
return this.api.
|
|
326
|
+
return this.api.getCurrentOrganization();
|
|
319
327
|
}
|
|
320
328
|
|
|
321
329
|
//
|
package/src/rbt_api.js
CHANGED
|
@@ -6,6 +6,32 @@ import RbtFile from './rbt_file.js';
|
|
|
6
6
|
import _ from 'lodash';
|
|
7
7
|
import { openDB } from 'idb';
|
|
8
8
|
|
|
9
|
+
/** IAC working org preference lives under module-scoped settings (`mod.iac`). Legacy reads still honor `mod.currentOrgId`. */
|
|
10
|
+
const USER_MOD_CURRENT_ORG_IAC = 'mod.iac.currentOrgId';
|
|
11
|
+
const USER_MOD_CURRENT_ORG_LEGACY = 'mod.currentOrgId';
|
|
12
|
+
|
|
13
|
+
/** @param {import('./rbt_user.js').default|null|undefined} user */
|
|
14
|
+
function readUserCurrentOrgPreference(user) {
|
|
15
|
+
if (!user || typeof user.get !== 'function') return '';
|
|
16
|
+
|
|
17
|
+
let v = user.get(USER_MOD_CURRENT_ORG_IAC);
|
|
18
|
+
if (v != null && String(v).trim() !== '') return String(v).trim();
|
|
19
|
+
v = user.get(USER_MOD_CURRENT_ORG_LEGACY);
|
|
20
|
+
if (v != null && String(v).trim() !== '') return String(v).trim();
|
|
21
|
+
|
|
22
|
+
const d = typeof user.getData === 'function' ? user.getData() : {};
|
|
23
|
+
v = _.get(d, 'mod.iac.currentOrgId') ?? _.get(d, 'mod.currentOrgId');
|
|
24
|
+
if (v != null && String(v).trim() !== '') return String(v).trim();
|
|
25
|
+
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** @param {import('./rbt_user.js').default} user */
|
|
30
|
+
function persistUserCurrentOrgPreference(user, orgId) {
|
|
31
|
+
if (!user?.set || orgId == null || String(orgId).trim() === '') return;
|
|
32
|
+
user.set(USER_MOD_CURRENT_ORG_IAC, String(orgId).trim());
|
|
33
|
+
}
|
|
34
|
+
|
|
9
35
|
export default class RbtApi {
|
|
10
36
|
|
|
11
37
|
constructor({ baseUrl, accesskey, authtoken=null, apikey=null, localStorageAdaptor=null, withCredentials=true }) {
|
|
@@ -471,24 +497,64 @@ export default class RbtApi {
|
|
|
471
497
|
}
|
|
472
498
|
|
|
473
499
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
500
|
+
/**
|
|
501
|
+
* Confirm email with either legacy composite string or { email, code } (6-digit from mod-iac-flows).
|
|
502
|
+
* @param {string|{ email: string, code: string }|{ emailConfirmCode: string }} confirmCodeOrParams
|
|
503
|
+
*/
|
|
504
|
+
async confirmUserEmail(confirmCodeOrParams) {
|
|
505
|
+
let params;
|
|
506
|
+
if (typeof confirmCodeOrParams === 'string') {
|
|
507
|
+
params = { emailConfirmCode: confirmCodeOrParams };
|
|
508
|
+
} else if (confirmCodeOrParams && typeof confirmCodeOrParams === 'object') {
|
|
509
|
+
const { email, code, emailConfirmCode } = confirmCodeOrParams;
|
|
510
|
+
if (email && code != null && String(code).length > 0) {
|
|
511
|
+
params = { email, code: String(code) };
|
|
512
|
+
} else if (emailConfirmCode) {
|
|
513
|
+
params = { emailConfirmCode };
|
|
514
|
+
} else {
|
|
515
|
+
const err = new Error('confirmUserEmail: pass a legacy string, { emailConfirmCode }, or { email, code }');
|
|
516
|
+
return this._handleError(err);
|
|
517
|
+
}
|
|
518
|
+
} else {
|
|
519
|
+
const err = new Error('confirmUserEmail: invalid argument');
|
|
520
|
+
return this._handleError(err);
|
|
521
|
+
}
|
|
477
522
|
|
|
478
523
|
try {
|
|
479
|
-
|
|
480
524
|
const response = await this.axios.post('/api/iac/confirmUserEmail', [params]);
|
|
481
|
-
|
|
482
525
|
if (response.data.ok === false) {
|
|
483
526
|
return this._handleError(response);
|
|
484
527
|
}
|
|
485
|
-
|
|
486
528
|
return response.data;
|
|
487
|
-
|
|
488
529
|
} catch (e) {
|
|
489
530
|
return this._handleError(e);
|
|
490
531
|
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/** Password reset email — use mod-iac-flows (not deprecated /api/iac/sendPasswordReset). */
|
|
535
|
+
async sendResetEmailViaFlows(email) {
|
|
536
|
+
const response = await this.axios.post('/api/iac-flows/sendResetEmail', { email });
|
|
537
|
+
return response.data;
|
|
538
|
+
}
|
|
491
539
|
|
|
540
|
+
async sendRegistrationVerificationEmail(email) {
|
|
541
|
+
const response = await this.axios.post('/api/iac-flows/sendRegistrationVerification', { email });
|
|
542
|
+
return response.data;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
async resendRegistrationCode(email) {
|
|
546
|
+
const response = await this.axios.post('/api/iac-flows/resendRegistrationCode', { email });
|
|
547
|
+
return response.data;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
async completePasswordReset({ email, code, newPassword }) {
|
|
551
|
+
const response = await this.axios.post('/api/iac/completePasswordReset', [
|
|
552
|
+
{ email, code, newPassword },
|
|
553
|
+
]);
|
|
554
|
+
if (response.data?.ok === false) {
|
|
555
|
+
return this._handleError(response);
|
|
556
|
+
}
|
|
557
|
+
return response.data;
|
|
492
558
|
}
|
|
493
559
|
|
|
494
560
|
async loadCurrentUserExtended(){
|
|
@@ -516,55 +582,55 @@ export default class RbtApi {
|
|
|
516
582
|
}
|
|
517
583
|
|
|
518
584
|
/**
|
|
519
|
-
* Load current organization for the authenticated user
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
* @param {boolean} forceReload - Force reload from server even if cached
|
|
585
|
+
* Load current organization for the authenticated user.
|
|
586
|
+
*
|
|
587
|
+
* Returns an organization **only when** `user.mod.iac.currentOrgId` is set (explicit selection via
|
|
588
|
+
* `switchOrganization` / `selectCurrentOrganization`; legacy reads also accept `mod.currentOrgId`).
|
|
589
|
+
* There is no fallback to “first org”; callers must guide the user to select an org first.
|
|
590
|
+
*
|
|
591
|
+
* @param {boolean} forceReload - Force reload from server even if cached ID matches preference
|
|
526
592
|
* @returns {Promise<RbtObject|null>} Organization object or null
|
|
527
593
|
*/
|
|
528
594
|
async loadCurrentOrganization(forceReload = false) {
|
|
529
595
|
try {
|
|
530
|
-
// Return cached if available and not forcing reload
|
|
531
|
-
if (this.currentOrganization && !forceReload) {
|
|
532
|
-
//console.log('[RbtApi] Returning cached currentOrganization:', this.currentOrganization.get('name'));
|
|
533
|
-
return this.currentOrganization;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
596
|
// Prevent duplicate concurrent loads
|
|
537
597
|
if (this._loadCurrentOrgPromise) {
|
|
538
|
-
//console.log('[RbtApi] Organization load already in progress');
|
|
539
598
|
return this._loadCurrentOrgPromise;
|
|
540
599
|
}
|
|
541
600
|
|
|
542
601
|
this._loadCurrentOrgPromise = (async () => {
|
|
543
602
|
try {
|
|
544
|
-
// Ensure user is loaded first
|
|
545
603
|
const user = await this.loadCurrentUser();
|
|
546
604
|
if (!user) {
|
|
547
|
-
|
|
605
|
+
this.currentOrganization = null;
|
|
548
606
|
return null;
|
|
549
607
|
}
|
|
550
608
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
// organizations array format: [{ id: 'org123', roles: ['owner'] }, ...]
|
|
554
|
-
const firstOrg = userData.organizations?.[0];
|
|
555
|
-
const orgId = userData.mod?.currentOrgId || (typeof firstOrg === 'object' ? firstOrg?.id : firstOrg);
|
|
556
|
-
|
|
609
|
+
const orgId = readUserCurrentOrgPreference(user);
|
|
610
|
+
|
|
557
611
|
if (!orgId) {
|
|
558
|
-
//console.log('[RbtApi]
|
|
612
|
+
//console.log('[RbtApi] No current organization selected (mod.iac.currentOrgId unset)');
|
|
613
|
+
this.currentOrganization = null;
|
|
614
|
+
if (this.localStorageAdaptor) {
|
|
615
|
+
try {
|
|
616
|
+
await this.localStorageAdaptor.removeItem('currentOrgId');
|
|
617
|
+
} catch (_) {
|
|
618
|
+
/* noop */
|
|
619
|
+
}
|
|
620
|
+
}
|
|
559
621
|
return null;
|
|
560
622
|
}
|
|
561
|
-
|
|
562
|
-
console.log('[RbtApi] Resolved organization ID:', orgId, 'from:', {
|
|
563
|
-
modCurrentOrgId: userData.mod?.currentOrgId,
|
|
564
|
-
firstOrg: firstOrg
|
|
565
|
-
});
|
|
566
623
|
|
|
567
|
-
|
|
624
|
+
if (
|
|
625
|
+
!forceReload &&
|
|
626
|
+
this.currentOrganization &&
|
|
627
|
+
String(this.currentOrganization.id) === orgId
|
|
628
|
+
) {
|
|
629
|
+
return this.currentOrganization;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
console.log('[RbtApi] Resolved organization ID:', orgId);
|
|
633
|
+
|
|
568
634
|
if (this.localStorageAdaptor) {
|
|
569
635
|
const cachedOrgId = await this.localStorageAdaptor.getItem('currentOrgId');
|
|
570
636
|
if (cachedOrgId && cachedOrgId !== orgId) {
|
|
@@ -572,20 +638,16 @@ export default class RbtApi {
|
|
|
572
638
|
}
|
|
573
639
|
}
|
|
574
640
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
const org = await this.get('<@iac.organization>', orgId);
|
|
578
|
-
|
|
641
|
+
const org = await this.load('<@iac.organization>', orgId);
|
|
642
|
+
|
|
579
643
|
if (org) {
|
|
580
|
-
this.currentOrganization = org;
|
|
581
|
-
//console.log('[RbtApi] Current organization loaded:', org.get('name'));
|
|
582
|
-
|
|
583
|
-
// Cache in storage if available
|
|
644
|
+
this.currentOrganization = org;
|
|
584
645
|
if (this.localStorageAdaptor) {
|
|
585
646
|
await this.localStorageAdaptor.setItem('currentOrgId', orgId);
|
|
586
647
|
}
|
|
587
648
|
} else {
|
|
588
649
|
console.warn('[RbtApi] Organization not found or not accessible:', orgId);
|
|
650
|
+
this.currentOrganization = null;
|
|
589
651
|
}
|
|
590
652
|
|
|
591
653
|
return this.currentOrganization;
|
|
@@ -621,7 +683,7 @@ export default class RbtApi {
|
|
|
621
683
|
//console.log('[RbtApi] Switching to organization:', orgId);
|
|
622
684
|
|
|
623
685
|
// Load the new organization
|
|
624
|
-
const org = await this.
|
|
686
|
+
const org = await this.load('<@iac.organization>', orgId);
|
|
625
687
|
if (!org) {
|
|
626
688
|
throw new Error(`Organization ${orgId} not found or not accessible`);
|
|
627
689
|
}
|
|
@@ -631,7 +693,7 @@ export default class RbtApi {
|
|
|
631
693
|
// Save preference to user
|
|
632
694
|
try {
|
|
633
695
|
const userObj = await this.loadUser(this.currentUser.id);
|
|
634
|
-
userObj
|
|
696
|
+
persistUserCurrentOrgPreference(userObj, orgId);
|
|
635
697
|
await userObj.save();
|
|
636
698
|
|
|
637
699
|
// Update cache
|
|
@@ -652,13 +714,17 @@ export default class RbtApi {
|
|
|
652
714
|
}
|
|
653
715
|
|
|
654
716
|
/**
|
|
655
|
-
* Get current organization (null-safe)
|
|
656
|
-
* Returns
|
|
657
|
-
*
|
|
658
|
-
* @returns {RbtObject|null} Current organization or null
|
|
717
|
+
* Get cached current organization (sync, null-safe).
|
|
718
|
+
* Returns **null** unless `mod.iac.currentOrgId` (or legacy `mod.currentOrgId`) matches `currentOrganization`.
|
|
659
719
|
*/
|
|
660
720
|
getCurrentOrganization() {
|
|
661
|
-
|
|
721
|
+
const org = this.currentOrganization;
|
|
722
|
+
if (!org) return null;
|
|
723
|
+
const user = this.currentUser;
|
|
724
|
+
const selected = readUserCurrentOrgPreference(user);
|
|
725
|
+
if (!selected) return null;
|
|
726
|
+
if (String(org.id) !== selected) return null;
|
|
727
|
+
return org;
|
|
662
728
|
}
|
|
663
729
|
|
|
664
730
|
/**
|
|
@@ -683,8 +749,8 @@ export default class RbtApi {
|
|
|
683
749
|
|
|
684
750
|
//console.log('[RbtApi] Selecting organization:', orgId);
|
|
685
751
|
|
|
686
|
-
// Load the organization
|
|
687
|
-
const org = await this.
|
|
752
|
+
// Load the organization via object load (not HTTP `get` — passing orgId as params breaks axios).
|
|
753
|
+
const org = await this.load('<@iac.organization>', orgId);
|
|
688
754
|
if (!org) {
|
|
689
755
|
throw new Error(`Organization ${orgId} not found or not accessible`);
|
|
690
756
|
}
|
|
@@ -709,11 +775,9 @@ export default class RbtApi {
|
|
|
709
775
|
//console.log('[RbtApi] Organization already in user organizations array');
|
|
710
776
|
}
|
|
711
777
|
|
|
712
|
-
// Set
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
user.set('mod', modData);
|
|
716
|
-
|
|
778
|
+
// Set current organization preference under mod.iac (module-namespaced settings)
|
|
779
|
+
persistUserCurrentOrgPreference(user, orgId);
|
|
780
|
+
|
|
717
781
|
// Save user record
|
|
718
782
|
//console.log('[RbtApi] Saving user with organization:', orgId);
|
|
719
783
|
await user.save();
|
|
@@ -956,6 +1020,7 @@ export default class RbtApi {
|
|
|
956
1020
|
* - excludeAttrs: An array of attribute paths to exclude from the response (e.g., ['details.log', 'internalData']).
|
|
957
1021
|
* Excludes the specified paths and all their subpaths.
|
|
958
1022
|
* - resolveReferences: An array of attribute names whose references should be resolved in the returned objects.
|
|
1023
|
+
* - resolveAttrs: Attribute paths whose mod / reference values should be resolved (e.g., ['configs.mod.guide.completion']).
|
|
959
1024
|
* - timeout: A numerical value in milliseconds to set a maximum time limit for the query execution.
|
|
960
1025
|
* - cache: Boolean. When true, enables a 10-second response cache for identical queries. Default: false (no caching).
|
|
961
1026
|
*
|
|
@@ -967,6 +1032,7 @@ export default class RbtApi {
|
|
|
967
1032
|
* requestAttrs: ['id', 'configs.title'],
|
|
968
1033
|
* excludeAttrs: ['details.log'],
|
|
969
1034
|
* resolveReferences: ['translatableContent'],
|
|
1035
|
+
* resolveAttrs: ['configs.mod.guide.completion'],
|
|
970
1036
|
* cache: true // opt-in to 10s response caching
|
|
971
1037
|
* });
|
|
972
1038
|
*
|
|
@@ -980,7 +1046,7 @@ export default class RbtApi {
|
|
|
980
1046
|
//console.log('RBTAPI.query INIT', type, params);
|
|
981
1047
|
|
|
982
1048
|
// Validate parameters - reject invalid parameter names
|
|
983
|
-
const validParams = ['type', 'where', 'orderBy', 'limit', 'resolveReferences', 'requestAttrs', 'excludeAttrs', 'timeout', 'enableRealtime', 'cache'];
|
|
1049
|
+
const validParams = ['type', 'where', 'orderBy', 'limit', 'resolveReferences', 'resolveAttrs', 'requestAttrs', 'excludeAttrs', 'timeout', 'enableRealtime', 'cache'];
|
|
984
1050
|
const invalidParams = Object.keys(params).filter(key => !validParams.includes(key));
|
|
985
1051
|
if (invalidParams.length > 0) {
|
|
986
1052
|
throw new Error(`Invalid query parameter(s): ${invalidParams.join(', ')}. Valid parameters are: ${validParams.join(', ')}`);
|
package/src/rbt_object.js
CHANGED
|
@@ -259,12 +259,54 @@ export default class RbtObject{
|
|
|
259
259
|
return clonedObject;
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Rebuild read_ids/write_ids record meta from iac grant arrays.
|
|
264
|
+
* Keeps denormalized columns in sync with dataJson.iac for delta saves.
|
|
265
|
+
*/
|
|
266
|
+
_syncIacRecordMeta() {
|
|
267
|
+
const iac = _.get(this._data, 'iac');
|
|
268
|
+
if (!iac) return;
|
|
269
|
+
|
|
270
|
+
const readIds = new Set();
|
|
271
|
+
const writeIds = new Set();
|
|
272
|
+
|
|
273
|
+
if (this.type === '<@iac.user>') {
|
|
274
|
+
writeIds.add(this.id);
|
|
275
|
+
readIds.add(this.id);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (iac.creator) {
|
|
279
|
+
writeIds.add(iac.creator);
|
|
280
|
+
readIds.add(iac.creator);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const collect = (grants, target) => {
|
|
284
|
+
if (!grants) return;
|
|
285
|
+
for (const key of ['users', 'userGroups', 'organizations', 'userSegments']) {
|
|
286
|
+
if (Array.isArray(grants[key])) {
|
|
287
|
+
grants[key].forEach((id) => target.add(id));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
collect(iac.readGrants, readIds);
|
|
292
|
+
collect(iac.writeGrants, writeIds);
|
|
293
|
+
|
|
294
|
+
this._internalData.read_ids = Array.from(readIds).join(',');
|
|
295
|
+
this._internalData.write_ids = Array.from(writeIds).join(',');
|
|
296
|
+
}
|
|
297
|
+
|
|
262
298
|
async save() {
|
|
263
299
|
if (!this._internalData.type) {
|
|
264
300
|
throw new Error('Cannot save object without type');
|
|
265
301
|
}
|
|
266
302
|
|
|
267
303
|
try {
|
|
304
|
+
const iacGrantChange = (this.rpcMeta.changes || []).some(
|
|
305
|
+
(path) => path.startsWith('iac.readGrants') || path.startsWith('iac.writeGrants')
|
|
306
|
+
);
|
|
307
|
+
if (iacGrantChange) {
|
|
308
|
+
this._syncIacRecordMeta();
|
|
309
|
+
}
|
|
268
310
|
|
|
269
311
|
let record;
|
|
270
312
|
if(this.rpcMeta.isNew){
|
|
@@ -399,6 +441,8 @@ export default class RbtObject{
|
|
|
399
441
|
}
|
|
400
442
|
}
|
|
401
443
|
|
|
444
|
+
this._syncIacRecordMeta();
|
|
445
|
+
|
|
402
446
|
// Save if requested
|
|
403
447
|
if (save) {
|
|
404
448
|
return await this.save();
|
|
@@ -558,6 +602,8 @@ export default class RbtObject{
|
|
|
558
602
|
this.set(groupsPath, existingGroups.filter(id => !groupIds.includes(id)));
|
|
559
603
|
}
|
|
560
604
|
|
|
605
|
+
this._syncIacRecordMeta();
|
|
606
|
+
|
|
561
607
|
// Save if requested
|
|
562
608
|
if (save) {
|
|
563
609
|
return await this.save();
|
package/src/version.js
CHANGED