endpoint-permissions-kit 0.1.0 → 0.2.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 +28 -20
- package/bin/pkit.mjs +2 -2
- package/dist/cjs/index.cjs +744 -474
- package/dist/cjs/index.cjs.map +16 -14
- package/dist/esm/cli/child.js +329 -352
- package/dist/esm/cli/child.js.map +11 -11
- package/dist/esm/cli/generate.js +78 -420
- package/dist/esm/cli/generate.js.map +5 -9
- package/dist/esm/index.js +746 -476
- package/dist/esm/index.js.map +16 -14
- package/dist/types/cli/generate.d.ts +6 -4
- package/dist/types/cli/protocol.d.ts +10 -7
- package/dist/types/constants.d.ts +9 -6
- package/dist/types/context.d.ts +5 -6
- package/dist/types/definitions.d.ts +15 -0
- package/dist/types/errors.d.ts +12 -11
- package/dist/types/identifiers.d.ts +21 -0
- package/dist/types/index.d.ts +16 -17
- package/dist/types/permissions.d.ts +10 -5
- package/dist/types/properties.d.ts +6 -0
- package/dist/types/registry.d.ts +4 -1
- package/dist/types/resolve.d.ts +50 -6
- package/dist/types/seal.d.ts +8 -1
- package/dist/types/state.d.ts +11 -9
- package/dist/types/types.d.ts +26 -34
- package/dist/types/validate.d.ts +5 -3
- package/package.json +1 -1
- package/dist/types/validators.d.ts +0 -53
package/dist/cjs/index.cjs
CHANGED
|
@@ -39,11 +39,11 @@ var __export = (target, all) => {
|
|
|
39
39
|
// src/index.ts
|
|
40
40
|
var exports_src = {};
|
|
41
41
|
__export(exports_src, {
|
|
42
|
-
METHODS: () =>
|
|
43
|
-
context: () =>
|
|
42
|
+
METHODS: () => METHODS2,
|
|
43
|
+
context: () => context_default,
|
|
44
44
|
default: () => src_default,
|
|
45
45
|
module: () => defineModule,
|
|
46
|
-
permissions: () =>
|
|
46
|
+
permissions: () => permissions_default,
|
|
47
47
|
pkit: () => pkit,
|
|
48
48
|
seal: () => seal,
|
|
49
49
|
validate: () => validate
|
|
@@ -51,426 +51,593 @@ __export(exports_src, {
|
|
|
51
51
|
module.exports = __toCommonJS(exports_src);
|
|
52
52
|
|
|
53
53
|
// src/constants.ts
|
|
54
|
-
var
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
var constants = {
|
|
55
|
+
METHODS: Object.freeze(["find", "update", "create", "remove"]),
|
|
56
|
+
GENERAL_ROLE: "general",
|
|
57
|
+
GLOBAL_HOOK_OWNER: "*",
|
|
58
|
+
ALL_FIELDS: "*",
|
|
59
|
+
MODULE_SEPARATOR: ".",
|
|
60
|
+
PERMISSION_ID_SEPARATOR: "::"
|
|
61
|
+
};
|
|
62
|
+
var constants_default = constants;
|
|
60
63
|
|
|
61
|
-
// src/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
// src/errors.ts
|
|
65
|
+
var errors = {
|
|
66
|
+
create(code, message) {
|
|
67
|
+
return Object.assign(new Error(message), { name: "PkitError", code });
|
|
68
|
+
},
|
|
69
|
+
describe(value) {
|
|
70
|
+
try {
|
|
71
|
+
return String(value);
|
|
72
|
+
} catch {
|
|
73
|
+
return typeof value;
|
|
74
|
+
}
|
|
67
75
|
}
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
};
|
|
77
|
+
var errors_default = errors;
|
|
70
78
|
|
|
71
|
-
// src/
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
// src/identifiers.ts
|
|
80
|
+
var identifiers = {
|
|
81
|
+
build(role, action, name) {
|
|
82
|
+
return `${role}${constants_default.PERMISSION_ID_SEPARATOR}${action}${constants_default.PERMISSION_ID_SEPARATOR}${name}`;
|
|
83
|
+
},
|
|
84
|
+
parse(value, code, subject) {
|
|
85
|
+
if (typeof value !== "string")
|
|
86
|
+
throw invalidIdentifier(value, code, subject);
|
|
87
|
+
const parts = value.split(constants_default.PERMISSION_ID_SEPARATOR);
|
|
88
|
+
const [role, action, name] = parts;
|
|
89
|
+
if (parts.length !== 3 || role === undefined || action === undefined || name === undefined) {
|
|
90
|
+
throw invalidIdentifier(value, code, subject);
|
|
91
|
+
}
|
|
92
|
+
const isValidRole = isCleanSegment(role) && role !== constants_default.GLOBAL_HOOK_OWNER;
|
|
93
|
+
const isValidName = isCleanSegment(name) && name !== constants_default.GLOBAL_HOOK_OWNER;
|
|
94
|
+
const isValidAction = action.split(constants_default.MODULE_SEPARATOR).every(isCleanSegment);
|
|
95
|
+
if (!isValidRole || !isValidName || !isValidAction)
|
|
96
|
+
throw invalidIdentifier(value, code, subject);
|
|
97
|
+
return { role, action, name };
|
|
98
|
+
},
|
|
99
|
+
checkRole(role) {
|
|
100
|
+
if (typeof role === "string" && isCleanSegment(role) && role !== constants_default.GLOBAL_HOOK_OWNER)
|
|
101
|
+
return;
|
|
102
|
+
throw errors_default.create("INVALID_DEFINITION", `invalid role: "${errors_default.describe(role)}" (non-empty string, no ":" or surrounding whitespace; "${constants_default.GLOBAL_HOOK_OWNER}" is reserved for global hooks)`);
|
|
103
|
+
},
|
|
104
|
+
checkModuleSegment(segment) {
|
|
105
|
+
if (typeof segment === "string" && isCleanSegment(segment) && !segment.includes(constants_default.MODULE_SEPARATOR))
|
|
106
|
+
return;
|
|
107
|
+
throw errors_default.create("INVALID_DEFINITION", `invalid module name: "${errors_default.describe(segment)}" (non-empty string, no dots, no ":" or surrounding whitespace)`);
|
|
108
|
+
},
|
|
109
|
+
checkName(name) {
|
|
110
|
+
if (typeof name === "string" && isCleanSegment(name) && name !== constants_default.GLOBAL_HOOK_OWNER)
|
|
111
|
+
return;
|
|
112
|
+
throw errors_default.create("INVALID_DEFINITION", `invalid permission name: "${errors_default.describe(name)}" (non-empty string, no ":" or surrounding whitespace; "*" is reserved)`);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
function isCleanSegment(value) {
|
|
116
|
+
return value.length > 0 && value.trim() === value && !value.includes(":");
|
|
117
|
+
}
|
|
118
|
+
function invalidIdentifier(value, code, subject) {
|
|
119
|
+
return errors_default.create(code, `${subject}: "${errors_default.describe(value)}" (format role::module::name)`);
|
|
74
120
|
}
|
|
121
|
+
var identifiers_default = identifiers;
|
|
75
122
|
|
|
76
|
-
// src/
|
|
77
|
-
var
|
|
78
|
-
var
|
|
79
|
-
var
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
// src/properties.ts
|
|
124
|
+
var PRUNED = Symbol("pruned");
|
|
125
|
+
var MAX_DEPTH = 1000;
|
|
126
|
+
var properties = {
|
|
127
|
+
checkDeclaredPath(property, permissionPath) {
|
|
128
|
+
if (property.includes("[") || property.includes("]")) {
|
|
129
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: array indexes are not allowed in properties: "${property}"`);
|
|
130
|
+
}
|
|
131
|
+
const segments = segmentsOf(property);
|
|
132
|
+
for (const segment of segments) {
|
|
133
|
+
if (segment.length === 0)
|
|
134
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: empty segment in property path: "${property}"`);
|
|
135
|
+
}
|
|
136
|
+
if (segments[0] === constants_default.ALL_FIELDS) {
|
|
137
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: a property path cannot start with "${constants_default.ALL_FIELDS}": "${property}"`);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
resolve(data, allowed, reserved, cropper) {
|
|
141
|
+
if (allowed === constants_default.ALL_FIELDS)
|
|
142
|
+
return data;
|
|
143
|
+
const patterns = [];
|
|
144
|
+
for (const pattern of allowed.concat(reserved))
|
|
145
|
+
patterns.push(segmentsOf(pattern));
|
|
146
|
+
const walk = { patterns, segments: [], ancestors: new Set([data]) };
|
|
147
|
+
if (cropper)
|
|
148
|
+
return cropData(data, walk);
|
|
149
|
+
rejectForbiddenPaths(data, walk);
|
|
150
|
+
return data;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
function segmentsOf(path) {
|
|
154
|
+
const segments = [];
|
|
155
|
+
let segment = "";
|
|
156
|
+
let index = 0;
|
|
157
|
+
while (index < path.length) {
|
|
158
|
+
const character = path[index];
|
|
159
|
+
if (character === "\\") {
|
|
160
|
+
segment += path[index + 1] ?? "";
|
|
161
|
+
index += 2;
|
|
100
162
|
continue;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
163
|
+
}
|
|
164
|
+
if (character === ".") {
|
|
165
|
+
segments.push(segment);
|
|
166
|
+
segment = "";
|
|
167
|
+
index += 1;
|
|
104
168
|
continue;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
if (grantedBy.length === 0)
|
|
110
|
-
return reachable ? DISABLED_ACCESS : UNASSIGNED_ACCESS;
|
|
111
|
-
const authorization = Object.freeze({ direct: false, grantedBy: Object.freeze(grantedBy.sort()) });
|
|
112
|
-
return { status: "granted", properties: Object.freeze([...properties]), authorization };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// src/validators.ts
|
|
116
|
-
function validateObject(value, failure) {
|
|
117
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
118
|
-
throw pkitError(failure.code, failure.message);
|
|
169
|
+
}
|
|
170
|
+
segment += character;
|
|
171
|
+
index += 1;
|
|
119
172
|
}
|
|
173
|
+
segments.push(segment);
|
|
174
|
+
return segments;
|
|
120
175
|
}
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
176
|
+
function isAllowedPath(segments, patterns) {
|
|
177
|
+
for (const pattern of patterns) {
|
|
178
|
+
if (pattern.length !== segments.length)
|
|
179
|
+
continue;
|
|
180
|
+
let isMatch = true;
|
|
181
|
+
for (let index = 0;index < segments.length; index += 1) {
|
|
182
|
+
const patternSegment = pattern[index];
|
|
183
|
+
if (patternSegment === constants_default.ALL_FIELDS)
|
|
184
|
+
continue;
|
|
185
|
+
if (patternSegment === segments[index])
|
|
186
|
+
continue;
|
|
187
|
+
isMatch = false;
|
|
188
|
+
break;
|
|
127
189
|
}
|
|
190
|
+
if (isMatch)
|
|
191
|
+
return true;
|
|
128
192
|
}
|
|
193
|
+
return false;
|
|
129
194
|
}
|
|
130
|
-
function
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (state.snapshot)
|
|
136
|
-
throw pkitError("SEALED", "pkit.seal() was already called: no more registrations allowed");
|
|
195
|
+
function isPlainObject(value) {
|
|
196
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
197
|
+
return false;
|
|
198
|
+
const prototype = Object.getPrototypeOf(value);
|
|
199
|
+
return prototype === Object.prototype || prototype === null;
|
|
137
200
|
}
|
|
138
|
-
function
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
}
|
|
201
|
+
function requireDepth(walk) {
|
|
202
|
+
if (walk.ancestors.size < MAX_DEPTH)
|
|
203
|
+
return;
|
|
204
|
+
throw new RangeError(`data is nested deeper than ${MAX_DEPTH} levels`);
|
|
142
205
|
}
|
|
143
|
-
function
|
|
144
|
-
if (
|
|
206
|
+
function setField(target, key, value) {
|
|
207
|
+
if (key === "__proto__") {
|
|
208
|
+
Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
|
|
145
209
|
return;
|
|
146
|
-
if (code === "ROLE_NOT_DECLARED") {
|
|
147
|
-
throw pkitError(code, `role "${String(role)}" is not declared. Available roles: ${[...roles].join(", ")}.
|
|
148
|
-
` + "Is pkit.context.set('roles', [...]) missing from pkit.config.js, or was it imported after this file?");
|
|
149
210
|
}
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
211
|
+
target[key] = value;
|
|
212
|
+
}
|
|
213
|
+
function cropValue(value, walk) {
|
|
214
|
+
if (Array.isArray(value)) {
|
|
215
|
+
if (value.length === 0)
|
|
216
|
+
return isAllowedPath(walk.segments, walk.patterns) ? [] : PRUNED;
|
|
217
|
+
if (walk.ancestors.has(value))
|
|
218
|
+
throw new RangeError("data contains a circular reference");
|
|
219
|
+
requireDepth(walk);
|
|
220
|
+
walk.ancestors.add(value);
|
|
221
|
+
const items = [];
|
|
222
|
+
for (const item of value) {
|
|
223
|
+
const croppedItem = cropValue(item, walk);
|
|
224
|
+
if (croppedItem === PRUNED)
|
|
225
|
+
continue;
|
|
226
|
+
items.push(croppedItem);
|
|
227
|
+
}
|
|
228
|
+
walk.ancestors.delete(value);
|
|
229
|
+
return items.length === 0 ? PRUNED : items;
|
|
230
|
+
}
|
|
231
|
+
if (isPlainObject(value)) {
|
|
232
|
+
const container = value;
|
|
233
|
+
const keys = Object.keys(container);
|
|
234
|
+
if (keys.length === 0)
|
|
235
|
+
return isAllowedPath(walk.segments, walk.patterns) ? {} : PRUNED;
|
|
236
|
+
if (walk.ancestors.has(container))
|
|
237
|
+
throw new RangeError("data contains a circular reference");
|
|
238
|
+
requireDepth(walk);
|
|
239
|
+
walk.ancestors.add(container);
|
|
240
|
+
const cropped = {};
|
|
241
|
+
let keptCount = 0;
|
|
242
|
+
for (const key of keys) {
|
|
243
|
+
walk.segments.push(key);
|
|
244
|
+
const croppedValue = cropValue(container[key], walk);
|
|
245
|
+
walk.segments.pop();
|
|
246
|
+
if (croppedValue === PRUNED)
|
|
247
|
+
continue;
|
|
248
|
+
setField(cropped, key, croppedValue);
|
|
249
|
+
keptCount += 1;
|
|
250
|
+
}
|
|
251
|
+
walk.ancestors.delete(container);
|
|
252
|
+
return keptCount === 0 ? PRUNED : cropped;
|
|
253
|
+
}
|
|
254
|
+
return isAllowedPath(walk.segments, walk.patterns) ? value : PRUNED;
|
|
255
|
+
}
|
|
256
|
+
function cropData(data, walk) {
|
|
257
|
+
const cropped = {};
|
|
258
|
+
for (const key of Object.keys(data)) {
|
|
259
|
+
walk.segments.push(key);
|
|
260
|
+
const croppedValue = cropValue(data[key], walk);
|
|
261
|
+
walk.segments.pop();
|
|
262
|
+
if (croppedValue === PRUNED)
|
|
263
|
+
continue;
|
|
264
|
+
setField(cropped, key, croppedValue);
|
|
156
265
|
}
|
|
157
|
-
|
|
158
|
-
code: "INVALID_DEFINITION",
|
|
159
|
-
message: "roles must be an array of non-empty strings",
|
|
160
|
-
minimumLength: 1
|
|
161
|
-
});
|
|
162
|
-
if (roles.length === 0)
|
|
163
|
-
throw pkitError("INVALID_DEFINITION", "roles must declare at least one role");
|
|
164
|
-
for (const role of roles)
|
|
165
|
-
validateRoleSegment(role);
|
|
266
|
+
return cropped;
|
|
166
267
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
268
|
+
function collectForbiddenPaths(value, walk, forbidden) {
|
|
269
|
+
if (Array.isArray(value)) {
|
|
270
|
+
if (value.length === 0 || walk.ancestors.has(value)) {
|
|
271
|
+
reportPath(walk, forbidden);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
requireDepth(walk);
|
|
275
|
+
walk.ancestors.add(value);
|
|
276
|
+
for (const item of value)
|
|
277
|
+
collectForbiddenPaths(item, walk, forbidden);
|
|
278
|
+
walk.ancestors.delete(value);
|
|
172
279
|
return;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
280
|
+
}
|
|
281
|
+
if (isPlainObject(value)) {
|
|
282
|
+
const container = value;
|
|
283
|
+
const keys = Object.keys(container);
|
|
284
|
+
if (keys.length === 0 || walk.ancestors.has(container)) {
|
|
285
|
+
reportPath(walk, forbidden);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
requireDepth(walk);
|
|
289
|
+
walk.ancestors.add(container);
|
|
290
|
+
for (const key of keys) {
|
|
291
|
+
walk.segments.push(key);
|
|
292
|
+
collectForbiddenPaths(container[key], walk, forbidden);
|
|
293
|
+
walk.segments.pop();
|
|
294
|
+
}
|
|
295
|
+
walk.ancestors.delete(container);
|
|
177
296
|
return;
|
|
178
|
-
|
|
297
|
+
}
|
|
298
|
+
reportPath(walk, forbidden);
|
|
179
299
|
}
|
|
180
|
-
function
|
|
181
|
-
if (
|
|
300
|
+
function reportPath(walk, forbidden) {
|
|
301
|
+
if (isAllowedPath(walk.segments, walk.patterns))
|
|
182
302
|
return;
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
function parsePermissionId(value, failure) {
|
|
186
|
-
if (typeof value !== "string")
|
|
187
|
-
throw pkitError(failure.code, failure.message);
|
|
188
|
-
const parts = value.split(PERMISSION_ID_SEPARATOR);
|
|
189
|
-
const [role, action, name] = parts;
|
|
190
|
-
if (parts.length !== 3 || role === undefined || action === undefined || name === undefined) {
|
|
191
|
-
throw pkitError(failure.code, failure.message);
|
|
192
|
-
}
|
|
193
|
-
const isValidRole = isCleanSegment(role) && role !== GLOBAL_HOOK_OWNER;
|
|
194
|
-
const isValidName = isCleanSegment(name) && name !== GLOBAL_HOOK_OWNER;
|
|
195
|
-
const isValidAction = action.split(MODULE_SEPARATOR).every(isCleanSegment);
|
|
196
|
-
if (!isValidRole || !isValidName || !isValidAction)
|
|
197
|
-
throw pkitError(failure.code, failure.message);
|
|
198
|
-
return { role, action, name };
|
|
199
|
-
}
|
|
200
|
-
function validateMethod(method, failure) {
|
|
201
|
-
if (METHODS.includes(method))
|
|
202
|
-
return;
|
|
203
|
-
throw pkitError(failure.code, `${failure.message}: method "${String(method)}" does not exist. Methods: ${METHODS.join(", ")}`);
|
|
303
|
+
forbidden.add(walk.segments.join("."));
|
|
204
304
|
}
|
|
205
|
-
function
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (properties === ALL_FIELDS)
|
|
212
|
-
return Object.freeze({ enabled: definition.enabled, properties });
|
|
213
|
-
validateStrings(properties, {
|
|
214
|
-
code: "INVALID_DEFINITION",
|
|
215
|
-
message: `${permissionPath}: properties must be string[] or '*'`,
|
|
216
|
-
minimumLength: 1
|
|
217
|
-
});
|
|
218
|
-
if (properties.includes(ALL_FIELDS)) {
|
|
219
|
-
throw pkitError("INVALID_DEFINITION", `${permissionPath}: '${ALL_FIELDS}' is only allowed as the whole properties value`);
|
|
220
|
-
}
|
|
221
|
-
if (new Set(properties).size !== properties.length) {
|
|
222
|
-
throw pkitError("INVALID_DEFINITION", `${permissionPath}: properties contains duplicate fields`);
|
|
223
|
-
}
|
|
224
|
-
return Object.freeze({ enabled: definition.enabled, properties: Object.freeze([...properties]) });
|
|
225
|
-
}
|
|
226
|
-
function readActionDefinitions(actions, permissionPath) {
|
|
227
|
-
validateObject(actions, { code: "INVALID_DEFINITION", message: `${permissionPath}: registerActions expects an object` });
|
|
228
|
-
const registeredActions = Object.create(null);
|
|
229
|
-
for (const [method, definition] of Object.entries(actions)) {
|
|
230
|
-
validateMethod(method, { code: "INVALID_DEFINITION", message: permissionPath });
|
|
231
|
-
registeredActions[method] = readActionDefinition(definition, `${permissionPath}.${method}`);
|
|
232
|
-
}
|
|
233
|
-
return Object.freeze(registeredActions);
|
|
234
|
-
}
|
|
235
|
-
function validateActions(actions, registration, state) {
|
|
236
|
-
const { action, name, role } = registration;
|
|
237
|
-
validateOpenRegistry(state);
|
|
238
|
-
validateRole(role, state.roles, "ROLE_NOT_DECLARED");
|
|
239
|
-
if (state.modules.get(action)?.names.get(name)?.actions.has(role)) {
|
|
240
|
-
throw pkitError("DUPLICATE_REGISTRATION", `"${action}::${name}" already has actions registered for role "${role}"`);
|
|
241
|
-
}
|
|
242
|
-
return readActionDefinitions(actions, `${action}::${name} [${role}]`);
|
|
243
|
-
}
|
|
244
|
-
function validateGrantActions(actions, registration, state) {
|
|
245
|
-
const { action, name, permissionId } = registration;
|
|
246
|
-
validateOpenRegistry(state);
|
|
247
|
-
const source = parsePermissionId(permissionId, {
|
|
248
|
-
code: "INVALID_DEFINITION",
|
|
249
|
-
message: `"${action}::${name}": invalid grantTo identifier: "${String(permissionId)}" (format role::module::name)`
|
|
250
|
-
});
|
|
251
|
-
validateRole(source.role, state.roles, "ROLE_NOT_DECLARED");
|
|
252
|
-
if (source.action === action && source.name === name) {
|
|
253
|
-
throw pkitError("INVALID_DEFINITION", `"${permissionId}" cannot grant to itself`);
|
|
305
|
+
function rejectForbiddenPaths(data, walk) {
|
|
306
|
+
const forbidden = new Set;
|
|
307
|
+
for (const key of Object.keys(data)) {
|
|
308
|
+
walk.segments.push(key);
|
|
309
|
+
collectForbiddenPaths(data[key], walk, forbidden);
|
|
310
|
+
walk.segments.pop();
|
|
254
311
|
}
|
|
255
|
-
if (
|
|
256
|
-
|
|
312
|
+
if (forbidden.size === 0)
|
|
313
|
+
return;
|
|
314
|
+
const fields = [...forbidden];
|
|
315
|
+
const error = errors_default.create("PROPERTIES_NOT_ALLOWED", `fields not allowed: ${fields.join(", ")}`);
|
|
316
|
+
throw Object.assign(error, { fields });
|
|
317
|
+
}
|
|
318
|
+
var properties_default = properties;
|
|
319
|
+
|
|
320
|
+
// src/state.ts
|
|
321
|
+
var STATE_KEY = Symbol.for("endpoint-permissions-kit");
|
|
322
|
+
var state = {
|
|
323
|
+
getOrCreate() {
|
|
324
|
+
const stateHost = globalThis;
|
|
325
|
+
if (stateHost[STATE_KEY] === undefined) {
|
|
326
|
+
stateHost[STATE_KEY] = {
|
|
327
|
+
roles: new Set([constants_default.GENERAL_ROLE]),
|
|
328
|
+
cropper: false,
|
|
329
|
+
reservedFields: [],
|
|
330
|
+
modules: new Map,
|
|
331
|
+
snapshot: null
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
return stateHost[STATE_KEY];
|
|
335
|
+
},
|
|
336
|
+
requireOpen(currentState) {
|
|
337
|
+
if (currentState.snapshot)
|
|
338
|
+
throw errors_default.create("SEALED", "pkit.seal() was already called: no more registrations allowed");
|
|
339
|
+
},
|
|
340
|
+
requireSnapshot(currentState) {
|
|
341
|
+
if (currentState.snapshot === null) {
|
|
342
|
+
throw errors_default.create("NOT_SEALED", "pkit.seal() has not been called: call it after importing every permission file");
|
|
343
|
+
}
|
|
344
|
+
return currentState.snapshot;
|
|
257
345
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
346
|
+
};
|
|
347
|
+
var state_default = state;
|
|
348
|
+
|
|
349
|
+
// src/context.ts
|
|
350
|
+
var context = Object.freeze({
|
|
351
|
+
set(key, value) {
|
|
352
|
+
const contextKey = checkKey(key);
|
|
353
|
+
const currentState = state_default.getOrCreate();
|
|
354
|
+
state_default.requireOpen(currentState);
|
|
355
|
+
if (contextKey === "cropper") {
|
|
356
|
+
if (typeof value !== "boolean")
|
|
357
|
+
throw errors_default.create("INVALID_DEFINITION", "cropper must be a boolean");
|
|
358
|
+
currentState.cropper = value;
|
|
359
|
+
return;
|
|
263
360
|
}
|
|
264
|
-
if (
|
|
265
|
-
|
|
361
|
+
if (contextKey === "reservedFields") {
|
|
362
|
+
currentState.reservedFields = Object.freeze(readReservedFields(value));
|
|
363
|
+
return;
|
|
266
364
|
}
|
|
365
|
+
currentState.roles = new Set(readRoleCatalog(value, currentState.modules.size));
|
|
366
|
+
},
|
|
367
|
+
get(key) {
|
|
368
|
+
const contextKey = checkKey(key);
|
|
369
|
+
const currentState = state_default.getOrCreate();
|
|
370
|
+
if (contextKey === "cropper")
|
|
371
|
+
return currentState.cropper;
|
|
372
|
+
const paths = contextKey === "roles" ? [...currentState.roles] : [...currentState.reservedFields];
|
|
373
|
+
return paths;
|
|
267
374
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (role !== undefined && role !== GLOBAL_HOOK_OWNER)
|
|
274
|
-
validateRole(role, state.roles, "ROLE_NOT_DECLARED");
|
|
275
|
-
const permissionPath = name === undefined ? action : `${action}::${name}`;
|
|
276
|
-
validateMethod(method, { code: "INVALID_DEFINITION", message: permissionPath });
|
|
277
|
-
if (typeof hook !== "function")
|
|
278
|
-
throw pkitError("INVALID_DEFINITION", `${permissionPath}: hook("${method}") expects a function`);
|
|
375
|
+
});
|
|
376
|
+
function checkKey(key) {
|
|
377
|
+
if (key === "roles" || key === "cropper" || key === "reservedFields")
|
|
378
|
+
return key;
|
|
379
|
+
throw errors_default.create("INVALID_DEFINITION", `unknown context key: "${errors_default.describe(key)}"`);
|
|
279
380
|
}
|
|
280
|
-
function
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
return true;
|
|
381
|
+
function readRoleCatalog(value, registeredModuleCount) {
|
|
382
|
+
if (registeredModuleCount > 0) {
|
|
383
|
+
throw errors_default.create("INVALID_DEFINITION", "roles must be declared before registering permissions: import pkit.config.js first");
|
|
284
384
|
}
|
|
285
|
-
|
|
385
|
+
if (!Array.isArray(value))
|
|
386
|
+
throw errors_default.create("INVALID_DEFINITION", "roles must be an array of non-empty strings");
|
|
387
|
+
for (const role of value) {
|
|
388
|
+
if (typeof role !== "string" || role.length === 0) {
|
|
389
|
+
throw errors_default.create("INVALID_DEFINITION", "roles must be an array of non-empty strings");
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const catalog = value;
|
|
393
|
+
if (catalog.length === 0)
|
|
394
|
+
throw errors_default.create("INVALID_DEFINITION", "roles must declare at least one role");
|
|
395
|
+
for (const role of catalog)
|
|
396
|
+
identifiers_default.checkRole(role);
|
|
397
|
+
return catalog;
|
|
286
398
|
}
|
|
287
|
-
function
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
399
|
+
function readReservedFields(value) {
|
|
400
|
+
if (!Array.isArray(value))
|
|
401
|
+
throw errors_default.create("INVALID_DEFINITION", "reservedFields must be an array of property paths");
|
|
402
|
+
const fields = [];
|
|
403
|
+
for (const field of value) {
|
|
404
|
+
if (typeof field !== "string")
|
|
405
|
+
throw errors_default.create("INVALID_DEFINITION", "reservedFields must be an array of property paths");
|
|
406
|
+
properties_default.checkDeclaredPath(field, "reservedFields");
|
|
407
|
+
fields.push(field);
|
|
293
408
|
}
|
|
294
|
-
return
|
|
409
|
+
return fields;
|
|
295
410
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
411
|
+
var context_default = context;
|
|
412
|
+
|
|
413
|
+
// src/resolve.ts
|
|
414
|
+
var DISABLED_ACCESS = Object.freeze({ status: "disabled" });
|
|
415
|
+
var UNASSIGNED_ACCESS = Object.freeze({ status: "unassigned" });
|
|
416
|
+
var resolve = {
|
|
417
|
+
identity(assignments, snapshot, roles) {
|
|
418
|
+
if (assignments === null || typeof assignments !== "object")
|
|
419
|
+
throw errors_default.create("INVALID_INPUT", "assignments must be an object");
|
|
420
|
+
const { role, permissions } = assignments;
|
|
421
|
+
if (typeof role !== "string")
|
|
422
|
+
throw errors_default.create("INVALID_INPUT", "role is required");
|
|
423
|
+
if (!roles.has(role))
|
|
424
|
+
throw errors_default.create("UNKNOWN_ROLE", `role "${role}" is not declared`);
|
|
425
|
+
if (!Array.isArray(permissions))
|
|
426
|
+
throw errors_default.create("INVALID_INPUT", "permissions must be an array of strings");
|
|
427
|
+
const assigned = new Set;
|
|
428
|
+
const names = new Map;
|
|
429
|
+
for (const permissionId of permissions) {
|
|
430
|
+
const reference = identifiers_default.parse(permissionId, "INVALID_INPUT", "invalid permission identifier");
|
|
431
|
+
if (reference.role !== role) {
|
|
432
|
+
throw errors_default.create("PERMISSION_ROLE_MISMATCH", `"${permissionId}" belongs to role "${reference.role}", not the authenticated role "${role}"`);
|
|
433
|
+
}
|
|
434
|
+
if (!snapshot.assignable.has(permissionId)) {
|
|
435
|
+
throw errors_default.create("UNKNOWN_PERMISSION", `"${permissionId}" is not an assignable permission`);
|
|
436
|
+
}
|
|
437
|
+
const assignedName = names.get(reference.action);
|
|
438
|
+
if (assignedName !== undefined && assignedName !== reference.name) {
|
|
439
|
+
throw errors_default.create("AMBIGUOUS_PERMISSION", `"${permissionId}" and "${identifiers_default.build(role, reference.action, assignedName)}" are both assigned: a request names no permission name, so module "${reference.action}" cannot be resolved`);
|
|
440
|
+
}
|
|
441
|
+
assigned.add(permissionId);
|
|
442
|
+
names.set(reference.action, reference.name);
|
|
301
443
|
}
|
|
302
|
-
|
|
303
|
-
|
|
444
|
+
return { role, assigned, names };
|
|
445
|
+
},
|
|
446
|
+
permission(registeredModule, action, identity) {
|
|
447
|
+
const assignedName = identity.names.get(action);
|
|
448
|
+
if (assignedName !== undefined) {
|
|
449
|
+
const assignedEntry = registeredModule.names.get(assignedName);
|
|
450
|
+
if (assignedEntry === undefined)
|
|
451
|
+
return;
|
|
452
|
+
return { permissionId: identifiers_default.build(identity.role, action, assignedName), entry: assignedEntry };
|
|
453
|
+
}
|
|
454
|
+
let chosen;
|
|
455
|
+
for (const [name, nameEntry] of registeredModule.names) {
|
|
456
|
+
const permissionId = identifiers_default.build(identity.role, action, name);
|
|
457
|
+
if (resolve.methodAccess(nameEntry, permissionId, identity.role, identity.assigned) === undefined)
|
|
458
|
+
continue;
|
|
459
|
+
if (chosen !== undefined) {
|
|
460
|
+
throw errors_default.create("AMBIGUOUS_PERMISSION", `grants reach "${chosen.permissionId}" and "${permissionId}": a request names no permission name, so module "${action}" cannot be resolved`);
|
|
461
|
+
}
|
|
462
|
+
chosen = { permissionId, entry: nameEntry };
|
|
463
|
+
}
|
|
464
|
+
return chosen;
|
|
465
|
+
},
|
|
466
|
+
access(nameEntry, permissionId, role, method, assigned) {
|
|
467
|
+
if (!assigned.has(permissionId))
|
|
468
|
+
return grantedAccess(nameEntry, method, assigned);
|
|
469
|
+
const definition = nameEntry.actions.get(role)?.[method];
|
|
470
|
+
if (!definition?.enabled)
|
|
471
|
+
return DISABLED_ACCESS;
|
|
472
|
+
return { status: "granted", properties: definition.properties };
|
|
473
|
+
},
|
|
474
|
+
methodAccess(nameEntry, permissionId, role, assigned) {
|
|
475
|
+
const methodAccess = Object.create(null);
|
|
476
|
+
if (assigned.has(permissionId)) {
|
|
477
|
+
const actions = nameEntry.actions.get(role);
|
|
478
|
+
for (const method of constants_default.METHODS)
|
|
479
|
+
methodAccess[method] = actions?.[method]?.enabled === true;
|
|
480
|
+
return Object.freeze(methodAccess);
|
|
481
|
+
}
|
|
482
|
+
const grantedMethods = new Set;
|
|
483
|
+
let isReachable = false;
|
|
484
|
+
for (const [enablingId, grant] of nameEntry.grants) {
|
|
485
|
+
if (!assigned.has(enablingId))
|
|
304
486
|
continue;
|
|
305
|
-
|
|
487
|
+
isReachable = true;
|
|
488
|
+
for (const method of Object.keys(grant.actions))
|
|
489
|
+
grantedMethods.add(method);
|
|
306
490
|
}
|
|
491
|
+
if (!isReachable)
|
|
492
|
+
return;
|
|
493
|
+
for (const method of constants_default.METHODS)
|
|
494
|
+
methodAccess[method] = grantedMethods.has(method);
|
|
495
|
+
return Object.freeze(methodAccess);
|
|
307
496
|
}
|
|
308
|
-
}
|
|
309
|
-
function
|
|
310
|
-
|
|
311
|
-
|
|
497
|
+
};
|
|
498
|
+
function grantedAccess(nameEntry, method, assigned) {
|
|
499
|
+
const fields = new Set;
|
|
500
|
+
let isGranted = false;
|
|
501
|
+
let isReachable = false;
|
|
502
|
+
for (const [enablingId, grant] of nameEntry.grants) {
|
|
503
|
+
if (!assigned.has(enablingId))
|
|
312
504
|
continue;
|
|
313
|
-
|
|
314
|
-
|
|
505
|
+
isReachable = true;
|
|
506
|
+
const definition = grant.actions[method];
|
|
507
|
+
if (!definition)
|
|
508
|
+
continue;
|
|
509
|
+
isGranted = true;
|
|
510
|
+
for (const field of definition.properties)
|
|
511
|
+
fields.add(field);
|
|
512
|
+
}
|
|
513
|
+
if (!isGranted)
|
|
514
|
+
return isReachable ? DISABLED_ACCESS : UNASSIGNED_ACCESS;
|
|
515
|
+
return { status: "granted", properties: Object.freeze([...fields]) };
|
|
516
|
+
}
|
|
517
|
+
var resolve_default = resolve;
|
|
518
|
+
|
|
519
|
+
// src/permissions.ts
|
|
520
|
+
var permissions = Object.freeze({
|
|
521
|
+
forUser(assignments) {
|
|
522
|
+
const currentState = state_default.getOrCreate();
|
|
523
|
+
const snapshot = state_default.requireSnapshot(currentState);
|
|
524
|
+
const identity = resolve_default.identity(assignments, snapshot, currentState.roles);
|
|
525
|
+
const access = Object.create(null);
|
|
526
|
+
for (const [action, registeredModule] of currentState.modules) {
|
|
527
|
+
const chosen = resolve_default.permission(registeredModule, action, identity);
|
|
528
|
+
if (!chosen)
|
|
315
529
|
continue;
|
|
316
|
-
|
|
530
|
+
const methodAccess = resolve_default.methodAccess(chosen.entry, chosen.permissionId, identity.role, identity.assigned);
|
|
531
|
+
if (methodAccess)
|
|
532
|
+
access[chosen.permissionId] = methodAccess;
|
|
317
533
|
}
|
|
534
|
+
return Object.freeze(access);
|
|
535
|
+
},
|
|
536
|
+
get named() {
|
|
537
|
+
return state_default.requireSnapshot(state_default.getOrCreate()).named;
|
|
318
538
|
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
539
|
+
});
|
|
540
|
+
var permissions_default = permissions;
|
|
541
|
+
|
|
542
|
+
// src/definitions.ts
|
|
543
|
+
var METHODS = new Set(constants_default.METHODS);
|
|
544
|
+
var definitions = {
|
|
545
|
+
checkMethod(method, code, subject) {
|
|
546
|
+
if (typeof method === "string" && METHODS.has(method))
|
|
547
|
+
return method;
|
|
548
|
+
throw errors_default.create(code, `${subject}: method "${errors_default.describe(method)}" does not exist. Methods: ${constants_default.METHODS.join(", ")}`);
|
|
549
|
+
},
|
|
550
|
+
readActions(actions, permissionPath) {
|
|
551
|
+
const declared = requireObject(actions, `${permissionPath}: registerActions expects an object`);
|
|
552
|
+
const registeredActions = Object.create(null);
|
|
553
|
+
for (const [method, definition] of Object.entries(declared)) {
|
|
554
|
+
definitions.checkMethod(method, "INVALID_DEFINITION", permissionPath);
|
|
555
|
+
registeredActions[method] = readActionDefinition(definition, `${permissionPath}.${method}`);
|
|
324
556
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
557
|
+
return Object.freeze(registeredActions);
|
|
558
|
+
},
|
|
559
|
+
readGrant(actions, permissionPath) {
|
|
560
|
+
const registeredActions = definitions.readActions(actions, permissionPath);
|
|
561
|
+
for (const [method, definition] of Object.entries(registeredActions)) {
|
|
562
|
+
if (definition.enabled !== true) {
|
|
563
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}.${method}: a grant does not allow enabled: false`);
|
|
564
|
+
}
|
|
565
|
+
if (definition.properties === constants_default.ALL_FIELDS) {
|
|
566
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}.${method}: a grant requires an explicit properties list`);
|
|
329
567
|
}
|
|
330
|
-
validateGrantReferences(permissionPath, nameEntry, modules);
|
|
331
|
-
validateRoleHooks(permissionPath, nameEntry);
|
|
332
568
|
}
|
|
569
|
+
return registeredActions;
|
|
333
570
|
}
|
|
571
|
+
};
|
|
572
|
+
function requireObject(value, message) {
|
|
573
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
574
|
+
throw errors_default.create("INVALID_DEFINITION", message);
|
|
575
|
+
return value;
|
|
334
576
|
}
|
|
335
|
-
function
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const reference = parsePermissionId(permissionId, {
|
|
340
|
-
code: "INVALID_INPUT",
|
|
341
|
-
message: `invalid permission identifier: "${permissionId}" (format role::module::name)`
|
|
342
|
-
});
|
|
343
|
-
if (reference.role !== role) {
|
|
344
|
-
throw pkitError("PERMISSION_ROLE_MISMATCH", `"${permissionId}" belongs to role "${reference.role}", not the authenticated role "${role}"`);
|
|
345
|
-
}
|
|
346
|
-
if (!assignable.has(permissionId)) {
|
|
347
|
-
throw pkitError("UNKNOWN_PERMISSION", `"${permissionId}" is not an assignable permission`);
|
|
348
|
-
}
|
|
349
|
-
assigned.add(permissionId);
|
|
577
|
+
function readActionDefinition(definition, permissionPath) {
|
|
578
|
+
const action = requireObject(definition, `${permissionPath}: must be an object`);
|
|
579
|
+
if (typeof action.enabled !== "boolean") {
|
|
580
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: enabled must be a boolean`);
|
|
350
581
|
}
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
function validateIdentity(assignments, state) {
|
|
354
|
-
validateSnapshot(state.snapshot);
|
|
355
|
-
const { role, permissions } = assignments;
|
|
356
|
-
if (typeof role !== "string")
|
|
357
|
-
throw pkitError("INVALID_INPUT", "role is required");
|
|
358
|
-
validateRole(role, state.roles, "UNKNOWN_ROLE");
|
|
359
|
-
return { role, assigned: validateAssignments(permissions, role, state.snapshot.assignable) };
|
|
360
|
-
}
|
|
361
|
-
function trimSelection(select, properties) {
|
|
362
|
-
validateStrings(select, { code: "INVALID_INPUT", message: "select must be an array of strings", minimumLength: 0 });
|
|
363
|
-
const selectedFields = [];
|
|
364
|
-
for (const field of select) {
|
|
365
|
-
if (properties.includes(field))
|
|
366
|
-
selectedFields.push(field);
|
|
582
|
+
if (action.properties === constants_default.ALL_FIELDS) {
|
|
583
|
+
return Object.freeze({ enabled: action.enabled, properties: constants_default.ALL_FIELDS });
|
|
367
584
|
}
|
|
368
|
-
return
|
|
585
|
+
return Object.freeze({ enabled: action.enabled, properties: readDeclaredProperties(action.properties, permissionPath) });
|
|
369
586
|
}
|
|
370
|
-
function
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if (!properties.includes(field))
|
|
374
|
-
forbiddenFields.push(field);
|
|
587
|
+
function readDeclaredProperties(value, permissionPath) {
|
|
588
|
+
if (!Array.isArray(value)) {
|
|
589
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: properties must be string[] or '${constants_default.ALL_FIELDS}'`);
|
|
375
590
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
function validateRequest(input, state) {
|
|
381
|
-
validateSnapshot(state.snapshot);
|
|
382
|
-
const { action, name, method } = input;
|
|
383
|
-
validateMethod(method, { code: "INVALID_INPUT", message: "method is required" });
|
|
384
|
-
if (method !== "find" && Object.hasOwn(input, "select"))
|
|
385
|
-
throw pkitError("INVALID_INPUT", "select only applies to find");
|
|
386
|
-
if (typeof action !== "string" || typeof name !== "string")
|
|
387
|
-
throw pkitError("INVALID_INPUT", "action and name are required");
|
|
388
|
-
const { role, assigned } = validateIdentity(input, state);
|
|
389
|
-
const registeredModule = state.modules.get(action);
|
|
390
|
-
if (!registeredModule)
|
|
391
|
-
throw pkitError("UNKNOWN_ACTION", `module "${action}" is not registered`);
|
|
392
|
-
const nameEntry = registeredModule.names.get(name);
|
|
393
|
-
if (!nameEntry)
|
|
394
|
-
throw pkitError("UNKNOWN_PERMISSION", `permission "${action}::${name}" is not registered`);
|
|
395
|
-
const permissionId = permissionIdOf(role, action, name);
|
|
396
|
-
const access = resolveAccess(nameEntry, permissionId, role, method, assigned);
|
|
397
|
-
if (access.status === "unassigned") {
|
|
398
|
-
throw pkitError("PERMISSION_NOT_ASSIGNED", `"${permissionId}" is not assigned or granted by the user permissions`);
|
|
591
|
+
for (const property of value) {
|
|
592
|
+
if (typeof property !== "string" || property.length === 0) {
|
|
593
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: properties must be string[] or '${constants_default.ALL_FIELDS}'`);
|
|
594
|
+
}
|
|
399
595
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
validateObject(data, { code: "INVALID_INPUT", message: "data must be an object" });
|
|
411
|
-
const { select } = input;
|
|
412
|
-
if (select === undefined)
|
|
413
|
-
return { ...request, result: properties };
|
|
414
|
-
if (properties === ALL_FIELDS) {
|
|
415
|
-
validateStrings(select, { code: "INVALID_INPUT", message: "select must be an array of strings", minimumLength: 0 });
|
|
416
|
-
return { ...request, result: select };
|
|
417
|
-
}
|
|
418
|
-
return { ...request, result: trimSelection(select, properties) };
|
|
419
|
-
}
|
|
420
|
-
validateObject(data, { code: "INVALID_INPUT", message: "data must be an object" });
|
|
421
|
-
if (properties !== ALL_FIELDS)
|
|
422
|
-
rejectForbiddenFields(data, properties, `${permissionId}.${method}`);
|
|
423
|
-
return { ...request, result: data };
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// src/context.ts
|
|
427
|
-
function setRoles(key, roles) {
|
|
428
|
-
validateContextKey(key);
|
|
429
|
-
const state = getOrCreateState();
|
|
430
|
-
validateRoleCatalog(roles, state);
|
|
431
|
-
state.roles = new Set(roles);
|
|
432
|
-
}
|
|
433
|
-
function getRoles(key) {
|
|
434
|
-
validateContextKey(key);
|
|
435
|
-
return [...getOrCreateState().roles];
|
|
596
|
+
const declared = value;
|
|
597
|
+
if (declared.includes(constants_default.ALL_FIELDS)) {
|
|
598
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: '${constants_default.ALL_FIELDS}' is only allowed as the whole properties value`);
|
|
599
|
+
}
|
|
600
|
+
if (new Set(declared).size !== declared.length) {
|
|
601
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: properties contains duplicate fields`);
|
|
602
|
+
}
|
|
603
|
+
for (const property of declared)
|
|
604
|
+
properties_default.checkDeclaredPath(property, permissionPath);
|
|
605
|
+
return Object.freeze([...declared]);
|
|
436
606
|
}
|
|
437
|
-
var
|
|
607
|
+
var definitions_default = definitions;
|
|
438
608
|
|
|
439
609
|
// src/registry.ts
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
return
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
ensureName(state, scope.action, scope.name).grants.set(scope.permissionId, grant);
|
|
455
|
-
return scope.builder;
|
|
610
|
+
var registry = {
|
|
611
|
+
defineModule(segment) {
|
|
612
|
+
identifiers_default.checkModuleSegment(segment);
|
|
613
|
+
return createModuleBuilder(segment);
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
function createModuleBuilder(action) {
|
|
617
|
+
const builder = {};
|
|
618
|
+
const scope = { action, builder };
|
|
619
|
+
return Object.assign(builder, {
|
|
620
|
+
module: appendModule.bind(null, action),
|
|
621
|
+
name: createNameBuilder.bind(null, action),
|
|
622
|
+
hook: registerModuleHook.bind(null, scope)
|
|
623
|
+
});
|
|
456
624
|
}
|
|
457
|
-
function
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
appendHook(ensureModule(state, scope.action).hooks, method, hook);
|
|
461
|
-
return scope.builder;
|
|
625
|
+
function appendModule(parentAction, segment) {
|
|
626
|
+
identifiers_default.checkModuleSegment(segment);
|
|
627
|
+
return createModuleBuilder(`${parentAction}${constants_default.MODULE_SEPARATOR}${segment}`);
|
|
462
628
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
629
|
+
function createNameBuilder(action, name) {
|
|
630
|
+
identifiers_default.checkName(name);
|
|
631
|
+
const builder = {};
|
|
632
|
+
const scope = { action, name, role: constants_default.GLOBAL_HOOK_OWNER, builder };
|
|
633
|
+
return Object.assign(builder, {
|
|
634
|
+
role: createRoleBuilder.bind(null, action, name),
|
|
635
|
+
grantTo: createGrantBuilder.bind(null, action, name),
|
|
636
|
+
hook: registerNameHook.bind(null, scope)
|
|
637
|
+
});
|
|
471
638
|
}
|
|
472
639
|
function createRoleBuilder(action, name, role) {
|
|
473
|
-
|
|
640
|
+
identifiers_default.checkRole(role);
|
|
474
641
|
const builder = {};
|
|
475
642
|
const scope = { action, name, role, builder };
|
|
476
643
|
return Object.assign(builder, {
|
|
@@ -483,43 +650,72 @@ function createGrantBuilder(action, name, permissionId) {
|
|
|
483
650
|
const scope = { action, name, permissionId, builder };
|
|
484
651
|
return Object.assign(builder, { registerActions: registerGrant.bind(null, scope) });
|
|
485
652
|
}
|
|
486
|
-
function
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
653
|
+
function registerActions(scope, actions) {
|
|
654
|
+
const currentState = state_default.getOrCreate();
|
|
655
|
+
state_default.requireOpen(currentState);
|
|
656
|
+
requireDeclaredRole(scope.role, currentState.roles);
|
|
657
|
+
if (currentState.modules.get(scope.action)?.names.get(scope.name)?.actions.has(scope.role)) {
|
|
658
|
+
throw errors_default.create("DUPLICATE_REGISTRATION", `"${scope.action}::${scope.name}" already has actions registered for role "${scope.role}"`);
|
|
659
|
+
}
|
|
660
|
+
const registeredActions = definitions_default.readActions(actions, `${scope.action}::${scope.name} [${scope.role}]`);
|
|
661
|
+
ensureName(currentState, scope.action, scope.name).actions.set(scope.role, registeredActions);
|
|
662
|
+
return scope.builder;
|
|
495
663
|
}
|
|
496
|
-
function
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}
|
|
664
|
+
function registerGrant(scope, actions) {
|
|
665
|
+
const currentState = state_default.getOrCreate();
|
|
666
|
+
state_default.requireOpen(currentState);
|
|
667
|
+
const source = identifiers_default.parse(scope.permissionId, "INVALID_DEFINITION", `"${scope.action}::${scope.name}": invalid grantTo identifier`);
|
|
668
|
+
requireDeclaredRole(source.role, currentState.roles);
|
|
669
|
+
if (source.action === scope.action && source.name === scope.name) {
|
|
670
|
+
throw errors_default.create("INVALID_DEFINITION", `"${scope.permissionId}" cannot grant to itself`);
|
|
671
|
+
}
|
|
672
|
+
if (currentState.modules.get(scope.action)?.names.get(scope.name)?.grants.has(scope.permissionId)) {
|
|
673
|
+
throw errors_default.create("DUPLICATE_REGISTRATION", `"${scope.action}::${scope.name}" already has a grant for "${scope.permissionId}"`);
|
|
674
|
+
}
|
|
675
|
+
const grantActions = definitions_default.readGrant(actions, `${scope.action}::${scope.name} [grantTo ${scope.permissionId}]`);
|
|
676
|
+
ensureName(currentState, scope.action, scope.name).grants.set(scope.permissionId, { source, actions: grantActions });
|
|
677
|
+
return scope.builder;
|
|
504
678
|
}
|
|
505
|
-
function
|
|
506
|
-
|
|
507
|
-
|
|
679
|
+
function registerModuleHook(scope, method, hook) {
|
|
680
|
+
const currentState = state_default.getOrCreate();
|
|
681
|
+
state_default.requireOpen(currentState);
|
|
682
|
+
checkHook(hook, method, scope.action);
|
|
683
|
+
appendHook(ensureModule(currentState, scope.action).hooks, method, hook);
|
|
684
|
+
return scope.builder;
|
|
685
|
+
}
|
|
686
|
+
function registerNameHook(scope, method, hook) {
|
|
687
|
+
const currentState = state_default.getOrCreate();
|
|
688
|
+
state_default.requireOpen(currentState);
|
|
689
|
+
if (scope.role !== constants_default.GLOBAL_HOOK_OWNER)
|
|
690
|
+
requireDeclaredRole(scope.role, currentState.roles);
|
|
691
|
+
checkHook(hook, method, `${scope.action}::${scope.name}`);
|
|
692
|
+
const nameEntry = ensureName(currentState, scope.action, scope.name);
|
|
693
|
+
const roleHooks = nameEntry.hooks.get(scope.role) ?? new Map;
|
|
694
|
+
nameEntry.hooks.set(scope.role, roleHooks);
|
|
695
|
+
appendHook(roleHooks, method, hook);
|
|
696
|
+
return scope.builder;
|
|
697
|
+
}
|
|
698
|
+
function checkHook(hook, method, permissionPath) {
|
|
699
|
+
definitions_default.checkMethod(method, "INVALID_DEFINITION", permissionPath);
|
|
700
|
+
if (typeof hook !== "function")
|
|
701
|
+
throw errors_default.create("INVALID_DEFINITION", `${permissionPath}: hook("${method}") expects a function`);
|
|
508
702
|
}
|
|
509
|
-
function
|
|
510
|
-
|
|
511
|
-
|
|
703
|
+
function requireDeclaredRole(role, roles) {
|
|
704
|
+
if (roles.has(role))
|
|
705
|
+
return;
|
|
706
|
+
throw errors_default.create("ROLE_NOT_DECLARED", `role "${role}" is not declared. Available roles: ${[...roles].join(", ")}.
|
|
707
|
+
` + "Is pkit.context.set('roles', [...]) missing from pkit.config.js, or was it imported after this file?");
|
|
512
708
|
}
|
|
513
|
-
function ensureModule(
|
|
514
|
-
const registeredModule =
|
|
709
|
+
function ensureModule(currentState, action) {
|
|
710
|
+
const registeredModule = currentState.modules.get(action);
|
|
515
711
|
if (registeredModule)
|
|
516
712
|
return registeredModule;
|
|
517
713
|
const newModule = { names: new Map, hooks: new Map };
|
|
518
|
-
|
|
714
|
+
currentState.modules.set(action, newModule);
|
|
519
715
|
return newModule;
|
|
520
716
|
}
|
|
521
|
-
function ensureName(
|
|
522
|
-
const registeredModule = ensureModule(
|
|
717
|
+
function ensureName(currentState, action, name) {
|
|
718
|
+
const registeredModule = ensureModule(currentState, action);
|
|
523
719
|
const registeredName = registeredModule.names.get(name);
|
|
524
720
|
if (registeredName)
|
|
525
721
|
return registeredName;
|
|
@@ -527,60 +723,158 @@ function ensureName(state, action, name) {
|
|
|
527
723
|
registeredModule.names.set(name, newName);
|
|
528
724
|
return newName;
|
|
529
725
|
}
|
|
726
|
+
function appendHook(methodHooks, method, hook) {
|
|
727
|
+
const hooks = methodHooks.get(method) ?? [];
|
|
728
|
+
methodHooks.set(method, hooks);
|
|
729
|
+
hooks.push(hook);
|
|
730
|
+
}
|
|
731
|
+
var registry_default = registry;
|
|
530
732
|
|
|
531
733
|
// src/seal.ts
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
734
|
+
var sealer = {
|
|
735
|
+
seal() {
|
|
736
|
+
const currentState = state_default.getOrCreate();
|
|
737
|
+
if (currentState.snapshot)
|
|
738
|
+
return;
|
|
739
|
+
checkRegistry(currentState.modules);
|
|
740
|
+
const named = Object.create(null);
|
|
741
|
+
for (const [action, registeredModule] of currentState.modules) {
|
|
742
|
+
for (const [name, nameEntry] of registeredModule.names) {
|
|
743
|
+
for (const [role, actions] of nameEntry.actions) {
|
|
744
|
+
named[identifiers_default.build(role, action, name)] = actions;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
currentState.snapshot = { named: Object.freeze(named), assignable: new Set(Object.keys(named)) };
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
function checkRegistry(modules) {
|
|
752
|
+
for (const [action, registeredModule] of modules) {
|
|
753
|
+
if (registeredModule.names.size === 0) {
|
|
754
|
+
throw errors_default.create("INVALID_DEFINITION", `"${action}" has hooks but no name with registered actions`);
|
|
755
|
+
}
|
|
539
756
|
for (const [name, nameEntry] of registeredModule.names) {
|
|
540
|
-
|
|
541
|
-
|
|
757
|
+
const permissionPath = `${action}::${name}`;
|
|
758
|
+
if (nameEntry.actions.size === 0) {
|
|
759
|
+
throw errors_default.create("INVALID_DEFINITION", `"${permissionPath}" has no registered actions for any role`);
|
|
542
760
|
}
|
|
761
|
+
checkGrantReferences(permissionPath, nameEntry, modules);
|
|
762
|
+
checkRoleHooks(permissionPath, nameEntry);
|
|
543
763
|
}
|
|
544
764
|
}
|
|
545
|
-
state.snapshot = { named: Object.freeze(named), assignable: new Set(Object.keys(named)) };
|
|
546
765
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
766
|
+
function checkGrantReferences(permissionPath, nameEntry, modules) {
|
|
767
|
+
for (const [permissionId, grant] of nameEntry.grants) {
|
|
768
|
+
const sourceEntry = modules.get(grant.source.action)?.names.get(grant.source.name);
|
|
769
|
+
if (!sourceEntry?.actions.has(grant.source.role)) {
|
|
770
|
+
throw errors_default.create("INVALID_DEFINITION", `"${permissionPath}": grantTo "${permissionId}" references a permission with no registered actions`);
|
|
771
|
+
}
|
|
772
|
+
for (const method of Object.keys(grant.actions)) {
|
|
773
|
+
if (declaresMethod(nameEntry, method))
|
|
774
|
+
continue;
|
|
775
|
+
throw errors_default.create("INVALID_DEFINITION", `"${permissionPath}": grantTo "${permissionId}" grants "${method}", which no role declares on that permission`);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
function declaresMethod(nameEntry, method) {
|
|
780
|
+
for (const actions of nameEntry.actions.values()) {
|
|
781
|
+
if (Object.hasOwn(actions, method))
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
function checkRoleHooks(permissionPath, nameEntry) {
|
|
787
|
+
for (const [hookRole, methodHooks] of nameEntry.hooks) {
|
|
788
|
+
if (hookRole === constants_default.GLOBAL_HOOK_OWNER)
|
|
789
|
+
continue;
|
|
790
|
+
for (const method of methodHooks.keys()) {
|
|
791
|
+
if (hasAccessPath(nameEntry, hookRole, method))
|
|
792
|
+
continue;
|
|
793
|
+
throw errors_default.create("INVALID_DEFINITION", `"${permissionPath}": hook for "${hookRole}" on "${method}" has no registered actions or grant for that role`);
|
|
575
794
|
}
|
|
576
795
|
}
|
|
577
|
-
return Object.freeze(access);
|
|
578
796
|
}
|
|
579
|
-
|
|
797
|
+
function hasAccessPath(nameEntry, role, method) {
|
|
798
|
+
if (nameEntry.actions.get(role)?.[method])
|
|
799
|
+
return true;
|
|
800
|
+
for (const grant of nameEntry.grants.values()) {
|
|
801
|
+
if (grant.source.role === role && grant.actions[method])
|
|
802
|
+
return true;
|
|
803
|
+
}
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
var seal_default = sealer;
|
|
580
807
|
|
|
581
808
|
// src/validate.ts
|
|
809
|
+
var validator = {
|
|
810
|
+
async validate(input) {
|
|
811
|
+
try {
|
|
812
|
+
const request = prepareRequest(input, state_default.getOrCreate());
|
|
813
|
+
const hookCalls = [];
|
|
814
|
+
for (const hook of request.hooks)
|
|
815
|
+
hookCalls.push(invokeHook(hook, request));
|
|
816
|
+
const hookResults = await Promise.allSettled(hookCalls);
|
|
817
|
+
const hookErrors = [];
|
|
818
|
+
for (const hookResult of hookResults) {
|
|
819
|
+
if (hookResult.status === "fulfilled")
|
|
820
|
+
continue;
|
|
821
|
+
const hookCause = hookResult.reason;
|
|
822
|
+
hookErrors.push({ code: "HOOK_ERROR", message: describeHookFailure(hookCause), cause: hookCause });
|
|
823
|
+
}
|
|
824
|
+
if (hookErrors.length)
|
|
825
|
+
return { result: null, errors: Object.freeze(hookErrors) };
|
|
826
|
+
return { result: { data: request.data }, errors: Object.freeze([]) };
|
|
827
|
+
} catch (cause) {
|
|
828
|
+
return { result: null, errors: Object.freeze([translateFailure(cause)]) };
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
function prepareRequest(input, currentState) {
|
|
833
|
+
const snapshot = state_default.requireSnapshot(currentState);
|
|
834
|
+
const method = definitions_default.checkMethod(input.method, "INVALID_INPUT", "method is required");
|
|
835
|
+
const { action, permissions } = input;
|
|
836
|
+
if (typeof action !== "string")
|
|
837
|
+
throw errors_default.create("INVALID_INPUT", "action is required");
|
|
838
|
+
const data = readOptionalObject(input.data, "data must be an object");
|
|
839
|
+
const context = readOptionalObject(input.context, "context must be an object");
|
|
840
|
+
const identity = resolve_default.identity(input, snapshot, currentState.roles);
|
|
841
|
+
const { role, assigned } = identity;
|
|
842
|
+
const registeredModule = currentState.modules.get(action);
|
|
843
|
+
if (!registeredModule)
|
|
844
|
+
throw errors_default.create("UNKNOWN_ACTION", `module "${action}" is not registered`);
|
|
845
|
+
const chosen = resolve_default.permission(registeredModule, action, identity);
|
|
846
|
+
if (!chosen) {
|
|
847
|
+
throw errors_default.create("PERMISSION_NOT_ASSIGNED", `no name of module "${action}" is assigned or granted to role "${role}" by the user permissions`);
|
|
848
|
+
}
|
|
849
|
+
const { permissionId, entry: nameEntry } = chosen;
|
|
850
|
+
const access = resolve_default.access(nameEntry, permissionId, role, method, assigned);
|
|
851
|
+
if (access.status === "unassigned") {
|
|
852
|
+
throw errors_default.create("PERMISSION_NOT_ASSIGNED", `"${permissionId}" is not assigned or granted by the user permissions`);
|
|
853
|
+
}
|
|
854
|
+
if (access.status === "disabled")
|
|
855
|
+
throw errors_default.create("METHOD_DISABLED", `"${permissionId}.${method}" is not enabled`);
|
|
856
|
+
const hookGroups = [
|
|
857
|
+
registeredModule.hooks.get(method),
|
|
858
|
+
nameEntry.hooks.get(constants_default.GLOBAL_HOOK_OWNER)?.get(method),
|
|
859
|
+
nameEntry.hooks.get(role)?.get(method)
|
|
860
|
+
];
|
|
861
|
+
const hooks = [];
|
|
862
|
+
for (const group of hookGroups) {
|
|
863
|
+
if (group)
|
|
864
|
+
hooks.push(...group);
|
|
865
|
+
}
|
|
866
|
+
const allowedData = properties_default.resolve(data, access.properties, currentState.reservedFields, currentState.cropper);
|
|
867
|
+
return { hooks, context, permissions, data: allowedData };
|
|
868
|
+
}
|
|
869
|
+
function readOptionalObject(value, message) {
|
|
870
|
+
if (value === undefined)
|
|
871
|
+
return {};
|
|
872
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
873
|
+
throw errors_default.create("INVALID_INPUT", message);
|
|
874
|
+
return value;
|
|
875
|
+
}
|
|
582
876
|
async function invokeHook(hook, request) {
|
|
583
|
-
return hook(request.data, request.context, request.
|
|
877
|
+
return hook(request.data, request.context, request.permissions);
|
|
584
878
|
}
|
|
585
879
|
function describeHookFailure(reason) {
|
|
586
880
|
try {
|
|
@@ -589,48 +883,24 @@ function describeHookFailure(reason) {
|
|
|
589
883
|
return "the hook threw a value that cannot be described";
|
|
590
884
|
}
|
|
591
885
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
const { registeredModule, nameEntry, permission, result } = request;
|
|
596
|
-
const { method, role } = permission;
|
|
597
|
-
const hookGroups = [
|
|
598
|
-
registeredModule.hooks.get(method),
|
|
599
|
-
nameEntry.hooks.get(GLOBAL_HOOK_OWNER)?.get(method),
|
|
600
|
-
nameEntry.hooks.get(role)?.get(method)
|
|
601
|
-
];
|
|
602
|
-
const hookCalls = [];
|
|
603
|
-
for (const hooks of hookGroups) {
|
|
604
|
-
if (!hooks)
|
|
605
|
-
continue;
|
|
606
|
-
for (const hook of hooks)
|
|
607
|
-
hookCalls.push(invokeHook(hook, request));
|
|
608
|
-
}
|
|
609
|
-
const hookResults = await Promise.allSettled(hookCalls);
|
|
610
|
-
const errors = [];
|
|
611
|
-
for (const hookResult of hookResults) {
|
|
612
|
-
if (hookResult.status === "fulfilled")
|
|
613
|
-
continue;
|
|
614
|
-
const hookCause = hookResult.reason;
|
|
615
|
-
errors.push({ code: "HOOK_ERROR", message: describeHookFailure(hookCause), cause: hookCause });
|
|
616
|
-
}
|
|
617
|
-
if (errors.length)
|
|
618
|
-
return { result: null, errors: Object.freeze(errors) };
|
|
619
|
-
return { result, errors: Object.freeze([]) };
|
|
620
|
-
} catch (cause) {
|
|
621
|
-
if (cause instanceof Error && cause.name === "PkitError") {
|
|
622
|
-
const permissionError = cause;
|
|
623
|
-
const error = permissionError.code === "PROPERTIES_NOT_ALLOWED" ? { code: permissionError.code, message: permissionError.message, fields: permissionError.fields } : { code: permissionError.code, message: permissionError.message };
|
|
624
|
-
return { result: null, errors: Object.freeze([error]) };
|
|
625
|
-
}
|
|
626
|
-
return {
|
|
627
|
-
result: null,
|
|
628
|
-
errors: Object.freeze([{ code: "VALIDATION_ERROR", message: "permission could not be validated", cause }])
|
|
629
|
-
};
|
|
886
|
+
function translateFailure(cause) {
|
|
887
|
+
if (!(cause instanceof Error) || cause.name !== "PkitError") {
|
|
888
|
+
return { code: "VALIDATION_ERROR", message: "permission could not be validated", cause };
|
|
630
889
|
}
|
|
890
|
+
const permissionError = cause;
|
|
891
|
+
if (permissionError.code === "PROPERTIES_NOT_ALLOWED") {
|
|
892
|
+
return { code: permissionError.code, message: permissionError.message, fields: permissionError.fields };
|
|
893
|
+
}
|
|
894
|
+
return { code: permissionError.code, message: permissionError.message };
|
|
631
895
|
}
|
|
896
|
+
var validate_default = validator;
|
|
897
|
+
|
|
632
898
|
// src/index.ts
|
|
633
|
-
var
|
|
899
|
+
var METHODS2 = constants_default.METHODS;
|
|
900
|
+
var seal = seal_default.seal;
|
|
901
|
+
var validate = validate_default.validate;
|
|
902
|
+
var defineModule = registry_default.defineModule;
|
|
903
|
+
var pkit = Object.freeze({ context: context_default, module: defineModule, seal, permissions: permissions_default, validate });
|
|
634
904
|
var src_default = pkit;
|
|
635
905
|
|
|
636
|
-
//# debugId=
|
|
906
|
+
//# debugId=276C6E13E676044E64756E2164756E21
|