@qikdev/sdk 1.0.8 → 1.0.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/main.js +1556 -1547
- package/package.json +1 -1
- package/src/api/qik.access.js +63 -11
- package/src/version.js +1 -1
package/package.json
CHANGED
package/src/api/qik.access.js
CHANGED
|
@@ -67,21 +67,23 @@ var QikAccess = function (QikCore) {
|
|
|
67
67
|
* const childScopes = sdk.access.getAllDescendants({title:'Global', children:[{title:'Australia', ...}, {title:'New Zealand', ...}]});
|
|
68
68
|
*/
|
|
69
69
|
service.getAllDescendants = function (scope) {
|
|
70
|
-
//Start by including the scope id
|
|
71
|
-
|
|
70
|
+
//Start by including the scope id. A Set because the same scope can be
|
|
71
|
+
//reachable by more than one path through the tree, and the duplicates
|
|
72
|
+
//were being carried all the way into hashPermissions.
|
|
73
|
+
var results = new Set();
|
|
72
74
|
|
|
73
75
|
addScope(scope);
|
|
74
76
|
|
|
75
77
|
function addScope(entry) {
|
|
76
78
|
//Add this scope to the results
|
|
77
79
|
var id = QikCore.utils.id(entry);
|
|
78
|
-
results.
|
|
80
|
+
results.add(id);
|
|
79
81
|
|
|
80
82
|
(entry.children || []).forEach(function (child) {
|
|
81
83
|
addScope(child);
|
|
82
84
|
});
|
|
83
85
|
}
|
|
84
|
-
return results;
|
|
86
|
+
return Array.from(results);
|
|
85
87
|
};
|
|
86
88
|
|
|
87
89
|
///////////////////////////////////////////////
|
|
@@ -93,8 +95,48 @@ var QikAccess = function (QikCore) {
|
|
|
93
95
|
* @example
|
|
94
96
|
* const permissions = sdk.access.hashPermissions({firstName:'Mighty', lastName:'Mouse', permissionSets:[...], ...});
|
|
95
97
|
*/
|
|
98
|
+
// Memo for hashPermissions, keyed on the session's cacheKey.
|
|
99
|
+
//
|
|
100
|
+
// actionableScopes() calls hashPermissions() on every single invocation, and
|
|
101
|
+
// a dashboard navigation performs well over a hundred access checks. For an
|
|
102
|
+
// ordinary session that is invisible, but a heavy one — hundreds of scopes
|
|
103
|
+
// and thousands of permission strings — rebuilds a six-figure number of
|
|
104
|
+
// (permission, scope) pairs each time. Measured on one production session:
|
|
105
|
+
// 127 calls x 28ms = 3.6 SECONDS of synchronous main-thread work per
|
|
106
|
+
// navigation, which is the whole of an observed 3.6s UI freeze.
|
|
107
|
+
//
|
|
108
|
+
// cacheKey already changes whenever the session does (it encodes the user,
|
|
109
|
+
// organisation, persona and the persona's updated timestamp), so it is the
|
|
110
|
+
// same key the server memoises this on. Only one entry is kept: the session
|
|
111
|
+
// in hand is the only one being asked about, and holding more would pin
|
|
112
|
+
// permission trees for users who have since signed out.
|
|
113
|
+
// A short TTL as a backstop, mirroring the server's own memo. cacheKey moves
|
|
114
|
+
// whenever the session is reissued, but permissions can in principle change
|
|
115
|
+
// underneath a session that keeps its key — a role being edited, say, which
|
|
116
|
+
// the server handles by invalidating the session rather than by bumping the
|
|
117
|
+
// persona. The TTL means any such staleness heals on its own within seconds
|
|
118
|
+
// instead of lasting for the life of the tab, while still collapsing the
|
|
119
|
+
// hundred-plus calls a single navigation makes into one.
|
|
120
|
+
var PERMISSION_HASH_TTL_MS = 5000;
|
|
121
|
+
var permissionHashMemo = null;
|
|
122
|
+
|
|
96
123
|
service.hashPermissions = function (user) {
|
|
97
|
-
var
|
|
124
|
+
var cacheKey = user?.cacheKey;
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
cacheKey &&
|
|
128
|
+
permissionHashMemo &&
|
|
129
|
+
permissionHashMemo.key === cacheKey &&
|
|
130
|
+
Date.now() - permissionHashMemo.at < PERMISSION_HASH_TTL_MS
|
|
131
|
+
) {
|
|
132
|
+
return permissionHashMemo.value;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Accumulate into Sets rather than rebuilding an array per permission
|
|
136
|
+
// string. The previous form did `[...new Set(existing.concat(allIDs))]`
|
|
137
|
+
// for every string in every scope — copy, rebuild, copy again — which is
|
|
138
|
+
// quadratic in the number of scopes granting that permission.
|
|
139
|
+
var accumulator = new Map();
|
|
98
140
|
|
|
99
141
|
for (var key in user?.permissions || {}) {
|
|
100
142
|
//Get the permission set
|
|
@@ -105,18 +147,28 @@ var QikAccess = function (QikCore) {
|
|
|
105
147
|
|
|
106
148
|
//For each permission defined in the set
|
|
107
149
|
(permissionSet.permissions || []).forEach(function (permissionString) {
|
|
108
|
-
|
|
109
|
-
if (!
|
|
110
|
-
|
|
150
|
+
var set = accumulator.get(permissionString);
|
|
151
|
+
if (!set) {
|
|
152
|
+
set = new Set();
|
|
153
|
+
accumulator.set(permissionString, set);
|
|
154
|
+
}
|
|
155
|
+
for (var i = 0; i < allIDs.length; i++) {
|
|
156
|
+
set.add(allIDs[i]);
|
|
111
157
|
}
|
|
112
|
-
results[permissionString] = [
|
|
113
|
-
...new Set(results[permissionString].concat(allIDs)),
|
|
114
|
-
];
|
|
115
158
|
});
|
|
116
159
|
}
|
|
117
160
|
|
|
161
|
+
var results = {};
|
|
162
|
+
accumulator.forEach(function (set, permissionString) {
|
|
163
|
+
results[permissionString] = Array.from(set);
|
|
164
|
+
});
|
|
165
|
+
|
|
118
166
|
///////////////////////////////////////////////
|
|
119
167
|
|
|
168
|
+
if (cacheKey) {
|
|
169
|
+
permissionHashMemo = { key: cacheKey, value: results, at: Date.now() };
|
|
170
|
+
}
|
|
171
|
+
|
|
120
172
|
return results;
|
|
121
173
|
};
|
|
122
174
|
|
package/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "1.0.
|
|
1
|
+
export const version = "1.0.10";
|