From fe0811fe6dba3e4f8b2dbacb727fe8f1a55a6a21 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Mon, 10 Apr 2023 18:14:43 +0200 Subject: [PATCH 01/53] add async common methods --- package.js | 1 + roles/roles_common_async.js | 1276 +++++++++++++++++++++++++++++++++++ roles/roles_server.js | 299 ++++---- 3 files changed, 1453 insertions(+), 123 deletions(-) create mode 100644 roles/roles_common_async.js diff --git a/package.js b/package.js index 90a65850..9075e79d 100644 --- a/package.js +++ b/package.js @@ -25,6 +25,7 @@ Package.onUse(function (api) { api.export('Roles') api.addFiles('roles/roles_common.js', both) + api.addFiles('roles/roles_common_async.js', both) api.addFiles('roles/roles_server.js', 'server') api.addFiles([ 'roles/client/debug.js', diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js new file mode 100644 index 00000000..753eaae8 --- /dev/null +++ b/roles/roles_common_async.js @@ -0,0 +1,1276 @@ +/* global Meteor, Roles, Mongo */ + +/** + * Provides functions related to user authorization. Compatible with built-in Meteor accounts packages. + * + * Roles are accessible throgh `Meteor.roles` collection and documents consist of: + * - `_id`: role name + * - `children`: list of subdocuments: + * - `_id` + * + * Children list elements are subdocuments so that they can be easier extended in the future or by plugins. + * + * Roles can have multiple parents and can be children (subroles) of multiple roles. + * + * Example: `{_id: 'admin', children: [{_id: 'editor'}]}` + * + * The assignment of a role to a user is stored in a collection, accessible through `Meteor.roleAssignment`. + * It's documents consist of + * - `_id`: Internal MongoDB id + * - `role`: A role object which got assigned. Usually only contains the `_id` property + * - `user`: A user object, usually only contains the `_id` property + * - `scope`: scope name + * - `inheritedRoles`: A list of all the roles objects inherited by the assigned role. + * + * @module Roles + */ +if (!Meteor.roles) { + Meteor.roles = new Mongo.Collection("roles"); +} + +if (!Meteor.roleAssignment) { + Meteor.roleAssignment = new Mongo.Collection("role-assignment"); +} + +/** + * @class Roles + */ +if (typeof Roles === "undefined") { + Roles = {}; // eslint-disable-line no-global-assign +} + +var getGroupsForUserDeprecationWarning = false; + +Object.assign(Roles, { + /** + * Used as a global group (now scope) name. Not used anymore. + * + * @property GLOBAL_GROUP + * @static + * @deprecated + */ + GLOBAL_GROUP: null, + + /** + * Create a new role. + * + * @method createRole + * @param {String} roleName Name of role. + * @param {Object} [options] Options: + * - `unlessExists`: if `true`, exception will not be thrown in the role already exists + * @return {String} ID of the new role or null. + * @static + */ + createRoleAsync: async function (roleName, options) { + Roles._checkRoleName(roleName); + + options = Object.assign( + { + unlessExists: false, + }, + options + ); + + var result = await Meteor.roles.upsertAsync( + { _id: roleName }, + { $setOnInsert: { children: [] } } + ); + + if (!result.insertedId) { + if (options.unlessExists) return null; + throw new Error("Role '" + roleName + "' already exists."); + } + + return result.insertedId; + }, + + /** + * Delete an existing role. + * + * If the role is set for any user, it is automatically unset. + * + * @method deleteRole + * @param {String} roleName Name of role. + * @static + */ + deleteRoleAsync: async function (roleName) { + var roles; + var inheritedRoles; + + Roles._checkRoleName(roleName); + + // Remove all assignments + await Meteor.roleAssignment.removeAsync({ + "role._id": roleName, + }); + + do { + // For all roles who have it as a dependency ... + roles = Roles._getParentRoleNames( + await Meteor.roles.findOneAsync({ _id: roleName }) + ); + + for (const r of await Meteor.roles + .find({ _id: { $in: roles } }) + .fetchAsync()) { + await Meteor.roles.updateAsync( + { + _id: r._id, + }, + { + $pull: { + children: { + _id: roleName, + }, + }, + } + ); + + inheritedRoles = await Roles._getInheritedRoleNamesAsync( + await Meteor.roles.findOneAsync({ _id: r._id }) + ); + await Meteor.roleAssignment.updateAsync( + { + "role._id": r._id, + }, + { + $set: { + inheritedRoles: [r._id, ...inheritedRoles].map((r2) => ({ + _id: r2, + })), + }, + }, + { multi: true } + ); + } + } while (roles.length > 0); + + // And finally remove the role itself + await Meteor.roles.removeAsync({ _id: roleName }); + }, + + /** + * Rename an existing role. + * + * @method renameRole + * @param {String} oldName Old name of a role. + * @param {String} newName New name of a role. + * @static + */ + renameRoleAsync: async function (oldName, newName) { + var role; + var count; + + Roles._checkRoleName(oldName); + Roles._checkRoleName(newName); + + if (oldName === newName) return; + + role = await Meteor.roles.findOneAsync({ _id: oldName }); + + if (!role) { + throw new Error("Role '" + oldName + "' does not exist."); + } + + role._id = newName; + + await Meteor.roles.insertAsync(role); + + do { + count = await Meteor.roleAssignment.updateAsync( + { + "role._id": oldName, + }, + { + $set: { + "role._id": newName, + }, + }, + { multi: true } + ); + } while (count > 0); + + do { + count = await Meteor.roleAssignment.updateAsync( + { + "inheritedRoles._id": oldName, + }, + { + $set: { + "inheritedRoles.$._id": newName, + }, + }, + { multi: true } + ); + } while (count > 0); + + do { + count = await Meteor.roles.updateAsync( + { + "children._id": oldName, + }, + { + $set: { + "children.$._id": newName, + }, + }, + { multi: true } + ); + } while (count > 0); + + await Meteor.roles.removeAsync({ _id: oldName }); + }, + + /** + * Add role parent to roles. + * + * Previous parents are kept (role can have multiple parents). For users which have the + * parent role set, new subroles are added automatically. + * + * @method addRolesToParent + * @param {Array|String} rolesNames Name(s) of role(s). + * @param {String} parentName Name of parent role. + * @static + */ + addRolesToParentAsync: async function (rolesNames, parentName) { + // ensure arrays + if (!Array.isArray(rolesNames)) rolesNames = [rolesNames]; + + for (const roleName of rolesNames) { + await Roles._addRoleToParentAsync(roleName, parentName); + } + }, + + /** + * @method _addRoleToParent + * @param {String} roleName Name of role. + * @param {String} parentName Name of parent role. + * @private + * @static + */ + _addRoleToParentAsync: async function (roleName, parentName) { + var role; + var count; + + Roles._checkRoleName(roleName); + Roles._checkRoleName(parentName); + + // query to get role's children + role = await Meteor.roles.findOneAsync({ _id: roleName }); + + if (!role) { + throw new Error("Role '" + roleName + "' does not exist."); + } + + // detect cycles + if ((await Roles._getInheritedRoleNamesAsync(role)).includes(parentName)) { + throw new Error( + "Roles '" + roleName + "' and '" + parentName + "' would form a cycle." + ); + } + + count = await Meteor.roles.updateAsync( + { + _id: parentName, + "children._id": { + $ne: role._id, + }, + }, + { + $push: { + children: { + _id: role._id, + }, + }, + } + ); + + // if there was no change, parent role might not exist, or role is + // already a subrole; in any case we do not have anything more to do + if (!count) return; + + await Meteor.roleAssignment.updateAsync( + { + "inheritedRoles._id": parentName, + }, + { + $push: { + inheritedRoles: { + $each: [ + role._id, + ...(await Roles._getInheritedRoleNamesAsync(role)), + ].map((r) => ({ _id: r })), + }, + }, + }, + { multi: true } + ); + }, + + /** + * Remove role parent from roles. + * + * Other parents are kept (role can have multiple parents). For users which have the + * parent role set, removed subrole is removed automatically. + * + * @method removeRolesFromParent + * @param {Array|String} rolesNames Name(s) of role(s). + * @param {String} parentName Name of parent role. + * @static + */ + removeRolesFromParentAsync: async function (rolesNames, parentName) { + // ensure arrays + if (!Array.isArray(rolesNames)) rolesNames = [rolesNames]; + + for (const roleName of rolesNames) { + await Roles._removeRoleFromParentAsync(roleName, parentName); + } + }, + + /** + * @method _removeRoleFromParent + * @param {String} roleName Name of role. + * @param {String} parentName Name of parent role. + * @private + * @static + */ + _removeRoleFromParentAsync: async function (roleName, parentName) { + Roles._checkRoleName(roleName); + Roles._checkRoleName(parentName); + + // check for role existence + // this would not really be needed, but we are trying to match addRolesToParent + let role = await Meteor.roles.findOneAsync( + { _id: roleName }, + { fields: { _id: 1 } } + ); + + if (!role) { + throw new Error("Role '" + roleName + "' does not exist."); + } + + const count = await Meteor.roles.updateAsync( + { + _id: parentName, + }, + { + $pull: { + children: { + _id: role._id, + }, + }, + } + ); + + // if there was no change, parent role might not exist, or role was + // already not a subrole; in any case we do not have anything more to do + if (!count) return; + + // For all roles who have had it as a dependency ... + const roles = [ + ...(await Roles._getParentRoleNamesAsync( + await Meteor.roles.findOneAsync({ _id: parentName }) + )), + parentName, + ]; + + for (const r of await Meteor.roles + .find({ _id: { $in: roles } }) + .fetchAsync()) { + const inheritedRoles = await Roles._getInheritedRoleNamesAsync( + await Meteor.roles.findOneAsync({ _id: r._id }) + ); + await Meteor.roleAssignment.updateAsync( + { + "role._id": r._id, + "inheritedRoles._id": role._id, + }, + { + $set: { + inheritedRoles: [r._id, ...inheritedRoles].map((r2) => ({ + _id: r2, + })), + }, + }, + { multi: true } + ); + } + }, + + /** + * Add users to roles. + * + * Adds roles to existing roles for each user. + * + * @example + * Roles.addUsersToRoles(userId, 'admin') + * Roles.addUsersToRoles(userId, ['view-secrets'], 'example.com') + * Roles.addUsersToRoles([user1, user2], ['user','editor']) + * Roles.addUsersToRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') + * + * @method addUsersToRoles + * @param {Array|String} users User ID(s) or object(s) with an `_id` field. + * @param {Array|String} roles Name(s) of roles to add users to. Roles have to exist. + * @param {Object|String} [options] Options: + * - `scope`: name of the scope, or `null` for the global role + * - `ifExists`: if `true`, do not throw an exception if the role does not exist + * + * Alternatively, it can be a scope name string. + * @static + */ + addUsersToRolesAsync: async function (users, roles, options) { + var id; + + if (!users) throw new Error("Missing 'users' param."); + if (!roles) throw new Error("Missing 'roles' param."); + + options = Roles._normalizeOptions(options); + + // ensure arrays + if (!Array.isArray(users)) users = [users]; + if (!Array.isArray(roles)) roles = [roles]; + + Roles._checkScopeName(options.scope); + + options = Object.assign( + { + ifExists: false, + }, + options + ); + + for (const user of users) { + if (typeof user === "object") { + id = user._id; + } else { + id = user; + } + + for (const role of roles) { + await Roles._addUserToRoleAsync(id, role, options); + } + } + }, + + /** + * Set users' roles. + * + * Replaces all existing roles with a new set of roles. + * + * @example + * Roles.setUserRoles(userId, 'admin') + * Roles.setUserRoles(userId, ['view-secrets'], 'example.com') + * Roles.setUserRoles([user1, user2], ['user','editor']) + * Roles.setUserRoles([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') + * + * @method setUserRoles + * @param {Array|String} users User ID(s) or object(s) with an `_id` field. + * @param {Array|String} roles Name(s) of roles to add users to. Roles have to exist. + * @param {Object|String} [options] Options: + * - `scope`: name of the scope, or `null` for the global role + * - `anyScope`: if `true`, remove all roles the user has, of any scope, if `false`, only the one in the same scope + * - `ifExists`: if `true`, do not throw an exception if the role does not exist + * + * Alternatively, it can be a scope name string. + * @static + */ + setUserRolesAsync: async function (users, roles, options) { + var id; + + if (!users) throw new Error("Missing 'users' param."); + if (!roles) throw new Error("Missing 'roles' param."); + + options = Roles._normalizeOptions(options); + + // ensure arrays + if (!Array.isArray(users)) users = [users]; + if (!Array.isArray(roles)) roles = [roles]; + + Roles._checkScopeName(options.scope); + + options = Object.assign( + { + ifExists: false, + anyScope: false, + }, + options + ); + + for (const user of users) { + if (typeof user === "object") { + id = user._id; + } else { + id = user; + } + // we first clear all roles for the user + const selector = { "user._id": id }; + if (!options.anyScope) { + selector.scope = options.scope; + } + + await Meteor.roleAssignment.removeAsync(selector); + + // and then add all + for (const role of roles) { + await Roles._addUserToRole(id, role, options); + } + } + }, + + /** + * Add one user to one role. + * + * @method _addUserToRole + * @param {String} userId The user ID. + * @param {String} roleName Name of the role to add the user to. The role have to exist. + * @param {Object} options Options: + * - `scope`: name of the scope, or `null` for the global role + * - `ifExists`: if `true`, do not throw an exception if the role does not exist + * @private + * @static + */ + _addUserToRole: async function (userId, roleName, options) { + Roles._checkRoleName(roleName); + Roles._checkScopeName(options.scope); + + if (!userId) { + return; + } + + const role = await Meteor.roles.findOneAsync( + { _id: roleName }, + { fields: { children: 1 } } + ); + + if (!role) { + if (options.ifExists) { + return []; + } else { + throw new Error("Role '" + roleName + "' does not exist."); + } + } + + // This might create duplicates, because we don't have a unique index, but that's all right. In case there are two, withdrawing the role will effectively kill them both. + const res = await Meteor.roleAssignment.upsertAsync( + { + "user._id": userId, + "role._id": roleName, + scope: options.scope, + }, + { + $setOnInsert: { + user: { _id: userId }, + role: { _id: roleName }, + scope: options.scope, + }, + } + ); + + if (res.insertedId) { + await Meteor.roleAssignment.updateAsync( + { _id: res.insertedId }, + { + $set: { + inheritedRoles: [ + roleName, + ...(await Roles._getInheritedRoleNamesAsync(role)), + ].map((r) => ({ _id: r })), + }, + } + ); + } + + return res; + }, + + /** + * Returns an array of role names the given role name is a child of. + * + * @example + * Roles._getParentRoleNames({ _id: 'admin', children; [] }) + * + * @method _getParentRoleNames + * @param {object} role The role object + * @private + * @static + */ + _getParentRoleNamesAsync: async function (role) { + var parentRoles; + + if (!role) { + return []; + } + + parentRoles = new Set([role._id]); + + for (const roleName of parentRoles) { + for (const parentRole of await Meteor.roles + .find({ "children._id": roleName }) + .fetchAsync()) { + parentRoles.add(parentRole._id); + } + } + + parentRoles.delete(role._id); + + return [...parentRoles]; + }, + + /** + * Returns an array of role names the given role name is a parent of. + * + * @example + * Roles._getInheritedRoleNames({ _id: 'admin', children; [] }) + * + * @method _getInheritedRoleNames + * @param {object} role The role object + * @private + * @static + */ + _getInheritedRoleNamesAsync: async function (role) { + const inheritedRoles = new Set(); + const nestedRoles = new Set([role]); + + for (const r in nestedRoles) { + const roles = await Meteor.roles + .find( + { _id: { $in: r.children.map((r) => r._id) } }, + { fields: { children: 1 } } + ) + .fetchAsync(); + + for (const r2 of roles) { + inheritedRoles.add(r2._id); + nestedRoles.add(r2); + } + } + + return [...inheritedRoles]; + }, + + /** + * Remove users from assigned roles. + * + * @example + * Roles.removeUsersFromRoles(userId, 'admin') + * Roles.removeUsersFromRoles([userId, user2], ['editor']) + * Roles.removeUsersFromRoles(userId, ['user'], 'group1') + * + * @method removeUsersFromRoles + * @param {Array|String} users User ID(s) or object(s) with an `_id` field. + * @param {Array|String} roles Name(s) of roles to remove users from. Roles have to exist. + * @param {Object|String} [options] Options: + * - `scope`: name of the scope, or `null` for the global role + * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * + * Alternatively, it can be a scope name string. + * @static + */ + removeUsersFromRolesAsync: async function (users, roles, options) { + if (!users) throw new Error("Missing 'users' param."); + if (!roles) throw new Error("Missing 'roles' param."); + + options = Roles._normalizeOptions(options); + + // ensure arrays + if (!Array.isArray(users)) users = [users]; + if (!Array.isArray(roles)) roles = [roles]; + + Roles._checkScopeName(options.scope); + + for (const user of users) { + if (!user) return; + + for (const role of roles) { + let id; + if (typeof user === "object") { + id = user._id; + } else { + id = user; + } + + await Roles._removeUserFromRoleAsync(id, role, options); + } + } + }, + + /** + * Remove one user from one role. + * + * @method _removeUserFromRole + * @param {String} userId The user ID. + * @param {String} roleName Name of the role to add the user to. The role have to exist. + * @param {Object} options Options: + * - `scope`: name of the scope, or `null` for the global role + * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * @private + * @static + */ + _removeUserFromRoleAsync: async function (userId, roleName, options) { + Roles._checkRoleName(roleName); + Roles._checkScopeName(options.scope); + + if (!userId) return; + + const selector = { + "user._id": userId, + "role._id": roleName, + }; + + if (!options.anyScope) { + selector.scope = options.scope; + } + + await Meteor.roleAssignment.removeAsync(selector); + }, + + /** + * Check if user has specified roles. + * + * @example + * // global roles + * Roles.userIsInRole(user, 'admin') + * Roles.userIsInRole(user, ['admin','editor']) + * Roles.userIsInRole(userId, 'admin') + * Roles.userIsInRole(userId, ['admin','editor']) + * + * // scope roles (global roles are still checked) + * Roles.userIsInRole(user, 'admin', 'group1') + * Roles.userIsInRole(userId, ['admin','editor'], 'group1') + * Roles.userIsInRole(userId, ['admin','editor'], {scope: 'group1'}) + * + * @method userIsInRole + * @param {String|Object} user User ID or an actual user object. + * @param {Array|String} roles Name of role or an array of roles to check against. If array, + * will return `true` if user is in _any_ role. + * Roles do not have to exist. + * @param {Object|String} [options] Options: + * - `scope`: name of the scope; if supplied, limits check to just that scope + * the user's global roles will always be checked whether scope is specified or not + * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * + * Alternatively, it can be a scope name string. + * @return {Boolean} `true` if user is in _any_ of the target roles + * @static + */ + userIsInRoleAsync: async function (user, roles, options) { + var id; + var selector; + + options = Roles._normalizeOptions(options); + + // ensure array to simplify code + if (!Array.isArray(roles)) roles = [roles]; + + roles = roles.filter((r) => r != null); + + if (!roles.length) return false; + + Roles._checkScopeName(options.scope); + + options = Object.assign( + { + anyScope: false, + }, + options + ); + + if (user && typeof user === "object") { + id = user._id; + } else { + id = user; + } + + if (!id) return false; + if (typeof id !== "string") return false; + + selector = { + "user._id": id, + }; + + if (!options.anyScope) { + selector.scope = { $in: [options.scope, null] }; + } + + // Convert to Promises first, then check via some + const rolesPromises = roles.map( + (roleName) => + new Promise(async (res, rej) => { + selector["inheritedRoles._id"] = roleName; + + res( + (await Meteor.roleAssignment + .find(selector, { limit: 1 }) + .countAsync()) > 0 + ); + }) + ); + + const result = await Promise.all(rolesPromises); + + return result.some((r) => r); + }, + + /** + * Retrieve user's roles. + * + * @method getRolesForUser + * @param {String|Object} user User ID or an actual user object. + * @param {Object|String} [options] Options: + * - `scope`: name of scope to provide roles for; if not specified, global roles are returned + * - `anyScope`: if set, role can be in any scope (`scope` and `onlyAssigned` options are ignored) + * - `onlyScoped`: if set, only roles in the specified scope are returned + * - `onlyAssigned`: return only assigned roles and not automatically inferred (like subroles) + * - `fullObjects`: return full roles objects (`true`) or just names (`false`) (`onlyAssigned` option is ignored) (default `false`) + * If you have a use-case for this option, please file a feature-request. You shouldn't need to use it as it's + * result strongly dependant on the internal data structure of this plugin. + * + * Alternatively, it can be a scope name string. + * @return {Array} Array of user's roles, unsorted. + * @static + */ + getRolesForUserAsync: async function (user, options) { + var id; + var selector; + var filter; + var roles; + + options = Roles._normalizeOptions(options); + + Roles._checkScopeName(options.scope); + + options = Object.assign( + { + fullObjects: false, + onlyAssigned: false, + anyScope: false, + onlyScoped: false, + }, + options + ); + + if (user && typeof user === "object") { + id = user._id; + } else { + id = user; + } + + if (!id) return []; + + selector = { + "user._id": id, + }; + + filter = { + fields: { "inheritedRoles._id": 1 }, + }; + + if (!options.anyScope) { + selector.scope = { $in: [options.scope] }; + + if (!options.onlyScoped) { + selector.scope.$in.push(null); + } + } + + if (options.onlyAssigned) { + delete filter.fields["inheritedRoles._id"]; + filter.fields["role._id"] = 1; + } + + if (options.fullObjects) { + delete filter.fields; + } + + roles = await Meteor.roleAssignment.find(selector, filter).fetchAsync(); + + if (options.fullObjects) { + return roles; + } + + return [ + ...new Set( + roles.reduce((rev, current) => { + if (current.inheritedRoles) { + return rev.concat(current.inheritedRoles.map((r) => r._id)); + } else if (current.role) { + rev.push(current.role._id); + } + return rev; + }, []) + ), + ]; + }, + + /** + * Retrieve cursor of all existing roles. + * + * @method getAllRoles + * @param {Object} [queryOptions] Options which are passed directly + * through to `Meteor.roles.find(query, options)`. + * @return {Cursor} Cursor of existing roles. + * @static + */ + getAllRoles: function (queryOptions) { + queryOptions = queryOptions || { sort: { _id: 1 } }; + + return Meteor.roles.find({}, queryOptions); + }, + + /** + * Retrieve all users who are in target role. + * + * Options: + * + * @method getUsersInRole + * @param {Array|String} roles Name of role or an array of roles. If array, users + * returned will have at least one of the roles + * specified but need not have _all_ roles. + * Roles do not have to exist. + * @param {Object|String} [options] Options: + * - `scope`: name of the scope to restrict roles to; user's global + * roles will also be checked + * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * - `onlyScoped`: if set, only roles in the specified scope are returned + * - `queryOptions`: options which are passed directly + * through to `Meteor.users.find(query, options)` + * + * Alternatively, it can be a scope name string. + * @param {Object} [queryOptions] Options which are passed directly + * through to `Meteor.users.find(query, options)` + * @return {Cursor} Cursor of users in roles. + * @static + */ + getUsersInRoleAsync: async function (roles, options, queryOptions) { + var ids; + + ids = ( + await Roles.getUserAssignmentsForRole(roles, options).fetchAsync() + ).map((a) => a.user._id); + + return Meteor.users.find( + { _id: { $in: ids } }, + (options && options.queryOptions) || queryOptions || {} + ); + }, + + /** + * Retrieve all assignments of a user which are for the target role. + * + * Options: + * + * @method getUserAssignmentsForRole + * @param {Array|String} roles Name of role or an array of roles. If array, users + * returned will have at least one of the roles + * specified but need not have _all_ roles. + * Roles do not have to exist. + * @param {Object|String} [options] Options: + * - `scope`: name of the scope to restrict roles to; user's global + * roles will also be checked + * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * - `queryOptions`: options which are passed directly + * through to `Meteor.roleAssignment.find(query, options)` + + * Alternatively, it can be a scope name string. + * @return {Cursor} Cursor of user assignments for roles. + * @static + */ + getUserAssignmentsForRole: function (roles, options) { + options = Roles._normalizeOptions(options); + + options = Object.assign( + { + anyScope: false, + queryOptions: {}, + }, + options + ); + + return Roles._getUsersInRoleCursor(roles, options, options.queryOptions); + }, + + /** + * @method _getUsersInRoleCursor + * @param {Array|String} roles Name of role or an array of roles. If array, ids of users are + * returned which have at least one of the roles + * assigned but need not have _all_ roles. + * Roles do not have to exist. + * @param {Object|String} [options] Options: + * - `scope`: name of the scope to restrict roles to; user's global + * roles will also be checked + * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * + * Alternatively, it can be a scope name string. + * @param {Object} [filter] Options which are passed directly + * through to `Meteor.roleAssignment.find(query, options)` + * @return {Object} Cursor to the assignment documents + * @private + * @static + */ + _getUsersInRoleCursor: function (roles, options, filter) { + var selector; + + options = Roles._normalizeOptions(options); + + options = Object.assign( + { + anyScope: false, + onlyScoped: false, + }, + options + ); + + // ensure array to simplify code + if (!Array.isArray(roles)) roles = [roles]; + + Roles._checkScopeName(options.scope); + + filter = Object.assign( + { + fields: { "user._id": 1 }, + }, + filter + ); + + selector = { + "inheritedRoles._id": { $in: roles }, + }; + + if (!options.anyScope) { + selector.scope = { $in: [options.scope] }; + + if (!options.onlyScoped) { + selector.scope.$in.push(null); + } + } + + return Meteor.roleAssignment.find(selector, filter); + }, + + /** + * Deprecated. Use `getScopesForUser` instead. + * + * @method getGroupsForUser + * @static + * @deprecated + */ + getGroupsForUserAsync: async function (...args) { + if (!getGroupsForUserDeprecationWarning) { + getGroupsForUserDeprecationWarning = true; + console && + console.warn( + "getGroupsForUser has been deprecated. Use getScopesForUser instead." + ); + } + + return Roles.getScopesForUser(...args); + }, + + /** + * Retrieve users scopes, if any. + * + * @method getScopesForUser + * @param {String|Object} user User ID or an actual user object. + * @param {Array|String} [roles] Name of roles to restrict scopes to. + * + * @return {Array} Array of user's scopes, unsorted. + * @static + */ + getScopesForUserAsync: async function (user, roles) { + var scopes; + var id; + + if (roles && !Array.isArray(roles)) roles = [roles]; + + if (user && typeof user === "object") { + id = user._id; + } else { + id = user; + } + + if (!id) return []; + + const selector = { + "user._id": id, + scope: { $ne: null }, + }; + + if (roles) { + selector["inheritedRoles._id"] = { $in: roles }; + } + + scopes = ( + await Meteor.roleAssignment + .find(selector, { fields: { scope: 1 } }) + .fetchAsync() + ).map((obi) => obi.scope); + + return [...new Set(scopes)]; + }, + + /** + * Rename a scope. + * + * Roles assigned with a given scope are changed to be under the new scope. + * + * @method renameScope + * @param {String} oldName Old name of a scope. + * @param {String} newName New name of a scope. + * @static + */ + renameScopeAsync: async function (oldName, newName) { + var count; + + Roles._checkScopeName(oldName); + Roles._checkScopeName(newName); + + if (oldName === newName) return; + + do { + count = await Meteor.roleAssignment.updateAsync( + { + scope: oldName, + }, + { + $set: { + scope: newName, + }, + }, + { multi: true } + ); + } while (count > 0); + }, + + /** + * Remove a scope. + * + * Roles assigned with a given scope are removed. + * + * @method removeScope + * @param {String} name The name of a scope. + * @static + */ + removeScopeAsync: async function (name) { + Roles._checkScopeName(name); + + await Meteor.roleAssignment.removeAsync({ scope: name }); + }, + + /** + * Throw an exception if `roleName` is an invalid role name. + * + * @method _checkRoleName + * @param {String} roleName A role name to match against. + * @private + * @static + */ + _checkRoleName: function (roleName) { + if ( + !roleName || + typeof roleName !== "string" || + roleName.trim() !== roleName + ) { + throw new Error("Invalid role name '" + roleName + "'."); + } + }, + + /** + * Find out if a role is an ancestor of another role. + * + * WARNING: If you check this on the client, please make sure all roles are published. + * + * @method isParentOf + * @param {String} parentRoleName The role you want to research. + * @param {String} childRoleName The role you expect to be among the children of parentRoleName. + * @static + */ + isParentOfAsync: async function (parentRoleName, childRoleName) { + if (parentRoleName === childRoleName) { + return true; + } + + if (parentRoleName == null || childRoleName == null) { + return false; + } + + Roles._checkRoleName(parentRoleName); + Roles._checkRoleName(childRoleName); + + var rolesToCheck = [parentRoleName]; + while (rolesToCheck.length !== 0) { + var roleName = rolesToCheck.pop(); + + if (roleName === childRoleName) { + return true; + } + + var role = await Meteor.roles.findOneAsync({ _id: roleName }); + + // This should not happen, but this is a problem to address at some other time. + if (!role) continue; + + rolesToCheck = rolesToCheck.concat(role.children.map((r) => r._id)); + } + + return false; + }, + + /** + * Normalize options. + * + * @method _normalizeOptions + * @param {Object} options Options to normalize. + * @return {Object} Normalized options. + * @private + * @static + */ + _normalizeOptions: function (options) { + options = options === undefined ? {} : options; + + if (options === null || typeof options === "string") { + options = { scope: options }; + } + + options.scope = Roles._normalizeScopeName(options.scope); + + return options; + }, + + /** + * Normalize scope name. + * + * @method _normalizeScopeName + * @param {String} scopeName A scope name to normalize. + * @return {String} Normalized scope name. + * @private + * @static + */ + _normalizeScopeName: function (scopeName) { + // map undefined and null to null + if (scopeName == null) { + return null; + } else { + return scopeName; + } + }, + + /** + * Throw an exception if `scopeName` is an invalid scope name. + * + * @method _checkRoleName + * @param {String} scopeName A scope name to match against. + * @private + * @static + */ + _checkScopeName: function (scopeName) { + if (scopeName === null) return; + + if ( + !scopeName || + typeof scopeName !== "string" || + scopeName.trim() !== scopeName + ) { + throw new Error("Invalid scope name '" + scopeName + "'."); + } + }, +}); diff --git a/roles/roles_server.js b/roles/roles_server.js index 9a1857d8..8bef6f7e 100644 --- a/roles/roles_server.js +++ b/roles/roles_server.js @@ -1,20 +1,44 @@ /* global Meteor, Roles */ -if (Meteor.roles.createIndex) { - Meteor.roleAssignment.createIndex({ 'user._id': 1, 'inheritedRoles._id': 1, scope: 1 }) - Meteor.roleAssignment.createIndex({ 'user._id': 1, 'role._id': 1, scope: 1 }) - Meteor.roleAssignment.createIndex({ 'role._id': 1 }) - Meteor.roleAssignment.createIndex({ scope: 1, 'user._id': 1, 'inheritedRoles._id': 1 }) // Adding userId and roleId might speed up other queries depending on the first index - Meteor.roleAssignment.createIndex({ 'inheritedRoles._id': 1 }) - - Meteor.roles.createIndex({ 'children._id': 1 }) +if (Meteor.roles.createIndexAsync) { + Meteor.roleAssignment.createIndexAsync({ + "user._id": 1, + "inheritedRoles._id": 1, + scope: 1, + }); + Meteor.roleAssignment.createIndexAsync({ + "user._id": 1, + "role._id": 1, + scope: 1, + }); + Meteor.roleAssignment.createIndexAsync({ "role._id": 1 }); + Meteor.roleAssignment.createIndexAsync({ + scope: 1, + "user._id": 1, + "inheritedRoles._id": 1, + }); // Adding userId and roleId might speed up other queries depending on the first index + Meteor.roleAssignment.createIndexAsync({ "inheritedRoles._id": 1 }); + + Meteor.roles.createIndexAsync({ "children._id": 1 }); } else { - Meteor.roleAssignment._ensureIndex({ 'user._id': 1, 'inheritedRoles._id': 1, scope: 1 }) - Meteor.roleAssignment._ensureIndex({ 'user._id': 1, 'role._id': 1, scope: 1 }) - Meteor.roleAssignment._ensureIndex({ 'role._id': 1 }) - Meteor.roleAssignment._ensureIndex({ scope: 1, 'user._id': 1, 'inheritedRoles._id': 1 }) // Adding userId and roleId might speed up other queries depending on the first index - Meteor.roleAssignment._ensureIndex({ 'inheritedRoles._id': 1 }) - - Meteor.roles._ensureIndex({ 'children._id': 1 }) + Meteor.roleAssignment._ensureIndex({ + "user._id": 1, + "inheritedRoles._id": 1, + scope: 1, + }); + Meteor.roleAssignment._ensureIndex({ + "user._id": 1, + "role._id": 1, + scope: 1, + }); + Meteor.roleAssignment._ensureIndex({ "role._id": 1 }); + Meteor.roleAssignment._ensureIndex({ + scope: 1, + "user._id": 1, + "inheritedRoles._id": 1, + }); // Adding userId and roleId might speed up other queries depending on the first index + Meteor.roleAssignment._ensureIndex({ "inheritedRoles._id": 1 }); + + Meteor.roles._ensureIndex({ "children._id": 1 }); } /* @@ -22,20 +46,17 @@ if (Meteor.roles.createIndex) { * * Use a named publish function so clients can check `ready()` state. */ -Meteor.publish('_roles', function () { - var loggedInUserId = this.userId - var fields = { roles: 1 } +Meteor.publish("_roles", function () { + var loggedInUserId = this.userId; + var fields = { roles: 1 }; if (!loggedInUserId) { - this.ready() - return + this.ready(); + return; } - return Meteor.users.find( - { _id: loggedInUserId }, - { fields: fields } - ) -}) + return Meteor.users.find({ _id: loggedInUserId }, { fields: fields }); +}); Object.assign(Roles, { /** @@ -48,7 +69,7 @@ Object.assign(Roles, { * @static */ _isNewRole: function (role) { - return !('name' in role) && 'children' in role + return !("name" in role) && "children" in role; }, /** @@ -61,7 +82,7 @@ Object.assign(Roles, { * @static */ _isOldRole: function (role) { - return 'name' in role && !('children' in role) + return "name" in role && !("children" in role); }, /** @@ -74,7 +95,7 @@ Object.assign(Roles, { * @static */ _isNewField: function (roles) { - return Array.isArray(roles) && (typeof roles[0] === 'object') + return Array.isArray(roles) && typeof roles[0] === "object"; }, /** @@ -87,7 +108,10 @@ Object.assign(Roles, { * @static */ _isOldField: function (roles) { - return (Array.isArray(roles) && (typeof roles[0] === 'string')) || ((typeof roles === 'object') && !Array.isArray(roles)) + return ( + (Array.isArray(roles) && typeof roles[0] === "string") || + (typeof roles === "object" && !Array.isArray(roles)) + ); }, /** @@ -99,12 +123,13 @@ Object.assign(Roles, { * @static */ _convertToNewRole: function (oldRole) { - if (!(typeof oldRole.name === 'string')) throw new Error("Role name '" + oldRole.name + "' is not a string.") + if (!(typeof oldRole.name === "string")) + throw new Error("Role name '" + oldRole.name + "' is not a string."); return { _id: oldRole.name, - children: [] - } + children: [], + }; }, /** @@ -116,11 +141,12 @@ Object.assign(Roles, { * @static */ _convertToOldRole: function (newRole) { - if (!(typeof newRole._id === 'string')) throw new Error("Role name '" + newRole._id + "' is not a string.") + if (!(typeof newRole._id === "string")) + throw new Error("Role name '" + newRole._id + "' is not a string."); return { - name: newRole._id - } + name: newRole._id, + }; }, /** @@ -133,38 +159,40 @@ Object.assign(Roles, { * @static */ _convertToNewField: function (oldRoles, convertUnderscoresToDots) { - var roles = [] + var roles = []; if (Array.isArray(oldRoles)) { oldRoles.forEach(function (role, index) { - if (!(typeof role === 'string')) throw new Error("Role '" + role + "' is not a string.") + if (!(typeof role === "string")) + throw new Error("Role '" + role + "' is not a string."); roles.push({ _id: role, scope: null, - assigned: true - }) - }) - } else if (typeof oldRoles === 'object') { + assigned: true, + }); + }); + } else if (typeof oldRoles === "object") { Object.entries(oldRoles).forEach(([group, rolesArray]) => { - if (group === '__global_roles__') { - group = null + if (group === "__global_roles__") { + group = null; } else if (convertUnderscoresToDots) { // unescape - group = group.replace(/_/g, '.') + group = group.replace(/_/g, "."); } rolesArray.forEach(function (role) { - if (!(typeof role === 'string')) throw new Error("Role '" + role + "' is not a string.") + if (!(typeof role === "string")) + throw new Error("Role '" + role + "' is not a string."); roles.push({ _id: role, scope: group, - assigned: true - }) - }) - }) + assigned: true, + }); + }); + }); } - return roles + return roles; }, /** @@ -177,40 +205,49 @@ Object.assign(Roles, { * @static */ _convertToOldField: function (newRoles, usingGroups) { - var roles + var roles; if (usingGroups) { - roles = {} + roles = {}; } else { - roles = [] + roles = []; } newRoles.forEach(function (userRole) { - if (!(typeof userRole === 'object')) throw new Error("Role '" + userRole + "' is not an object.") + if (!(typeof userRole === "object")) + throw new Error("Role '" + userRole + "' is not an object."); // We assume that we are converting back a failed migration, so values can only be // what were valid values in 1.0. So no group names starting with $ and no subroles. if (userRole.scope) { - if (!usingGroups) throw new Error("Role '" + userRole._id + "' with scope '" + userRole.scope + "' without enabled groups.") + if (!usingGroups) + throw new Error( + "Role '" + + userRole._id + + "' with scope '" + + userRole.scope + + "' without enabled groups." + ); // escape - var scope = userRole.scope.replace(/\./g, '_') + var scope = userRole.scope.replace(/\./g, "_"); - if (scope[0] === '$') throw new Error("Group name '" + scope + "' start with $.") + if (scope[0] === "$") + throw new Error("Group name '" + scope + "' start with $."); - roles[scope] = roles[scope] || [] - roles[scope].push(userRole._id) + roles[scope] = roles[scope] || []; + roles[scope].push(userRole._id); } else { if (usingGroups) { - roles.__global_roles__ = roles.__global_roles__ || [] - roles.__global_roles__.push(userRole._id) + roles.__global_roles__ = roles.__global_roles__ || []; + roles.__global_roles__.push(userRole._id); } else { - roles.push(userRole._id) + roles.push(userRole._id); } } - }) - return roles + }); + return roles; }, /** @@ -222,13 +259,16 @@ Object.assign(Roles, { * @static */ _defaultUpdateUser: function (user, roles) { - Meteor.users.update({ - _id: user._id, - // making sure nothing changed in meantime - roles: user.roles - }, { - $set: { roles } - }) + Meteor.users.update( + { + _id: user._id, + // making sure nothing changed in meantime + roles: user.roles, + }, + { + $set: { roles }, + } + ); }, /** @@ -240,8 +280,8 @@ Object.assign(Roles, { * @static */ _defaultUpdateRole: function (oldRole, newRole) { - Meteor.roles.remove(oldRole._id) - Meteor.roles.insert(newRole) + Meteor.roles.remove(oldRole._id); + Meteor.roles.insert(newRole); }, /** @@ -254,10 +294,10 @@ Object.assign(Roles, { */ _dropCollectionIndex: function (collection, indexName) { try { - collection._dropIndex(indexName) + collection._dropIndex(indexName); } catch (e) { - if (e.name !== 'MongoError') throw e - if (!/index not found/.test(e.err || e.errmsg)) throw e + if (e.name !== "MongoError") throw e; + if (!/index not found/.test(e.err || e.errmsg)) throw e; } }, @@ -273,22 +313,25 @@ Object.assign(Roles, { * @static */ _forwardMigrate: function (updateUser, updateRole, convertUnderscoresToDots) { - updateUser = updateUser || Roles._defaultUpdateUser - updateRole = updateRole || Roles._defaultUpdateRole + updateUser = updateUser || Roles._defaultUpdateUser; + updateRole = updateRole || Roles._defaultUpdateRole; - Roles._dropCollectionIndex(Meteor.roles, 'name_1') + Roles._dropCollectionIndex(Meteor.roles, "name_1"); Meteor.roles.find().forEach(function (role, index, cursor) { if (!Roles._isNewRole(role)) { - updateRole(role, Roles._convertToNewRole(role)) + updateRole(role, Roles._convertToNewRole(role)); } - }) + }); Meteor.users.find().forEach(function (user, index, cursor) { if (!Roles._isNewField(user.roles)) { - updateUser(user, Roles._convertToNewField(user.roles, convertUnderscoresToDots)) + updateUser( + user, + Roles._convertToNewField(user.roles, convertUnderscoresToDots) + ); } - }) + }); }, /** @@ -301,21 +344,26 @@ Object.assign(Roles, { * @static */ _forwardMigrate2: function (userSelector) { - userSelector = userSelector || {} - Object.assign(userSelector, { roles: { $ne: null } }) + userSelector = userSelector || {}; + Object.assign(userSelector, { roles: { $ne: null } }); Meteor.users.find(userSelector).forEach(function (user, index) { - user.roles.filter((r) => r.assigned).forEach(r => { - // Added `ifExists` to make it less error-prone - Roles._addUserToRole(user._id, r._id, { scope: r.scope, ifExists: true }) - }) - - Meteor.users.update({ _id: user._id }, { $unset: { roles: '' } }) - }) + user.roles + .filter((r) => r.assigned) + .forEach((r) => { + // Added `ifExists` to make it less error-prone + Roles._addUserToRole(user._id, r._id, { + scope: r.scope, + ifExists: true, + }); + }); + + Meteor.users.update({ _id: user._id }, { $unset: { roles: "" } }); + }); // No need to keep the indexes around - Roles._dropCollectionIndex(Meteor.users, 'roles._id_1_roles.scope_1') - Roles._dropCollectionIndex(Meteor.users, 'roles.scope_1') + Roles._dropCollectionIndex(Meteor.users, "roles._id_1_roles.scope_1"); + Roles._dropCollectionIndex(Meteor.users, "roles.scope_1"); }, /** @@ -334,23 +382,23 @@ Object.assign(Roles, { * @static */ _backwardMigrate: function (updateUser, updateRole, usingGroups) { - updateUser = updateUser || Roles._defaultUpdateUser - updateRole = updateRole || Roles._defaultUpdateRole + updateUser = updateUser || Roles._defaultUpdateUser; + updateRole = updateRole || Roles._defaultUpdateRole; - Roles._dropCollectionIndex(Meteor.users, 'roles._id_1_roles.scope_1') - Roles._dropCollectionIndex(Meteor.users, 'roles.scope_1') + Roles._dropCollectionIndex(Meteor.users, "roles._id_1_roles.scope_1"); + Roles._dropCollectionIndex(Meteor.users, "roles.scope_1"); Meteor.roles.find().forEach(function (role, index, cursor) { if (!Roles._isOldRole(role)) { - updateRole(role, Roles._convertToOldRole(role)) + updateRole(role, Roles._convertToOldRole(role)); } - }) + }); Meteor.users.find().forEach(function (user, index, cursor) { if (!Roles._isOldField(user.roles)) { - updateUser(user, Roles._convertToOldField(user.roles, usingGroups)) + updateUser(user, Roles._convertToOldField(user.roles, usingGroups)); } - }) + }); }, /** @@ -363,44 +411,49 @@ Object.assign(Roles, { * @static */ _backwardMigrate2: function (assignmentSelector) { - assignmentSelector = assignmentSelector || {} + assignmentSelector = assignmentSelector || {}; if (Meteor.users.createIndex) { - Meteor.users.createIndex({ 'roles._id': 1, 'roles.scope': 1 }) - Meteor.users.createIndex({ 'roles.scope': 1 }) + Meteor.users.createIndex({ "roles._id": 1, "roles.scope": 1 }); + Meteor.users.createIndex({ "roles.scope": 1 }); } else { - Meteor.users._ensureIndex({ 'roles._id': 1, 'roles.scope': 1 }) - Meteor.users._ensureIndex({ 'roles.scope': 1 }) + Meteor.users._ensureIndex({ "roles._id": 1, "roles.scope": 1 }); + Meteor.users._ensureIndex({ "roles.scope": 1 }); } - Meteor.roleAssignment.find(assignmentSelector).forEach(r => { - const roles = Meteor.users.findOne({ _id: r.user._id }).roles || [] + Meteor.roleAssignment.find(assignmentSelector).forEach((r) => { + const roles = Meteor.users.findOne({ _id: r.user._id }).roles || []; - const currentRole = roles.find(oldRole => oldRole._id === r.role._id && oldRole.scope === r.scope) + const currentRole = roles.find( + (oldRole) => oldRole._id === r.role._id && oldRole.scope === r.scope + ); if (currentRole) { - currentRole.assigned = true + currentRole.assigned = true; } else { roles.push({ _id: r.role._id, scope: r.scope, - assigned: true - }) + assigned: true, + }); - r.inheritedRoles.forEach(inheritedRole => { - const currentInheritedRole = roles.find(oldRole => oldRole._id === inheritedRole._id && oldRole.scope === r.scope) + r.inheritedRoles.forEach((inheritedRole) => { + const currentInheritedRole = roles.find( + (oldRole) => + oldRole._id === inheritedRole._id && oldRole.scope === r.scope + ); if (!currentInheritedRole) { roles.push({ _id: inheritedRole._id, scope: r.scope, - assigned: false - }) + assigned: false, + }); } - }) + }); } - Meteor.users.update({ _id: r.user._id }, { $set: { roles } }) - Meteor.roleAssignment.remove({ _id: r._id }) - }) - } -}) + Meteor.users.update({ _id: r.user._id }, { $set: { roles } }); + Meteor.roleAssignment.remove({ _id: r._id }); + }); + }, +}); From 0796250c20adc3abe92edbad3daefc6573102a48 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Wed, 12 Apr 2023 13:06:24 +0200 Subject: [PATCH 02/53] method names --- .gitignore | 1 + roles/roles_common_async.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 11e07b25..03f05ca1 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ docs/ node_modules/ .npm/ someapp/ +.DS_Store \ No newline at end of file diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 753eaae8..456328aa 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -529,7 +529,7 @@ Object.assign(Roles, { * @private * @static */ - _addUserToRole: async function (userId, roleName, options) { + _addUserToRoleAsync: async function (userId, roleName, options) { Roles._checkRoleName(roleName); Roles._checkScopeName(options.scope); From 67675d331264d5c3a5fbb460f30b4545ce96e807 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Wed, 26 Apr 2023 17:11:58 +0200 Subject: [PATCH 03/53] buggy Role check fixed --- roles/roles_common_async.js | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 456328aa..ac416026 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -41,6 +41,19 @@ if (typeof Roles === "undefined") { var getGroupsForUserDeprecationWarning = false; +/** + * Helper, resolves async some + * @param {*} arr + * @param {*} predicate + * @returns + */ +const asyncSome = async (arr, predicate) => { + for (let e of arr) { + if (await predicate(e)) return true; + } + return false; +}; + Object.assign(Roles, { /** * Used as a global group (now scope) name. Not used anymore. @@ -792,23 +805,16 @@ Object.assign(Roles, { selector.scope = { $in: [options.scope, null] }; } - // Convert to Promises first, then check via some - const rolesPromises = roles.map( - (roleName) => - new Promise(async (res, rej) => { - selector["inheritedRoles._id"] = roleName; - - res( - (await Meteor.roleAssignment - .find(selector, { limit: 1 }) - .countAsync()) > 0 - ); - }) - ); - - const result = await Promise.all(rolesPromises); + const res = await asyncSome(roles, async (roleName) => { + selector["inheritedRoles._id"] = roleName; + const out = + (await Meteor.roleAssignment + .find(selector, { limit: 1 }) + .countAsync()) > 0; + return out; + }); - return result.some((r) => r); + return res; }, /** From 4a56f242a7d1dd48800695ecde0c9b63ff6d88c2 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Mon, 22 May 2023 08:20:21 +0200 Subject: [PATCH 04/53] async fixes --- roles/roles_common_async.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index ac416026..09428593 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -564,6 +564,28 @@ Object.assign(Roles, { } // This might create duplicates, because we don't have a unique index, but that's all right. In case there are two, withdrawing the role will effectively kill them both. + const existingAssignment = await Meteor.roleAssignment.findOneAsync({ + "user._id": userId, + "role._id": roleName, + scope: options.scope, + }); + + let insertedId; + if (existingAssignment) { + await Meteor.roleAssignment.updateAsync(existingAssignment._id, { + $set: { + user: { _id: userId }, + role: { _id: roleName }, + scope: options.scope, + }, + }); + } else { + insertedId = await Meteor.roleAssignment.insertAsync({ + user: { _id: userId }, + role: { _id: roleName }, + scope: options.scope, + }); + } const res = await Meteor.roleAssignment.upsertAsync( { "user._id": userId, @@ -579,9 +601,9 @@ Object.assign(Roles, { } ); - if (res.insertedId) { + if (insertedId) { await Meteor.roleAssignment.updateAsync( - { _id: res.insertedId }, + { _id: insertedId }, { $set: { inheritedRoles: [ From d1ff02d5f2fb816048e174adad8174942ffe0813 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Mon, 22 May 2023 11:07:28 +0200 Subject: [PATCH 05/53] add roles fixes --- roles/roles_common_async.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 09428593..30a86608 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -571,6 +571,7 @@ Object.assign(Roles, { }); let insertedId; + let res; if (existingAssignment) { await Meteor.roleAssignment.updateAsync(existingAssignment._id, { $set: { @@ -579,6 +580,8 @@ Object.assign(Roles, { scope: options.scope, }, }); + + res = await Meteor.roleAssignment.findOneAsync(existingAssignment._id); } else { insertedId = await Meteor.roleAssignment.insertAsync({ user: { _id: userId }, @@ -586,7 +589,7 @@ Object.assign(Roles, { scope: options.scope, }); } - const res = await Meteor.roleAssignment.upsertAsync( + /*const res = await Meteor.roleAssignment.upsertAsync( { "user._id": userId, "role._id": roleName, @@ -599,7 +602,7 @@ Object.assign(Roles, { scope: options.scope, }, } - ); + );*/ if (insertedId) { await Meteor.roleAssignment.updateAsync( @@ -613,6 +616,8 @@ Object.assign(Roles, { }, } ); + + res = await Meteor.roleAssignment.findOneAsync({ _id: insertedId }); } return res; From 366f4fd5f4fa0d6de4e8d4f2c40895649cf693cc Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Mon, 22 May 2023 17:54:06 +0200 Subject: [PATCH 06/53] create Role upsert fix --- roles/roles_common_async.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 30a86608..5d71357d 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -84,17 +84,29 @@ Object.assign(Roles, { options ); - var result = await Meteor.roles.upsertAsync( - { _id: roleName }, - { $setOnInsert: { children: [] } } - ); + let insertedId = null; + + const existingRole = await Meteor.roles.findOneAsync({ _id: roleName }); + + if (existingRole) { + await Meteor.roles.updateAsync( + { _id: roleName }, + { $setOnInsert: { children: [] } } + ); + return null; + } else { + insertedId = await Meteor.roles.insertAsync({ + _id: roleName, + children: [], + }); + } - if (!result.insertedId) { + if (!insertedId) { if (options.unlessExists) return null; throw new Error("Role '" + roleName + "' already exists."); } - return result.insertedId; + return insertedId; }, /** From d2fc40957455aa6f53aa93bd113d488def21fc08 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:53:41 +0200 Subject: [PATCH 07/53] re-added fiber version of createIndex --- roles/roles_server.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/roles/roles_server.js b/roles/roles_server.js index 8bef6f7e..e42ba29e 100644 --- a/roles/roles_server.js +++ b/roles/roles_server.js @@ -19,6 +19,26 @@ if (Meteor.roles.createIndexAsync) { Meteor.roleAssignment.createIndexAsync({ "inheritedRoles._id": 1 }); Meteor.roles.createIndexAsync({ "children._id": 1 }); +} else if (Meteor.roles.createIndex) { + Meteor.roleAssignment.createIndex({ + "user._id": 1, + "inheritedRoles._id": 1, + scope: 1, + }); + Meteor.roleAssignment.createIndex({ + "user._id": 1, + "role._id": 1, + scope: 1, + }); + Meteor.roleAssignment.createIndex({ "role._id": 1 }); + Meteor.roleAssignment.createIndex({ + scope: 1, + "user._id": 1, + "inheritedRoles._id": 1, + }); // Adding userId and roleId might speed up other queries depending on the first index + Meteor.roleAssignment.createIndex({ "inheritedRoles._id": 1 }); + + Meteor.roles.createIndex({ "children._id": 1 }); } else { Meteor.roleAssignment._ensureIndex({ "user._id": 1, From 64519897c73d115b9d632c59d80aa63f1cd28aa5 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 08:56:03 +0200 Subject: [PATCH 08/53] build(core): add lint script to package.json --- package.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/package.json b/package.json index e8948dbe..83a5b220 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,18 @@ "setup-test": "rm -rf ./someapp && meteor create --minimal someapp && cd someapp && cp ../.coverage.json . && meteor npm i --save puppeteer && mkdir packages && ln -s ../../ ./packages/roles", "test": "npm run setup-test && cd someapp && TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles; istanbul report --include .coverage/summary.json --root . --dir .coverage", "test:watch": "cd someapp && TEST_WATCH=1 COVERAGE=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", + "lint": "standard -v ./", "todobeforepublish": "rm -rf .npm/ node_modules/ someapp/ docs/" }, "dependencies": { "istanbul": "^0.4.5", "standard": "^17.1.0", "yuidocjs": "^0.10.2" + }, + "standard": { + "ignore": [ + "**/.meteor/", + "**/packages/" + ] } } From 4c853eb884cd08fa05b284666aebb5cf1713e14b Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 09:08:45 +0200 Subject: [PATCH 09/53] fix: standard lint fixed --- package.js | 6 +- package.json | 4 +- roles/client/debug.js | 2 +- roles/client/uiHelpers.js | 6 +- roles/roles_common.js | 77 +++++++------------- roles/roles_server.js | 20 +++--- roles/tests/client.js | 26 ++++--- roles/tests/server.js | 144 ++++++++++++++++++-------------------- 8 files changed, 126 insertions(+), 159 deletions(-) diff --git a/package.js b/package.js index 3e61a7f9..e15b6b12 100644 --- a/package.js +++ b/package.js @@ -10,7 +10,7 @@ Package.describe({ Package.onUse(function (api) { api.versionsFrom(['1.12', '2.3', '2.8.0']) - var both = ['client', 'server'] + const both = ['client', 'server'] api.use([ 'ecmascript', @@ -45,12 +45,12 @@ Package.onTest(function (api) { ]) Npm.depends({ - 'chai': '4.2.0' + chai: '4.2.0' }) api.versionsFrom('2.3') - var both = ['client', 'server'] + const both = ['client', 'server'] // `accounts-password` is included so `Meteor.users` exists diff --git a/package.json b/package.json index 83a5b220..c7b64671 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "test": "npm run setup-test && cd someapp && TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles; istanbul report --include .coverage/summary.json --root . --dir .coverage", "test:watch": "cd someapp && TEST_WATCH=1 COVERAGE=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", "lint": "standard -v ./", + "lint:fix": "standard --fix -v ./", "todobeforepublish": "rm -rf .npm/ node_modules/ someapp/ docs/" }, "dependencies": { @@ -14,7 +15,8 @@ "standard": { "ignore": [ "**/.meteor/", - "**/packages/" + "**/packages/", + "examples/" ] } } diff --git a/roles/client/debug.js b/roles/client/debug.js index 0cb1f431..4e2ebd33 100644 --- a/roles/client/debug.js +++ b/roles/client/debug.js @@ -13,7 +13,7 @@ Roles.debug = false try { if (localStorage) { - var temp = localStorage.getItem('Roles.debug') + const temp = localStorage.getItem('Roles.debug') if (typeof temp !== 'undefined') { Roles.debug = !!temp diff --git a/roles/client/uiHelpers.js b/roles/client/uiHelpers.js index 7ee2991c..e73040a8 100644 --- a/roles/client/uiHelpers.js +++ b/roles/client/uiHelpers.js @@ -42,9 +42,9 @@ Roles._uiHelpers = { * @for UIHelpers */ isInRole: function (role, scope) { - var user = Meteor.user() - var comma = (role || '').indexOf(',') - var roles + const user = Meteor.user() + const comma = (role || '').indexOf(',') + let roles if (!user) return false if (!Match.test(role, String)) return false diff --git a/roles/roles_common.js b/roles/roles_common.js index 629bdea7..f05d6206 100644 --- a/roles/roles_common.js +++ b/roles/roles_common.js @@ -39,7 +39,7 @@ if (typeof Roles === 'undefined') { Roles = {} // eslint-disable-line no-global-assign } -var getGroupsForUserDeprecationWarning = false +let getGroupsForUserDeprecationWarning = false Object.assign(Roles, { @@ -69,7 +69,7 @@ Object.assign(Roles, { unlessExists: false }, options) - var result = Meteor.roles.upsert({ _id: roleName }, { $setOnInsert: { children: [] } }) + const result = Meteor.roles.upsert({ _id: roleName }, { $setOnInsert: { children: [] } }) if (!result.insertedId) { if (options.unlessExists) return null @@ -89,8 +89,8 @@ Object.assign(Roles, { * @static */ deleteRole: function (roleName) { - var roles - var inheritedRoles + let roles + let inheritedRoles Roles._checkRoleName(roleName) @@ -138,15 +138,14 @@ Object.assign(Roles, { * @static */ renameRole: function (oldName, newName) { - var role - var count + let count Roles._checkRoleName(oldName) Roles._checkRoleName(newName) if (oldName === newName) return - role = Meteor.roles.findOne({ _id: oldName }) + const role = Meteor.roles.findOne({ _id: oldName }) if (!role) { throw new Error('Role \'' + oldName + '\' does not exist.') @@ -217,14 +216,11 @@ Object.assign(Roles, { * @static */ _addRoleToParent: function (roleName, parentName) { - var role - var count - Roles._checkRoleName(roleName) Roles._checkRoleName(parentName) // query to get role's children - role = Meteor.roles.findOne({ _id: roleName }) + const role = Meteor.roles.findOne({ _id: roleName }) if (!role) { throw new Error('Role \'' + roleName + '\' does not exist.') @@ -235,7 +231,7 @@ Object.assign(Roles, { throw new Error('Roles \'' + roleName + '\' and \'' + parentName + '\' would form a cycle.') } - count = Meteor.roles.update({ + const count = Meteor.roles.update({ _id: parentName, 'children._id': { $ne: role._id @@ -294,7 +290,7 @@ Object.assign(Roles, { // check for role existence // this would not really be needed, but we are trying to match addRolesToParent - let role = Meteor.roles.findOne({ _id: roleName }, { fields: { _id: 1 } }) + const role = Meteor.roles.findOne({ _id: roleName }, { fields: { _id: 1 } }) if (!role) { throw new Error('Role \'' + roleName + '\' does not exist.') @@ -352,7 +348,7 @@ Object.assign(Roles, { * @static */ addUsersToRoles: function (users, roles, options) { - var id + let id if (!users) throw new Error('Missing \'users\' param.') if (!roles) throw new Error('Missing \'roles\' param.') @@ -405,7 +401,7 @@ Object.assign(Roles, { * @static */ setUserRoles: function (users, roles, options) { - var id + let id if (!users) throw new Error('Missing \'users\' param.') if (!roles) throw new Error('Missing \'roles\' param.') @@ -510,13 +506,11 @@ Object.assign(Roles, { * @static */ _getParentRoleNames: function (role) { - var parentRoles - if (!role) { return [] } - parentRoles = new Set([role._id]) + const parentRoles = new Set([role._id]) parentRoles.forEach(roleName => { Meteor.roles.find({ 'children._id': roleName }).fetch().forEach(parentRole => { @@ -662,9 +656,7 @@ Object.assign(Roles, { * @static */ userIsInRole: function (user, roles, options) { - var id - var selector - + let id options = Roles._normalizeOptions(options) // ensure array to simplify code @@ -689,9 +681,7 @@ Object.assign(Roles, { if (!id) return false if (typeof id !== 'string') return false - selector = { - 'user._id': id - } + const selector = { 'user._id': id } if (!options.anyScope) { selector.scope = { $in: [options.scope, null] } @@ -723,10 +713,7 @@ Object.assign(Roles, { * @static */ getRolesForUser: function (user, options) { - var id - var selector - var filter - var roles + let id options = Roles._normalizeOptions(options) @@ -747,13 +734,8 @@ Object.assign(Roles, { if (!id) return [] - selector = { - 'user._id': id - } - - filter = { - fields: { 'inheritedRoles._id': 1 } - } + const selector = { 'user._id': id } + const filter = { fields: { 'inheritedRoles._id': 1 } } if (!options.anyScope) { selector.scope = { $in: [options.scope] } @@ -772,7 +754,7 @@ Object.assign(Roles, { delete filter.fields } - roles = Meteor.roleAssignment.find(selector, filter).fetch() + const roles = Meteor.roleAssignment.find(selector, filter).fetch() if (options.fullObjects) { return roles @@ -828,9 +810,7 @@ Object.assign(Roles, { * @static */ getUsersInRole: function (roles, options, queryOptions) { - var ids - - ids = Roles.getUserAssignmentsForRole(roles, options).fetch().map(a => a.user._id) + const ids = Roles.getUserAssignmentsForRole(roles, options).fetch().map(a => a.user._id) return Meteor.users.find({ _id: { $in: ids } }, ((options && options.queryOptions) || queryOptions) || {}) }, @@ -886,8 +866,6 @@ Object.assign(Roles, { * @static */ _getUsersInRoleCursor: function (roles, options, filter) { - var selector - options = Roles._normalizeOptions(options) options = Object.assign({ @@ -904,9 +882,7 @@ Object.assign(Roles, { fields: { 'user._id': 1 } }, filter) - selector = { - 'inheritedRoles._id': { $in: roles } - } + const selector = { 'inheritedRoles._id': { $in: roles } } if (!options.anyScope) { selector.scope = { $in: [options.scope] } @@ -946,8 +922,7 @@ Object.assign(Roles, { * @static */ getScopesForUser: function (user, roles) { - var scopes - var id + let id if (roles && !Array.isArray(roles)) roles = [roles] @@ -968,7 +943,7 @@ Object.assign(Roles, { selector['inheritedRoles._id'] = { $in: roles } } - scopes = Meteor.roleAssignment.find(selector, { fields: { scope: 1 } }).fetch().map(obi => obi.scope) + const scopes = Meteor.roleAssignment.find(selector, { fields: { scope: 1 } }).fetch().map(obi => obi.scope) return [...new Set(scopes)] }, @@ -984,7 +959,7 @@ Object.assign(Roles, { * @static */ renameScope: function (oldName, newName) { - var count + let count Roles._checkScopeName(oldName) Roles._checkScopeName(newName) @@ -1053,15 +1028,15 @@ Object.assign(Roles, { Roles._checkRoleName(parentRoleName) Roles._checkRoleName(childRoleName) - var rolesToCheck = [parentRoleName] + let rolesToCheck = [parentRoleName] while (rolesToCheck.length !== 0) { - var roleName = rolesToCheck.pop() + const roleName = rolesToCheck.pop() if (roleName === childRoleName) { return true } - var role = Meteor.roles.findOne({ _id: roleName }) + const role = Meteor.roles.findOne({ _id: roleName }) // This should not happen, but this is a problem to address at some other time. if (!role) continue diff --git a/roles/roles_server.js b/roles/roles_server.js index ec104820..a432e6cc 100644 --- a/roles/roles_server.js +++ b/roles/roles_server.js @@ -22,23 +22,25 @@ if (Meteor.roles.createIndexAsync) { ].forEach(index => indexFnAssignment(index)) indexFnRoles({ 'children._id': 1 }) - /* * Publish logged-in user's roles so client-side checks can work. * * Use a named publish function so clients can check `ready()` state. */ -Meteor.publish("_roles", function () { - var loggedInUserId = this.userId; - var fields = { roles: 1 }; +Meteor.publish('_roles', function () { + const loggedInUserId = this.userId + const fields = { roles: 1 } if (!loggedInUserId) { this.ready(); return; } - return Meteor.users.find({ _id: loggedInUserId }, { fields: fields }); -}); + return Meteor.users.find( + { _id: loggedInUserId }, + { fields } + ) +}) Object.assign(Roles, { /** @@ -141,7 +143,7 @@ Object.assign(Roles, { * @static */ _convertToNewField: function (oldRoles, convertUnderscoresToDots) { - var roles = []; + const roles = [] if (Array.isArray(oldRoles)) { oldRoles.forEach(function (role, index) { if (!(typeof role === "string")) @@ -187,7 +189,7 @@ Object.assign(Roles, { * @static */ _convertToOldField: function (newRoles, usingGroups) { - var roles; + let roles if (usingGroups) { roles = {}; @@ -213,7 +215,7 @@ Object.assign(Roles, { ); // escape - var scope = userRole.scope.replace(/\./g, "_"); + const scope = userRole.scope.replace(/\./g, '_') if (scope[0] === "$") throw new Error("Group name '" + scope + "' start with $."); diff --git a/roles/tests/client.js b/roles/tests/client.js index daaab19a..67dc0cab 100644 --- a/roles/tests/client.js +++ b/roles/tests/client.js @@ -9,33 +9,32 @@ import { assert } from 'chai' import '../roles_common' describe('roles', function () { - var users - var roles = ['admin', 'editor', 'user'] + const roles = ['admin', 'editor', 'user'] Tracker.autorun(function () { Roles.assignmentSubscription = Meteor.subscribe('_roleAssignments') }) - users = { - 'eve': { + const users = { + eve: { _id: 'eve' }, - 'bob': { + bob: { _id: 'bob' }, - 'joe': { + joe: { _id: 'joe' } } function testUser (username, expectedRoles, scope) { - var user = users[username] + const user = users[username] // test using user object rather than userId to avoid mocking roles.forEach(function (role) { - var expected = expectedRoles.includes(role) - var msg = username + ' expected to have \'' + role + '\' permission but does not' - var nmsg = username + ' had un-expected permission ' + role + const expected = expectedRoles.includes(role) + const msg = username + ' expected to have \'' + role + '\' permission but does not' + const nmsg = username + ' had un-expected permission ' + role if (expected) { assert.isTrue(Roles.userIsInRole(user, role, scope), msg) @@ -107,9 +106,8 @@ describe('roles', function () { }) it('can check current users roles via template helper', function () { - var isInRole - var expected - var actual + let expected + let actual if (!Roles._handlebarsHelpers) { // probably running package tests outside of a Meteor app. @@ -117,7 +115,7 @@ describe('roles', function () { return } - isInRole = Roles._handlebarsHelpers.isInRole + const isInRole = Roles._handlebarsHelpers.isInRole assert.equal(typeof isInRole, 'function', "'isInRole' helper not registered") expected = true diff --git a/roles/tests/server.js b/roles/tests/server.js index c416ba2e..71cab248 100644 --- a/roles/tests/server.js +++ b/roles/tests/server.js @@ -15,12 +15,14 @@ Meteor.roleAssignment.allow({ remove () { return true } }) +const hasProp = (target, prop) => Object.hasOwnProperty.call(target, prop) + describe('roles', function () { - var users = {} - var roles = ['admin', 'editor', 'user'] + let users = {} + const roles = ['admin', 'editor', 'user'] Meteor.publish('_roleAssignments', function () { - var loggedInUserId = this.userId + const loggedInUserId = this.userId if (!loggedInUserId) { this.ready() @@ -31,12 +33,12 @@ describe('roles', function () { }) function addUser (name) { - return Meteor.users.insert({ 'username': name }) + return Meteor.users.insert({ username: name }) } function testUser (username, expectedRoles, scope) { - var userId = users[username] - var userObj = Meteor.users.findOne({ _id: userId }) + const userId = users[username] + const userObj = Meteor.users.findOne({ _id: userId }) // check using user ids (makes db calls) _innerTest(userId, username, expectedRoles, scope) @@ -48,9 +50,9 @@ describe('roles', function () { function _innerTest (userParam, username, expectedRoles, scope) { // test that user has only the roles expected and no others roles.forEach(function (role) { - var expected = expectedRoles.includes(role) - var msg = username + ' expected to have \'' + role + '\' role but does not' - var nmsg = username + ' had the following un-expected role: ' + role + const expected = expectedRoles.includes(role) + const msg = username + ' expected to have \'' + role + '\' role but does not' + const nmsg = username + ' had the following un-expected role: ' + role if (expected) { assert.isTrue(Roles.userIsInRole(userParam, role, scope), msg) @@ -66,18 +68,18 @@ describe('roles', function () { Meteor.users.remove({}) users = { - 'eve': addUser('eve'), - 'bob': addUser('bob'), - 'joe': addUser('joe') + eve: addUser('eve'), + bob: addUser('bob'), + joe: addUser('joe') } }) it('can create and delete roles', function () { - var role1Id = Roles.createRole('test1') + const role1Id = Roles.createRole('test1') assert.equal(Meteor.roles.findOne()._id, 'test1') assert.equal(Meteor.roles.findOne(role1Id)._id, 'test1') - var role2Id = Roles.createRole('test2') + const role2Id = Roles.createRole('test2') assert.equal(Meteor.roles.findOne({ _id: 'test2' })._id, 'test2') assert.equal(Meteor.roles.findOne(role2Id)._id, 'test2') @@ -275,13 +277,11 @@ describe('roles', function () { }) it('can check user against several roles at once', function () { - var user - Roles.createRole('admin') Roles.createRole('user') Roles.addUsersToRoles(users.eve, ['admin', 'user']) - user = Meteor.users.findOne({ _id: users.eve }) + const user = Meteor.users.findOne({ _id: users.eve }) // we can check the non-existing role assert.isTrue(Roles.userIsInRole(user, ['editor', 'admin'])) @@ -365,8 +365,8 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var eve = Meteor.users.findOne({ _id: users.eve }) - var bob = Meteor.users.findOne({ _id: users.bob }) + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) Roles.addUsersToRoles(eve, ['admin', 'user']) @@ -500,8 +500,8 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var eve = Meteor.users.findOne({ _id: users.eve }) - var bob = Meteor.users.findOne({ _id: users.bob }) + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) // remove user role - one user Roles.addUsersToRoles([eve, bob], ['editor', 'user']) @@ -637,8 +637,8 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var eve = Meteor.users.findOne({ _id: users.eve }) - var bob = Meteor.users.findOne({ _id: users.bob }) + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) Roles.setUserRoles([users.eve, bob], ['editor', 'user']) testUser('eve', ['editor', 'user']) @@ -672,9 +672,9 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var eve = Meteor.users.findOne({ _id: users.eve }) - var bob = Meteor.users.findOne({ _id: users.bob }) - var joe = Meteor.users.findOne({ _id: users.joe }) + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) + const joe = Meteor.users.findOne({ _id: users.joe }) Roles.setUserRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') Roles.setUserRoles([users.bob, users.joe], ['admin'], 'scope2') @@ -732,7 +732,7 @@ describe('roles', function () { Roles.createRole('admin') Roles.createRole('editor') - var eve = Meteor.users.findOne({ _id: users.eve }) + const eve = Meteor.users.findOne({ _id: users.eve }) Roles.addUsersToRoles(eve, 'admin', Roles.GLOBAL_SCOPE) testUser('eve', ['admin'], 'scope1') @@ -747,7 +747,7 @@ describe('roles', function () { Roles.createRole('admin') Roles.createRole('editor') - var eve = Meteor.users.findOne({ _id: users.eve }) + const eve = Meteor.users.findOne({ _id: users.eve }) assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) @@ -776,8 +776,8 @@ describe('roles', function () { }) // compare roles, sorted alphabetically - var expected = roles - var actual = Roles.getAllRoles().fetch().map(r => r._id) + const expected = roles + const actual = Roles.getAllRoles().fetch().map(r => r._id) assert.sameMembers(actual, expected) @@ -799,8 +799,8 @@ describe('roles', function () { Roles.createRole('admin') Roles.createRole('user') - var userId = users.eve - var userObj + const userId = users.eve + let userObj // by userId assert.sameMembers(Roles.getRolesForUser(userId), []) @@ -827,7 +827,7 @@ describe('roles', function () { role: { _id: 'user' }, scope: null, user: { _id: userId }, - inheritedRoles: [{ '_id': 'user' }] + inheritedRoles: [{ _id: 'user' }] }]) }) @@ -835,8 +835,8 @@ describe('roles', function () { Roles.createRole('admin') Roles.createRole('user') - var userId = users.eve - var userObj + const userId = users.eve + let userObj // by userId assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), []) @@ -979,7 +979,7 @@ describe('roles', function () { Roles.createRole('admin') Roles.createRole('user') - var userId = users.eve + const userId = users.eve // add roles Roles.addUsersToRoles(userId, ['user'], 'scope1') @@ -1011,8 +1011,7 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var userId = users.eve - var userObj + const userId = users.eve Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) Roles.addUsersToRoles([users.eve], ['admin', 'user'], 'scope1') @@ -1022,7 +1021,7 @@ describe('roles', function () { assert.sameMembers(Roles.getRolesForUser(userId), ['editor']) // by user object - userObj = Meteor.users.findOne({ _id: userId }) + const userObj = Meteor.users.findOne({ _id: userId }) assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), ['editor', 'admin', 'user']) assert.sameMembers(Roles.getRolesForUser(userObj), ['editor']) }) @@ -1030,8 +1029,8 @@ describe('roles', function () { it('getRolesForUser should not return null entries if user has no roles for scope', function () { Roles.createRole('editor') - var userId = users.eve - var userObj + const userId = users.eve + let userObj // by userId assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), []) @@ -1057,18 +1056,14 @@ describe('roles', function () { it('getRolesForUser should not fail during a call of addUsersToRoles', function () { Roles.createRole('editor') - var userId = users.eve - - const promises = [ - ]; - + const userId = users.eve + const promises = [] const interval = setInterval(() => { - promises.push(Promise.resolve().then(() => { Roles.getRolesForUser(userId); })); - }, 0); - - Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) - clearInterval(interval); + promises.push(Promise.resolve().then(() => { Roles.getRolesForUser(userId) })) + }, 0) + Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + clearInterval(interval) return Promise.all(promises) }) @@ -1086,8 +1081,7 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var userId = users.eve - var userObj + const userId = users.eve Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') Roles.addUsersToRoles([users.eve], ['admin', 'user'], 'scope2') @@ -1096,7 +1090,7 @@ describe('roles', function () { assert.sameMembers(Roles.getScopesForUser(userId), ['scope1', 'scope2']) // by user object - userObj = Meteor.users.findOne({ _id: userId }) + const userObj = Meteor.users.findOne({ _id: userId }) assert.sameMembers(Roles.getScopesForUser(userObj), ['scope1', 'scope2']) }) @@ -1105,8 +1099,7 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var userId = users.eve - var userObj + const userId = users.eve Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'scope2') @@ -1117,7 +1110,7 @@ describe('roles', function () { assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) // by user object - userObj = Meteor.users.findOne({ _id: userId }) + const userObj = Meteor.users.findOne({ _id: userId }) assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) @@ -1127,8 +1120,7 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var userId = users.eve - var userObj + const userId = users.eve Roles.addUsersToRoles([users.eve], ['editor', 'user']) @@ -1139,7 +1131,7 @@ describe('roles', function () { assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), []) // by user object - userObj = Meteor.users.findOne({ _id: userId }) + const userObj = Meteor.users.findOne({ _id: userId }) assert.sameMembers(Roles.getScopesForUser(userObj), []) assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), []) assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), []) @@ -1147,8 +1139,7 @@ describe('roles', function () { }) it('can get all groups for user by role array', function () { - var userId = users.eve - var userObj + const userId = users.eve Roles.createRole('user') Roles.createRole('editor') @@ -1170,7 +1161,7 @@ describe('roles', function () { assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'moderator']), ['group2', 'group3']) // by user object, one role - userObj = Meteor.users.findOne({ _id: userId }) + const userObj = Meteor.users.findOne({ _id: userId }) assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['group2']) assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['group1', 'group2']) assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) @@ -1186,8 +1177,7 @@ describe('roles', function () { Roles.createRole('user') Roles.createRole('editor') - var userId = users.eve - var userObj + const userId = users.eve Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'scope2') @@ -1203,7 +1193,7 @@ describe('roles', function () { assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'editor', 'admin']), ['scope1', 'scope2']) // by user object - userObj = Meteor.users.findOne({ _id: userId }) + const userObj = Meteor.users.findOne({ _id: userId }) assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) @@ -1221,8 +1211,8 @@ describe('roles', function () { Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user']) Roles.addUsersToRoles([users.bob, users.joe], ['editor']) - var expected = [users.eve, users.joe] - var actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + const expected = [users.eve, users.joe] + const actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) assert.sameMembers(actual, expected) }) @@ -1234,8 +1224,8 @@ describe('roles', function () { Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user'], 'scope1') Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') - var expected = [users.eve, users.joe] - var actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) + let expected = [users.eve, users.joe] + let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) assert.sameMembers(actual, expected) @@ -1258,8 +1248,8 @@ describe('roles', function () { Roles.addUsersToRoles([users.eve], ['admin', 'user'], Roles.GLOBAL_SCOPE) Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') - var expected = [users.eve] - var actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) + let expected = [users.eve] + let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) assert.sameMembers(actual, expected) @@ -1285,8 +1275,8 @@ describe('roles', function () { Roles.addUsersToRoles([users.eve], ['admin'], Roles.GLOBAL_SCOPE) Roles.addUsersToRoles([users.bob], ['admin'], 'scope1') - var expected = [users.eve] - var actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + let expected = [users.eve] + let actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) assert.sameMembers(actual, expected) expected = [users.eve, users.bob] @@ -1305,11 +1295,11 @@ describe('roles', function () { Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user'], 'scope1') Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') - var results = Roles.getUsersInRole('admin', 'scope1', { fields: { username: 0 }, limit: 1 }).fetch() + const results = Roles.getUsersInRole('admin', 'scope1', { fields: { username: 0 }, limit: 1 }).fetch() assert.equal(1, results.length) - assert.isTrue(results[0].hasOwnProperty('_id')) - assert.isFalse(results[0].hasOwnProperty('username')) + assert.isTrue(hasProp(results[0], '_id')) + assert.isFalse(hasProp(results[0], 'username')) }) it('can use Roles.GLOBAL_SCOPE to assign blanket roles', function () { From 527307c5cb92370329f51ac89f0c2a13e7ff99e4 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:14:27 +0200 Subject: [PATCH 10/53] tests: added complete working test and dev infrastructure project --- testapp/.coverage.json | 6 + testapp/.gitignore | 4 + testapp/.meteor/.finished-upgraders | 19 + testapp/.meteor/.gitignore | 1 + testapp/.meteor/.id | 7 + testapp/.meteor/packages | 18 + testapp/.meteor/platforms | 2 + testapp/.meteor/release | 1 + testapp/.meteor/versions | 62 + testapp/package-lock.json | 5317 +++++++++++++++++++++++++++ testapp/package.json | 40 + 11 files changed, 5477 insertions(+) create mode 100644 testapp/.coverage.json create mode 100644 testapp/.gitignore create mode 100644 testapp/.meteor/.finished-upgraders create mode 100644 testapp/.meteor/.gitignore create mode 100644 testapp/.meteor/.id create mode 100644 testapp/.meteor/packages create mode 100644 testapp/.meteor/platforms create mode 100644 testapp/.meteor/release create mode 100644 testapp/.meteor/versions create mode 100644 testapp/package-lock.json create mode 100644 testapp/package.json diff --git a/testapp/.coverage.json b/testapp/.coverage.json new file mode 100644 index 00000000..918fc888 --- /dev/null +++ b/testapp/.coverage.json @@ -0,0 +1,6 @@ +{ + "include": [ + "**/packages/roles/**/*", + "**/packages/*alanning_roles.js" + ] +} diff --git a/testapp/.gitignore b/testapp/.gitignore new file mode 100644 index 00000000..d1f89f83 --- /dev/null +++ b/testapp/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +.npm/ +.coverage/ +packages/ diff --git a/testapp/.meteor/.finished-upgraders b/testapp/.meteor/.finished-upgraders new file mode 100644 index 00000000..c07b6ff7 --- /dev/null +++ b/testapp/.meteor/.finished-upgraders @@ -0,0 +1,19 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package +1.4.3-split-account-service-packages +1.5-add-dynamic-import-package +1.7-split-underscore-from-meteor-base +1.8.3-split-jquery-from-blaze diff --git a/testapp/.meteor/.gitignore b/testapp/.meteor/.gitignore new file mode 100644 index 00000000..40830374 --- /dev/null +++ b/testapp/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/testapp/.meteor/.id b/testapp/.meteor/.id new file mode 100644 index 00000000..404dd747 --- /dev/null +++ b/testapp/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +uffl2v6ap9ck.g2922xjmnljm diff --git a/testapp/.meteor/packages b/testapp/.meteor/packages new file mode 100644 index 00000000..63f32aa2 --- /dev/null +++ b/testapp/.meteor/packages @@ -0,0 +1,18 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +meteor@1.11.2 # Shared foundation for all Meteor packages +static-html@1.3.2 # Define static page content in .html files +standard-minifier-css@1.9.2 # CSS minifier run for production mode +standard-minifier-js@2.8.1 # JS minifier run for production mode +es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers +ecmascript@0.16.7 # Enable ECMAScript2015+ syntax in app code +typescript@4.9.4 # Enable TypeScript syntax in .ts and .tsx modules +shell-server@0.5.0 # Server-side component of the `meteor shell` command +webapp@1.13.5 # Serves a Meteor app over HTTP +server-render@0.4.1 # Support for server-side rendering +hot-module-replacement@0.5.3 # Rebuilds the client if there is a change on the client without restarting the server + diff --git a/testapp/.meteor/platforms b/testapp/.meteor/platforms new file mode 100644 index 00000000..efeba1b5 --- /dev/null +++ b/testapp/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/testapp/.meteor/release b/testapp/.meteor/release new file mode 100644 index 00000000..e8cfc7ec --- /dev/null +++ b/testapp/.meteor/release @@ -0,0 +1 @@ +METEOR@2.12 diff --git a/testapp/.meteor/versions b/testapp/.meteor/versions new file mode 100644 index 00000000..24b50021 --- /dev/null +++ b/testapp/.meteor/versions @@ -0,0 +1,62 @@ +autoupdate@1.8.0 +babel-compiler@7.10.4 +babel-runtime@1.5.1 +base64@1.0.12 +blaze-tools@1.1.3 +boilerplate-generator@1.7.1 +caching-compiler@1.2.2 +caching-html-compiler@1.2.1 +callback-hook@1.5.1 +check@1.3.2 +ddp@1.4.1 +ddp-client@2.6.1 +ddp-common@1.4.0 +ddp-server@2.6.1 +diff-sequence@1.1.2 +dynamic-import@0.7.3 +ecmascript@0.16.7 +ecmascript-runtime@0.8.1 +ecmascript-runtime-client@0.12.1 +ecmascript-runtime-server@0.11.0 +ejson@1.1.3 +es5-shim@4.8.0 +fetch@0.1.3 +hot-code-push@1.0.4 +hot-module-replacement@0.5.3 +html-tools@1.1.3 +htmljs@1.1.1 +http@1.0.10 +id-map@1.1.1 +inter-process-messaging@0.1.1 +logging@1.3.2 +meteor@1.11.2 +meteortesting:browser-tests@1.4.2 +meteortesting:mocha@2.1.0 +meteortesting:mocha-core@8.0.1 +minifier-css@1.6.4 +minifier-js@2.7.5 +modern-browsers@0.1.9 +modules@0.19.0 +modules-runtime@0.13.1 +modules-runtime-hot@0.14.2 +mongo-id@1.0.8 +promise@0.12.2 +random@1.2.1 +react-fast-refresh@0.2.7 +reload@1.3.1 +retry@1.1.0 +routepolicy@1.1.1 +server-render@0.4.1 +shell-server@0.5.0 +socket-stream-client@0.5.1 +spacebars-compiler@1.3.1 +standard-minifier-css@1.9.2 +standard-minifier-js@2.8.1 +static-html@1.3.2 +templating-tools@1.2.2 +tracker@1.3.2 +typescript@4.9.4 +underscore@1.0.13 +url@1.3.2 +webapp@1.13.5 +webapp-hashing@1.1.1 diff --git a/testapp/package-lock.json b/testapp/package-lock.json new file mode 100644 index 00000000..375467bb --- /dev/null +++ b/testapp/package-lock.json @@ -0,0 +1,5317 @@ +{ + "name": "someapp", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.5" + } + }, + "@babel/compat-data": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "dev": true + }, + "@babel/core": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.1" + } + }, + "@babel/generator": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", + "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "dev": true, + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "dev": true, + "requires": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" + } + }, + "@babel/highlight": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "dev": true + }, + "@babel/runtime": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/traverse": { + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", + "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + } + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", + "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + } + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@puppeteer/browsers": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz", + "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==", + "dev": true, + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/node": { + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", + "dev": true, + "optional": true + }, + "@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array.prototype.findlastindex": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz", + "integrity": "sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, + "asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "optional": true + }, + "assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", + "optional": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", + "optional": true + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + } + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", + "optional": true, + "requires": { + "hoek": "0.9.x" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserslist": { + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001518", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001518.tgz", + "integrity": "sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chromium-bidi": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.7.tgz", + "integrity": "sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==", + "dev": true, + "requires": { + "mitt": "3.0.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "optional": true, + "requires": { + "delayed-stream": "0.0.5" + } + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cosmiconfig": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", + "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "dev": true, + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "requires": { + "node-fetch": "2.6.7" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", + "optional": true, + "requires": { + "boom": "0.4.x" + } + }, + "ctype": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", + "integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==", + "optional": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + } + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "optional": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "devtools-protocol": { + "version": "0.0.1107588", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz", + "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.479", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.479.tgz", + "integrity": "sha512-ABv1nHMIR8I5n3O3Een0gr6i0mfM+YcTZqjHy3pAYaOjgFG+BMquuKrSyfYf5CbEkLr9uM05RA3pOk4udNB/aQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", + "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.2", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true + }, + "eslint-config-standard-jsx": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz", + "integrity": "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-es": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", + "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz", + "integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.12.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "resolve": "^1.22.3", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", + "dev": true, + "requires": { + "is-core-module": "^2.12.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-plugin-n": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz", + "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", + "dev": true, + "requires": { + "builtins": "^5.0.1", + "eslint-plugin-es": "^4.1.0", + "eslint-utils": "^3.0.0", + "ignore": "^5.1.1", + "is-core-module": "^2.11.0", + "minimatch": "^3.1.2", + "resolve": "^1.22.1", + "semver": "^7.3.8" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true + }, + "eslint-plugin-react": { + "version": "7.33.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.1.tgz", + "integrity": "sha512-L093k0WAMvr6VhNwReB8VgOq5s2LesZmrpPdKz/kZElQDzqS7G7+DnKoqT+w4JwuiGeAhAvHO0fvy0Eyk4ejDA==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==" + }, + "form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", + "optional": true, + "requires": { + "async": "~0.9.0", + "combined-stream": "~0.0.4", + "mime": "~1.2.11" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==", + "optional": true + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==", + "optional": true + } + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + } + }, + "hawk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", + "integrity": "sha512-am8sVA2bCJIw8fuuVcKvmmNnGFUGW8spTkVtj2fXTEZVkfN42bwFZFtDem57eFi+NSxurJB8EQ7Jd3uCHLn8Vw==", + "optional": true, + "requires": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.9.x", + "sntp": "0.2.x" + } + }, + "hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", + "optional": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", + "optional": true, + "requires": { + "asn1": "0.1.11", + "assert-plus": "^0.1.5", + "ctype": "0.5.3" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + } + }, + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "linkify-it": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", + "integrity": "sha512-eGHwtlABkp1NOJSiKUNqBf3SYAS5jPHtvRXPAgNaQwTqmkTahjtiLH9NtxdR5IOPhNvwNMN/diswSfZKzUkhGg==", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "markdown-it": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz", + "integrity": "sha512-Rl8dHHeLuAh3E72OPY0tY7CLvlxgHiLhlshIYswAAabAg4YDBLa6e/LTgNkkxBO2K61ESzoquPQFMw/iMrT1PA==", + "requires": { + "argparse": "~1.0.2", + "entities": "~1.1.1", + "linkify-it": "~1.2.0", + "mdurl": "~1.0.0", + "uc.micro": "^1.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + } + } + }, + "mdn-links": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz", + "integrity": "sha512-m+gI2Hrgro1O0SwqHd9cFkqN8VGzP56eprB63gxu6z9EFQDMeaR083wcNqMVADIbgiMP/TOCCe0ZIXHLBv2tUg==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "meteor-node-stubs": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.5.tgz", + "integrity": "sha512-FLlOFZx3KnZ5s3yPCK+x58DyX9ewN+oQ12LcpwBXMLtzJ/YyprMQVivd6KIrahZbKJrNenPNUGuDS37WUFg+Mw==", + "requires": { + "assert": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.22.0", + "elliptic": "^6.5.4", + "events": "^3.3.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.0", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "0.0.1", + "url": "^0.11.0", + "util": "^0.12.4", + "vm-browserify": "^1.1.2" + }, + "dependencies": { + "asn1.js": { + "version": "5.4.1", + "bundled": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "assert": { + "version": "2.0.0", + "bundled": true, + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "available-typed-arrays": { + "version": "1.0.4", + "bundled": true + }, + "base64-js": { + "version": "1.5.1", + "bundled": true + }, + "bn.js": { + "version": "5.2.0", + "bundled": true + }, + "brorand": { + "version": "1.1.0", + "bundled": true + }, + "browserify-aes": { + "version": "1.2.0", + "bundled": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "bundled": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "bundled": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "bundled": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "bundled": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "bundled": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "5.7.1", + "bundled": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-xor": { + "version": "1.0.3", + "bundled": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "bundled": true + }, + "call-bind": { + "version": "1.0.2", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "cipher-base": { + "version": "1.0.4", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "console-browserify": { + "version": "1.2.0", + "bundled": true + }, + "constants-browserify": { + "version": "1.0.0", + "bundled": true + }, + "create-ecdh": { + "version": "4.0.4", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "bundled": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "bundled": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "bundled": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "define-properties": { + "version": "1.1.3", + "bundled": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "des.js": { + "version": "1.0.1", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "diffie-hellman": { + "version": "5.0.3", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "domain-browser": { + "version": "4.22.0", + "bundled": true + }, + "elliptic": { + "version": "6.5.4", + "bundled": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "es-abstract": { + "version": "1.18.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "bundled": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "bundled": true + }, + "events": { + "version": "3.3.0", + "bundled": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "bundled": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "foreach": { + "version": "2.0.5", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "get-intrinsic": { + "version": "1.1.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "bundled": true + }, + "has-symbols": { + "version": "1.0.2", + "bundled": true + }, + "hash-base": { + "version": "3.1.0", + "bundled": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "bundled": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "bundled": true + }, + "ieee754": { + "version": "1.2.1", + "bundled": true + }, + "inherits": { + "version": "2.0.4", + "bundled": true + }, + "is-arguments": { + "version": "1.1.0", + "bundled": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-bigint": { + "version": "1.0.2", + "bundled": true + }, + "is-boolean-object": { + "version": "1.1.1", + "bundled": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "bundled": true + }, + "is-date-object": { + "version": "1.0.4", + "bundled": true + }, + "is-generator-function": { + "version": "1.0.9", + "bundled": true + }, + "is-nan": { + "version": "1.3.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "bundled": true + }, + "is-number-object": { + "version": "1.0.5", + "bundled": true + }, + "is-regex": { + "version": "1.1.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.6", + "bundled": true + }, + "is-symbol": { + "version": "1.0.4", + "bundled": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.5", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, + "md5.js": { + "version": "1.3.5", + "bundled": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "bundled": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "bundled": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "bundled": true + }, + "object-inspect": { + "version": "1.10.3", + "bundled": true + }, + "object-is": { + "version": "1.1.5", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "bundled": true + }, + "object.assign": { + "version": "4.1.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "os-browserify": { + "version": "0.3.0", + "bundled": true + }, + "pako": { + "version": "1.0.11", + "bundled": true + }, + "parse-asn1": { + "version": "5.1.6", + "bundled": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "path-browserify": { + "version": "1.0.1", + "bundled": true + }, + "pbkdf2": { + "version": "3.1.2", + "bundled": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "process": { + "version": "0.11.10", + "bundled": true + }, + "public-encrypt": { + "version": "4.0.3", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "querystring": { + "version": "0.2.0", + "bundled": true + }, + "querystring-es3": { + "version": "0.2.1", + "bundled": true + }, + "randombytes": { + "version": "2.1.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "bundled": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "ripemd160": { + "version": "2.0.2", + "bundled": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "setimmediate": { + "version": "1.0.5", + "bundled": true + }, + "sha.js": { + "version": "2.4.11", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "stream-browserify": { + "version": "3.0.0", + "bundled": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "stream-http": { + "version": "3.2.0", + "bundled": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "timers-browserify": { + "version": "2.0.12", + "bundled": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tty-browserify": { + "version": "0.0.1", + "bundled": true + }, + "unbox-primitive": { + "version": "1.0.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "url": { + "version": "0.11.0", + "bundled": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "bundled": true + } + } + }, + "util": { + "version": "0.12.4", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "vm-browserify": { + "version": "1.1.2", + "bundled": true + }, + "which-boxed-primitive": { + "version": "1.0.2", + "bundled": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.4", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, + "xtend": { + "version": "4.0.2", + "bundled": true + } + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", + "dev": true + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==" + }, + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.groupby": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.0.tgz", + "integrity": "sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "get-intrinsic": "^1.2.1" + } + }, + "object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-conf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + } + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "optional": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "puppeteer": { + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.11.1.tgz", + "integrity": "sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==", + "dev": true, + "requires": { + "@puppeteer/browsers": "0.5.0", + "cosmiconfig": "8.1.3", + "https-proxy-agent": "5.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "puppeteer-core": "19.11.1" + } + }, + "puppeteer-core": { + "version": "19.11.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.11.1.tgz", + "integrity": "sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==", + "dev": true, + "requires": { + "@puppeteer/browsers": "0.5.0", + "chromium-bidi": "0.4.7", + "cross-fetch": "3.1.5", + "debug": "4.3.4", + "devtools-protocol": "0.0.1107588", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.1", + "proxy-from-env": "1.1.0", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.13.0" + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "request": { + "version": "2.40.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz", + "integrity": "sha512-waNoGB4Z7bPn+lgqPk7l7hhze4Vd68jKccnwLeS7vr9GMxz0iWQbYTbBNWzfIk87Urx7V44pu29qjF/omej+Fw==", + "requires": { + "aws-sign2": "~0.5.0", + "forever-agent": "~0.5.0", + "form-data": "~0.1.0", + "hawk": "1.1.1", + "http-signature": "~0.10.0", + "json-stringify-safe": "~5.0.0", + "mime-types": "~1.0.1", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.3.0", + "qs": "~1.0.0", + "stringstream": "~0.0.4", + "tough-cookie": ">=0.12.0", + "tunnel-agent": "~0.4.0" + }, + "dependencies": { + "mime-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", + "integrity": "sha512-echfutj/t5SoTL4WZpqjA1DCud1XO0WQF3/GJ48YBmc4ZMhCK77QA6Z/w6VTQERLKuJ4drze3kw2TUT8xZXVNw==" + }, + "qs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz", + "integrity": "sha512-tHuOP9TN/1VmDM/ylApGK1QF3PSIP8I6bHDEfoKNQeViREQ/sfu1bAUrA1hoDun8p8Tpm7jcsz47g+3PiGoYdg==" + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "optional": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", + "optional": true, + "requires": { + "hoek": "0.9.x" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.0.tgz", + "integrity": "sha512-jaDqlNSzLtWYW4lvQmU0EnxWMUGQiwHasZl5ZEIwx3S/ijZDjZOzs1y1QqKwKs5vqnFpGtizo4NOYX2s0Voq/g==", + "dev": true, + "requires": { + "eslint": "^8.41.0", + "eslint-config-standard": "17.1.0", + "eslint-config-standard-jsx": "^11.0.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-n": "^15.7.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-react": "^7.32.2", + "standard-engine": "^15.0.0", + "version-guard": "^1.1.1" + } + }, + "standard-engine": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.1.0.tgz", + "integrity": "sha512-VHysfoyxFu/ukT+9v49d4BRXIokFRZuH3z1VRxzFArZdjSCFpro6rEIU3ji7e4AoAtuSfKBkiOmsrDqKW5ZSRw==", + "dev": true, + "requires": { + "get-stdin": "^8.0.0", + "minimist": "^1.2.6", + "pkg-conf": "^3.1.0", + "xdg-basedir": "^4.0.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "optional": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "optional": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", + "optional": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "version-guard": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/version-guard/-/version-guard-1.1.1.tgz", + "integrity": "sha512-MGQLX89UxmYHgDvcXyjBI0cbmoW+t/dANDppNPrno64rYr8nH4SHSuElQuSYdXGEs0mUzdQe1BY+FhVPNsAmJQ==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true + }, + "which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "yui": { + "version": "3.18.1", + "resolved": "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz", + "integrity": "sha512-M4/mHnq5uGvpwKEpRBh3SclL70cpDEus9LNGnrK5ZBzp4HOoueY7EkXfgtRBd+9VOQHWlFukXL2udHE53N4Wqw==", + "requires": { + "request": "~2.40.0" + } + }, + "yuidocjs": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.10.2.tgz", + "integrity": "sha512-g0ZrXsaCmQL9zsvkgD+RxWDsMNkHne5tK72iWYodro9JQlfKxePcV1dwbGhKMy/fl1XCIW3R3erZudohU+PcEw==", + "requires": { + "express": "^4.13.1", + "graceful-fs": "^4.1.2", + "markdown-it": "^4.3.0", + "mdn-links": "^0.1.0", + "minimatch": "^3.0.2", + "rimraf": "^2.4.1", + "yui": "^3.18.1" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + } + } +} diff --git a/testapp/package.json b/testapp/package.json new file mode 100644 index 00000000..2902dffc --- /dev/null +++ b/testapp/package.json @@ -0,0 +1,40 @@ +{ + "name": "testapp", + "private": true, + "scripts": { + "setup": "mkdir packages && ln -s ../../ ./packages/roles", + "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", + "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", + "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", + "report": "nyc report -t .coverage", + "lint": "standard -v ./packages/roles", + "lint:fix": "standard --fix -v ./packages/roles" + }, + "dependencies": { + "@babel/runtime": "^7.17.9", + "meteor-node-stubs": "^1.2.1", + "yuidocjs": "^0.10.2" + }, + "devDependencies": { + "babel-plugin-istanbul": "^6.1.1", + "nyc": "^15.1.0", + "puppeteer": "^19.4.0", + "standard": "^17.1.0" + }, + "babel": { + "env": { + "COVERAGE": { + "plugins": [ + "istanbul" + ] + } + } + }, + "standard": { + "ignore": [ + "**/.meteor/", + "**/examples/", + "**/testapp" + ] + } +} From 42b26bbf1bee0729a14a8d3e95e644b99181946f Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:18:45 +0200 Subject: [PATCH 11/53] docs: add contribution guidelines and testing guide --- CONTRIBUTING.md | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 9 ++--- 2 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..de40874f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,104 @@ +# Contributing to Meteor Roles + +Any contribution to this repository is highly appreciated! + +## Setup development env + +### Clone project and create a new branch to work on + +First, clone this repository and create a new branch to work on. +Branch names should start with a descriptive suffix of their intended outcome, for example: + +- `feature-` for features +- `tests-` for contributions that improve testing +- `fix-` for general fixes +- `build-` for contributions that update the build process +- `ci-` for contributions that improve/update the ci + +```shell +$ git clone git@github.com:Meteor-Community-Packages/meteor-roles.git +$ cd meteor-roles +$ git checkout -b fix-some-issue +``` + +### Initialize test app + +We use a proxy Meteor application to run our tests and handle coverage etc. +This app contains several npm scripts to provide the complete toolchain that is required +for your development and testing needs. + +The setup is very easy. Go into the `testapp` directory, install dependencies and link +the package: + +```shell +$ cd testapp +$ meteor npm install +$ meteor npm run setup # this is important for the tools to work! +``` + +## Development toolchain + +The `testapp` comes with some builtin scripts you can utilize during your development. +They will also be picked up by our CI during pull requests. +Therefore, it's a good call for you, that if they pass or fail, the CI will do so, too. + +**Note: all tools require the npm `setup` script has been executed at least once!** + +### Linter + +We use `standard` as our linter. You can run either the linter or use it's autofix feature for +the most common issues: + +```shell +# in testapp +$ meteor npm run lint # show only outputs +$ meteor npm run lint:fix # with fixes + outputs +``` + +### Tests + +We provide three forms of tests: once, watch, coverage + +#### Once + +Simply runs the test suite once, without coverage collection: + +```shell +$ meteor npm run test +``` + +#### Watch + +Runs the test suite in watch mode, good to use during active development, where your changes +are picked up automatically to re-run the tests: + +```shell +$ meteor npm run test:watch +``` + +#### Coverage + +Runs the test suite once, including coverage report generation. +Generates an html and json report output. + +```shell +$ meteor npm run test:coverage +$ meteor npm run report # summary output in console +``` + +If you want to watch the HTML output to find (un)covered lines, open +the file at `testapp/.coverage/index.html` in your browser. + +## Open a pull request + +If you open a pull request, please make sure the following requirements are met: + +- the `lint` script is passing +- the `test` script is passing +- your contribution is on point and solves one issue (not multiple) +- your commit messages are descriptive and informative +- complex changes are documented in the code with comments or jsDoc-compatible documentation + +Please understand, that there will be a review process and your contribution +might require changes before being merged. This is entirely to ensure quality and is +never used as a personal offense. diff --git a/README.md b/README.md index fad3b5e7..97424b9d 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ There are also older versions of this package: * [Usage examples](#roles-usage) * [Online API docs](#roles-docs) * [Example apps](#roles-example-apps) -* [Running tests](#roles-testing) +* [Running tests](#roles-contributions-development-and-tests)
@@ -467,8 +467,7 @@ The `examples` directory contains Meteor apps which show off the following featu -### Tests +### Contributions, development and tests -To run tests: - 1. `cd meteor-roles` - 2. `npm run test` +Please read our [contribution guidelines](./CONTRIBUTING.md), +which also describe how to set up and run the linter and tests. From 5029e7a1c344f8820a0e27c8dd9789ea93de3232 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:19:07 +0200 Subject: [PATCH 12/53] core: update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 03f05ca1..a8b51588 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ docs/ node_modules/ .npm/ someapp/ -.DS_Store \ No newline at end of file +.DS_Store +.coverage/ From 49d6574154b7f0920ee858faf79d4c49eb8db422 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:19:32 +0200 Subject: [PATCH 13/53] core: move package json to testapp --- package-lock.json | 2800 --------------------------------------------- package.json | 22 - 2 files changed, 2822 deletions(-) delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index fac22c16..00000000 --- a/package-lock.json +++ /dev/null @@ -1,2800 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==" - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==" - }, - "@eslint/eslintrc": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", - "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - } - } - }, - "@eslint/js": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", - "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==" - }, - "@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - }, - "abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=" - }, - "acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "optional": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "is-string": "^1.0.7" - } - }, - "array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" - } - }, - "asn1": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", - "integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc=", - "optional": true - }, - "assert-plus": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", - "integrity": "sha1-7nQAlBMALYTOxyGcasgRgS5yMWA=", - "optional": true - }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" - }, - "aws-sign2": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", - "integrity": "sha1-xXED96F/wDfwLXwuZLYC6iI/fWM=", - "optional": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "boom": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", - "integrity": "sha1-emNune1O/O+xnO9JR6PGffrukRs=", - "optional": true, - "requires": { - "hoek": "0.9.x" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "requires": { - "semver": "^7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "combined-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", - "integrity": "sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8=", - "optional": true, - "requires": { - "delayed-stream": "0.0.5" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "dependencies": { - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "cryptiles": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", - "integrity": "sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw=", - "optional": true, - "requires": { - "boom": "0.4.x" - } - }, - "ctype": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", - "integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8=", - "optional": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "delayed-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", - "integrity": "sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8=", - "optional": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "requires": { - "esutils": "^2.0.2" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "requires": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" - }, - "dependencies": { - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - } - } - }, - "es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "requires": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" - } - }, - "eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.1.0", - "@eslint/js": "8.44.0", - "@humanwhocodes/config-array": "^0.11.10", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.6.0", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "requires": { - "prelude-ls": "^1.2.1" - } - } - } - }, - "eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==" - }, - "eslint-config-standard-jsx": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-11.0.0.tgz", - "integrity": "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ==" - }, - "eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" - } - } - }, - "eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-plugin-n": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz", - "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", - "requires": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.11.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.8" - }, - "dependencies": { - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "eslint-plugin-promise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", - "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==" - }, - "eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - }, - "resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" - } - } - }, - "eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==" - }, - "espree": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", - "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "requires": { - "flat-cache": "^3.0.4" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "forever-agent": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", - "integrity": "sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA=" - }, - "form-data": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", - "integrity": "sha1-kavXiKupcCsaq/qLwBAxoqyeOxI=", - "optional": true, - "requires": { - "async": "~0.9.0", - "combined-stream": "~0.0.4", - "mime": "~1.2.11" - }, - "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", - "optional": true - }, - "mime": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", - "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=", - "optional": true - } - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - } - } - }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==" - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "requires": { - "type-fest": "^0.20.2" - } - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "requires": { - "define-properties": "^1.1.3" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" - }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hawk": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", - "integrity": "sha1-h81JH5tG5OKurKM1QWdmiF0tHtk=", - "optional": true, - "requires": { - "boom": "0.4.x", - "cryptiles": "0.2.x", - "hoek": "0.9.x", - "sntp": "0.2.x" - } - }, - "hoek": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", - "integrity": "sha1-PTIkYrrfB3Fup+uFuviAec3c5QU=", - "optional": true - }, - "http-signature": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", - "integrity": "sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY=", - "optional": true, - "requires": { - "asn1": "0.1.11", - "assert-plus": "^0.1.5", - "ctype": "0.5.3" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "dependencies": { - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - } - } - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "dependencies": { - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" - }, - "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "istanbul": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", - "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.8.x", - "esprima": "2.7.x", - "glob": "^5.0.15", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - } - } - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "requires": { - "minimist": "^1.2.0" - } - }, - "jsx-ast-utils": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.4.tgz", - "integrity": "sha512-fX2TVdCViod6HwKEtSWGHs57oFhVfCMwieb9PuRDgjDPh5XeqJiHFFFJCHxU5cnTc3Bu/GRL+kPiFmw8XWOfKw==", - "requires": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "linkify-it": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz", - "integrity": "sha1-B3NSbDF8j9E71TTuHRgP+Iq/iBo=", - "requires": { - "uc.micro": "^1.0.1" - } - }, - "load-json-file": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", - "requires": { - "graceful-fs": "^4.1.15", - "parse-json": "^4.0.0", - "pify": "^4.0.1", - "strip-bom": "^3.0.0", - "type-fest": "^0.3.0" - }, - "dependencies": { - "type-fest": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==" - } - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz", - "integrity": "sha1-PfNz2+pYepp/7z5WMRtokI91xBQ=", - "requires": { - "argparse": "~1.0.2", - "entities": "~1.1.1", - "linkify-it": "~1.2.0", - "mdurl": "~1.0.0", - "uc.micro": "^1.0.0" - } - }, - "mdn-links": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz", - "integrity": "sha1-4kyDuXy0xYhsw58veAcF+/4nOqU=" - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" - }, - "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", - "requires": { - "mime-db": "1.42.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" - }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "requires": { - "abbrev": "1" - } - }, - "oauth-sign": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", - "integrity": "sha1-y1QPk7srIqfVlBaRoojWDo6pOG4=", - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "requires": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "pkg-conf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", - "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", - "requires": { - "find-up": "^3.0.0", - "load-json-file": "^5.2.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" - } - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", - "optional": true - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "optional": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" - }, - "request": { - "version": "2.40.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.40.0.tgz", - "integrity": "sha1-TdZw9pbx5uhC5mtLXoOTAaub62c=", - "requires": { - "aws-sign2": "~0.5.0", - "forever-agent": "~0.5.0", - "form-data": "~0.1.0", - "hawk": "1.1.1", - "http-signature": "~0.10.0", - "json-stringify-safe": "~5.0.0", - "mime-types": "~1.0.1", - "node-uuid": "~1.4.0", - "oauth-sign": "~0.3.0", - "qs": "~1.0.0", - "stringstream": "~0.0.4", - "tough-cookie": ">=0.12.0", - "tunnel-agent": "~0.4.0" - }, - "dependencies": { - "mime-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz", - "integrity": "sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4=" - }, - "qs": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz", - "integrity": "sha1-UKk+K1r2aRwxvOpdrnjubqGQN2g=" - } - } - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "optional": true - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "dependencies": { - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - } - } - }, - "sntp": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", - "integrity": "sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA=", - "optional": true, - "requires": { - "hoek": "0.9.x" - } - }, - "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/standard/-/standard-17.1.0.tgz", - "integrity": "sha512-jaDqlNSzLtWYW4lvQmU0EnxWMUGQiwHasZl5ZEIwx3S/ijZDjZOzs1y1QqKwKs5vqnFpGtizo4NOYX2s0Voq/g==", - "requires": { - "eslint": "^8.41.0", - "eslint-config-standard": "17.1.0", - "eslint-config-standard-jsx": "^11.0.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.32.2", - "standard-engine": "^15.0.0", - "version-guard": "^1.1.1" - } - }, - "standard-engine": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-15.1.0.tgz", - "integrity": "sha512-VHysfoyxFu/ukT+9v49d4BRXIokFRZuH3z1VRxzFArZdjSCFpro6rEIU3ji7e4AoAtuSfKBkiOmsrDqKW5ZSRw==", - "requires": { - "get-stdin": "^8.0.0", - "minimist": "^1.2.6", - "pkg-conf": "^3.1.0", - "xdg-basedir": "^4.0.0" - } - }, - "string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - } - }, - "stringstream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", - "optional": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==" - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "requires": { - "has-flag": "^1.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "optional": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - } - }, - "tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" - }, - "uglify-js": { - "version": "3.6.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.9.tgz", - "integrity": "sha512-pcnnhaoG6RtrvHJ1dFncAe8Od6Nuy30oaJ82ts6//sGSXOP5UjBMEthiProjXmMNHOfd93sqlkztifFMcb+4yw==", - "optional": true, - "requires": { - "commander": "~2.20.3", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - } - } - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "optional": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "optional": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "version-guard": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/version-guard/-/version-guard-1.1.1.tgz", - "integrity": "sha512-MGQLX89UxmYHgDvcXyjBI0cbmoW+t/dANDppNPrno64rYr8nH4SHSuElQuSYdXGEs0mUzdQe1BY+FhVPNsAmJQ==" - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==" - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - }, - "yui": { - "version": "3.18.1", - "resolved": "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz", - "integrity": "sha1-4AAmnsCntvvHQcu4/L0OZRF7AUw=", - "requires": { - "request": "~2.40.0" - } - }, - "yuidocjs": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.10.2.tgz", - "integrity": "sha1-M5JJZ85hkCTNcO9pTiZ9L5iPc/Y=", - "requires": { - "express": "^4.13.1", - "graceful-fs": "^4.1.2", - "markdown-it": "^4.3.0", - "mdn-links": "^0.1.0", - "minimatch": "^3.0.2", - "rimraf": "^2.4.1", - "yui": "^3.18.1" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index c7b64671..00000000 --- a/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "scripts": { - "setup-test": "rm -rf ./someapp && meteor create --minimal someapp && cd someapp && cp ../.coverage.json . && meteor npm i --save puppeteer && mkdir packages && ln -s ../../ ./packages/roles", - "test": "npm run setup-test && cd someapp && TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles; istanbul report --include .coverage/summary.json --root . --dir .coverage", - "test:watch": "cd someapp && TEST_WATCH=1 COVERAGE=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", - "lint": "standard -v ./", - "lint:fix": "standard --fix -v ./", - "todobeforepublish": "rm -rf .npm/ node_modules/ someapp/ docs/" - }, - "dependencies": { - "istanbul": "^0.4.5", - "standard": "^17.1.0", - "yuidocjs": "^0.10.2" - }, - "standard": { - "ignore": [ - "**/.meteor/", - "**/packages/", - "examples/" - ] - } -} From 94566ccfdc92311614134ed5549f8cdf6febec56 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:20:08 +0200 Subject: [PATCH 14/53] tests: fix tests to enable complete coverage #report --- package.js | 6 +++--- roles/roles_server.js | 7 +++++-- roles/tests/client.js | 36 +++++++++++++----------------------- roles/tests/server.js | 8 ++++++-- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/package.js b/package.js index e15b6b12..904fd2f9 100644 --- a/package.js +++ b/package.js @@ -39,9 +39,9 @@ Package.onUse(function (api) { Package.onTest(function (api) { // Add code coverage api.use([ - 'lmieulet:meteor-packages-coverage@0.2.0', + 'lmieulet:meteor-legacy-coverage', 'lmieulet:meteor-coverage@3.2.0', - 'meteortesting:mocha' + 'meteortesting:mocha@2.1.0' ]) Npm.depends({ @@ -60,6 +60,6 @@ Package.onTest(function (api) { 'mongo' ], both) - api.addFiles('roles/tests/client.js', 'client') api.addFiles('roles/tests/server.js', 'server') + api.addFiles('roles/tests/client.js', 'client') }) diff --git a/roles/roles_server.js b/roles/roles_server.js index a432e6cc..174f310f 100644 --- a/roles/roles_server.js +++ b/roles/roles_server.js @@ -280,8 +280,11 @@ Object.assign(Roles, { try { collection._dropIndex(indexName); } catch (e) { - if (e.name !== "MongoError") throw e; - if (!/index not found/.test(e.err || e.errmsg)) throw e; + const indexNotFound = /index not found/.test(e.message || e.err || e.errmsg) + + if (!indexNotFound) { + throw e + } } }, diff --git a/roles/tests/client.js b/roles/tests/client.js index 67dc0cab..84e8808f 100644 --- a/roles/tests/client.js +++ b/roles/tests/client.js @@ -2,19 +2,19 @@ /* global Roles */ import { Meteor } from 'meteor/meteor' -import { Tracker } from 'meteor/tracker' import { assert } from 'chai' // To ensure that the files are loaded for coverage import '../roles_common' +const safeInsert = (collection, data) => { + try { + collection.insert(data) + } catch (e) {} +} + describe('roles', function () { const roles = ['admin', 'editor', 'user'] - - Tracker.autorun(function () { - Roles.assignmentSubscription = Meteor.subscribe('_roleAssignments') - }) - const users = { eve: { _id: 'eve' @@ -57,52 +57,42 @@ describe('roles', function () { Meteor.user = meteorUserMethod }) - beforeEach((done) => { - Meteor.roleAssignment.insert({ + beforeEach(() => { + safeInsert(Meteor.roleAssignment, { user: users.eve, role: { _id: 'admin' }, inheritedRoles: [{ _id: 'admin' }] }) - Meteor.roleAssignment.insert({ + safeInsert(Meteor.roleAssignment, { user: users.eve, role: { _id: 'editor' }, inheritedRoles: [{ _id: 'editor' }] }) - Meteor.roleAssignment.insert({ + safeInsert(Meteor.roleAssignment, { user: users.bob, role: { _id: 'user' }, inheritedRoles: [{ _id: 'user' }], scope: 'group1' }) - Meteor.roleAssignment.insert({ + safeInsert(Meteor.roleAssignment, { user: users.bob, role: { _id: 'editor' }, inheritedRoles: [{ _id: 'editor' }], scope: 'group2' }) - Meteor.roleAssignment.insert({ + safeInsert(Meteor.roleAssignment, { user: users.joe, role: { _id: 'admin' }, inheritedRoles: [{ _id: 'admin' }] }) - Meteor.roleAssignment.insert({ + safeInsert(Meteor.roleAssignment, { user: users.joe, role: { _id: 'editor' }, inheritedRoles: [{ _id: 'editor' }], scope: 'group1' }) - - const timer = () => { - if (!Roles.assignmentSubscription.ready()) { - Meteor.setTimeout(timer, 100) - } else { - done() - } - } - - timer() }) it('can check current users roles via template helper', function () { diff --git a/roles/tests/server.js b/roles/tests/server.js index 71cab248..b3fb854d 100644 --- a/roles/tests/server.js +++ b/roles/tests/server.js @@ -1418,7 +1418,7 @@ describe('roles', function () { assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope2')) }) - it('migration without global groups', function () { + it('migration without global groups (to v2)', function () { assert.isOk(Meteor.roles.insert({ name: 'admin' })) assert.isOk(Meteor.roles.insert({ name: 'editor' })) assert.isOk(Meteor.roles.insert({ name: 'user' })) @@ -1487,7 +1487,9 @@ describe('roles', function () { }) }) - it('migration with global groups', function () { + it('migration without global groups (to v3)') + + it('migration with global groups (to v2)', function () { assert.isOk(Meteor.roles.insert({ name: 'admin' })) assert.isOk(Meteor.roles.insert({ name: 'editor' })) assert.isOk(Meteor.roles.insert({ name: 'user' })) @@ -1615,6 +1617,8 @@ describe('roles', function () { }) }) + it('migration with global groups (to v3)') + it('_addUserToRole', function () { Roles.createRole('admin') From 494d63b5399b715c28149338ef9fa9d69f3639d8 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:40:38 +0200 Subject: [PATCH 15/53] core: add .meteorignore for package publishing --- .meteorignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .meteorignore diff --git a/.meteorignore b/.meteorignore new file mode 100644 index 00000000..c13dcb8e --- /dev/null +++ b/.meteorignore @@ -0,0 +1,3 @@ +/testapp +/tests +**/*tests.js \ No newline at end of file From 9109a9cf9278d4da04e5c83170a74d12cc037d43 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:41:04 +0200 Subject: [PATCH 16/53] ci: add testsuite --- .github/workflows/testsuite.yml | 65 +++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/workflows/testsuite.yml diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml new file mode 100644 index 00000000..2b007de6 --- /dev/null +++ b/.github/workflows/testsuite.yml @@ -0,0 +1,65 @@ +# the test suite runs the tests (headless, server+client) for multiple Meteor releases +name: Test suite +on: + push: + branches: + - master + pull_request: + +jobs: + lint: + name: Javascript standard lint + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: setup node + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: cache dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-16-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-16- + + - run: cd testapp && npm ci && npm run setup && npm run lint + + test: + name: Meteor ${{ matrix.meteorRelease }} package tests + needs: [lint] + runs-on: ubuntu-latest + strategy: + matrix: + meteorRelease: + - '--release 2.3' + - '--release 2.7.3' + - '--release 2.12.0' + # Latest version + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Setup meteor + uses: meteorengineer/setup-meteor@v1 + with: + meteor-release: ${{ matrix.meteorRelease }} + + - name: cache dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-16-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-16- + + - run: cd testapp && npm run ci && npm run setup && npm run test From bfb1cc54fe0c2076c2bb4d0991c5a6fa31e90c5d Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:46:34 +0200 Subject: [PATCH 17/53] core: ignore examples folder on publishing --- .meteorignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.meteorignore b/.meteorignore index c13dcb8e..e5abd9bb 100644 --- a/.meteorignore +++ b/.meteorignore @@ -1,3 +1,4 @@ /testapp /tests -**/*tests.js \ No newline at end of file +**/*tests.js +/examples From 993bae57c32a1ea5fd18e08418daba9df51af3cb Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:48:04 +0200 Subject: [PATCH 18/53] ci: fix matrix args --- .github/workflows/testsuite.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 2b007de6..a192827a 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -30,15 +30,15 @@ jobs: - run: cd testapp && npm ci && npm run setup && npm run lint test: - name: Meteor ${{ matrix.meteorRelease }} package tests + name: Meteor package tests needs: [lint] runs-on: ubuntu-latest strategy: matrix: meteorRelease: - - '--release 2.3' - - '--release 2.7.3' - - '--release 2.12.0' + - '2.3' + - '2.7.3' + - '2.12.0' # Latest version steps: - name: Checkout code @@ -49,7 +49,7 @@ jobs: with: node-version: 16 - - name: Setup meteor + - name: Setup meteor ${{ matrix.meteorRelease }} uses: meteorengineer/setup-meteor@v1 with: meteor-release: ${{ matrix.meteorRelease }} From 62b6822db504d3961f52a4c70dc781ce82909126 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:50:54 +0200 Subject: [PATCH 19/53] build(core): move chai dependency to package.json --- package.js | 4 --- testapp/package-lock.json | 65 ++++++++++++++++++++++++++++++++++++++- testapp/package.json | 1 + 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/package.js b/package.js index 904fd2f9..c08772ed 100644 --- a/package.js +++ b/package.js @@ -44,10 +44,6 @@ Package.onTest(function (api) { 'meteortesting:mocha@2.1.0' ]) - Npm.depends({ - chai: '4.2.0' - }) - api.versionsFrom('2.3') const both = ['client', 'server'] diff --git a/testapp/package-lock.json b/testapp/package-lock.json index 375467bb..4d42b56e 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -1,5 +1,5 @@ { - "name": "someapp", + "name": "testapp", "requires": true, "lockfileVersion": 1, "dependencies": { @@ -741,6 +741,12 @@ "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", "optional": true }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -962,6 +968,21 @@ "integrity": "sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA==", "dev": true }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -973,6 +994,12 @@ "supports-color": "^5.3.0" } }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -1159,6 +1186,15 @@ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2194,6 +2230,12 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, "get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -2935,6 +2977,15 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4129,6 +4180,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -4937,6 +4994,12 @@ "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", "optional": true }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", diff --git a/testapp/package.json b/testapp/package.json index 2902dffc..e70b46da 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "babel-plugin-istanbul": "^6.1.1", + "chai": "^4.3.7", "nyc": "^15.1.0", "puppeteer": "^19.4.0", "standard": "^17.1.0" From cef37789bd549103b638818d504d9d7671d11520 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:55:02 +0200 Subject: [PATCH 20/53] fix(tests): use correct path in testapp setup script --- testapp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testapp/package.json b/testapp/package.json index e70b46da..e26525ca 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -2,7 +2,7 @@ "name": "testapp", "private": true, "scripts": { - "setup": "mkdir packages && ln -s ../../ ./packages/roles", + "setup": "mkdir packages && ln -s ../ ./packages/roles", "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", From e8a0803091c05e667b3864c2bfb9868984b7c31a Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 12:08:23 +0200 Subject: [PATCH 21/53] fix(tests/ci): update paths and lint args to run linter --- package.js | 2 +- testapp/package.json | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.js b/package.js index c08772ed..db40327c 100644 --- a/package.js +++ b/package.js @@ -1,4 +1,4 @@ -/* global Package, Npm */ +/* eslint-env meteor */ Package.describe({ summary: 'Authorization package for Meteor', diff --git a/testapp/package.json b/testapp/package.json index e26525ca..f894d6e5 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -2,13 +2,13 @@ "name": "testapp", "private": true, "scripts": { - "setup": "mkdir packages && ln -s ../ ./packages/roles", - "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", - "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", - "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", + "setup": "mkdir -p packages && ln -sfn ../../ ./packages/meteor-roles", + "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/meteor-roles", + "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/meteor-roles", + "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/meteor-roles", "report": "nyc report -t .coverage", - "lint": "standard -v ./packages/roles", - "lint:fix": "standard --fix -v ./packages/roles" + "lint": "standard ../", + "lint:fix": "standard --fix ../" }, "dependencies": { "@babel/runtime": "^7.17.9", From eb544d6760e889e07cb3d302d3b7d4e34ee5b343 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 12:10:55 +0200 Subject: [PATCH 22/53] ci: fix tests install --- .github/workflows/testsuite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index a192827a..b7db8de6 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -62,4 +62,4 @@ jobs: restore-keys: | ${{ runner.os }}-node-16- - - run: cd testapp && npm run ci && npm run setup && npm run test + - run: cd testapp && npm ci && npm run setup && npm run test From dea8b4319df37669ab09d67b6268909f54a4c0e4 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 12:14:30 +0200 Subject: [PATCH 23/53] ci: fix meteor version to 2.12 --- .github/workflows/testsuite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index b7db8de6..54a3d379 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -38,7 +38,7 @@ jobs: meteorRelease: - '2.3' - '2.7.3' - - '2.12.0' + - '2.12' # Latest version steps: - name: Checkout code From eaeb5e6b7304c76b8a1e043bc04aa1d88e009016 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 08:56:03 +0200 Subject: [PATCH 24/53] build(core): add lint script to package.json --- package.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 00000000..83a5b220 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "scripts": { + "setup-test": "rm -rf ./someapp && meteor create --minimal someapp && cd someapp && cp ../.coverage.json . && meteor npm i --save puppeteer && mkdir packages && ln -s ../../ ./packages/roles", + "test": "npm run setup-test && cd someapp && TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles; istanbul report --include .coverage/summary.json --root . --dir .coverage", + "test:watch": "cd someapp && TEST_WATCH=1 COVERAGE=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", + "lint": "standard -v ./", + "todobeforepublish": "rm -rf .npm/ node_modules/ someapp/ docs/" + }, + "dependencies": { + "istanbul": "^0.4.5", + "standard": "^17.1.0", + "yuidocjs": "^0.10.2" + }, + "standard": { + "ignore": [ + "**/.meteor/", + "**/packages/" + ] + } +} From 58cb565657576e3b9509af47e65bfb8fd20c9991 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 09:08:45 +0200 Subject: [PATCH 25/53] fix: standard lint fixed --- package.js | 4 ++++ package.json | 4 +++- roles/tests/client.js | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/package.js b/package.js index db40327c..baf94dce 100644 --- a/package.js +++ b/package.js @@ -44,6 +44,10 @@ Package.onTest(function (api) { 'meteortesting:mocha@2.1.0' ]) + Npm.depends({ + chai: '4.2.0' + }) + api.versionsFrom('2.3') const both = ['client', 'server'] diff --git a/package.json b/package.json index 83a5b220..c7b64671 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "test": "npm run setup-test && cd someapp && TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles; istanbul report --include .coverage/summary.json --root . --dir .coverage", "test:watch": "cd someapp && TEST_WATCH=1 COVERAGE=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", "lint": "standard -v ./", + "lint:fix": "standard --fix -v ./", "todobeforepublish": "rm -rf .npm/ node_modules/ someapp/ docs/" }, "dependencies": { @@ -14,7 +15,8 @@ "standard": { "ignore": [ "**/.meteor/", - "**/packages/" + "**/packages/", + "examples/" ] } } diff --git a/roles/tests/client.js b/roles/tests/client.js index 84e8808f..839973f4 100644 --- a/roles/tests/client.js +++ b/roles/tests/client.js @@ -15,6 +15,11 @@ const safeInsert = (collection, data) => { describe('roles', function () { const roles = ['admin', 'editor', 'user'] + + Tracker.autorun(function () { + Roles.assignmentSubscription = Meteor.subscribe('_roleAssignments') + }) + const users = { eve: { _id: 'eve' From 9a8e83205e0783e500d45db0ef91bbf4c237a24c Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:14:27 +0200 Subject: [PATCH 26/53] tests: added complete working test and dev infrastructure project --- testapp/package-lock.json | 65 +-------------------------------------- testapp/package.json | 13 ++++---- 2 files changed, 7 insertions(+), 71 deletions(-) diff --git a/testapp/package-lock.json b/testapp/package-lock.json index 4d42b56e..375467bb 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -1,5 +1,5 @@ { - "name": "testapp", + "name": "someapp", "requires": true, "lockfileVersion": 1, "dependencies": { @@ -741,12 +741,6 @@ "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", "optional": true }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -968,21 +962,6 @@ "integrity": "sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA==", "dev": true }, - "chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -994,12 +973,6 @@ "supports-color": "^5.3.0" } }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true - }, "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -1186,15 +1159,6 @@ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, - "deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2230,12 +2194,6 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", - "dev": true - }, "get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -2977,15 +2935,6 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, - "loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", - "dev": true, - "requires": { - "get-func-name": "^2.0.0" - } - }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4180,12 +4129,6 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -4994,12 +4937,6 @@ "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", "optional": true }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", diff --git a/testapp/package.json b/testapp/package.json index f894d6e5..2902dffc 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -2,13 +2,13 @@ "name": "testapp", "private": true, "scripts": { - "setup": "mkdir -p packages && ln -sfn ../../ ./packages/meteor-roles", - "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/meteor-roles", - "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/meteor-roles", - "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/meteor-roles", + "setup": "mkdir packages && ln -s ../../ ./packages/roles", + "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", + "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", + "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", "report": "nyc report -t .coverage", - "lint": "standard ../", - "lint:fix": "standard --fix ../" + "lint": "standard -v ./packages/roles", + "lint:fix": "standard --fix -v ./packages/roles" }, "dependencies": { "@babel/runtime": "^7.17.9", @@ -17,7 +17,6 @@ }, "devDependencies": { "babel-plugin-istanbul": "^6.1.1", - "chai": "^4.3.7", "nyc": "^15.1.0", "puppeteer": "^19.4.0", "standard": "^17.1.0" From 5e22b58fa6d03194f0f6453574f9597a57424a2c Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:19:07 +0200 Subject: [PATCH 27/53] core: update gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index a8b51588..497cb990 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,4 @@ smart.lock docs/ node_modules/ .npm/ -someapp/ -.DS_Store .coverage/ From 8e175c75f4560db2dfa846f5d2cbe9fc4256a581 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:19:32 +0200 Subject: [PATCH 28/53] core: move package json to testapp --- package.json | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 package.json diff --git a/package.json b/package.json deleted file mode 100644 index c7b64671..00000000 --- a/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "scripts": { - "setup-test": "rm -rf ./someapp && meteor create --minimal someapp && cd someapp && cp ../.coverage.json . && meteor npm i --save puppeteer && mkdir packages && ln -s ../../ ./packages/roles", - "test": "npm run setup-test && cd someapp && TEST_BROWSER_DRIVER=puppeteer COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles; istanbul report --include .coverage/summary.json --root . --dir .coverage", - "test:watch": "cd someapp && TEST_WATCH=1 COVERAGE=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", - "lint": "standard -v ./", - "lint:fix": "standard --fix -v ./", - "todobeforepublish": "rm -rf .npm/ node_modules/ someapp/ docs/" - }, - "dependencies": { - "istanbul": "^0.4.5", - "standard": "^17.1.0", - "yuidocjs": "^0.10.2" - }, - "standard": { - "ignore": [ - "**/.meteor/", - "**/packages/", - "examples/" - ] - } -} From 796689d9d19af18e905e4fe3b6316b357504d761 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:20:08 +0200 Subject: [PATCH 29/53] tests: fix tests to enable complete coverage #report --- roles/tests/client.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/roles/tests/client.js b/roles/tests/client.js index 839973f4..84e8808f 100644 --- a/roles/tests/client.js +++ b/roles/tests/client.js @@ -15,11 +15,6 @@ const safeInsert = (collection, data) => { describe('roles', function () { const roles = ['admin', 'editor', 'user'] - - Tracker.autorun(function () { - Roles.assignmentSubscription = Meteor.subscribe('_roleAssignments') - }) - const users = { eve: { _id: 'eve' From d9a7ee738c7eb144deab86524d69ffe98b7d457f Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:40:38 +0200 Subject: [PATCH 30/53] core: add .meteorignore for package publishing --- .meteorignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.meteorignore b/.meteorignore index e5abd9bb..8cc899f2 100644 --- a/.meteorignore +++ b/.meteorignore @@ -1,4 +1,3 @@ /testapp /tests **/*tests.js -/examples From 0caa9f807944d1203ba4aa1ad112b74a95dda460 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:41:04 +0200 Subject: [PATCH 31/53] ci: add testsuite --- .github/workflows/testsuite.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 54a3d379..2b007de6 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -30,15 +30,15 @@ jobs: - run: cd testapp && npm ci && npm run setup && npm run lint test: - name: Meteor package tests + name: Meteor ${{ matrix.meteorRelease }} package tests needs: [lint] runs-on: ubuntu-latest strategy: matrix: meteorRelease: - - '2.3' - - '2.7.3' - - '2.12' + - '--release 2.3' + - '--release 2.7.3' + - '--release 2.12.0' # Latest version steps: - name: Checkout code @@ -49,7 +49,7 @@ jobs: with: node-version: 16 - - name: Setup meteor ${{ matrix.meteorRelease }} + - name: Setup meteor uses: meteorengineer/setup-meteor@v1 with: meteor-release: ${{ matrix.meteorRelease }} @@ -62,4 +62,4 @@ jobs: restore-keys: | ${{ runner.os }}-node-16- - - run: cd testapp && npm ci && npm run setup && npm run test + - run: cd testapp && npm run ci && npm run setup && npm run test From f95eea63e4abc52ef431e41a731832a45a58ddc8 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:46:34 +0200 Subject: [PATCH 32/53] core: ignore examples folder on publishing --- .meteorignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.meteorignore b/.meteorignore index 8cc899f2..e5abd9bb 100644 --- a/.meteorignore +++ b/.meteorignore @@ -1,3 +1,4 @@ /testapp /tests **/*tests.js +/examples From c6920ac966ca7e1ce977658e72a390f6e39fb285 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:48:04 +0200 Subject: [PATCH 33/53] ci: fix matrix args --- .github/workflows/testsuite.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 2b007de6..a192827a 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -30,15 +30,15 @@ jobs: - run: cd testapp && npm ci && npm run setup && npm run lint test: - name: Meteor ${{ matrix.meteorRelease }} package tests + name: Meteor package tests needs: [lint] runs-on: ubuntu-latest strategy: matrix: meteorRelease: - - '--release 2.3' - - '--release 2.7.3' - - '--release 2.12.0' + - '2.3' + - '2.7.3' + - '2.12.0' # Latest version steps: - name: Checkout code @@ -49,7 +49,7 @@ jobs: with: node-version: 16 - - name: Setup meteor + - name: Setup meteor ${{ matrix.meteorRelease }} uses: meteorengineer/setup-meteor@v1 with: meteor-release: ${{ matrix.meteorRelease }} From ab44ffe6d9e720546002b6a6534e812de103726c Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:50:54 +0200 Subject: [PATCH 34/53] build(core): move chai dependency to package.json --- package.js | 4 --- testapp/package-lock.json | 65 ++++++++++++++++++++++++++++++++++++++- testapp/package.json | 1 + 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/package.js b/package.js index baf94dce..db40327c 100644 --- a/package.js +++ b/package.js @@ -44,10 +44,6 @@ Package.onTest(function (api) { 'meteortesting:mocha@2.1.0' ]) - Npm.depends({ - chai: '4.2.0' - }) - api.versionsFrom('2.3') const both = ['client', 'server'] diff --git a/testapp/package-lock.json b/testapp/package-lock.json index 375467bb..4d42b56e 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -1,5 +1,5 @@ { - "name": "someapp", + "name": "testapp", "requires": true, "lockfileVersion": 1, "dependencies": { @@ -741,6 +741,12 @@ "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", "optional": true }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -962,6 +968,21 @@ "integrity": "sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA==", "dev": true }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -973,6 +994,12 @@ "supports-color": "^5.3.0" } }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -1159,6 +1186,15 @@ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2194,6 +2230,12 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, "get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -2935,6 +2977,15 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4129,6 +4180,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -4937,6 +4994,12 @@ "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", "optional": true }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", diff --git a/testapp/package.json b/testapp/package.json index 2902dffc..e70b46da 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "babel-plugin-istanbul": "^6.1.1", + "chai": "^4.3.7", "nyc": "^15.1.0", "puppeteer": "^19.4.0", "standard": "^17.1.0" From a690b716917c625007ca12a3d432bd724bd17068 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 11:55:02 +0200 Subject: [PATCH 35/53] fix(tests): use correct path in testapp setup script --- testapp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testapp/package.json b/testapp/package.json index e70b46da..e26525ca 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -2,7 +2,7 @@ "name": "testapp", "private": true, "scripts": { - "setup": "mkdir packages && ln -s ../../ ./packages/roles", + "setup": "mkdir packages && ln -s ../ ./packages/roles", "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", From 5e788e2ca78245b952b447f50015ee19641d3742 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 12:08:23 +0200 Subject: [PATCH 36/53] fix(tests/ci): update paths and lint args to run linter --- testapp/package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testapp/package.json b/testapp/package.json index e26525ca..f894d6e5 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -2,13 +2,13 @@ "name": "testapp", "private": true, "scripts": { - "setup": "mkdir packages && ln -s ../ ./packages/roles", - "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", - "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/roles", - "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/roles", + "setup": "mkdir -p packages && ln -sfn ../../ ./packages/meteor-roles", + "test": "TEST_BROWSER_DRIVER=puppeteer meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/meteor-roles", + "test:watch": "TEST_BROWSER_DRIVER=puppeteer TEST_WATCH=1 meteor test-packages --raw-logs --driver-package meteortesting:mocha ./packages/meteor-roles", + "test:coverage": "TEST_BROWSER_DRIVER=puppeteer TEST_CLIENT=1 TEST_SERVER=1 COVERAGE=1 COVERAGE_OUT_JSON=1 COVERAGE_OUT_HTML=1 COVERAGE_APP_FOLDER=$(pwd)/ meteor test-packages --raw-logs --once --driver-package meteortesting:mocha ./packages/meteor-roles", "report": "nyc report -t .coverage", - "lint": "standard -v ./packages/roles", - "lint:fix": "standard --fix -v ./packages/roles" + "lint": "standard ../", + "lint:fix": "standard --fix ../" }, "dependencies": { "@babel/runtime": "^7.17.9", From 5ab110641d03e7a6ba228c200e927a81ffe148f5 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 12:10:55 +0200 Subject: [PATCH 37/53] ci: fix tests install --- .github/workflows/testsuite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index a192827a..b7db8de6 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -62,4 +62,4 @@ jobs: restore-keys: | ${{ runner.os }}-node-16- - - run: cd testapp && npm run ci && npm run setup && npm run test + - run: cd testapp && npm ci && npm run setup && npm run test From 111c251bbeaa3b1168f177e4b7a07db450bb8617 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Tue, 1 Aug 2023 12:14:30 +0200 Subject: [PATCH 38/53] ci: fix meteor version to 2.12 --- .github/workflows/testsuite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index b7db8de6..54a3d379 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -38,7 +38,7 @@ jobs: meteorRelease: - '2.3' - '2.7.3' - - '2.12.0' + - '2.12' # Latest version steps: - name: Checkout code From 20ab907ce764196e4c19d2455bc2248a722841d9 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Tue, 1 Aug 2023 13:40:33 +0200 Subject: [PATCH 39/53] rebase --- .DS_Store | Bin 0 -> 6148 bytes roles/.DS_Store | Bin 0 -> 6148 bytes someapp/.coverage.json | 6 + someapp/.gitignore | 1 + someapp/.meteor/.finished-upgraders | 19 + someapp/.meteor/.gitignore | 1 + someapp/.meteor/.id | 7 + someapp/.meteor/packages | 18 + someapp/.meteor/platforms | 2 + someapp/.meteor/release | 1 + someapp/.meteor/versions | 57 ++ someapp/client/main.css | 4 + someapp/client/main.html | 21 + someapp/client/main.js | 1 + someapp/package-lock.json | 1428 +++++++++++++++++++++++++++ someapp/package.json | 22 + someapp/packages/roles | 1 + someapp/server/main.js | 15 + someapp/tests/main.js | 20 + 19 files changed, 1624 insertions(+) create mode 100644 .DS_Store create mode 100644 roles/.DS_Store create mode 100644 someapp/.coverage.json create mode 100644 someapp/.gitignore create mode 100644 someapp/.meteor/.finished-upgraders create mode 100644 someapp/.meteor/.gitignore create mode 100644 someapp/.meteor/.id create mode 100644 someapp/.meteor/packages create mode 100644 someapp/.meteor/platforms create mode 100644 someapp/.meteor/release create mode 100644 someapp/.meteor/versions create mode 100644 someapp/client/main.css create mode 100644 someapp/client/main.html create mode 100644 someapp/client/main.js create mode 100644 someapp/package-lock.json create mode 100644 someapp/package.json create mode 120000 someapp/packages/roles create mode 100644 someapp/server/main.js create mode 100644 someapp/tests/main.js diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..97a2704690b7e919d553c06d7dd398da483f2f27 GIT binary patch literal 6148 zcmeHKI|>3Z5S{S@f{mqRuHX%V=n1@lg<>NLiq>0sE|2D$PqQrBt%dRiCNG)HOUNsB zc0@$ikHbo2AtE!lp}cJ9n(do+Y?KiN!g0p^xw~D?*UPDs+ZQnIRBm#Wvm9G|+o4eb zDnJFO02QDDLo1LKb~YdSV4g<>sKC!FVBd!VH>`vFwWF@JzDKCs3H1s3Sx0ZYtL(k~e8vCo8K6MFZ2F0j(* zGp6)rS~uh93*Kp`tSp$B)4oyX^resVUNZlTD&4K~uK)9O-==l9_ujM1dGbTt5?_-u z;0!nezs>;9Y?0Qnp<8Fb8E^)+49NE(QU$Ywm7#t*X!Hs|Y%;7uU+xl86BA|$D?^S@ zf|U}jG^8s=uyV#@%F7Z~hE|TCGqX>cIiwp((AgP}nvReex^)Jefqe#!?6D)~|LFVs z|9+7_IRnnXzhWRXhvVUZuawT#+RMpV8>x>}5y`6zw + Minimal Meteor app + + + +

Minimal Meteor app

+

+ This Meteor app uses as few Meteor packages as possible, to keep the + client JavaScript bundle as small as possible. +

+ + + +

Learn Meteor!

+ + diff --git a/someapp/client/main.js b/someapp/client/main.js new file mode 100644 index 00000000..fb4b5bae --- /dev/null +++ b/someapp/client/main.js @@ -0,0 +1 @@ +console.log(`Greetings from ${module.id}!`) diff --git a/someapp/package-lock.json b/someapp/package-lock.json new file mode 100644 index 00000000..ef2dbadb --- /dev/null +++ b/someapp/package-lock.json @@ -0,0 +1,1428 @@ +{ + "name": "someapp", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "requires": { + "@babel/highlight": "^7.22.5" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" + }, + "@babel/highlight": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/runtime": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@puppeteer/browsers": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.5.tgz", + "integrity": "sha512-a0gpUa+XlxZHotoOklh99X6RC5R+hQGcVcYOH+oOIEBfQXPp8Z5c765XAu/zhxsjRuAZN4Xx4vZNlwN4wJro2A==", + "requires": { + "debug": "4.3.4", + "extract-zip": "2.0.1", + "http-proxy-agent": "7.0.0", + "https-proxy-agent": "7.0.1", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "socks-proxy-agent": "8.0.1", + "tar-fs": "3.0.4", + "unbzip2-stream": "1.4.3", + "yargs": "17.7.1" + } + }, + "@types/node": { + "version": "20.4.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", + "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==", + "optional": true + }, + "@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, + "chromium-bidi": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", + "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", + "requires": { + "mitt": "3.0.0" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "requires": { + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "requires": { + "node-fetch": "^2.6.12" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "devtools-protocol": { + "version": "0.0.1135028", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1135028.tgz", + "integrity": "sha512-jEcNGrh6lOXNRJvZb9RjeevtZGrgugPKSMJZxfyxWQnhlKawMPhMtk/dfC+Z/6xNXExlzTKlY5LzIAK/fRpQIw==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "fast-fifo": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz", + "integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==" + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "requires": { + "pend": "~1.2.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", + "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "meteor-node-stubs": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.5.tgz", + "integrity": "sha512-FLlOFZx3KnZ5s3yPCK+x58DyX9ewN+oQ12LcpwBXMLtzJ/YyprMQVivd6KIrahZbKJrNenPNUGuDS37WUFg+Mw==", + "requires": { + "assert": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.22.0", + "elliptic": "^6.5.4", + "events": "^3.3.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.0", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "0.0.1", + "url": "^0.11.0", + "util": "^0.12.4", + "vm-browserify": "^1.1.2" + }, + "dependencies": { + "asn1.js": { + "version": "5.4.1", + "bundled": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "assert": { + "version": "2.0.0", + "bundled": true, + "requires": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "available-typed-arrays": { + "version": "1.0.4", + "bundled": true + }, + "base64-js": { + "version": "1.5.1", + "bundled": true + }, + "bn.js": { + "version": "5.2.0", + "bundled": true + }, + "brorand": { + "version": "1.1.0", + "bundled": true + }, + "browserify-aes": { + "version": "1.2.0", + "bundled": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "bundled": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "bundled": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "bundled": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "bundled": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "bundled": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "5.7.1", + "bundled": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-xor": { + "version": "1.0.3", + "bundled": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "bundled": true + }, + "call-bind": { + "version": "1.0.2", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "cipher-base": { + "version": "1.0.4", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "console-browserify": { + "version": "1.2.0", + "bundled": true + }, + "constants-browserify": { + "version": "1.0.0", + "bundled": true + }, + "create-ecdh": { + "version": "4.0.4", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "bundled": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "bundled": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "bundled": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "define-properties": { + "version": "1.1.3", + "bundled": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "des.js": { + "version": "1.0.1", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "diffie-hellman": { + "version": "5.0.3", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "domain-browser": { + "version": "4.22.0", + "bundled": true + }, + "elliptic": { + "version": "6.5.4", + "bundled": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "es-abstract": { + "version": "1.18.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "bundled": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-object-assign": { + "version": "1.1.0", + "bundled": true + }, + "events": { + "version": "3.3.0", + "bundled": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "bundled": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "foreach": { + "version": "2.0.5", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "get-intrinsic": { + "version": "1.1.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "bundled": true + }, + "has-symbols": { + "version": "1.0.2", + "bundled": true + }, + "hash-base": { + "version": "3.1.0", + "bundled": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "bundled": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "bundled": true + }, + "ieee754": { + "version": "1.2.1", + "bundled": true + }, + "inherits": { + "version": "2.0.4", + "bundled": true + }, + "is-arguments": { + "version": "1.1.0", + "bundled": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-bigint": { + "version": "1.0.2", + "bundled": true + }, + "is-boolean-object": { + "version": "1.1.1", + "bundled": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "bundled": true + }, + "is-date-object": { + "version": "1.0.4", + "bundled": true + }, + "is-generator-function": { + "version": "1.0.9", + "bundled": true + }, + "is-nan": { + "version": "1.3.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "bundled": true + }, + "is-number-object": { + "version": "1.0.5", + "bundled": true + }, + "is-regex": { + "version": "1.1.3", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.6", + "bundled": true + }, + "is-symbol": { + "version": "1.0.4", + "bundled": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.5", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, + "md5.js": { + "version": "1.3.5", + "bundled": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "bundled": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "bundled": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "bundled": true + }, + "object-inspect": { + "version": "1.10.3", + "bundled": true + }, + "object-is": { + "version": "1.1.5", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "bundled": true + }, + "object.assign": { + "version": "4.1.2", + "bundled": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "os-browserify": { + "version": "0.3.0", + "bundled": true + }, + "pako": { + "version": "1.0.11", + "bundled": true + }, + "parse-asn1": { + "version": "5.1.6", + "bundled": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "path-browserify": { + "version": "1.0.1", + "bundled": true + }, + "pbkdf2": { + "version": "3.1.2", + "bundled": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "process": { + "version": "0.11.10", + "bundled": true + }, + "public-encrypt": { + "version": "4.0.3", + "bundled": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "bundled": true + } + } + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "querystring": { + "version": "0.2.0", + "bundled": true + }, + "querystring-es3": { + "version": "0.2.1", + "bundled": true + }, + "randombytes": { + "version": "2.1.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "bundled": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "ripemd160": { + "version": "2.0.2", + "bundled": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "setimmediate": { + "version": "1.0.5", + "bundled": true + }, + "sha.js": { + "version": "2.4.11", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "stream-browserify": { + "version": "3.0.0", + "bundled": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "stream-http": { + "version": "3.2.0", + "bundled": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "bundled": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "timers-browserify": { + "version": "2.0.12", + "bundled": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tty-browserify": { + "version": "0.0.1", + "bundled": true + }, + "unbox-primitive": { + "version": "1.0.1", + "bundled": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "url": { + "version": "0.11.0", + "bundled": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "bundled": true + } + } + }, + "util": { + "version": "0.12.4", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "vm-browserify": { + "version": "1.1.2", + "bundled": true + }, + "which-boxed-primitive": { + "version": "1.0.2", + "bundled": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.4", + "bundled": true, + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, + "xtend": { + "version": "4.0.2", + "bundled": true + } + } + }, + "mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "puppeteer": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-20.8.2.tgz", + "integrity": "sha512-+VRywTRGF09UyiesFL7pcU19Cq7vf2HsE/eulwSpl7YHcr8g8X+Va4qLmp7mOECwteGvP7rU8vQ7PP43fcubbA==", + "requires": { + "@puppeteer/browsers": "1.4.5", + "cosmiconfig": "8.2.0", + "puppeteer-core": "20.8.2" + } + }, + "puppeteer-core": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.8.2.tgz", + "integrity": "sha512-dWo60gFuFPdNhdabW9MMm6GpvkG6tND2D8FvrZ2MF+HggNApHrvLfbERj8vD6vXKV7UqDAJO0KI1OMo3S3Cm5w==", + "requires": { + "@puppeteer/browsers": "1.4.5", + "chromium-bidi": "0.4.16", + "cross-fetch": "4.0.0", + "debug": "4.3.4", + "devtools-protocol": "0.0.1135028", + "ws": "8.13.0" + } + }, + "queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", + "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", + "requires": { + "agent-base": "^7.0.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + } + }, + "streamx": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz", + "integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==", + "requires": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "requires": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "requires": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/someapp/package.json b/someapp/package.json new file mode 100644 index 00000000..fd0ec41c --- /dev/null +++ b/someapp/package.json @@ -0,0 +1,22 @@ +{ + "name": "someapp", + "private": true, + "scripts": { + "start": "meteor run", + "test": "meteor test --once --driver-package meteortesting:mocha", + "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha", + "visualize": "meteor --production --extra-packages bundle-visualizer" + }, + "dependencies": { + "@babel/runtime": "^7.17.9", + "meteor-node-stubs": "^1.2.1", + "puppeteer": "^20.8.2" + }, + "meteor": { + "mainModule": { + "client": "client/main.js", + "server": "server/main.js" + }, + "testModule": "tests/main.js" + } +} diff --git a/someapp/packages/roles b/someapp/packages/roles new file mode 120000 index 00000000..6581736d --- /dev/null +++ b/someapp/packages/roles @@ -0,0 +1 @@ +../../ \ No newline at end of file diff --git a/someapp/server/main.js b/someapp/server/main.js new file mode 100644 index 00000000..0f22191a --- /dev/null +++ b/someapp/server/main.js @@ -0,0 +1,15 @@ +import { Meteor } from 'meteor/meteor' +import { onPageLoad } from 'meteor/server-render' + +Meteor.startup(() => { + // Code to run on server startup. + console.log(`Greetings from ${module.id}!`) +}) + +onPageLoad(sink => { + // Code to run on every request. + sink.renderIntoElementById( + 'server-render-target', + `Server time: ${new Date()}` + ) +}) diff --git a/someapp/tests/main.js b/someapp/tests/main.js new file mode 100644 index 00000000..9a7482e7 --- /dev/null +++ b/someapp/tests/main.js @@ -0,0 +1,20 @@ +import assert from 'assert' + +describe('someapp', function () { + it('package.json has correct name', async function () { + const { name } = await import('../package.json') + assert.strictEqual(name, 'someapp') + }) + + if (Meteor.isClient) { + it('client is not server', function () { + assert.strictEqual(Meteor.isServer, false) + }) + } + + if (Meteor.isServer) { + it('server is not client', function () { + assert.strictEqual(Meteor.isClient, false) + }) + } +}) From 1c3c756ed27e7dda69622a3c5929452e72ba4ec3 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Thu, 24 Aug 2023 12:09:56 +0200 Subject: [PATCH 40/53] =?UTF-8?q?Run=20lint=20&=20fix=20lint=20issues=20?= =?UTF-8?q?=F0=9F=92=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- roles/roles_common_async.js | 653 ++++++++++++++++++------------------ roles/roles_server.js | 187 +++++------ someapp/tests/main.js | 2 + testapp/package-lock.json | 14 +- testapp/package.json | 4 +- 5 files changed, 421 insertions(+), 439 deletions(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 5d71357d..9a97bee8 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -25,21 +25,21 @@ * @module Roles */ if (!Meteor.roles) { - Meteor.roles = new Mongo.Collection("roles"); + Meteor.roles = new Mongo.Collection('roles') } if (!Meteor.roleAssignment) { - Meteor.roleAssignment = new Mongo.Collection("role-assignment"); + Meteor.roleAssignment = new Mongo.Collection('role-assignment') } /** * @class Roles */ -if (typeof Roles === "undefined") { - Roles = {}; // eslint-disable-line no-global-assign +if (typeof Roles === 'undefined') { + Roles = {} // eslint-disable-line no-global-assign } -var getGroupsForUserDeprecationWarning = false; +let getGroupsForUserDeprecationWarning = false /** * Helper, resolves async some @@ -48,11 +48,11 @@ var getGroupsForUserDeprecationWarning = false; * @returns */ const asyncSome = async (arr, predicate) => { - for (let e of arr) { - if (await predicate(e)) return true; + for (const e of arr) { + if (await predicate(e)) return true } - return false; -}; + return false +} Object.assign(Roles, { /** @@ -75,38 +75,38 @@ Object.assign(Roles, { * @static */ createRoleAsync: async function (roleName, options) { - Roles._checkRoleName(roleName); + Roles._checkRoleName(roleName) options = Object.assign( { - unlessExists: false, + unlessExists: false }, options - ); + ) - let insertedId = null; + let insertedId = null - const existingRole = await Meteor.roles.findOneAsync({ _id: roleName }); + const existingRole = await Meteor.roles.findOneAsync({ _id: roleName }) if (existingRole) { await Meteor.roles.updateAsync( { _id: roleName }, { $setOnInsert: { children: [] } } - ); - return null; + ) + return null } else { insertedId = await Meteor.roles.insertAsync({ _id: roleName, - children: [], - }); + children: [] + }) } if (!insertedId) { - if (options.unlessExists) return null; - throw new Error("Role '" + roleName + "' already exists."); + if (options.unlessExists) return null + throw new Error("Role '" + roleName + "' already exists.") } - return insertedId; + return insertedId }, /** @@ -119,59 +119,59 @@ Object.assign(Roles, { * @static */ deleteRoleAsync: async function (roleName) { - var roles; - var inheritedRoles; + let roles + let inheritedRoles - Roles._checkRoleName(roleName); + Roles._checkRoleName(roleName) // Remove all assignments await Meteor.roleAssignment.removeAsync({ - "role._id": roleName, - }); + 'role._id': roleName + }) do { // For all roles who have it as a dependency ... roles = Roles._getParentRoleNames( await Meteor.roles.findOneAsync({ _id: roleName }) - ); + ) for (const r of await Meteor.roles .find({ _id: { $in: roles } }) .fetchAsync()) { await Meteor.roles.updateAsync( { - _id: r._id, + _id: r._id }, { $pull: { children: { - _id: roleName, - }, - }, + _id: roleName + } + } } - ); + ) inheritedRoles = await Roles._getInheritedRoleNamesAsync( await Meteor.roles.findOneAsync({ _id: r._id }) - ); + ) await Meteor.roleAssignment.updateAsync( { - "role._id": r._id, + 'role._id': r._id }, { $set: { inheritedRoles: [r._id, ...inheritedRoles].map((r2) => ({ - _id: r2, - })), - }, + _id: r2 + })) + } }, { multi: true } - ); + ) } - } while (roles.length > 0); + } while (roles.length > 0) // And finally remove the role itself - await Meteor.roles.removeAsync({ _id: roleName }); + await Meteor.roles.removeAsync({ _id: roleName }) }, /** @@ -183,67 +183,66 @@ Object.assign(Roles, { * @static */ renameRoleAsync: async function (oldName, newName) { - var role; - var count; + let count - Roles._checkRoleName(oldName); - Roles._checkRoleName(newName); + Roles._checkRoleName(oldName) + Roles._checkRoleName(newName) - if (oldName === newName) return; + if (oldName === newName) return - role = await Meteor.roles.findOneAsync({ _id: oldName }); + const role = await Meteor.roles.findOneAsync({ _id: oldName }) if (!role) { - throw new Error("Role '" + oldName + "' does not exist."); + throw new Error("Role '" + oldName + "' does not exist.") } - role._id = newName; + role._id = newName - await Meteor.roles.insertAsync(role); + await Meteor.roles.insertAsync(role) do { count = await Meteor.roleAssignment.updateAsync( { - "role._id": oldName, + 'role._id': oldName }, { $set: { - "role._id": newName, - }, + 'role._id': newName + } }, { multi: true } - ); - } while (count > 0); + ) + } while (count > 0) do { count = await Meteor.roleAssignment.updateAsync( { - "inheritedRoles._id": oldName, + 'inheritedRoles._id': oldName }, { $set: { - "inheritedRoles.$._id": newName, - }, + 'inheritedRoles.$._id': newName + } }, { multi: true } - ); - } while (count > 0); + ) + } while (count > 0) do { count = await Meteor.roles.updateAsync( { - "children._id": oldName, + 'children._id': oldName }, { $set: { - "children.$._id": newName, - }, + 'children.$._id': newName + } }, { multi: true } - ); - } while (count > 0); + ) + } while (count > 0) - await Meteor.roles.removeAsync({ _id: oldName }); + await Meteor.roles.removeAsync({ _id: oldName }) }, /** @@ -259,10 +258,10 @@ Object.assign(Roles, { */ addRolesToParentAsync: async function (rolesNames, parentName) { // ensure arrays - if (!Array.isArray(rolesNames)) rolesNames = [rolesNames]; + if (!Array.isArray(rolesNames)) rolesNames = [rolesNames] for (const roleName of rolesNames) { - await Roles._addRoleToParentAsync(roleName, parentName); + await Roles._addRoleToParentAsync(roleName, parentName) } }, @@ -274,62 +273,59 @@ Object.assign(Roles, { * @static */ _addRoleToParentAsync: async function (roleName, parentName) { - var role; - var count; - - Roles._checkRoleName(roleName); - Roles._checkRoleName(parentName); + Roles._checkRoleName(roleName) + Roles._checkRoleName(parentName) // query to get role's children - role = await Meteor.roles.findOneAsync({ _id: roleName }); + const role = await Meteor.roles.findOneAsync({ _id: roleName }) if (!role) { - throw new Error("Role '" + roleName + "' does not exist."); + throw new Error("Role '" + roleName + "' does not exist.") } // detect cycles if ((await Roles._getInheritedRoleNamesAsync(role)).includes(parentName)) { throw new Error( "Roles '" + roleName + "' and '" + parentName + "' would form a cycle." - ); + ) } - count = await Meteor.roles.updateAsync( + const count = await Meteor.roles.updateAsync( { _id: parentName, - "children._id": { - $ne: role._id, - }, + 'children._id': { + $ne: role._id + } }, { $push: { children: { - _id: role._id, - }, - }, + _id: role._id + } + } } - ); + ) // if there was no change, parent role might not exist, or role is // already a subrole; in any case we do not have anything more to do - if (!count) return; + if (!count) return await Meteor.roleAssignment.updateAsync( { - "inheritedRoles._id": parentName, + 'inheritedRoles._id': parentName }, { $push: { inheritedRoles: { $each: [ role._id, - ...(await Roles._getInheritedRoleNamesAsync(role)), - ].map((r) => ({ _id: r })), - }, - }, + ...(await Roles._getInheritedRoleNamesAsync(role)) + ].map((r) => ({ _id: r })) + } + } }, { multi: true } - ); + ) }, /** @@ -345,10 +341,10 @@ Object.assign(Roles, { */ removeRolesFromParentAsync: async function (rolesNames, parentName) { // ensure arrays - if (!Array.isArray(rolesNames)) rolesNames = [rolesNames]; + if (!Array.isArray(rolesNames)) rolesNames = [rolesNames] for (const roleName of rolesNames) { - await Roles._removeRoleFromParentAsync(roleName, parentName); + await Roles._removeRoleFromParentAsync(roleName, parentName) } }, @@ -360,65 +356,65 @@ Object.assign(Roles, { * @static */ _removeRoleFromParentAsync: async function (roleName, parentName) { - Roles._checkRoleName(roleName); - Roles._checkRoleName(parentName); + Roles._checkRoleName(roleName) + Roles._checkRoleName(parentName) // check for role existence // this would not really be needed, but we are trying to match addRolesToParent - let role = await Meteor.roles.findOneAsync( + const role = await Meteor.roles.findOneAsync( { _id: roleName }, { fields: { _id: 1 } } - ); + ) if (!role) { - throw new Error("Role '" + roleName + "' does not exist."); + throw new Error("Role '" + roleName + "' does not exist.") } const count = await Meteor.roles.updateAsync( { - _id: parentName, + _id: parentName }, { $pull: { children: { - _id: role._id, - }, - }, + _id: role._id + } + } } - ); + ) // if there was no change, parent role might not exist, or role was // already not a subrole; in any case we do not have anything more to do - if (!count) return; + if (!count) return // For all roles who have had it as a dependency ... const roles = [ ...(await Roles._getParentRoleNamesAsync( await Meteor.roles.findOneAsync({ _id: parentName }) )), - parentName, - ]; + parentName + ] for (const r of await Meteor.roles .find({ _id: { $in: roles } }) .fetchAsync()) { const inheritedRoles = await Roles._getInheritedRoleNamesAsync( await Meteor.roles.findOneAsync({ _id: r._id }) - ); + ) await Meteor.roleAssignment.updateAsync( { - "role._id": r._id, - "inheritedRoles._id": role._id, + 'role._id': r._id, + 'inheritedRoles._id': role._id }, { $set: { inheritedRoles: [r._id, ...inheritedRoles].map((r2) => ({ - _id: r2, - })), - }, + _id: r2 + })) + } }, { multi: true } - ); + ) } }, @@ -444,35 +440,35 @@ Object.assign(Roles, { * @static */ addUsersToRolesAsync: async function (users, roles, options) { - var id; + let id - if (!users) throw new Error("Missing 'users' param."); - if (!roles) throw new Error("Missing 'roles' param."); + if (!users) throw new Error("Missing 'users' param.") + if (!roles) throw new Error("Missing 'roles' param.") - options = Roles._normalizeOptions(options); + options = Roles._normalizeOptions(options) // ensure arrays - if (!Array.isArray(users)) users = [users]; - if (!Array.isArray(roles)) roles = [roles]; + if (!Array.isArray(users)) users = [users] + if (!Array.isArray(roles)) roles = [roles] - Roles._checkScopeName(options.scope); + Roles._checkScopeName(options.scope) options = Object.assign( { - ifExists: false, + ifExists: false }, options - ); + ) for (const user of users) { - if (typeof user === "object") { - id = user._id; + if (typeof user === 'object') { + id = user._id } else { - id = user; + id = user } for (const role of roles) { - await Roles._addUserToRoleAsync(id, role, options); + await Roles._addUserToRoleAsync(id, role, options) } } }, @@ -500,44 +496,44 @@ Object.assign(Roles, { * @static */ setUserRolesAsync: async function (users, roles, options) { - var id; + let id - if (!users) throw new Error("Missing 'users' param."); - if (!roles) throw new Error("Missing 'roles' param."); + if (!users) throw new Error("Missing 'users' param.") + if (!roles) throw new Error("Missing 'roles' param.") - options = Roles._normalizeOptions(options); + options = Roles._normalizeOptions(options) // ensure arrays - if (!Array.isArray(users)) users = [users]; - if (!Array.isArray(roles)) roles = [roles]; + if (!Array.isArray(users)) users = [users] + if (!Array.isArray(roles)) roles = [roles] - Roles._checkScopeName(options.scope); + Roles._checkScopeName(options.scope) options = Object.assign( { ifExists: false, - anyScope: false, + anyScope: false }, options - ); + ) for (const user of users) { - if (typeof user === "object") { - id = user._id; + if (typeof user === 'object') { + id = user._id } else { - id = user; + id = user } // we first clear all roles for the user - const selector = { "user._id": id }; + const selector = { 'user._id': id } if (!options.anyScope) { - selector.scope = options.scope; + selector.scope = options.scope } - await Meteor.roleAssignment.removeAsync(selector); + await Meteor.roleAssignment.removeAsync(selector) // and then add all for (const role of roles) { - await Roles._addUserToRole(id, role, options); + await Roles._addUserToRole(id, role, options) } } }, @@ -555,53 +551,53 @@ Object.assign(Roles, { * @static */ _addUserToRoleAsync: async function (userId, roleName, options) { - Roles._checkRoleName(roleName); - Roles._checkScopeName(options.scope); + Roles._checkRoleName(roleName) + Roles._checkScopeName(options.scope) if (!userId) { - return; + return } const role = await Meteor.roles.findOneAsync( { _id: roleName }, { fields: { children: 1 } } - ); + ) if (!role) { if (options.ifExists) { - return []; + return [] } else { - throw new Error("Role '" + roleName + "' does not exist."); + throw new Error("Role '" + roleName + "' does not exist.") } } // This might create duplicates, because we don't have a unique index, but that's all right. In case there are two, withdrawing the role will effectively kill them both. const existingAssignment = await Meteor.roleAssignment.findOneAsync({ - "user._id": userId, - "role._id": roleName, - scope: options.scope, - }); + 'user._id': userId, + 'role._id': roleName, + scope: options.scope + }) - let insertedId; - let res; + let insertedId + let res if (existingAssignment) { await Meteor.roleAssignment.updateAsync(existingAssignment._id, { $set: { user: { _id: userId }, role: { _id: roleName }, - scope: options.scope, - }, - }); + scope: options.scope + } + }) - res = await Meteor.roleAssignment.findOneAsync(existingAssignment._id); + res = await Meteor.roleAssignment.findOneAsync(existingAssignment._id) } else { insertedId = await Meteor.roleAssignment.insertAsync({ user: { _id: userId }, role: { _id: roleName }, - scope: options.scope, - }); + scope: options.scope + }) } - /*const res = await Meteor.roleAssignment.upsertAsync( + /* const res = await Meteor.roleAssignment.upsertAsync( { "user._id": userId, "role._id": roleName, @@ -614,7 +610,7 @@ Object.assign(Roles, { scope: options.scope, }, } - );*/ + ); */ if (insertedId) { await Meteor.roleAssignment.updateAsync( @@ -623,16 +619,16 @@ Object.assign(Roles, { $set: { inheritedRoles: [ roleName, - ...(await Roles._getInheritedRoleNamesAsync(role)), - ].map((r) => ({ _id: r })), - }, + ...(await Roles._getInheritedRoleNamesAsync(role)) + ].map((r) => ({ _id: r })) + } } - ); + ) - res = await Meteor.roleAssignment.findOneAsync({ _id: insertedId }); + res = await Meteor.roleAssignment.findOneAsync({ _id: insertedId }) } - return res; + return res }, /** @@ -647,25 +643,23 @@ Object.assign(Roles, { * @static */ _getParentRoleNamesAsync: async function (role) { - var parentRoles; - if (!role) { - return []; + return [] } - parentRoles = new Set([role._id]); + const parentRoles = new Set([role._id]) for (const roleName of parentRoles) { for (const parentRole of await Meteor.roles - .find({ "children._id": roleName }) + .find({ 'children._id': roleName }) .fetchAsync()) { - parentRoles.add(parentRole._id); + parentRoles.add(parentRole._id) } } - parentRoles.delete(role._id); + parentRoles.delete(role._id) - return [...parentRoles]; + return [...parentRoles] }, /** @@ -680,8 +674,8 @@ Object.assign(Roles, { * @static */ _getInheritedRoleNamesAsync: async function (role) { - const inheritedRoles = new Set(); - const nestedRoles = new Set([role]); + const inheritedRoles = new Set() + const nestedRoles = new Set([role]) for (const r in nestedRoles) { const roles = await Meteor.roles @@ -689,15 +683,15 @@ Object.assign(Roles, { { _id: { $in: r.children.map((r) => r._id) } }, { fields: { children: 1 } } ) - .fetchAsync(); + .fetchAsync() for (const r2 of roles) { - inheritedRoles.add(r2._id); - nestedRoles.add(r2); + inheritedRoles.add(r2._id) + nestedRoles.add(r2) } } - return [...inheritedRoles]; + return [...inheritedRoles] }, /** @@ -719,29 +713,29 @@ Object.assign(Roles, { * @static */ removeUsersFromRolesAsync: async function (users, roles, options) { - if (!users) throw new Error("Missing 'users' param."); - if (!roles) throw new Error("Missing 'roles' param."); + if (!users) throw new Error("Missing 'users' param.") + if (!roles) throw new Error("Missing 'roles' param.") - options = Roles._normalizeOptions(options); + options = Roles._normalizeOptions(options) // ensure arrays - if (!Array.isArray(users)) users = [users]; - if (!Array.isArray(roles)) roles = [roles]; + if (!Array.isArray(users)) users = [users] + if (!Array.isArray(roles)) roles = [roles] - Roles._checkScopeName(options.scope); + Roles._checkScopeName(options.scope) for (const user of users) { - if (!user) return; + if (!user) return for (const role of roles) { - let id; - if (typeof user === "object") { - id = user._id; + let id + if (typeof user === 'object') { + id = user._id } else { - id = user; + id = user } - await Roles._removeUserFromRoleAsync(id, role, options); + await Roles._removeUserFromRoleAsync(id, role, options) } } }, @@ -759,21 +753,21 @@ Object.assign(Roles, { * @static */ _removeUserFromRoleAsync: async function (userId, roleName, options) { - Roles._checkRoleName(roleName); - Roles._checkScopeName(options.scope); + Roles._checkRoleName(roleName) + Roles._checkScopeName(options.scope) - if (!userId) return; + if (!userId) return const selector = { - "user._id": userId, - "role._id": roleName, - }; + 'user._id': userId, + 'role._id': roleName + } if (!options.anyScope) { - selector.scope = options.scope; + selector.scope = options.scope } - await Meteor.roleAssignment.removeAsync(selector); + await Meteor.roleAssignment.removeAsync(selector) }, /** @@ -806,54 +800,53 @@ Object.assign(Roles, { * @static */ userIsInRoleAsync: async function (user, roles, options) { - var id; - var selector; + let id - options = Roles._normalizeOptions(options); + options = Roles._normalizeOptions(options) // ensure array to simplify code - if (!Array.isArray(roles)) roles = [roles]; + if (!Array.isArray(roles)) roles = [roles] - roles = roles.filter((r) => r != null); + roles = roles.filter((r) => r != null) - if (!roles.length) return false; + if (!roles.length) return false - Roles._checkScopeName(options.scope); + Roles._checkScopeName(options.scope) options = Object.assign( { - anyScope: false, + anyScope: false }, options - ); + ) - if (user && typeof user === "object") { - id = user._id; + if (user && typeof user === 'object') { + id = user._id } else { - id = user; + id = user } - if (!id) return false; - if (typeof id !== "string") return false; + if (!id) return false + if (typeof id !== 'string') return false - selector = { - "user._id": id, - }; + const selector = { + 'user._id': id + } if (!options.anyScope) { - selector.scope = { $in: [options.scope, null] }; + selector.scope = { $in: [options.scope, null] } } const res = await asyncSome(roles, async (roleName) => { - selector["inheritedRoles._id"] = roleName; + selector['inheritedRoles._id'] = roleName const out = (await Meteor.roleAssignment .find(selector, { limit: 1 }) - .countAsync()) > 0; - return out; - }); + .countAsync()) > 0 + return out + }) - return res; + return res }, /** @@ -875,76 +868,73 @@ Object.assign(Roles, { * @static */ getRolesForUserAsync: async function (user, options) { - var id; - var selector; - var filter; - var roles; + let id - options = Roles._normalizeOptions(options); + options = Roles._normalizeOptions(options) - Roles._checkScopeName(options.scope); + Roles._checkScopeName(options.scope) options = Object.assign( { fullObjects: false, onlyAssigned: false, anyScope: false, - onlyScoped: false, + onlyScoped: false }, options - ); + ) - if (user && typeof user === "object") { - id = user._id; + if (user && typeof user === 'object') { + id = user._id } else { - id = user; + id = user } - if (!id) return []; + if (!id) return [] - selector = { - "user._id": id, - }; + const selector = { + 'user._id': id + } - filter = { - fields: { "inheritedRoles._id": 1 }, - }; + const filter = { + fields: { 'inheritedRoles._id': 1 } + } if (!options.anyScope) { - selector.scope = { $in: [options.scope] }; + selector.scope = { $in: [options.scope] } if (!options.onlyScoped) { - selector.scope.$in.push(null); + selector.scope.$in.push(null) } } if (options.onlyAssigned) { - delete filter.fields["inheritedRoles._id"]; - filter.fields["role._id"] = 1; + delete filter.fields['inheritedRoles._id'] + filter.fields['role._id'] = 1 } if (options.fullObjects) { - delete filter.fields; + delete filter.fields } - roles = await Meteor.roleAssignment.find(selector, filter).fetchAsync(); + const roles = await Meteor.roleAssignment.find(selector, filter).fetchAsync() if (options.fullObjects) { - return roles; + return roles } return [ ...new Set( roles.reduce((rev, current) => { if (current.inheritedRoles) { - return rev.concat(current.inheritedRoles.map((r) => r._id)); + return rev.concat(current.inheritedRoles.map((r) => r._id)) } else if (current.role) { - rev.push(current.role._id); + rev.push(current.role._id) } - return rev; + return rev }, []) - ), - ]; + ) + ] }, /** @@ -957,9 +947,9 @@ Object.assign(Roles, { * @static */ getAllRoles: function (queryOptions) { - queryOptions = queryOptions || { sort: { _id: 1 } }; + queryOptions = queryOptions || { sort: { _id: 1 } } - return Meteor.roles.find({}, queryOptions); + return Meteor.roles.find({}, queryOptions) }, /** @@ -987,16 +977,14 @@ Object.assign(Roles, { * @static */ getUsersInRoleAsync: async function (roles, options, queryOptions) { - var ids; - - ids = ( + const ids = ( await Roles.getUserAssignmentsForRole(roles, options).fetchAsync() - ).map((a) => a.user._id); + ).map((a) => a.user._id) return Meteor.users.find( { _id: { $in: ids } }, (options && options.queryOptions) || queryOptions || {} - ); + ) }, /** @@ -1021,17 +1009,17 @@ Object.assign(Roles, { * @static */ getUserAssignmentsForRole: function (roles, options) { - options = Roles._normalizeOptions(options); + options = Roles._normalizeOptions(options) options = Object.assign( { anyScope: false, - queryOptions: {}, + queryOptions: {} }, options - ); + ) - return Roles._getUsersInRoleCursor(roles, options, options.queryOptions); + return Roles._getUsersInRoleCursor(roles, options, options.queryOptions) }, /** @@ -1053,43 +1041,41 @@ Object.assign(Roles, { * @static */ _getUsersInRoleCursor: function (roles, options, filter) { - var selector; - - options = Roles._normalizeOptions(options); + options = Roles._normalizeOptions(options) options = Object.assign( { anyScope: false, - onlyScoped: false, + onlyScoped: false }, options - ); + ) // ensure array to simplify code - if (!Array.isArray(roles)) roles = [roles]; + if (!Array.isArray(roles)) roles = [roles] - Roles._checkScopeName(options.scope); + Roles._checkScopeName(options.scope) filter = Object.assign( { - fields: { "user._id": 1 }, + fields: { 'user._id': 1 } }, filter - ); + ) - selector = { - "inheritedRoles._id": { $in: roles }, - }; + const selector = { + 'inheritedRoles._id': { $in: roles } + } if (!options.anyScope) { - selector.scope = { $in: [options.scope] }; + selector.scope = { $in: [options.scope] } if (!options.onlyScoped) { - selector.scope.$in.push(null); + selector.scope.$in.push(null) } } - return Meteor.roleAssignment.find(selector, filter); + return Meteor.roleAssignment.find(selector, filter) }, /** @@ -1101,14 +1087,14 @@ Object.assign(Roles, { */ getGroupsForUserAsync: async function (...args) { if (!getGroupsForUserDeprecationWarning) { - getGroupsForUserDeprecationWarning = true; + getGroupsForUserDeprecationWarning = true console && console.warn( - "getGroupsForUser has been deprecated. Use getScopesForUser instead." - ); + 'getGroupsForUser has been deprecated. Use getScopesForUser instead.' + ) } - return Roles.getScopesForUser(...args); + return Roles.getScopesForUser(...args) }, /** @@ -1122,35 +1108,34 @@ Object.assign(Roles, { * @static */ getScopesForUserAsync: async function (user, roles) { - var scopes; - var id; + let id - if (roles && !Array.isArray(roles)) roles = [roles]; + if (roles && !Array.isArray(roles)) roles = [roles] - if (user && typeof user === "object") { - id = user._id; + if (user && typeof user === 'object') { + id = user._id } else { - id = user; + id = user } - if (!id) return []; + if (!id) return [] const selector = { - "user._id": id, - scope: { $ne: null }, - }; + 'user._id': id, + scope: { $ne: null } + } if (roles) { - selector["inheritedRoles._id"] = { $in: roles }; + selector['inheritedRoles._id'] = { $in: roles } } - scopes = ( + const scopes = ( await Meteor.roleAssignment .find(selector, { fields: { scope: 1 } }) .fetchAsync() - ).map((obi) => obi.scope); + ).map((obi) => obi.scope) - return [...new Set(scopes)]; + return [...new Set(scopes)] }, /** @@ -1164,26 +1149,26 @@ Object.assign(Roles, { * @static */ renameScopeAsync: async function (oldName, newName) { - var count; + let count - Roles._checkScopeName(oldName); - Roles._checkScopeName(newName); + Roles._checkScopeName(oldName) + Roles._checkScopeName(newName) - if (oldName === newName) return; + if (oldName === newName) return do { count = await Meteor.roleAssignment.updateAsync( { - scope: oldName, + scope: oldName }, { $set: { - scope: newName, - }, + scope: newName + } }, { multi: true } - ); - } while (count > 0); + ) + } while (count > 0) }, /** @@ -1196,9 +1181,9 @@ Object.assign(Roles, { * @static */ removeScopeAsync: async function (name) { - Roles._checkScopeName(name); + Roles._checkScopeName(name) - await Meteor.roleAssignment.removeAsync({ scope: name }); + await Meteor.roleAssignment.removeAsync({ scope: name }) }, /** @@ -1212,10 +1197,10 @@ Object.assign(Roles, { _checkRoleName: function (roleName) { if ( !roleName || - typeof roleName !== "string" || + typeof roleName !== 'string' || roleName.trim() !== roleName ) { - throw new Error("Invalid role name '" + roleName + "'."); + throw new Error("Invalid role name '" + roleName + "'.") } }, @@ -1231,33 +1216,33 @@ Object.assign(Roles, { */ isParentOfAsync: async function (parentRoleName, childRoleName) { if (parentRoleName === childRoleName) { - return true; + return true } if (parentRoleName == null || childRoleName == null) { - return false; + return false } - Roles._checkRoleName(parentRoleName); - Roles._checkRoleName(childRoleName); + Roles._checkRoleName(parentRoleName) + Roles._checkRoleName(childRoleName) - var rolesToCheck = [parentRoleName]; + let rolesToCheck = [parentRoleName] while (rolesToCheck.length !== 0) { - var roleName = rolesToCheck.pop(); + const roleName = rolesToCheck.pop() if (roleName === childRoleName) { - return true; + return true } - var role = await Meteor.roles.findOneAsync({ _id: roleName }); + const role = await Meteor.roles.findOneAsync({ _id: roleName }) // This should not happen, but this is a problem to address at some other time. - if (!role) continue; + if (!role) continue - rolesToCheck = rolesToCheck.concat(role.children.map((r) => r._id)); + rolesToCheck = rolesToCheck.concat(role.children.map((r) => r._id)) } - return false; + return false }, /** @@ -1270,15 +1255,15 @@ Object.assign(Roles, { * @static */ _normalizeOptions: function (options) { - options = options === undefined ? {} : options; + options = options === undefined ? {} : options - if (options === null || typeof options === "string") { - options = { scope: options }; + if (options === null || typeof options === 'string') { + options = { scope: options } } - options.scope = Roles._normalizeScopeName(options.scope); + options.scope = Roles._normalizeScopeName(options.scope) - return options; + return options }, /** @@ -1293,9 +1278,9 @@ Object.assign(Roles, { _normalizeScopeName: function (scopeName) { // map undefined and null to null if (scopeName == null) { - return null; + return null } else { - return scopeName; + return scopeName } }, @@ -1308,14 +1293,14 @@ Object.assign(Roles, { * @static */ _checkScopeName: function (scopeName) { - if (scopeName === null) return; + if (scopeName === null) return if ( !scopeName || - typeof scopeName !== "string" || + typeof scopeName !== 'string' || scopeName.trim() !== scopeName ) { - throw new Error("Invalid scope name '" + scopeName + "'."); + throw new Error("Invalid scope name '" + scopeName + "'.") } - }, -}); + } +}) diff --git a/roles/roles_server.js b/roles/roles_server.js index 174f310f..fdf03794 100644 --- a/roles/roles_server.js +++ b/roles/roles_server.js @@ -32,8 +32,8 @@ Meteor.publish('_roles', function () { const fields = { roles: 1 } if (!loggedInUserId) { - this.ready(); - return; + this.ready() + return } return Meteor.users.find( @@ -53,7 +53,7 @@ Object.assign(Roles, { * @static */ _isNewRole: function (role) { - return !("name" in role) && "children" in role; + return !('name' in role) && 'children' in role }, /** @@ -66,7 +66,7 @@ Object.assign(Roles, { * @static */ _isOldRole: function (role) { - return "name" in role && !("children" in role); + return 'name' in role && !('children' in role) }, /** @@ -79,7 +79,7 @@ Object.assign(Roles, { * @static */ _isNewField: function (roles) { - return Array.isArray(roles) && typeof roles[0] === "object"; + return Array.isArray(roles) && typeof roles[0] === 'object' }, /** @@ -93,9 +93,9 @@ Object.assign(Roles, { */ _isOldField: function (roles) { return ( - (Array.isArray(roles) && typeof roles[0] === "string") || - (typeof roles === "object" && !Array.isArray(roles)) - ); + (Array.isArray(roles) && typeof roles[0] === 'string') || + (typeof roles === 'object' && !Array.isArray(roles)) + ) }, /** @@ -107,13 +107,12 @@ Object.assign(Roles, { * @static */ _convertToNewRole: function (oldRole) { - if (!(typeof oldRole.name === "string")) - throw new Error("Role name '" + oldRole.name + "' is not a string."); + if (!(typeof oldRole.name === 'string')) { throw new Error("Role name '" + oldRole.name + "' is not a string.") } return { _id: oldRole.name, - children: [], - }; + children: [] + } }, /** @@ -125,12 +124,11 @@ Object.assign(Roles, { * @static */ _convertToOldRole: function (newRole) { - if (!(typeof newRole._id === "string")) - throw new Error("Role name '" + newRole._id + "' is not a string."); + if (!(typeof newRole._id === 'string')) { throw new Error("Role name '" + newRole._id + "' is not a string.") } return { - name: newRole._id, - }; + name: newRole._id + } }, /** @@ -146,37 +144,35 @@ Object.assign(Roles, { const roles = [] if (Array.isArray(oldRoles)) { oldRoles.forEach(function (role, index) { - if (!(typeof role === "string")) - throw new Error("Role '" + role + "' is not a string."); + if (!(typeof role === 'string')) { throw new Error("Role '" + role + "' is not a string.") } roles.push({ _id: role, scope: null, - assigned: true, - }); - }); - } else if (typeof oldRoles === "object") { + assigned: true + }) + }) + } else if (typeof oldRoles === 'object') { Object.entries(oldRoles).forEach(([group, rolesArray]) => { - if (group === "__global_roles__") { - group = null; + if (group === '__global_roles__') { + group = null } else if (convertUnderscoresToDots) { // unescape - group = group.replace(/_/g, "."); + group = group.replace(/_/g, '.') } rolesArray.forEach(function (role) { - if (!(typeof role === "string")) - throw new Error("Role '" + role + "' is not a string."); + if (!(typeof role === 'string')) { throw new Error("Role '" + role + "' is not a string.") } roles.push({ _id: role, scope: group, - assigned: true, - }); - }); - }); + assigned: true + }) + }) + }) } - return roles; + return roles }, /** @@ -192,46 +188,45 @@ Object.assign(Roles, { let roles if (usingGroups) { - roles = {}; + roles = {} } else { - roles = []; + roles = [] } newRoles.forEach(function (userRole) { - if (!(typeof userRole === "object")) - throw new Error("Role '" + userRole + "' is not an object."); + if (!(typeof userRole === 'object')) { throw new Error("Role '" + userRole + "' is not an object.") } // We assume that we are converting back a failed migration, so values can only be // what were valid values in 1.0. So no group names starting with $ and no subroles. if (userRole.scope) { - if (!usingGroups) + if (!usingGroups) { throw new Error( "Role '" + userRole._id + "' with scope '" + userRole.scope + "' without enabled groups." - ); + ) + } // escape const scope = userRole.scope.replace(/\./g, '_') - if (scope[0] === "$") - throw new Error("Group name '" + scope + "' start with $."); + if (scope[0] === '$') { throw new Error("Group name '" + scope + "' start with $.") } - roles[scope] = roles[scope] || []; - roles[scope].push(userRole._id); + roles[scope] = roles[scope] || [] + roles[scope].push(userRole._id) } else { if (usingGroups) { - roles.__global_roles__ = roles.__global_roles__ || []; - roles.__global_roles__.push(userRole._id); + roles.__global_roles__ = roles.__global_roles__ || [] + roles.__global_roles__.push(userRole._id) } else { - roles.push(userRole._id); + roles.push(userRole._id) } } - }); - return roles; + }) + return roles }, /** @@ -247,12 +242,12 @@ Object.assign(Roles, { { _id: user._id, // making sure nothing changed in meantime - roles: user.roles, + roles: user.roles }, { - $set: { roles }, + $set: { roles } } - ); + ) }, /** @@ -264,8 +259,8 @@ Object.assign(Roles, { * @static */ _defaultUpdateRole: function (oldRole, newRole) { - Meteor.roles.remove(oldRole._id); - Meteor.roles.insert(newRole); + Meteor.roles.remove(oldRole._id) + Meteor.roles.insert(newRole) }, /** @@ -278,7 +273,7 @@ Object.assign(Roles, { */ _dropCollectionIndex: function (collection, indexName) { try { - collection._dropIndex(indexName); + collection._dropIndex(indexName) } catch (e) { const indexNotFound = /index not found/.test(e.message || e.err || e.errmsg) @@ -300,25 +295,25 @@ Object.assign(Roles, { * @static */ _forwardMigrate: function (updateUser, updateRole, convertUnderscoresToDots) { - updateUser = updateUser || Roles._defaultUpdateUser; - updateRole = updateRole || Roles._defaultUpdateRole; + updateUser = updateUser || Roles._defaultUpdateUser + updateRole = updateRole || Roles._defaultUpdateRole - Roles._dropCollectionIndex(Meteor.roles, "name_1"); + Roles._dropCollectionIndex(Meteor.roles, 'name_1') Meteor.roles.find().forEach(function (role, index, cursor) { if (!Roles._isNewRole(role)) { - updateRole(role, Roles._convertToNewRole(role)); + updateRole(role, Roles._convertToNewRole(role)) } - }); + }) Meteor.users.find().forEach(function (user, index, cursor) { if (!Roles._isNewField(user.roles)) { updateUser( user, Roles._convertToNewField(user.roles, convertUnderscoresToDots) - ); + ) } - }); + }) }, /** @@ -331,8 +326,8 @@ Object.assign(Roles, { * @static */ _forwardMigrate2: function (userSelector) { - userSelector = userSelector || {}; - Object.assign(userSelector, { roles: { $ne: null } }); + userSelector = userSelector || {} + Object.assign(userSelector, { roles: { $ne: null } }) Meteor.users.find(userSelector).forEach(function (user, index) { user.roles @@ -341,16 +336,16 @@ Object.assign(Roles, { // Added `ifExists` to make it less error-prone Roles._addUserToRole(user._id, r._id, { scope: r.scope, - ifExists: true, - }); - }); + ifExists: true + }) + }) - Meteor.users.update({ _id: user._id }, { $unset: { roles: "" } }); - }); + Meteor.users.update({ _id: user._id }, { $unset: { roles: '' } }) + }) // No need to keep the indexes around - Roles._dropCollectionIndex(Meteor.users, "roles._id_1_roles.scope_1"); - Roles._dropCollectionIndex(Meteor.users, "roles.scope_1"); + Roles._dropCollectionIndex(Meteor.users, 'roles._id_1_roles.scope_1') + Roles._dropCollectionIndex(Meteor.users, 'roles.scope_1') }, /** @@ -369,23 +364,23 @@ Object.assign(Roles, { * @static */ _backwardMigrate: function (updateUser, updateRole, usingGroups) { - updateUser = updateUser || Roles._defaultUpdateUser; - updateRole = updateRole || Roles._defaultUpdateRole; + updateUser = updateUser || Roles._defaultUpdateUser + updateRole = updateRole || Roles._defaultUpdateRole - Roles._dropCollectionIndex(Meteor.users, "roles._id_1_roles.scope_1"); - Roles._dropCollectionIndex(Meteor.users, "roles.scope_1"); + Roles._dropCollectionIndex(Meteor.users, 'roles._id_1_roles.scope_1') + Roles._dropCollectionIndex(Meteor.users, 'roles.scope_1') Meteor.roles.find().forEach(function (role, index, cursor) { if (!Roles._isOldRole(role)) { - updateRole(role, Roles._convertToOldRole(role)); + updateRole(role, Roles._convertToOldRole(role)) } - }); + }) Meteor.users.find().forEach(function (user, index, cursor) { if (!Roles._isOldField(user.roles)) { - updateUser(user, Roles._convertToOldField(user.roles, usingGroups)); + updateUser(user, Roles._convertToOldField(user.roles, usingGroups)) } - }); + }) }, /** @@ -398,49 +393,49 @@ Object.assign(Roles, { * @static */ _backwardMigrate2: function (assignmentSelector) { - assignmentSelector = assignmentSelector || {}; + assignmentSelector = assignmentSelector || {} if (Meteor.users.createIndex) { - Meteor.users.createIndex({ "roles._id": 1, "roles.scope": 1 }); - Meteor.users.createIndex({ "roles.scope": 1 }); + Meteor.users.createIndex({ 'roles._id': 1, 'roles.scope': 1 }) + Meteor.users.createIndex({ 'roles.scope': 1 }) } else { - Meteor.users._ensureIndex({ "roles._id": 1, "roles.scope": 1 }); - Meteor.users._ensureIndex({ "roles.scope": 1 }); + Meteor.users._ensureIndex({ 'roles._id': 1, 'roles.scope': 1 }) + Meteor.users._ensureIndex({ 'roles.scope': 1 }) } Meteor.roleAssignment.find(assignmentSelector).forEach((r) => { - const roles = Meteor.users.findOne({ _id: r.user._id }).roles || []; + const roles = Meteor.users.findOne({ _id: r.user._id }).roles || [] const currentRole = roles.find( (oldRole) => oldRole._id === r.role._id && oldRole.scope === r.scope - ); + ) if (currentRole) { - currentRole.assigned = true; + currentRole.assigned = true } else { roles.push({ _id: r.role._id, scope: r.scope, - assigned: true, - }); + assigned: true + }) r.inheritedRoles.forEach((inheritedRole) => { const currentInheritedRole = roles.find( (oldRole) => oldRole._id === inheritedRole._id && oldRole.scope === r.scope - ); + ) if (!currentInheritedRole) { roles.push({ _id: inheritedRole._id, scope: r.scope, - assigned: false, - }); + assigned: false + }) } - }); + }) } - Meteor.users.update({ _id: r.user._id }, { $set: { roles } }); - Meteor.roleAssignment.remove({ _id: r._id }); - }); - }, -}); + Meteor.users.update({ _id: r.user._id }, { $set: { roles } }) + Meteor.roleAssignment.remove({ _id: r._id }) + }) + } +}) diff --git a/someapp/tests/main.js b/someapp/tests/main.js index 9a7482e7..a161c8d8 100644 --- a/someapp/tests/main.js +++ b/someapp/tests/main.js @@ -1,3 +1,5 @@ +/* eslint-env mocha */ +import { Meteor } from 'meteor/meteor' import assert from 'assert' describe('someapp', function () { diff --git a/testapp/package-lock.json b/testapp/package-lock.json index 4d42b56e..7a2921ca 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -200,11 +200,11 @@ "dev": true }, "@babel/runtime": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", - "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", + "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" } }, "@babel/template": { @@ -4408,9 +4408,9 @@ } }, "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "regexp.prototype.flags": { "version": "1.5.0", diff --git a/testapp/package.json b/testapp/package.json index f894d6e5..f986e8f7 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -11,8 +11,8 @@ "lint:fix": "standard --fix ../" }, "dependencies": { - "@babel/runtime": "^7.17.9", - "meteor-node-stubs": "^1.2.1", + "@babel/runtime": "^7.22.10", + "meteor-node-stubs": "^1.2.5", "yuidocjs": "^0.10.2" }, "devDependencies": { From c0a1c9a405ff060c6144963f599384a8adb42b2f Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Fri, 25 Aug 2023 09:29:30 +0200 Subject: [PATCH 41/53] Remove someapp --- someapp/.coverage.json | 6 - someapp/.gitignore | 1 - someapp/.meteor/.finished-upgraders | 19 - someapp/.meteor/.gitignore | 1 - someapp/.meteor/.id | 7 - someapp/.meteor/packages | 18 - someapp/.meteor/platforms | 2 - someapp/.meteor/release | 1 - someapp/.meteor/versions | 57 -- someapp/client/main.css | 4 - someapp/client/main.html | 21 - someapp/client/main.js | 1 - someapp/package-lock.json | 1428 --------------------------- someapp/package.json | 22 - someapp/packages/roles | 1 - someapp/server/main.js | 15 - someapp/tests/main.js | 22 - 17 files changed, 1626 deletions(-) delete mode 100644 someapp/.coverage.json delete mode 100644 someapp/.gitignore delete mode 100644 someapp/.meteor/.finished-upgraders delete mode 100644 someapp/.meteor/.gitignore delete mode 100644 someapp/.meteor/.id delete mode 100644 someapp/.meteor/packages delete mode 100644 someapp/.meteor/platforms delete mode 100644 someapp/.meteor/release delete mode 100644 someapp/.meteor/versions delete mode 100644 someapp/client/main.css delete mode 100644 someapp/client/main.html delete mode 100644 someapp/client/main.js delete mode 100644 someapp/package-lock.json delete mode 100644 someapp/package.json delete mode 120000 someapp/packages/roles delete mode 100644 someapp/server/main.js delete mode 100644 someapp/tests/main.js diff --git a/someapp/.coverage.json b/someapp/.coverage.json deleted file mode 100644 index 918fc888..00000000 --- a/someapp/.coverage.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "include": [ - "**/packages/roles/**/*", - "**/packages/*alanning_roles.js" - ] -} diff --git a/someapp/.gitignore b/someapp/.gitignore deleted file mode 100644 index 40b878db..00000000 --- a/someapp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ \ No newline at end of file diff --git a/someapp/.meteor/.finished-upgraders b/someapp/.meteor/.finished-upgraders deleted file mode 100644 index c07b6ff7..00000000 --- a/someapp/.meteor/.finished-upgraders +++ /dev/null @@ -1,19 +0,0 @@ -# This file contains information which helps Meteor properly upgrade your -# app when you run 'meteor update'. You should check it into version control -# with your project. - -notices-for-0.9.0 -notices-for-0.9.1 -0.9.4-platform-file -notices-for-facebook-graph-api-2 -1.2.0-standard-minifiers-package -1.2.0-meteor-platform-split -1.2.0-cordova-changes -1.2.0-breaking-changes -1.3.0-split-minifiers-package -1.4.0-remove-old-dev-bundle-link -1.4.1-add-shell-server-package -1.4.3-split-account-service-packages -1.5-add-dynamic-import-package -1.7-split-underscore-from-meteor-base -1.8.3-split-jquery-from-blaze diff --git a/someapp/.meteor/.gitignore b/someapp/.meteor/.gitignore deleted file mode 100644 index 40830374..00000000 --- a/someapp/.meteor/.gitignore +++ /dev/null @@ -1 +0,0 @@ -local diff --git a/someapp/.meteor/.id b/someapp/.meteor/.id deleted file mode 100644 index fedba0b5..00000000 --- a/someapp/.meteor/.id +++ /dev/null @@ -1,7 +0,0 @@ -# This file contains a token that is unique to your project. -# Check it into your repository along with the rest of this directory. -# It can be used for purposes such as: -# - ensuring you don't accidentally deploy one app on top of another -# - providing package authors with aggregated statistics - -mgytvi9cz557.lvsfnftl2z8 diff --git a/someapp/.meteor/packages b/someapp/.meteor/packages deleted file mode 100644 index 63f32aa2..00000000 --- a/someapp/.meteor/packages +++ /dev/null @@ -1,18 +0,0 @@ -# Meteor packages used by this project, one per line. -# Check this file (and the other files in this directory) into your repository. -# -# 'meteor add' and 'meteor remove' will edit this file for you, -# but you can also edit it by hand. - -meteor@1.11.2 # Shared foundation for all Meteor packages -static-html@1.3.2 # Define static page content in .html files -standard-minifier-css@1.9.2 # CSS minifier run for production mode -standard-minifier-js@2.8.1 # JS minifier run for production mode -es5-shim@4.8.0 # ECMAScript 5 compatibility for older browsers -ecmascript@0.16.7 # Enable ECMAScript2015+ syntax in app code -typescript@4.9.4 # Enable TypeScript syntax in .ts and .tsx modules -shell-server@0.5.0 # Server-side component of the `meteor shell` command -webapp@1.13.5 # Serves a Meteor app over HTTP -server-render@0.4.1 # Support for server-side rendering -hot-module-replacement@0.5.3 # Rebuilds the client if there is a change on the client without restarting the server - diff --git a/someapp/.meteor/platforms b/someapp/.meteor/platforms deleted file mode 100644 index efeba1b5..00000000 --- a/someapp/.meteor/platforms +++ /dev/null @@ -1,2 +0,0 @@ -server -browser diff --git a/someapp/.meteor/release b/someapp/.meteor/release deleted file mode 100644 index e8cfc7ec..00000000 --- a/someapp/.meteor/release +++ /dev/null @@ -1 +0,0 @@ -METEOR@2.12 diff --git a/someapp/.meteor/versions b/someapp/.meteor/versions deleted file mode 100644 index 67a85b1d..00000000 --- a/someapp/.meteor/versions +++ /dev/null @@ -1,57 +0,0 @@ -autoupdate@1.8.0 -babel-compiler@7.10.4 -babel-runtime@1.5.1 -base64@1.0.12 -blaze-tools@1.1.3 -boilerplate-generator@1.7.1 -caching-compiler@1.2.2 -caching-html-compiler@1.2.1 -callback-hook@1.5.1 -check@1.3.2 -ddp@1.4.1 -ddp-client@2.6.1 -ddp-common@1.4.0 -ddp-server@2.6.1 -diff-sequence@1.1.2 -dynamic-import@0.7.3 -ecmascript@0.16.7 -ecmascript-runtime@0.8.1 -ecmascript-runtime-client@0.12.1 -ecmascript-runtime-server@0.11.0 -ejson@1.1.3 -es5-shim@4.8.0 -fetch@0.1.3 -hot-code-push@1.0.4 -hot-module-replacement@0.5.3 -html-tools@1.1.3 -htmljs@1.1.1 -id-map@1.1.1 -inter-process-messaging@0.1.1 -logging@1.3.2 -meteor@1.11.2 -minifier-css@1.6.4 -minifier-js@2.7.5 -modern-browsers@0.1.9 -modules@0.19.0 -modules-runtime@0.13.1 -modules-runtime-hot@0.14.2 -mongo-id@1.0.8 -promise@0.12.2 -random@1.2.1 -react-fast-refresh@0.2.7 -reload@1.3.1 -retry@1.1.0 -routepolicy@1.1.1 -server-render@0.4.1 -shell-server@0.5.0 -socket-stream-client@0.5.1 -spacebars-compiler@1.3.1 -standard-minifier-css@1.9.2 -standard-minifier-js@2.8.1 -static-html@1.3.2 -templating-tools@1.2.2 -tracker@1.3.2 -typescript@4.9.4 -underscore@1.0.13 -webapp@1.13.5 -webapp-hashing@1.1.1 diff --git a/someapp/client/main.css b/someapp/client/main.css deleted file mode 100644 index 7f354f0f..00000000 --- a/someapp/client/main.css +++ /dev/null @@ -1,4 +0,0 @@ -body { - padding: 10px; - font-family: sans-serif; -} diff --git a/someapp/client/main.html b/someapp/client/main.html deleted file mode 100644 index 19789db4..00000000 --- a/someapp/client/main.html +++ /dev/null @@ -1,21 +0,0 @@ - - Minimal Meteor app - - - -

Minimal Meteor app

-

- This Meteor app uses as few Meteor packages as possible, to keep the - client JavaScript bundle as small as possible. -

- - - -

Learn Meteor!

- - diff --git a/someapp/client/main.js b/someapp/client/main.js deleted file mode 100644 index fb4b5bae..00000000 --- a/someapp/client/main.js +++ /dev/null @@ -1 +0,0 @@ -console.log(`Greetings from ${module.id}!`) diff --git a/someapp/package-lock.json b/someapp/package-lock.json deleted file mode 100644 index ef2dbadb..00000000 --- a/someapp/package-lock.json +++ /dev/null @@ -1,1428 +0,0 @@ -{ - "name": "someapp", - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", - "requires": { - "@babel/highlight": "^7.22.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" - }, - "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/runtime": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", - "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@puppeteer/browsers": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.5.tgz", - "integrity": "sha512-a0gpUa+XlxZHotoOklh99X6RC5R+hQGcVcYOH+oOIEBfQXPp8Z5c765XAu/zhxsjRuAZN4Xx4vZNlwN4wJro2A==", - "requires": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "http-proxy-agent": "7.0.0", - "https-proxy-agent": "7.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "socks-proxy-agent": "8.0.1", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - } - }, - "@types/node": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", - "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==", - "optional": true - }, - "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "optional": true, - "requires": { - "@types/node": "*" - } - }, - "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "requires": { - "debug": "^4.3.4" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "b4a": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", - "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - } - } - }, - "chromium-bidi": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz", - "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==", - "requires": { - "mitt": "3.0.0" - } - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "cosmiconfig": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", - "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", - "requires": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - } - }, - "cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "requires": { - "node-fetch": "^2.6.12" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "devtools-protocol": { - "version": "0.0.1135028", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1135028.tgz", - "integrity": "sha512-jEcNGrh6lOXNRJvZb9RjeevtZGrgugPKSMJZxfyxWQnhlKawMPhMtk/dfC+Z/6xNXExlzTKlY5LzIAK/fRpQIw==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - } - }, - "fast-fifo": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz", - "integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==" - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "requires": { - "pend": "~1.2.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", - "requires": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - } - }, - "https-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz", - "integrity": "sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ==", - "requires": { - "agent-base": "^7.0.2", - "debug": "4" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "meteor-node-stubs": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.5.tgz", - "integrity": "sha512-FLlOFZx3KnZ5s3yPCK+x58DyX9ewN+oQ12LcpwBXMLtzJ/YyprMQVivd6KIrahZbKJrNenPNUGuDS37WUFg+Mw==", - "requires": { - "assert": "^2.0.0", - "browserify-zlib": "^0.2.0", - "buffer": "^5.7.1", - "console-browserify": "^1.2.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.12.0", - "domain-browser": "^4.22.0", - "elliptic": "^6.5.4", - "events": "^3.3.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "^1.0.0", - "process": "^0.11.10", - "punycode": "^1.4.1", - "querystring-es3": "^0.2.1", - "readable-stream": "^3.6.0", - "stream-browserify": "^3.0.0", - "stream-http": "^3.2.0", - "string_decoder": "^1.3.0", - "timers-browserify": "^2.0.12", - "tty-browserify": "0.0.1", - "url": "^0.11.0", - "util": "^0.12.4", - "vm-browserify": "^1.1.2" - }, - "dependencies": { - "asn1.js": { - "version": "5.4.1", - "bundled": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "bundled": true - } - } - }, - "assert": { - "version": "2.0.0", - "bundled": true, - "requires": { - "es6-object-assign": "^1.1.0", - "is-nan": "^1.2.1", - "object-is": "^1.0.1", - "util": "^0.12.0" - } - }, - "available-typed-arrays": { - "version": "1.0.4", - "bundled": true - }, - "base64-js": { - "version": "1.5.1", - "bundled": true - }, - "bn.js": { - "version": "5.2.0", - "bundled": true - }, - "brorand": { - "version": "1.1.0", - "bundled": true - }, - "browserify-aes": { - "version": "1.2.0", - "bundled": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "bundled": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "bundled": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.1.0", - "bundled": true, - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "bundled": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "browserify-zlib": { - "version": "0.2.0", - "bundled": true, - "requires": { - "pako": "~1.0.5" - } - }, - "buffer": { - "version": "5.7.1", - "bundled": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-xor": { - "version": "1.0.3", - "bundled": true - }, - "builtin-status-codes": { - "version": "3.0.0", - "bundled": true - }, - "call-bind": { - "version": "1.0.2", - "bundled": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "cipher-base": { - "version": "1.0.4", - "bundled": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "console-browserify": { - "version": "1.2.0", - "bundled": true - }, - "constants-browserify": { - "version": "1.0.0", - "bundled": true - }, - "create-ecdh": { - "version": "4.0.4", - "bundled": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "bundled": true - } - } - }, - "create-hash": { - "version": "1.2.0", - "bundled": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "bundled": true, - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "bundled": true, - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "define-properties": { - "version": "1.1.3", - "bundled": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "des.js": { - "version": "1.0.1", - "bundled": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "diffie-hellman": { - "version": "5.0.3", - "bundled": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "bundled": true - } - } - }, - "domain-browser": { - "version": "4.22.0", - "bundled": true - }, - "elliptic": { - "version": "6.5.4", - "bundled": true, - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "bundled": true - } - } - }, - "es-abstract": { - "version": "1.18.3", - "bundled": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "bundled": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-object-assign": { - "version": "1.1.0", - "bundled": true - }, - "events": { - "version": "3.3.0", - "bundled": true - }, - "evp_bytestokey": { - "version": "1.0.3", - "bundled": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "foreach": { - "version": "2.0.5", - "bundled": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true - }, - "get-intrinsic": { - "version": "1.1.1", - "bundled": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "has": { - "version": "1.0.3", - "bundled": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "bundled": true - }, - "has-symbols": { - "version": "1.0.2", - "bundled": true - }, - "hash-base": { - "version": "3.1.0", - "bundled": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "hash.js": { - "version": "1.1.7", - "bundled": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "bundled": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "https-browserify": { - "version": "1.0.0", - "bundled": true - }, - "ieee754": { - "version": "1.2.1", - "bundled": true - }, - "inherits": { - "version": "2.0.4", - "bundled": true - }, - "is-arguments": { - "version": "1.1.0", - "bundled": true, - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-bigint": { - "version": "1.0.2", - "bundled": true - }, - "is-boolean-object": { - "version": "1.1.1", - "bundled": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-callable": { - "version": "1.2.3", - "bundled": true - }, - "is-date-object": { - "version": "1.0.4", - "bundled": true - }, - "is-generator-function": { - "version": "1.0.9", - "bundled": true - }, - "is-nan": { - "version": "1.3.2", - "bundled": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "bundled": true - }, - "is-number-object": { - "version": "1.0.5", - "bundled": true - }, - "is-regex": { - "version": "1.1.3", - "bundled": true, - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.6", - "bundled": true - }, - "is-symbol": { - "version": "1.0.4", - "bundled": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.5", - "bundled": true, - "requires": { - "available-typed-arrays": "^1.0.2", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.0-next.2", - "foreach": "^2.0.5", - "has-symbols": "^1.0.1" - } - }, - "md5.js": { - "version": "1.3.5", - "bundled": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "bundled": true, - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "bundled": true - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "bundled": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "bundled": true - }, - "object-inspect": { - "version": "1.10.3", - "bundled": true - }, - "object-is": { - "version": "1.1.5", - "bundled": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "bundled": true - }, - "object.assign": { - "version": "4.1.2", - "bundled": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "os-browserify": { - "version": "0.3.0", - "bundled": true - }, - "pako": { - "version": "1.0.11", - "bundled": true - }, - "parse-asn1": { - "version": "5.1.6", - "bundled": true, - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "path-browserify": { - "version": "1.0.1", - "bundled": true - }, - "pbkdf2": { - "version": "3.1.2", - "bundled": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "process": { - "version": "0.11.10", - "bundled": true - }, - "public-encrypt": { - "version": "4.0.3", - "bundled": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "bundled": true - } - } - }, - "punycode": { - "version": "1.4.1", - "bundled": true - }, - "querystring": { - "version": "0.2.0", - "bundled": true - }, - "querystring-es3": { - "version": "0.2.1", - "bundled": true - }, - "randombytes": { - "version": "2.1.0", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "bundled": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "bundled": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "ripemd160": { - "version": "2.0.2", - "bundled": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "setimmediate": { - "version": "1.0.5", - "bundled": true - }, - "sha.js": { - "version": "2.4.11", - "bundled": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "stream-browserify": { - "version": "3.0.0", - "bundled": true, - "requires": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "stream-http": { - "version": "3.2.0", - "bundled": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "bundled": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "bundled": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string_decoder": { - "version": "1.3.0", - "bundled": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "timers-browserify": { - "version": "2.0.12", - "bundled": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "tty-browserify": { - "version": "0.0.1", - "bundled": true - }, - "unbox-primitive": { - "version": "1.0.1", - "bundled": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "url": { - "version": "0.11.0", - "bundled": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "bundled": true - } - } - }, - "util": { - "version": "0.12.4", - "bundled": true, - "requires": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", - "which-typed-array": "^1.1.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "vm-browserify": { - "version": "1.1.2", - "bundled": true - }, - "which-boxed-primitive": { - "version": "1.0.2", - "bundled": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-typed-array": { - "version": "1.1.4", - "bundled": true, - "requires": { - "available-typed-arrays": "^1.0.2", - "call-bind": "^1.0.0", - "es-abstract": "^1.18.0-next.1", - "foreach": "^2.0.5", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.1", - "is-typed-array": "^1.1.3" - } - }, - "xtend": { - "version": "4.0.2", - "bundled": true - } - } - }, - "mitt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", - "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "puppeteer": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-20.8.2.tgz", - "integrity": "sha512-+VRywTRGF09UyiesFL7pcU19Cq7vf2HsE/eulwSpl7YHcr8g8X+Va4qLmp7mOECwteGvP7rU8vQ7PP43fcubbA==", - "requires": { - "@puppeteer/browsers": "1.4.5", - "cosmiconfig": "8.2.0", - "puppeteer-core": "20.8.2" - } - }, - "puppeteer-core": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.8.2.tgz", - "integrity": "sha512-dWo60gFuFPdNhdabW9MMm6GpvkG6tND2D8FvrZ2MF+HggNApHrvLfbERj8vD6vXKV7UqDAJO0KI1OMo3S3Cm5w==", - "requires": { - "@puppeteer/browsers": "1.4.5", - "chromium-bidi": "0.4.16", - "cross-fetch": "4.0.0", - "debug": "4.3.4", - "devtools-protocol": "0.0.1135028", - "ws": "8.13.0" - } - }, - "queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" - }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" - }, - "socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - } - }, - "socks-proxy-agent": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz", - "integrity": "sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ==", - "requires": { - "agent-base": "^7.0.1", - "debug": "^4.3.4", - "socks": "^2.7.1" - } - }, - "streamx": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.0.tgz", - "integrity": "sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg==", - "requires": { - "fast-fifo": "^1.1.0", - "queue-tick": "^1.0.1" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "tar-fs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", - "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", - "requires": { - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - } - }, - "tar-stream": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", - "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", - "requires": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "unbzip2-stream": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", - "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "requires": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - } - } -} diff --git a/someapp/package.json b/someapp/package.json deleted file mode 100644 index fd0ec41c..00000000 --- a/someapp/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "someapp", - "private": true, - "scripts": { - "start": "meteor run", - "test": "meteor test --once --driver-package meteortesting:mocha", - "test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha", - "visualize": "meteor --production --extra-packages bundle-visualizer" - }, - "dependencies": { - "@babel/runtime": "^7.17.9", - "meteor-node-stubs": "^1.2.1", - "puppeteer": "^20.8.2" - }, - "meteor": { - "mainModule": { - "client": "client/main.js", - "server": "server/main.js" - }, - "testModule": "tests/main.js" - } -} diff --git a/someapp/packages/roles b/someapp/packages/roles deleted file mode 120000 index 6581736d..00000000 --- a/someapp/packages/roles +++ /dev/null @@ -1 +0,0 @@ -../../ \ No newline at end of file diff --git a/someapp/server/main.js b/someapp/server/main.js deleted file mode 100644 index 0f22191a..00000000 --- a/someapp/server/main.js +++ /dev/null @@ -1,15 +0,0 @@ -import { Meteor } from 'meteor/meteor' -import { onPageLoad } from 'meteor/server-render' - -Meteor.startup(() => { - // Code to run on server startup. - console.log(`Greetings from ${module.id}!`) -}) - -onPageLoad(sink => { - // Code to run on every request. - sink.renderIntoElementById( - 'server-render-target', - `Server time: ${new Date()}` - ) -}) diff --git a/someapp/tests/main.js b/someapp/tests/main.js deleted file mode 100644 index a161c8d8..00000000 --- a/someapp/tests/main.js +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-env mocha */ -import { Meteor } from 'meteor/meteor' -import assert from 'assert' - -describe('someapp', function () { - it('package.json has correct name', async function () { - const { name } = await import('../package.json') - assert.strictEqual(name, 'someapp') - }) - - if (Meteor.isClient) { - it('client is not server', function () { - assert.strictEqual(Meteor.isServer, false) - }) - } - - if (Meteor.isServer) { - it('server is not client', function () { - assert.strictEqual(Meteor.isClient, false) - }) - } -}) From e03fa6cb374cd700a677c85778d697f91769da6b Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Fri, 25 Aug 2023 09:32:36 +0200 Subject: [PATCH 42/53] Remove .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + roles/.DS_Store | Bin 6148 -> 0 bytes roles/.gitignore | 1 + 4 files changed, 2 insertions(+) delete mode 100644 .DS_Store delete mode 100644 roles/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 97a2704690b7e919d553c06d7dd398da483f2f27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKI|>3Z5S{S@f{mqRuHX%V=n1@lg<>NLiq>0sE|2D$PqQrBt%dRiCNG)HOUNsB zc0@$ikHbo2AtE!lp}cJ9n(do+Y?KiN!g0p^xw~D?*UPDs+ZQnIRBm#Wvm9G|+o4eb zDnJFO02QDDLo1LKb~YdSV4g<>sKC!FVBd!VH>`vFwWF@JzDKCs3H1s3Sx0ZYtL(k~e8vCo8K6MFZ2F0j(* zGp6)rS~uh93*Kp`tSp$B)4oyX^resVUNZlTD&4K~uK)9O-==l9_ujM1dGbTt5?_-u z;0!nezs>;9Y?0Qnp<8Fb8E^)+49NE(QU$Ywm7#t*X!Hs|Y%;7uU+xl86BA|$D?^S@ zf|U}jG^8s=uyV#@%F7Z~hE|TCGqX>cIiwp((AgP}nvReex^)Jefqe#!?6D)~|LFVs z|9+7_IRnnXzhWRXhvVUZuawT#+RMpV8>x>}5y`6zw Date: Fri, 25 Aug 2023 10:05:32 +0200 Subject: [PATCH 43/53] Async client tests Also adjusted Meteor versions for test and package --- .github/workflows/testsuite.yml | 5 +- package.js | 3 +- roles/tests/clientAsync.js | 138 ++ roles/tests/serverAsync.js | 2277 +++++++++++++++++++++++++++++++ 4 files changed, 2419 insertions(+), 4 deletions(-) create mode 100644 roles/tests/clientAsync.js create mode 100644 roles/tests/serverAsync.js diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 54a3d379..aa1ff189 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -36,9 +36,8 @@ jobs: strategy: matrix: meteorRelease: - - '2.3' - - '2.7.3' - - '2.12' + - '2.8.0' + - '2.13' # Latest version steps: - name: Checkout code diff --git a/package.js b/package.js index c7f59953..4a01cbbc 100644 --- a/package.js +++ b/package.js @@ -8,7 +8,7 @@ Package.describe({ }) Package.onUse(function (api) { - api.versionsFrom(['1.12', '2.3', '2.8.0']) + api.versionsFrom(['2.8.0']) const both = ['client', 'server'] @@ -58,4 +58,5 @@ Package.onTest(function (api) { api.addFiles('roles/tests/server.js', 'server') api.addFiles('roles/tests/client.js', 'client') + api.addFiles('roles/tests/clientAsync.js', 'client') }) diff --git a/roles/tests/clientAsync.js b/roles/tests/clientAsync.js new file mode 100644 index 00000000..c931896c --- /dev/null +++ b/roles/tests/clientAsync.js @@ -0,0 +1,138 @@ +/* eslint-env mocha */ +/* global Roles */ + +import { Meteor } from 'meteor/meteor' +import { assert } from 'chai' + +// To ensure that the files are loaded for coverage +import '../roles_common' + +const safeInsert = async (collection, data) => { + try { + await collection.insertAsync(data) + } catch (e) {} +} + +describe('roles async', function () { + const roles = ['admin', 'editor', 'user'] + const users = { + eve: { + _id: 'eve' + }, + bob: { + _id: 'bob' + }, + joe: { + _id: 'joe' + } + } + + async function testUser (username, expectedRoles, scope) { + const user = users[username] + + // test using user object rather than userId to avoid mocking + for (const role of roles) { + const expected = expectedRoles.includes(role) + const msg = username + ' expected to have \'' + role + '\' permission but does not' + const nmsg = username + ' had un-expected permission ' + role + + if (expected) { + assert.isTrue(await Roles.userIsInRoleAsync(user, role, scope), msg) + } else { + assert.isFalse(await Roles.userIsInRoleAsync(user, role, scope), nmsg) + } + } + } + + let meteorUserMethod + before(() => { + meteorUserMethod = Meteor.user + // Mock Meteor.user() for isInRole handlebars helper testing + Meteor.user = function () { + return users.eve + } + }) + + after(() => { + Meteor.user = meteorUserMethod + }) + + beforeEach(async () => { + await safeInsert(Meteor.roleAssignment, { + user: users.eve, + role: { _id: 'admin' }, + inheritedRoles: [{ _id: 'admin' }] + }) + await safeInsert(Meteor.roleAssignment, { + user: users.eve, + role: { _id: 'editor' }, + inheritedRoles: [{ _id: 'editor' }] + }) + + await safeInsert(Meteor.roleAssignment, { + user: users.bob, + role: { _id: 'user' }, + inheritedRoles: [{ _id: 'user' }], + scope: 'group1' + }) + await safeInsert(Meteor.roleAssignment, { + user: users.bob, + role: { _id: 'editor' }, + inheritedRoles: [{ _id: 'editor' }], + scope: 'group2' + }) + + await safeInsert(Meteor.roleAssignment, { + user: users.joe, + role: { _id: 'admin' }, + inheritedRoles: [{ _id: 'admin' }] + }) + await safeInsert(Meteor.roleAssignment, { + user: users.joe, + role: { _id: 'editor' }, + inheritedRoles: [{ _id: 'editor' }], + scope: 'group1' + }) + }) + + it('can check current users roles via template helper', function () { + let expected + let actual + + if (!Roles._handlebarsHelpers) { + // probably running package tests outside of a Meteor app. + // skip this test. + return + } + + const isInRole = Roles._handlebarsHelpers.isInRole + assert.equal(typeof isInRole, 'function', "'isInRole' helper not registered") + + expected = true + actual = isInRole('admin, editor') + assert.equal(actual, expected) + + expected = true + actual = isInRole('admin') + assert.equal(actual, expected) + + expected = false + actual = isInRole('unknown') + assert.equal(actual, expected) + }) + + it('can check if user is in role', async function () { + await testUser('eve', ['admin', 'editor']) + }) + + it('can check if user is in role by group', async function () { + await testUser('bob', ['user'], 'group1') + await testUser('bob', ['editor'], 'group2') + }) + + it('can check if user is in role with Roles.GLOBAL_GROUP', async function () { + await testUser('joe', ['admin']) + await testUser('joe', ['admin'], Roles.GLOBAL_GROUP) + await testUser('joe', ['admin', 'editor'], 'group1') + }) +}) diff --git a/roles/tests/serverAsync.js b/roles/tests/serverAsync.js new file mode 100644 index 00000000..b3fb854d --- /dev/null +++ b/roles/tests/serverAsync.js @@ -0,0 +1,2277 @@ +/* eslint-env mocha */ +/* global Roles */ + +import { Meteor } from 'meteor/meteor' +import { assert } from 'chai' + +// To ensure that the files are loaded for coverage +import '../roles_server' +import '../roles_common' + +// To allow inserting on the client, needed for testing. +Meteor.roleAssignment.allow({ + insert () { return true }, + update () { return true }, + remove () { return true } +}) + +const hasProp = (target, prop) => Object.hasOwnProperty.call(target, prop) + +describe('roles', function () { + let users = {} + const roles = ['admin', 'editor', 'user'] + + Meteor.publish('_roleAssignments', function () { + const loggedInUserId = this.userId + + if (!loggedInUserId) { + this.ready() + return + } + + return Meteor.roleAssignment.find({ _id: loggedInUserId }) + }) + + function addUser (name) { + return Meteor.users.insert({ username: name }) + } + + function testUser (username, expectedRoles, scope) { + const userId = users[username] + const userObj = Meteor.users.findOne({ _id: userId }) + + // check using user ids (makes db calls) + _innerTest(userId, username, expectedRoles, scope) + + // check using passed-in user object + _innerTest(userObj, username, expectedRoles, scope) + } + + function _innerTest (userParam, username, expectedRoles, scope) { + // test that user has only the roles expected and no others + roles.forEach(function (role) { + const expected = expectedRoles.includes(role) + const msg = username + ' expected to have \'' + role + '\' role but does not' + const nmsg = username + ' had the following un-expected role: ' + role + + if (expected) { + assert.isTrue(Roles.userIsInRole(userParam, role, scope), msg) + } else { + assert.isFalse(Roles.userIsInRole(userParam, role, scope), nmsg) + } + }) + } + + beforeEach(function () { + Meteor.roles.remove({}) + Meteor.roleAssignment.remove({}) + Meteor.users.remove({}) + + users = { + eve: addUser('eve'), + bob: addUser('bob'), + joe: addUser('joe') + } + }) + + it('can create and delete roles', function () { + const role1Id = Roles.createRole('test1') + assert.equal(Meteor.roles.findOne()._id, 'test1') + assert.equal(Meteor.roles.findOne(role1Id)._id, 'test1') + + const role2Id = Roles.createRole('test2') + assert.equal(Meteor.roles.findOne({ _id: 'test2' })._id, 'test2') + assert.equal(Meteor.roles.findOne(role2Id)._id, 'test2') + + assert.equal(Meteor.roles.find().count(), 2) + + Roles.deleteRole('test1') + assert.equal(typeof Meteor.roles.findOne({ _id: 'test1' }), 'undefined') + + Roles.deleteRole('test2') + assert.equal(typeof Meteor.roles.findOne(), 'undefined') + }) + + it('can try to remove non-existing roles without crashing', function () { + Roles.deleteRole('non-existing-role') + }) + + it('can\'t create duplicate roles', function () { + Roles.createRole('test1') + assert.throws(function () { Roles.createRole('test1') }) + assert.isNull(Roles.createRole('test1', { unlessExists: true })) + }) + + it('can\'t create role with empty names', function () { + assert.throws(function () { + Roles.createRole('') + }, /Invalid role name/) + assert.throws(function () { + Roles.createRole(null) + }, /Invalid role name/) + assert.throws(function () { + Roles.createRole(' ') + }, /Invalid role name/) + assert.throws(function () { + Roles.createRole(' foobar') + }, /Invalid role name/) + assert.throws(function () { + Roles.createRole(' foobar ') + }, /Invalid role name/) + }) + + it('can\'t use invalid scope names', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + + assert.throws(function () { + Roles.addUsersToRoles(users.eve, ['admin', 'user'], '') + }, /Invalid scope name/) + assert.throws(function () { + Roles.addUsersToRoles(users.eve, ['admin', 'user'], ' ') + }, /Invalid scope name/) + assert.throws(function () { + Roles.addUsersToRoles(users.eve, ['admin', 'user'], ' foobar') + }, /Invalid scope name/) + assert.throws(function () { + Roles.addUsersToRoles(users.eve, ['admin', 'user'], ' foobar ') + }, /Invalid scope name/) + assert.throws(function () { + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 42) + }, /Invalid scope name/) + }) + + it('can check if user is in role', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.addUsersToRoles(users.eve, ['admin', 'user']) + + testUser('eve', ['admin', 'user']) + }) + + it('can check if user is in role by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('eve', ['editor'], 'scope2') + + assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope2')) + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], 'scope1')) + + assert.isTrue(Roles.userIsInRole(users.eve, ['admin', 'user'], { anyScope: true })) + assert.isTrue(Roles.userIsInRole(users.eve, ['editor'], { anyScope: true })) + }) + + it('can check if user is in role by scope through options', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + Roles.addUsersToRoles(users.eve, ['admin', 'user'], { scope: 'scope1' }) + Roles.addUsersToRoles(users.eve, ['editor'], { scope: 'scope2' }) + + testUser('eve', ['admin', 'user'], { scope: 'scope1' }) + testUser('eve', ['editor'], { scope: 'scope2' }) + }) + + it('can check if user is in role by scope with global role', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + Roles.addUsersToRoles(users.eve, ['admin']) + + assert.isTrue(Roles.userIsInRole(users.eve, ['user'], 'scope1')) + assert.isTrue(Roles.userIsInRole(users.eve, ['editor'], 'scope2')) + + assert.isFalse(Roles.userIsInRole(users.eve, ['user'])) + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'])) + assert.isFalse(Roles.userIsInRole(users.eve, ['user'], null)) + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], null)) + + assert.isFalse(Roles.userIsInRole(users.eve, ['user'], 'scope2')) + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], 'scope1')) + + assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], 'scope2')) + assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], 'scope1')) + assert.isTrue(Roles.userIsInRole(users.eve, ['admin'])) + assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], null)) + }) + + it('renaming scopes', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('eve', ['editor'], 'scope2') + + Roles.renameScope('scope1', 'scope3') + + testUser('eve', ['admin', 'user'], 'scope3') + testUser('eve', ['editor'], 'scope2') + + assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope1')) + assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope2')) + + assert.throws(function () { + Roles.renameScope('scope3') + }, /Invalid scope name/) + + Roles.renameScope('scope3', null) + + testUser('eve', ['admin', 'user', 'editor'], 'scope2') + + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'])) + assert.isTrue(Roles.userIsInRole(users.eve, ['admin'])) + assert.isTrue(Roles.userIsInRole(users.eve, ['user'])) + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], null)) + assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], null)) + assert.isTrue(Roles.userIsInRole(users.eve, ['user'], null)) + + Roles.renameScope(null, 'scope2') + + testUser('eve', ['admin', 'user', 'editor'], 'scope2') + + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'])) + assert.isFalse(Roles.userIsInRole(users.eve, ['admin'])) + assert.isFalse(Roles.userIsInRole(users.eve, ['user'])) + assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], null)) + assert.isFalse(Roles.userIsInRole(users.eve, ['admin'], null)) + assert.isFalse(Roles.userIsInRole(users.eve, ['user'], null)) + }) + + it('removing scopes', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('eve', ['editor'], 'scope2') + + Roles.removeScope('scope1') + + testUser('eve', ['editor'], 'scope2') + + assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope1')) + assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope2')) + }) + + it('can check if non-existant user is in role', function () { + assert.isFalse(Roles.userIsInRole('1', 'admin')) + }) + + it('can check if null user is in role', function () { + assert.isFalse(Roles.userIsInRole(null, 'admin')) + }) + + it('can check user against several roles at once', function () { + Roles.createRole('admin') + Roles.createRole('user') + + Roles.addUsersToRoles(users.eve, ['admin', 'user']) + const user = Meteor.users.findOne({ _id: users.eve }) + + // we can check the non-existing role + assert.isTrue(Roles.userIsInRole(user, ['editor', 'admin'])) + }) + + it('can\'t add non-existent user to role', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles(['1'], ['admin']) + assert.equal(Meteor.users.findOne({ _id: '1' }), undefined) + }) + + it('can\'t add user to non-existent role', function () { + assert.throws(function () { + Roles.addUsersToRoles(users.eve, ['admin']) + }, /Role 'admin' does not exist/) + Roles.addUsersToRoles(users.eve, ['admin'], { ifExists: true }) + }) + + it('can\'t set non-existent user to role', function () { + Roles.createRole('admin') + + Roles.setUserRoles(['1'], ['admin']) + assert.equal(Meteor.users.findOne({ _id: '1' }), undefined) + }) + + it('can\'t set user to non-existent role', function () { + assert.throws(function () { + Roles.setUserRoles(users.eve, ['admin']) + }, /Role 'admin' does not exist/) + Roles.setUserRoles(users.eve, ['admin'], { ifExists: true }) + }) + + it('can add individual users to roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.addUsersToRoles(users.eve, ['admin', 'user']) + + testUser('eve', ['admin', 'user']) + testUser('bob', []) + testUser('joe', []) + + Roles.addUsersToRoles(users.joe, ['editor', 'user']) + + testUser('eve', ['admin', 'user']) + testUser('bob', []) + testUser('joe', ['editor', 'user']) + }) + + it('can add individual users to roles by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('bob', [], 'scope1') + testUser('joe', [], 'scope1') + + testUser('eve', [], 'scope2') + testUser('bob', [], 'scope2') + testUser('joe', [], 'scope2') + + Roles.addUsersToRoles(users.joe, ['editor', 'user'], 'scope1') + Roles.addUsersToRoles(users.bob, ['editor', 'user'], 'scope2') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('bob', [], 'scope1') + testUser('joe', ['editor', 'user'], 'scope1') + + testUser('eve', [], 'scope2') + testUser('bob', ['editor', 'user'], 'scope2') + testUser('joe', [], 'scope2') + }) + + it('can add user to roles via user object', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) + + Roles.addUsersToRoles(eve, ['admin', 'user']) + + testUser('eve', ['admin', 'user']) + testUser('bob', []) + testUser('joe', []) + + Roles.addUsersToRoles(bob, ['editor']) + + testUser('eve', ['admin', 'user']) + testUser('bob', ['editor']) + testUser('joe', []) + }) + + it('can add user to roles multiple times', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.addUsersToRoles(users.eve, ['admin', 'user']) + Roles.addUsersToRoles(users.eve, ['admin', 'user']) + + testUser('eve', ['admin', 'user']) + testUser('bob', []) + testUser('joe', []) + + Roles.addUsersToRoles(users.bob, ['admin']) + Roles.addUsersToRoles(users.bob, ['editor']) + + testUser('eve', ['admin', 'user']) + testUser('bob', ['admin', 'editor']) + testUser('joe', []) + }) + + it('can add user to roles multiple times by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('bob', [], 'scope1') + testUser('joe', [], 'scope1') + + Roles.addUsersToRoles(users.bob, ['admin'], 'scope1') + Roles.addUsersToRoles(users.bob, ['editor'], 'scope1') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('bob', ['admin', 'editor'], 'scope1') + testUser('joe', [], 'scope1') + }) + + it('can add multiple users to roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.addUsersToRoles([users.eve, users.bob], ['admin', 'user']) + + testUser('eve', ['admin', 'user']) + testUser('bob', ['admin', 'user']) + testUser('joe', []) + + Roles.addUsersToRoles([users.bob, users.joe], ['editor', 'user']) + + testUser('eve', ['admin', 'user']) + testUser('bob', ['admin', 'editor', 'user']) + testUser('joe', ['editor', 'user']) + }) + + it('can add multiple users to roles by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.addUsersToRoles([users.eve, users.bob], ['admin', 'user'], 'scope1') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('bob', ['admin', 'user'], 'scope1') + testUser('joe', [], 'scope1') + + testUser('eve', [], 'scope2') + testUser('bob', [], 'scope2') + testUser('joe', [], 'scope2') + + Roles.addUsersToRoles([users.bob, users.joe], ['editor', 'user'], 'scope1') + Roles.addUsersToRoles([users.bob, users.joe], ['editor', 'user'], 'scope2') + + testUser('eve', ['admin', 'user'], 'scope1') + testUser('bob', ['admin', 'editor', 'user'], 'scope1') + testUser('joe', ['editor', 'user'], 'scope1') + + testUser('eve', [], 'scope2') + testUser('bob', ['editor', 'user'], 'scope2') + testUser('joe', ['editor', 'user'], 'scope2') + }) + + it('can remove individual users from roles', function () { + Roles.createRole('user') + Roles.createRole('editor') + + // remove user role - one user + Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user']) + testUser('eve', ['editor', 'user']) + testUser('bob', ['editor', 'user']) + Roles.removeUsersFromRoles(users.eve, ['user']) + testUser('eve', ['editor']) + testUser('bob', ['editor', 'user']) + }) + + it('can remove user from roles multiple times', function () { + Roles.createRole('user') + Roles.createRole('editor') + + // remove user role - one user + Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user']) + testUser('eve', ['editor', 'user']) + testUser('bob', ['editor', 'user']) + Roles.removeUsersFromRoles(users.eve, ['user']) + testUser('eve', ['editor']) + testUser('bob', ['editor', 'user']) + + // try remove again + Roles.removeUsersFromRoles(users.eve, ['user']) + testUser('eve', ['editor']) + }) + + it('can remove users from roles via user object', function () { + Roles.createRole('user') + Roles.createRole('editor') + + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) + + // remove user role - one user + Roles.addUsersToRoles([eve, bob], ['editor', 'user']) + testUser('eve', ['editor', 'user']) + testUser('bob', ['editor', 'user']) + Roles.removeUsersFromRoles(eve, ['user']) + testUser('eve', ['editor']) + testUser('bob', ['editor', 'user']) + }) + + it('can remove individual users from roles by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + // remove user role - one user + Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') + Roles.addUsersToRoles([users.joe, users.bob], ['admin'], 'scope2') + testUser('eve', ['editor', 'user'], 'scope1') + testUser('bob', ['editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope2') + + Roles.removeUsersFromRoles(users.eve, ['user'], 'scope1') + testUser('eve', ['editor'], 'scope1') + testUser('bob', ['editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope2') + }) + + it('can remove individual users from roles by scope through options', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + // remove user role - one user + Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], { scope: 'scope1' }) + Roles.addUsersToRoles([users.joe, users.bob], ['admin'], { scope: 'scope2' }) + testUser('eve', ['editor', 'user'], 'scope1') + testUser('bob', ['editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope2') + + Roles.removeUsersFromRoles(users.eve, ['user'], { scope: 'scope1' }) + testUser('eve', ['editor'], 'scope1') + testUser('bob', ['editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope2') + }) + + it('can remove multiple users from roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + // remove user role - two users + Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user']) + testUser('eve', ['editor', 'user']) + testUser('bob', ['editor', 'user']) + + assert.isFalse(Roles.userIsInRole(users.joe, 'admin')) + Roles.addUsersToRoles([users.bob, users.joe], ['admin', 'user']) + testUser('bob', ['admin', 'user', 'editor']) + testUser('joe', ['admin', 'user']) + Roles.removeUsersFromRoles([users.bob, users.joe], ['admin']) + testUser('bob', ['user', 'editor']) + testUser('joe', ['user']) + }) + + it('can remove multiple users from roles by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + // remove user role - one user + Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') + Roles.addUsersToRoles([users.joe, users.bob], ['admin'], 'scope2') + testUser('eve', ['editor', 'user'], 'scope1') + testUser('bob', ['editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope2') + + Roles.removeUsersFromRoles([users.eve, users.bob], ['user'], 'scope1') + testUser('eve', ['editor'], 'scope1') + testUser('bob', ['editor'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope2') + + Roles.removeUsersFromRoles([users.joe, users.bob], ['admin'], 'scope2') + testUser('eve', [], 'scope2') + testUser('bob', [], 'scope2') + testUser('joe', [], 'scope2') + }) + + it('can remove multiple users from roles of any scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + // remove user role - one user + Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') + Roles.addUsersToRoles([users.joe, users.bob], ['user'], 'scope2') + testUser('eve', ['editor', 'user'], 'scope1') + testUser('bob', ['editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['user'], 'scope2') + testUser('joe', ['user'], 'scope2') + + Roles.removeUsersFromRoles([users.eve, users.bob], ['user'], { anyScope: true }) + testUser('eve', ['editor'], 'scope1') + testUser('bob', ['editor'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', [], 'scope2') + testUser('joe', ['user'], 'scope2') + }) + + it('can set user roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) + + Roles.setUserRoles([users.eve, bob], ['editor', 'user']) + testUser('eve', ['editor', 'user']) + testUser('bob', ['editor', 'user']) + testUser('joe', []) + + // use addUsersToRoles add some roles + Roles.addUsersToRoles([bob, users.joe], ['admin']) + testUser('eve', ['editor', 'user']) + testUser('bob', ['admin', 'editor', 'user']) + testUser('joe', ['admin']) + + Roles.setUserRoles([eve, bob], ['user']) + testUser('eve', ['user']) + testUser('bob', ['user']) + testUser('joe', ['admin']) + + Roles.setUserRoles(bob, 'editor') + testUser('eve', ['user']) + testUser('bob', ['editor']) + testUser('joe', ['admin']) + + Roles.setUserRoles([users.joe, users.bob], []) + testUser('eve', ['user']) + testUser('bob', []) + testUser('joe', []) + }) + + it('can set user roles by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + const eve = Meteor.users.findOne({ _id: users.eve }) + const bob = Meteor.users.findOne({ _id: users.bob }) + const joe = Meteor.users.findOne({ _id: users.joe }) + + Roles.setUserRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') + Roles.setUserRoles([users.bob, users.joe], ['admin'], 'scope2') + testUser('eve', ['editor', 'user'], 'scope1') + testUser('bob', ['editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope2') + + // use addUsersToRoles add some roles + Roles.addUsersToRoles([users.eve, users.bob], ['admin'], 'scope1') + Roles.addUsersToRoles([users.bob, users.joe], ['editor'], 'scope2') + testUser('eve', ['admin', 'editor', 'user'], 'scope1') + testUser('bob', ['admin', 'editor', 'user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', [], 'scope2') + testUser('bob', ['admin', 'editor'], 'scope2') + testUser('joe', ['admin', 'editor'], 'scope2') + + Roles.setUserRoles([eve, bob], ['user'], 'scope1') + Roles.setUserRoles([eve, joe], ['editor'], 'scope2') + testUser('eve', ['user'], 'scope1') + testUser('bob', ['user'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', ['editor'], 'scope2') + testUser('bob', ['admin', 'editor'], 'scope2') + testUser('joe', ['editor'], 'scope2') + + Roles.setUserRoles(bob, 'editor', 'scope1') + testUser('eve', ['user'], 'scope1') + testUser('bob', ['editor'], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', ['editor'], 'scope2') + testUser('bob', ['admin', 'editor'], 'scope2') + testUser('joe', ['editor'], 'scope2') + + assert.isTrue(Roles.getRolesForUser(users.bob, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) + assert.isFalse(Roles.getRolesForUser(users.joe, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) + + Roles.setUserRoles([bob, users.joe], [], 'scope1') + testUser('eve', ['user'], 'scope1') + testUser('bob', [], 'scope1') + testUser('joe', [], 'scope1') + testUser('eve', ['editor'], 'scope2') + testUser('bob', ['admin', 'editor'], 'scope2') + testUser('joe', ['editor'], 'scope2') + + // When roles in a given scope are removed, we do not want any dangling database content for that scope. + assert.isFalse(Roles.getRolesForUser(users.bob, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) + assert.isFalse(Roles.getRolesForUser(users.joe, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) + }) + + it('can set user roles by scope including GLOBAL_SCOPE', function () { + Roles.createRole('admin') + Roles.createRole('editor') + + const eve = Meteor.users.findOne({ _id: users.eve }) + + Roles.addUsersToRoles(eve, 'admin', Roles.GLOBAL_SCOPE) + testUser('eve', ['admin'], 'scope1') + testUser('eve', ['admin']) + + Roles.setUserRoles(eve, 'editor', Roles.GLOBAL_SCOPE) + testUser('eve', ['editor'], 'scope2') + testUser('eve', ['editor']) + }) + + it('can set user roles by scope and anyScope', function () { + Roles.createRole('admin') + Roles.createRole('editor') + + const eve = Meteor.users.findOne({ _id: users.eve }) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + + Roles.addUsersToRoles(eve, 'admin') + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + Roles.setUserRoles(eve, 'editor', { anyScope: true, scope: 'scope2' }) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'editor' }, + scope: 'scope2', + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'editor' }] + }]) + }) + + it('can get all roles', function () { + roles.forEach(function (role) { + Roles.createRole(role) + }) + + // compare roles, sorted alphabetically + const expected = roles + const actual = Roles.getAllRoles().fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + + assert.sameMembers(Roles.getAllRoles({ sort: { _id: -1 } }).fetch().map(r => r._id), expected.reverse()) + }) + + it('get an empty list of roles for an empty user', function () { + assert.sameMembers(Roles.getRolesForUser(undefined), []) + assert.sameMembers(Roles.getRolesForUser(null), []) + assert.sameMembers(Roles.getRolesForUser({}), []) + }) + + it('get an empty list of roles for non-existant user', function () { + assert.sameMembers(Roles.getRolesForUser('1'), []) + assert.sameMembers(Roles.getRolesForUser('1', 'scope1'), []) + }) + + it('can get all roles for user', function () { + Roles.createRole('admin') + Roles.createRole('user') + + const userId = users.eve + let userObj + + // by userId + assert.sameMembers(Roles.getRolesForUser(userId), []) + + // by user object + userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getRolesForUser(userObj), []) + + Roles.addUsersToRoles(userId, ['admin', 'user']) + + // by userId + assert.sameMembers(Roles.getRolesForUser(userId), ['admin', 'user']) + + // by user object + userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getRolesForUser(userObj), ['admin', 'user']) + + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: null, + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }] + }]) + }) + + it('can get all roles for user by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + + const userId = users.eve + let userObj + + // by userId + assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), []) + + // by user object + userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), []) + + // add roles + Roles.addUsersToRoles(userId, ['admin', 'user'], 'scope1') + Roles.addUsersToRoles(userId, ['admin'], 'scope2') + + // by userId + assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), ['admin', 'user']) + assert.sameMembers(Roles.getRolesForUser(userId, 'scope2'), ['admin']) + assert.sameMembers(Roles.getRolesForUser(userId), []) + + // by user object + userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), ['admin', 'user']) + assert.sameMembers(Roles.getRolesForUser(userObj, 'scope2'), ['admin']) + assert.sameMembers(Roles.getRolesForUser(userObj), []) + + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }] + }]) + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }] + }, { + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + Roles.createRole('PERMISSION') + Roles.addRolesToParent('PERMISSION', 'user') + + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }]) + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope1' }), ['admin', 'user', 'PERMISSION']) + assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope2' }), ['admin']) + + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }, { + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(Roles.getRolesForUser(userId, { anyScope: true }), ['admin', 'user', 'PERMISSION']) + + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope1', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }]) + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope2', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope1', onlyAssigned: true }), ['admin', 'user']) + assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope2', onlyAssigned: true }), ['admin']) + + assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, anyScope: true, onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }, { + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(Roles.getRolesForUser(userId, { anyScope: true, onlyAssigned: true }), ['admin', 'user']) + }) + + it('can get only scoped roles for user', function () { + Roles.createRole('admin') + Roles.createRole('user') + + const userId = users.eve + + // add roles + Roles.addUsersToRoles(userId, ['user'], 'scope1') + Roles.addUsersToRoles(userId, ['admin']) + + Roles.createRole('PERMISSION') + Roles.addRolesToParent('PERMISSION', 'user') + + assert.sameMembers(Roles.getRolesForUser(userId, { onlyScoped: true, scope: 'scope1' }), ['user', 'PERMISSION']) + assert.sameMembers(Roles.getRolesForUser(userId, { onlyScoped: true, onlyAssigned: true, scope: 'scope1' }), ['user']) + assert.sameDeepMembers(Roles.getRolesForUser(userId, { onlyScoped: true, fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }]) + }) + + it('can get all roles for user by scope with periods in name', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles(users.joe, ['admin'], 'example.k12.va.us') + + assert.sameMembers(Roles.getRolesForUser(users.joe, 'example.k12.va.us'), ['admin']) + }) + + it('can get all roles for user by scope including Roles.GLOBAL_SCOPE', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + const userId = users.eve + + Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + Roles.addUsersToRoles([users.eve], ['admin', 'user'], 'scope1') + + // by userId + assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), ['editor', 'admin', 'user']) + assert.sameMembers(Roles.getRolesForUser(userId), ['editor']) + + // by user object + const userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), ['editor', 'admin', 'user']) + assert.sameMembers(Roles.getRolesForUser(userObj), ['editor']) + }) + + it('getRolesForUser should not return null entries if user has no roles for scope', function () { + Roles.createRole('editor') + + const userId = users.eve + let userObj + + // by userId + assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), []) + assert.sameMembers(Roles.getRolesForUser(userId), []) + + // by user object + userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), []) + assert.sameMembers(Roles.getRolesForUser(userObj), []) + + Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + + // by userId + assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), ['editor']) + assert.sameMembers(Roles.getRolesForUser(userId), ['editor']) + + // by user object + userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), ['editor']) + assert.sameMembers(Roles.getRolesForUser(userObj), ['editor']) + }) + + it('getRolesForUser should not fail during a call of addUsersToRoles', function () { + Roles.createRole('editor') + + const userId = users.eve + const promises = [] + const interval = setInterval(() => { + promises.push(Promise.resolve().then(() => { Roles.getRolesForUser(userId) })) + }, 0) + + Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + clearInterval(interval) + + return Promise.all(promises) + }) + + it('returns an empty list of scopes for null as user-id', function () { + assert.sameMembers(Roles.getScopesForUser(undefined), []) + assert.sameMembers(Roles.getScopesForUser(null), []) + assert.sameMembers(Roles.getScopesForUser('foo'), []) + assert.sameMembers(Roles.getScopesForUser({}), []) + assert.sameMembers(Roles.getScopesForUser({ _id: 'foo' }), []) + }) + + it('can get all scopes for user', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + const userId = users.eve + + Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') + Roles.addUsersToRoles([users.eve], ['admin', 'user'], 'scope2') + + // by userId + assert.sameMembers(Roles.getScopesForUser(userId), ['scope1', 'scope2']) + + // by user object + const userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getScopesForUser(userObj), ['scope1', 'scope2']) + }) + + it('can get all scopes for user by role', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + const userId = users.eve + + Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') + Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'scope2') + + // by userId + assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) + assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) + + // by user object + const userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) + assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) + }) + + it('getScopesForUser returns [] when not using scopes', function () { + Roles.createRole('user') + Roles.createRole('editor') + + const userId = users.eve + + Roles.addUsersToRoles([users.eve], ['editor', 'user']) + + // by userId + assert.sameMembers(Roles.getScopesForUser(userId), []) + assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), []) + assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), []) + assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), []) + + // by user object + const userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getScopesForUser(userObj), []) + assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), []) + assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), []) + assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), []) + }) + + it('can get all groups for user by role array', function () { + const userId = users.eve + + Roles.createRole('user') + Roles.createRole('editor') + Roles.createRole('moderator') + Roles.createRole('admin') + + Roles.addUsersToRoles([users.eve], ['editor'], 'group1') + Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'group2') + Roles.addUsersToRoles([users.eve], ['moderator'], 'group3') + + // by userId, one role + assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['group2']) + assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['group1', 'group2']) + assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) + + // by userId, multiple roles + assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), ['group1', 'group2']) + assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'moderator']), ['group1', 'group2', 'group3']) + assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'moderator']), ['group2', 'group3']) + + // by user object, one role + const userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['group2']) + assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['group1', 'group2']) + assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) + + // by user object, multiple roles + assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), ['group1', 'group2']) + assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'moderator']), ['group1', 'group2', 'group3']) + assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'moderator']), ['group2', 'group3']) + }) + + it('getting all scopes for user does not include GLOBAL_SCOPE', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + const userId = users.eve + + Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') + Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'scope2') + Roles.addUsersToRoles([users.eve], ['editor', 'user', 'admin'], Roles.GLOBAL_SCOPE) + + // by userId + assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) + assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) + assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['scope2']) + assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['scope1', 'scope2']) + assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) + assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'editor', 'admin']), ['scope1', 'scope2']) + + // by user object + const userObj = Meteor.users.findOne({ _id: userId }) + assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) + assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) + assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['scope2']) + assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['scope1', 'scope2']) + assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) + assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'editor', 'admin']), ['scope1', 'scope2']) + }) + + it('can get all users in role', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user']) + Roles.addUsersToRoles([users.bob, users.joe], ['editor']) + + const expected = [users.eve, users.joe] + const actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + }) + + it('can get all users in role by scope', function () { + Roles.createRole('admin') + Roles.createRole('user') + + Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user'], 'scope1') + Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') + + let expected = [users.eve, users.joe] + let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + + expected = [users.eve, users.joe] + actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) + assert.sameMembers(actual, expected) + + expected = [users.eve, users.bob, users.joe] + actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) + assert.sameMembers(actual, expected) + + actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + assert.sameMembers(actual, []) + }) + + it('can get all users in role by scope including Roles.GLOBAL_SCOPE', function () { + Roles.createRole('admin') + Roles.createRole('user') + + Roles.addUsersToRoles([users.eve], ['admin', 'user'], Roles.GLOBAL_SCOPE) + Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') + + let expected = [users.eve] + let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + + expected = [users.eve, users.bob, users.joe] + actual = Roles.getUsersInRole('admin', 'scope2').fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + + expected = [users.eve] + actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + + expected = [users.eve, users.bob, users.joe] + actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + }) + + it('can get all users in role by scope excluding Roles.GLOBAL_SCOPE', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles([users.eve], ['admin'], Roles.GLOBAL_SCOPE) + Roles.addUsersToRoles([users.bob], ['admin'], 'scope1') + + let expected = [users.eve] + let actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + assert.sameMembers(actual, expected) + + expected = [users.eve, users.bob] + actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) + assert.sameMembers(actual, expected) + + expected = [users.bob] + actual = Roles.getUsersInRole('admin', { scope: 'scope1', onlyScoped: true }).fetch().map(r => r._id) + assert.sameMembers(actual, expected) + }) + + it('can get all users in role by scope and passes through mongo query arguments', function () { + Roles.createRole('admin') + Roles.createRole('user') + + Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user'], 'scope1') + Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') + + const results = Roles.getUsersInRole('admin', 'scope1', { fields: { username: 0 }, limit: 1 }).fetch() + + assert.equal(1, results.length) + assert.isTrue(hasProp(results[0], '_id')) + assert.isFalse(hasProp(results[0], 'username')) + }) + + it('can use Roles.GLOBAL_SCOPE to assign blanket roles', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) + + testUser('eve', [], 'scope1') + testUser('joe', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope1') + testUser('bob', ['admin'], 'scope2') + testUser('bob', ['admin'], 'scope1') + + Roles.removeUsersFromRoles(users.joe, ['admin'], Roles.GLOBAL_SCOPE) + + testUser('eve', [], 'scope1') + testUser('joe', [], 'scope2') + testUser('joe', [], 'scope1') + testUser('bob', ['admin'], 'scope2') + testUser('bob', ['admin'], 'scope1') + }) + + it('Roles.GLOBAL_SCOPE is independent of other scopes', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles([users.joe, users.bob], ['admin'], 'scope5') + Roles.addUsersToRoles([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) + + testUser('eve', [], 'scope1') + testUser('joe', ['admin'], 'scope5') + testUser('joe', ['admin'], 'scope2') + testUser('joe', ['admin'], 'scope1') + testUser('bob', ['admin'], 'scope5') + testUser('bob', ['admin'], 'scope2') + testUser('bob', ['admin'], 'scope1') + + Roles.removeUsersFromRoles(users.joe, ['admin'], Roles.GLOBAL_SCOPE) + + testUser('eve', [], 'scope1') + testUser('joe', ['admin'], 'scope5') + testUser('joe', [], 'scope2') + testUser('joe', [], 'scope1') + testUser('bob', ['admin'], 'scope5') + testUser('bob', ['admin'], 'scope2') + testUser('bob', ['admin'], 'scope1') + }) + + it('Roles.GLOBAL_SCOPE also checked when scope not specified', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles(users.joe, 'admin', Roles.GLOBAL_SCOPE) + + testUser('joe', ['admin']) + + Roles.removeUsersFromRoles(users.joe, 'admin', Roles.GLOBAL_SCOPE) + + testUser('joe', []) + }) + + it('can use \'.\' in scope name', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles(users.joe, ['admin'], 'example.com') + testUser('joe', ['admin'], 'example.com') + }) + + it('can use multiple periods in scope name', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles(users.joe, ['admin'], 'example.k12.va.us') + testUser('joe', ['admin'], 'example.k12.va.us') + }) + + it('renaming of roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + + Roles.setUserRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') + Roles.setUserRoles([users.bob, users.joe], ['user', 'admin'], 'scope2') + + assert.isTrue(Roles.userIsInRole(users.eve, 'editor', 'scope1')) + assert.isFalse(Roles.userIsInRole(users.eve, 'editor', 'scope2')) + + assert.isFalse(Roles.userIsInRole(users.joe, 'admin', 'scope1')) + assert.isTrue(Roles.userIsInRole(users.joe, 'admin', 'scope2')) + + assert.isTrue(Roles.userIsInRole(users.eve, 'user', 'scope1')) + assert.isTrue(Roles.userIsInRole(users.bob, 'user', 'scope1')) + assert.isFalse(Roles.userIsInRole(users.joe, 'user', 'scope1')) + + assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope2')) + assert.isTrue(Roles.userIsInRole(users.bob, 'user', 'scope2')) + assert.isTrue(Roles.userIsInRole(users.joe, 'user', 'scope2')) + + assert.isFalse(Roles.userIsInRole(users.eve, 'user2', 'scope1')) + assert.isFalse(Roles.userIsInRole(users.eve, 'user2', 'scope2')) + + Roles.renameRole('user', 'user2') + + assert.isTrue(Roles.userIsInRole(users.eve, 'editor', 'scope1')) + assert.isFalse(Roles.userIsInRole(users.eve, 'editor', 'scope2')) + + assert.isFalse(Roles.userIsInRole(users.joe, 'admin', 'scope1')) + assert.isTrue(Roles.userIsInRole(users.joe, 'admin', 'scope2')) + + assert.isTrue(Roles.userIsInRole(users.eve, 'user2', 'scope1')) + assert.isTrue(Roles.userIsInRole(users.bob, 'user2', 'scope1')) + assert.isFalse(Roles.userIsInRole(users.joe, 'user2', 'scope1')) + + assert.isFalse(Roles.userIsInRole(users.eve, 'user2', 'scope2')) + assert.isTrue(Roles.userIsInRole(users.bob, 'user2', 'scope2')) + assert.isTrue(Roles.userIsInRole(users.joe, 'user2', 'scope2')) + + assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope1')) + assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope2')) + }) + + it('migration without global groups (to v2)', function () { + assert.isOk(Meteor.roles.insert({ name: 'admin' })) + assert.isOk(Meteor.roles.insert({ name: 'editor' })) + assert.isOk(Meteor.roles.insert({ name: 'user' })) + + assert.isOk(Meteor.users.update(users.eve, { $set: { roles: ['admin', 'editor'] } })) + assert.isOk(Meteor.users.update(users.bob, { $set: { roles: [] } })) + assert.isOk(Meteor.users.update(users.joe, { $set: { roles: ['user'] } })) + + Roles._forwardMigrate() + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'admin', + scope: null, + assigned: true + }, { + _id: 'editor', + scope: null, + assigned: true + }] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'user', + scope: null, + assigned: true + }] + }) + + assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { + _id: 'admin', + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { + _id: 'editor', + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { + _id: 'user', + children: [] + }) + + Roles._backwardMigrate(null, null, false) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: ['admin', 'editor'] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: ['user'] + }) + + assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { + name: 'admin' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { + name: 'editor' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { + name: 'user' + }) + }) + + it('migration without global groups (to v3)') + + it('migration with global groups (to v2)', function () { + assert.isOk(Meteor.roles.insert({ name: 'admin' })) + assert.isOk(Meteor.roles.insert({ name: 'editor' })) + assert.isOk(Meteor.roles.insert({ name: 'user' })) + + assert.isOk(Meteor.users.update(users.eve, { $set: { roles: { __global_roles__: ['admin', 'editor'], foo_bla: ['user'] } } })) + assert.isOk(Meteor.users.update(users.bob, { $set: { roles: { } } })) + assert.isOk(Meteor.users.update(users.joe, { $set: { roles: { __global_roles__: ['user'], foo_bla: ['user'] } } })) + + Roles._forwardMigrate(null, null, false) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'admin', + scope: null, + assigned: true + }, { + _id: 'editor', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo_bla', + assigned: true + }] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'user', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo_bla', + assigned: true + }] + }) + + assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { + _id: 'admin', + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { + _id: 'editor', + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { + _id: 'user', + children: [] + }) + + Roles._backwardMigrate(null, null, true) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: { + __global_roles__: ['admin', 'editor'], + foo_bla: ['user'] + } + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: {} + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: { + __global_roles__: ['user'], + foo_bla: ['user'] + } + }) + + assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { + name: 'admin' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { + name: 'editor' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { + name: 'user' + }) + + Roles._forwardMigrate(null, null, true) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'admin', + scope: null, + assigned: true + }, { + _id: 'editor', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo.bla', + assigned: true + }] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'user', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo.bla', + assigned: true + }] + }) + + assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { + _id: 'admin', + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { + _id: 'editor', + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { + _id: 'user', + children: [] + }) + }) + + it('migration with global groups (to v3)') + + it('_addUserToRole', function () { + Roles.createRole('admin') + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + + assert.include( + Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), + 'insertedId' + ) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + assert.notInclude( + Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), + 'insertedId' + ) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'admin' }] + }]) + }) + + it('_removeUserFromRole', function () { + Roles.createRole('admin') + + Roles.addUsersToRoles(users.eve, 'admin') + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + Roles._removeUserFromRole(users.eve, 'admin', { scope: null }) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + }) + + it('keep assigned roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('ALL_PERMISSIONS') + Roles.createRole('VIEW_PERMISSION') + Roles.createRole('EDIT_PERMISSION') + Roles.createRole('DELETE_PERMISSION') + Roles.addRolesToParent('ALL_PERMISSIONS', 'user') + Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') + Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') + Roles.addRolesToParent('DELETE_PERMISSION', 'admin') + + Roles.addUsersToRoles(users.eve, ['user']) + + assert.isTrue(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }]) + + Roles.addUsersToRoles(users.eve, 'VIEW_PERMISSION') + + assert.isTrue(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }, { + role: { _id: 'VIEW_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'VIEW_PERMISSION' } + ] + }]) + + Roles.removeUsersFromRoles(users.eve, 'user') + + assert.isTrue(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'VIEW_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'VIEW_PERMISSION' } + ] + }]) + + Roles.removeUsersFromRoles(users.eve, 'VIEW_PERMISSION') + + assert.isFalse(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + }) + + it('adds children of the added role to the assignments', function () { + Roles.createRole('admin') + Roles.createRole('ALBUM.ADMIN') + Roles.createRole('ALBUM.VIEW') + Roles.createRole('TRACK.ADMIN') + Roles.createRole('TRACK.VIEW') + + Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') + Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') + + Roles.addRolesToParent('ALBUM.ADMIN', 'admin') + + Roles.addUsersToRoles(users.eve, ['admin']) + + assert.isFalse(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) + + Roles.addRolesToParent('TRACK.ADMIN', 'admin') + + assert.isTrue(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) + }) + + it('removes children of the removed role from the assignments', function () { + Roles.createRole('admin') + Roles.createRole('ALBUM.ADMIN') + Roles.createRole('ALBUM.VIEW') + Roles.createRole('TRACK.ADMIN') + Roles.createRole('TRACK.VIEW') + + Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') + Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') + + Roles.addRolesToParent('ALBUM.ADMIN', 'admin') + Roles.addRolesToParent('TRACK.ADMIN', 'admin') + + Roles.addUsersToRoles(users.eve, ['admin']) + + assert.isTrue(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) + + Roles.removeRolesFromParent('TRACK.ADMIN', 'admin') + + assert.isFalse(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) + }) + + it('modify assigned hierarchical roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('ALL_PERMISSIONS') + Roles.createRole('VIEW_PERMISSION') + Roles.createRole('EDIT_PERMISSION') + Roles.createRole('DELETE_PERMISSION') + Roles.addRolesToParent('ALL_PERMISSIONS', 'user') + Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') + Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') + Roles.addRolesToParent('DELETE_PERMISSION', 'admin') + + Roles.addUsersToRoles(users.eve, ['user']) + Roles.addUsersToRoles(users.eve, ['ALL_PERMISSIONS'], 'scope') + + assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION', 'scope')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }]) + + Roles.createRole('MODERATE_PERMISSION') + + Roles.addRolesToParent('MODERATE_PERMISSION', 'ALL_PERMISSIONS') + + assert.isTrue(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION')) + assert.isTrue(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION', 'scope')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }]) + + Roles.addUsersToRoles(users.eve, ['admin']) + + assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) + assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }, { + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'admin' }, + { _id: 'DELETE_PERMISSION' } + ] + }]) + + Roles.addRolesToParent('DELETE_PERMISSION', 'ALL_PERMISSIONS') + + assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) + assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }, { + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'admin' }, + { _id: 'DELETE_PERMISSION' } + ] + }]) + + Roles.removeUsersFromRoles(users.eve, ['admin']) + + assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) + assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }]) + + Roles.deleteRole('ALL_PERMISSIONS') + + assert.isFalse(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) + + assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION', 'scope')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' } + ] + }]) + }) + + it('delete role with overlapping hierarchical roles', function () { + Roles.createRole('role1') + Roles.createRole('role2') + Roles.createRole('COMMON_PERMISSION_1') + Roles.createRole('COMMON_PERMISSION_2') + Roles.createRole('COMMON_PERMISSION_3') + Roles.createRole('EXTRA_PERMISSION_ROLE_1') + Roles.createRole('EXTRA_PERMISSION_ROLE_2') + + Roles.addRolesToParent('COMMON_PERMISSION_1', 'role1') + Roles.addRolesToParent('COMMON_PERMISSION_2', 'role1') + Roles.addRolesToParent('COMMON_PERMISSION_3', 'role1') + Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_1', 'role1') + + Roles.addRolesToParent('COMMON_PERMISSION_1', 'role2') + Roles.addRolesToParent('COMMON_PERMISSION_2', 'role2') + Roles.addRolesToParent('COMMON_PERMISSION_3', 'role2') + Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_2', 'role2') + + Roles.addUsersToRoles(users.eve, 'role1') + Roles.addUsersToRoles(users.eve, 'role2') + + assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }, { + role: { _id: 'role2' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role2' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_2' } + ] + }]) + + Roles.removeUsersFromRoles(users.eve, 'role2') + + assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isFalse(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }]) + + Roles.addUsersToRoles(users.eve, 'role2') + + assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }, { + role: { _id: 'role2' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role2' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_2' } + ] + }]) + + Roles.deleteRole('role2') + + assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isFalse(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }]) + }) + + it('set parent on assigned role', function () { + Roles.createRole('admin') + Roles.createRole('EDIT_PERMISSION') + + Roles.addUsersToRoles(users.eve, 'EDIT_PERMISSION') + + assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + Roles.addRolesToParent('EDIT_PERMISSION', 'admin') + + assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + }) + + it('remove parent on assigned role', function () { + Roles.createRole('admin') + Roles.createRole('EDIT_PERMISSION') + + Roles.addRolesToParent('EDIT_PERMISSION', 'admin') + + Roles.addUsersToRoles(users.eve, 'EDIT_PERMISSION') + + assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + Roles.removeRolesFromParent('EDIT_PERMISSION', 'admin') + + assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + }) + + it('adding and removing extra role parents', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('EDIT_PERMISSION') + + Roles.addRolesToParent('EDIT_PERMISSION', 'admin') + + Roles.addUsersToRoles(users.eve, 'EDIT_PERMISSION') + + assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + Roles.addRolesToParent('EDIT_PERMISSION', 'user') + + assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + Roles.removeRolesFromParent('EDIT_PERMISSION', 'user') + + assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) + + assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + }) + + it('cyclic roles', function () { + Roles.createRole('admin') + Roles.createRole('editor') + Roles.createRole('user') + + Roles.addRolesToParent('editor', 'admin') + Roles.addRolesToParent('user', 'editor') + + assert.throws(function () { + Roles.addRolesToParent('admin', 'user') + }, /form a cycle/) + }) + + it('userIsInRole returns false for unknown roles', function () { + Roles.createRole('admin') + Roles.createRole('user') + Roles.createRole('editor') + Roles.addUsersToRoles(users.eve, ['admin', 'user']) + Roles.addUsersToRoles(users.eve, ['editor']) + + assert.isFalse(Roles.userIsInRole(users.eve, 'unknown')) + assert.isFalse(Roles.userIsInRole(users.eve, [])) + assert.isFalse(Roles.userIsInRole(users.eve, null)) + assert.isFalse(Roles.userIsInRole(users.eve, undefined)) + + assert.isFalse(Roles.userIsInRole(users.eve, 'unknown', { anyScope: true })) + assert.isFalse(Roles.userIsInRole(users.eve, [], { anyScope: true })) + assert.isFalse(Roles.userIsInRole(users.eve, null, { anyScope: true })) + assert.isFalse(Roles.userIsInRole(users.eve, undefined, { anyScope: true })) + + assert.isFalse(Roles.userIsInRole(users.eve, ['Role1', 'Role2', undefined], 'GroupName')) + }) + + it('userIsInRole returns false if user is a function', function () { + Roles.createRole('admin') + Roles.addUsersToRoles(users.eve, ['admin']) + + assert.isFalse(Roles.userIsInRole(() => {}, 'admin')) + }) + + describe('isParentOf', function () { + it('returns false for unknown roles', function () { + Roles.createRole('admin') + + assert.isFalse(Roles.isParentOf('admin', 'unknown')) + assert.isFalse(Roles.isParentOf('admin', null)) + assert.isFalse(Roles.isParentOf('admin', undefined)) + + assert.isFalse(Roles.isParentOf('unknown', 'admin')) + assert.isFalse(Roles.isParentOf(null, 'admin')) + assert.isFalse(Roles.isParentOf(undefined, 'admin')) + }) + + it('returns false if role is not parent of', function () { + Roles.createRole('admin') + Roles.createRole('editor') + Roles.createRole('user') + Roles.addRolesToParent(['editor'], 'admin') + Roles.addRolesToParent(['user'], 'editor') + + assert.isFalse(Roles.isParentOf('user', 'admin')) + assert.isFalse(Roles.isParentOf('editor', 'admin')) + }) + + it('returns true if role is parent of the demanded role', function () { + Roles.createRole('admin') + Roles.createRole('editor') + Roles.createRole('user') + Roles.addRolesToParent(['editor'], 'admin') + Roles.addRolesToParent(['user'], 'editor') + + assert.isTrue(Roles.isParentOf('admin', 'user')) + assert.isTrue(Roles.isParentOf('editor', 'user')) + assert.isTrue(Roles.isParentOf('admin', 'editor')) + + assert.isTrue(Roles.isParentOf('admin', 'admin')) + assert.isTrue(Roles.isParentOf('editor', 'editor')) + assert.isTrue(Roles.isParentOf('user', 'user')) + }) + }) +}) From 5037425b21871fe2633c23ce4ebe3a83627cd6d8 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Fri, 25 Aug 2023 11:31:28 +0200 Subject: [PATCH 44/53] Start work on async server tests --- package.js | 1 + roles/tests/serverAsync.js | 11 +++++++---- testapp/package-lock.json | 9 +++++++++ testapp/package.json | 1 + 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/package.js b/package.js index 4a01cbbc..f362cf22 100644 --- a/package.js +++ b/package.js @@ -57,6 +57,7 @@ Package.onTest(function (api) { ], both) api.addFiles('roles/tests/server.js', 'server') + api.addFiles('roles/tests/serverAsync.js', 'server') api.addFiles('roles/tests/client.js', 'client') api.addFiles('roles/tests/clientAsync.js', 'client') }) diff --git a/roles/tests/serverAsync.js b/roles/tests/serverAsync.js index b3fb854d..d3385ce0 100644 --- a/roles/tests/serverAsync.js +++ b/roles/tests/serverAsync.js @@ -2,7 +2,10 @@ /* global Roles */ import { Meteor } from 'meteor/meteor' -import { assert } from 'chai' +import chai, { assert, expect } from 'chai' +import chaiAsPromised from 'chai-as-promised' + +chai.use(chaiAsPromised) // To ensure that the files are loaded for coverage import '../roles_server' @@ -17,7 +20,7 @@ Meteor.roleAssignment.allow({ const hasProp = (target, prop) => Object.hasOwnProperty.call(target, prop) -describe('roles', function () { +describe('roles async', async function () { let users = {} const roles = ['admin', 'editor', 'user'] @@ -32,8 +35,8 @@ describe('roles', function () { return Meteor.roleAssignment.find({ _id: loggedInUserId }) }) - function addUser (name) { - return Meteor.users.insert({ username: name }) + async function addUser (name) { + return await Meteor.users.insertAsync({ username: name }) } function testUser (username, expectedRoles, scope) { diff --git a/testapp/package-lock.json b/testapp/package-lock.json index 7a2921ca..12d666b9 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -983,6 +983,15 @@ "type-detect": "^4.0.5" } }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", diff --git a/testapp/package.json b/testapp/package.json index f986e8f7..42e60dab 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -18,6 +18,7 @@ "devDependencies": { "babel-plugin-istanbul": "^6.1.1", "chai": "^4.3.7", + "chai-as-promised": "^7.1.1", "nyc": "^15.1.0", "puppeteer": "^19.4.0", "standard": "^17.1.0" From a0b1859bf451cd118820cd98c106f5a8d14dd203 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Fri, 25 Aug 2023 12:33:20 +0200 Subject: [PATCH 45/53] Improve JSDocs And import Meteor and Mongo --- roles/roles_common_async.js | 63 ++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 9a97bee8..de847a97 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -1,4 +1,6 @@ -/* global Meteor, Roles, Mongo */ +/* global Roles */ +import { Meteor } from 'meteor/meteor' +import { Mongo } from 'meteor/mongo' /** * Provides functions related to user authorization. Compatible with built-in Meteor accounts packages. @@ -45,7 +47,7 @@ let getGroupsForUserDeprecationWarning = false * Helper, resolves async some * @param {*} arr * @param {*} predicate - * @returns + * @returns {Promise} */ const asyncSome = async (arr, predicate) => { for (const e of arr) { @@ -71,7 +73,7 @@ Object.assign(Roles, { * @param {String} roleName Name of role. * @param {Object} [options] Options: * - `unlessExists`: if `true`, exception will not be thrown in the role already exists - * @return {String} ID of the new role or null. + * @return {Promise} ID of the new role or null. * @static */ createRoleAsync: async function (roleName, options) { @@ -103,7 +105,7 @@ Object.assign(Roles, { if (!insertedId) { if (options.unlessExists) return null - throw new Error("Role '" + roleName + "' already exists.") + throw new Meteor.Error("Role '" + roleName + "' already exists.") } return insertedId @@ -116,6 +118,7 @@ Object.assign(Roles, { * * @method deleteRole * @param {String} roleName Name of role. + * @returns {Promise} * @static */ deleteRoleAsync: async function (roleName) { @@ -180,6 +183,7 @@ Object.assign(Roles, { * @method renameRole * @param {String} oldName Old name of a role. * @param {String} newName New name of a role. + * @returns {Promise} * @static */ renameRoleAsync: async function (oldName, newName) { @@ -193,7 +197,7 @@ Object.assign(Roles, { const role = await Meteor.roles.findOneAsync({ _id: oldName }) if (!role) { - throw new Error("Role '" + oldName + "' does not exist.") + throw new Meteor.Error("Role '" + oldName + "' does not exist.") } role._id = newName @@ -254,6 +258,7 @@ Object.assign(Roles, { * @method addRolesToParent * @param {Array|String} rolesNames Name(s) of role(s). * @param {String} parentName Name of parent role. + * @returns {Promise} * @static */ addRolesToParentAsync: async function (rolesNames, parentName) { @@ -269,6 +274,7 @@ Object.assign(Roles, { * @method _addRoleToParent * @param {String} roleName Name of role. * @param {String} parentName Name of parent role. + * @returns {Promise} * @private * @static */ @@ -280,12 +286,12 @@ Object.assign(Roles, { const role = await Meteor.roles.findOneAsync({ _id: roleName }) if (!role) { - throw new Error("Role '" + roleName + "' does not exist.") + throw new Meteor.Error("Role '" + roleName + "' does not exist.") } // detect cycles if ((await Roles._getInheritedRoleNamesAsync(role)).includes(parentName)) { - throw new Error( + throw new Meteor.Error( "Roles '" + roleName + "' and '" + parentName + "' would form a cycle." ) } @@ -337,6 +343,7 @@ Object.assign(Roles, { * @method removeRolesFromParent * @param {Array|String} rolesNames Name(s) of role(s). * @param {String} parentName Name of parent role. + * @returns {Promise} * @static */ removeRolesFromParentAsync: async function (rolesNames, parentName) { @@ -352,6 +359,7 @@ Object.assign(Roles, { * @method _removeRoleFromParent * @param {String} roleName Name of role. * @param {String} parentName Name of parent role. + * @returns {Promise} * @private * @static */ @@ -367,7 +375,7 @@ Object.assign(Roles, { ) if (!role) { - throw new Error("Role '" + roleName + "' does not exist.") + throw new Meteor.Error("Role '" + roleName + "' does not exist.") } const count = await Meteor.roles.updateAsync( @@ -435,6 +443,7 @@ Object.assign(Roles, { * @param {Object|String} [options] Options: * - `scope`: name of the scope, or `null` for the global role * - `ifExists`: if `true`, do not throw an exception if the role does not exist + * @returns {Promise} * * Alternatively, it can be a scope name string. * @static @@ -442,8 +451,8 @@ Object.assign(Roles, { addUsersToRolesAsync: async function (users, roles, options) { let id - if (!users) throw new Error("Missing 'users' param.") - if (!roles) throw new Error("Missing 'roles' param.") + if (!users) throw new Meteor.Error("Missing 'users' param.") + if (!roles) throw new Meteor.Error("Missing 'roles' param.") options = Roles._normalizeOptions(options) @@ -491,6 +500,7 @@ Object.assign(Roles, { * - `scope`: name of the scope, or `null` for the global role * - `anyScope`: if `true`, remove all roles the user has, of any scope, if `false`, only the one in the same scope * - `ifExists`: if `true`, do not throw an exception if the role does not exist + * @returns {Promise} * * Alternatively, it can be a scope name string. * @static @@ -498,8 +508,8 @@ Object.assign(Roles, { setUserRolesAsync: async function (users, roles, options) { let id - if (!users) throw new Error("Missing 'users' param.") - if (!roles) throw new Error("Missing 'roles' param.") + if (!users) throw new Meteor.Error("Missing 'users' param.") + if (!roles) throw new Meteor.Error("Missing 'roles' param.") options = Roles._normalizeOptions(options) @@ -547,6 +557,7 @@ Object.assign(Roles, { * @param {Object} options Options: * - `scope`: name of the scope, or `null` for the global role * - `ifExists`: if `true`, do not throw an exception if the role does not exist + * @returns {Promise} * @private * @static */ @@ -567,7 +578,7 @@ Object.assign(Roles, { if (options.ifExists) { return [] } else { - throw new Error("Role '" + roleName + "' does not exist.") + throw new Meteor.Error("Role '" + roleName + "' does not exist.") } } @@ -639,6 +650,7 @@ Object.assign(Roles, { * * @method _getParentRoleNames * @param {object} role The role object + * @returns {Promise} * @private * @static */ @@ -670,6 +682,7 @@ Object.assign(Roles, { * * @method _getInheritedRoleNames * @param {object} role The role object + * @returns {Promise} * @private * @static */ @@ -708,13 +721,14 @@ Object.assign(Roles, { * @param {Object|String} [options] Options: * - `scope`: name of the scope, or `null` for the global role * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * @returns {Promise} * * Alternatively, it can be a scope name string. * @static */ removeUsersFromRolesAsync: async function (users, roles, options) { - if (!users) throw new Error("Missing 'users' param.") - if (!roles) throw new Error("Missing 'roles' param.") + if (!users) throw new Meteor.Error("Missing 'users' param.") + if (!roles) throw new Meteor.Error("Missing 'roles' param.") options = Roles._normalizeOptions(options) @@ -749,6 +763,7 @@ Object.assign(Roles, { * @param {Object} options Options: * - `scope`: name of the scope, or `null` for the global role * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) + * @returns {Promise} * @private * @static */ @@ -796,7 +811,7 @@ Object.assign(Roles, { * - `anyScope`: if set, role can be in any scope (`scope` option is ignored) * * Alternatively, it can be a scope name string. - * @return {Boolean} `true` if user is in _any_ of the target roles + * @return {Promise} `true` if user is in _any_ of the target roles * @static */ userIsInRoleAsync: async function (user, roles, options) { @@ -864,7 +879,7 @@ Object.assign(Roles, { * result strongly dependant on the internal data structure of this plugin. * * Alternatively, it can be a scope name string. - * @return {Array} Array of user's roles, unsorted. + * @return {Promise} Array of user's roles, unsorted. * @static */ getRolesForUserAsync: async function (user, options) { @@ -973,7 +988,7 @@ Object.assign(Roles, { * Alternatively, it can be a scope name string. * @param {Object} [queryOptions] Options which are passed directly * through to `Meteor.users.find(query, options)` - * @return {Cursor} Cursor of users in roles. + * @return {Promise} Cursor of users in roles. * @static */ getUsersInRoleAsync: async function (roles, options, queryOptions) { @@ -1082,6 +1097,7 @@ Object.assign(Roles, { * Deprecated. Use `getScopesForUser` instead. * * @method getGroupsForUser + * @returns {Promise} * @static * @deprecated */ @@ -1094,7 +1110,7 @@ Object.assign(Roles, { ) } - return Roles.getScopesForUser(...args) + return await Roles.getScopesForUser(...args) }, /** @@ -1104,7 +1120,7 @@ Object.assign(Roles, { * @param {String|Object} user User ID or an actual user object. * @param {Array|String} [roles] Name of roles to restrict scopes to. * - * @return {Array} Array of user's scopes, unsorted. + * @return {Promise} Array of user's scopes, unsorted. * @static */ getScopesForUserAsync: async function (user, roles) { @@ -1146,6 +1162,7 @@ Object.assign(Roles, { * @method renameScope * @param {String} oldName Old name of a scope. * @param {String} newName New name of a scope. + * @returns {Promise} * @static */ renameScopeAsync: async function (oldName, newName) { @@ -1178,6 +1195,7 @@ Object.assign(Roles, { * * @method removeScope * @param {String} name The name of a scope. + * @returns {Promise} * @static */ removeScopeAsync: async function (name) { @@ -1200,7 +1218,7 @@ Object.assign(Roles, { typeof roleName !== 'string' || roleName.trim() !== roleName ) { - throw new Error("Invalid role name '" + roleName + "'.") + throw new Meteor.Error(500,"Invalid role name '" + roleName + "'.") } }, @@ -1212,6 +1230,7 @@ Object.assign(Roles, { * @method isParentOf * @param {String} parentRoleName The role you want to research. * @param {String} childRoleName The role you expect to be among the children of parentRoleName. + * @returns {Promise} * @static */ isParentOfAsync: async function (parentRoleName, childRoleName) { @@ -1300,7 +1319,7 @@ Object.assign(Roles, { typeof scopeName !== 'string' || scopeName.trim() !== scopeName ) { - throw new Error("Invalid scope name '" + scopeName + "'.") + throw new Meteor.Error("Invalid scope name '" + scopeName + "'.") } } }) From a299af350c95358409a98a50c5d4593ec80f2b89 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Fri, 25 Aug 2023 13:04:13 +0200 Subject: [PATCH 46/53] Revert Meteor.Error Not for this PR --- roles/roles_common_async.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index de847a97..ad9c0fcd 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -105,7 +105,7 @@ Object.assign(Roles, { if (!insertedId) { if (options.unlessExists) return null - throw new Meteor.Error("Role '" + roleName + "' already exists.") + throw new Error("Role '" + roleName + "' already exists.") } return insertedId @@ -197,7 +197,7 @@ Object.assign(Roles, { const role = await Meteor.roles.findOneAsync({ _id: oldName }) if (!role) { - throw new Meteor.Error("Role '" + oldName + "' does not exist.") + throw new Error("Role '" + oldName + "' does not exist.") } role._id = newName @@ -286,12 +286,12 @@ Object.assign(Roles, { const role = await Meteor.roles.findOneAsync({ _id: roleName }) if (!role) { - throw new Meteor.Error("Role '" + roleName + "' does not exist.") + throw new Error("Role '" + roleName + "' does not exist.") } // detect cycles if ((await Roles._getInheritedRoleNamesAsync(role)).includes(parentName)) { - throw new Meteor.Error( + throw new Error( "Roles '" + roleName + "' and '" + parentName + "' would form a cycle." ) } @@ -375,7 +375,7 @@ Object.assign(Roles, { ) if (!role) { - throw new Meteor.Error("Role '" + roleName + "' does not exist.") + throw new Error("Role '" + roleName + "' does not exist.") } const count = await Meteor.roles.updateAsync( @@ -451,8 +451,8 @@ Object.assign(Roles, { addUsersToRolesAsync: async function (users, roles, options) { let id - if (!users) throw new Meteor.Error("Missing 'users' param.") - if (!roles) throw new Meteor.Error("Missing 'roles' param.") + if (!users) throw new Error("Missing 'users' param.") + if (!roles) throw new Error("Missing 'roles' param.") options = Roles._normalizeOptions(options) @@ -508,8 +508,8 @@ Object.assign(Roles, { setUserRolesAsync: async function (users, roles, options) { let id - if (!users) throw new Meteor.Error("Missing 'users' param.") - if (!roles) throw new Meteor.Error("Missing 'roles' param.") + if (!users) throw new Error("Missing 'users' param.") + if (!roles) throw new Error("Missing 'roles' param.") options = Roles._normalizeOptions(options) @@ -578,7 +578,7 @@ Object.assign(Roles, { if (options.ifExists) { return [] } else { - throw new Meteor.Error("Role '" + roleName + "' does not exist.") + throw new Error("Role '" + roleName + "' does not exist.") } } @@ -727,8 +727,8 @@ Object.assign(Roles, { * @static */ removeUsersFromRolesAsync: async function (users, roles, options) { - if (!users) throw new Meteor.Error("Missing 'users' param.") - if (!roles) throw new Meteor.Error("Missing 'roles' param.") + if (!users) throw new Error("Missing 'users' param.") + if (!roles) throw new Error("Missing 'roles' param.") options = Roles._normalizeOptions(options) @@ -1218,7 +1218,7 @@ Object.assign(Roles, { typeof roleName !== 'string' || roleName.trim() !== roleName ) { - throw new Meteor.Error(500,"Invalid role name '" + roleName + "'.") + throw new Error("Invalid role name '" + roleName + "'.") } }, @@ -1319,7 +1319,7 @@ Object.assign(Roles, { typeof scopeName !== 'string' || scopeName.trim() !== scopeName ) { - throw new Meteor.Error("Invalid scope name '" + scopeName + "'.") + throw new Error("Invalid scope name '" + scopeName + "'.") } } }) From a8bc5a80ac615b1b2f560a914eddd7afc3dfd62b Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sun, 24 Sep 2023 12:18:19 +0200 Subject: [PATCH 47/53] Get more async tests and fix lint test error --- roles/tests/serverAsync.js | 4065 ++++++++++++++++++------------------ testapp/.meteor/packages | 2 +- testapp/.meteor/release | 2 +- testapp/.meteor/versions | 9 +- 4 files changed, 2037 insertions(+), 2041 deletions(-) diff --git a/roles/tests/serverAsync.js b/roles/tests/serverAsync.js index d3385ce0..5b4fda6f 100644 --- a/roles/tests/serverAsync.js +++ b/roles/tests/serverAsync.js @@ -2,15 +2,15 @@ /* global Roles */ import { Meteor } from 'meteor/meteor' -import chai, { assert, expect } from 'chai' +import chai, { assert } from 'chai' import chaiAsPromised from 'chai-as-promised' -chai.use(chaiAsPromised) - // To ensure that the files are loaded for coverage import '../roles_server' import '../roles_common' +chai.use(chaiAsPromised) + // To allow inserting on the client, needed for testing. Meteor.roleAssignment.allow({ insert () { return true }, @@ -39,733 +39,734 @@ describe('roles async', async function () { return await Meteor.users.insertAsync({ username: name }) } - function testUser (username, expectedRoles, scope) { + async function testUser (username, expectedRoles, scope) { const userId = users[username] - const userObj = Meteor.users.findOne({ _id: userId }) + const userObj = await Meteor.users.findOneAsync({ _id: userId }) // check using user ids (makes db calls) - _innerTest(userId, username, expectedRoles, scope) + await _innerTest(userId, username, expectedRoles, scope) // check using passed-in user object - _innerTest(userObj, username, expectedRoles, scope) + await _innerTest(userObj, username, expectedRoles, scope) } - function _innerTest (userParam, username, expectedRoles, scope) { + async function _innerTest (userParam, username, expectedRoles, scope) { // test that user has only the roles expected and no others - roles.forEach(function (role) { + for (const role of roles) { const expected = expectedRoles.includes(role) const msg = username + ' expected to have \'' + role + '\' role but does not' const nmsg = username + ' had the following un-expected role: ' + role if (expected) { - assert.isTrue(Roles.userIsInRole(userParam, role, scope), msg) + assert.isTrue(await Roles.userIsInRoleAsync(userParam, role, scope), msg) } else { - assert.isFalse(Roles.userIsInRole(userParam, role, scope), nmsg) + assert.isFalse(await Roles.userIsInRoleAsync(userParam, role, scope), nmsg) } - }) + } } - beforeEach(function () { - Meteor.roles.remove({}) - Meteor.roleAssignment.remove({}) - Meteor.users.remove({}) + beforeEach(async function () { + await Meteor.roles.removeAsync({}) + await Meteor.roleAssignment.removeAsync({}) + await Meteor.users.removeAsync({}) users = { - eve: addUser('eve'), - bob: addUser('bob'), - joe: addUser('joe') + eve: await addUser('eve'), + bob: await addUser('bob'), + joe: await addUser('joe') } }) - it('can create and delete roles', function () { - const role1Id = Roles.createRole('test1') - assert.equal(Meteor.roles.findOne()._id, 'test1') - assert.equal(Meteor.roles.findOne(role1Id)._id, 'test1') + it('can create and delete roles', async function () { + const role1Id = await Roles.createRoleAsync('test1') + const test1a = await Meteor.roles.findOneAsync() + const test1b = await Meteor.roles.findOneAsync(role1Id) + assert.equal(test1a._id, 'test1') + assert.equal(test1b._id, 'test1') - const role2Id = Roles.createRole('test2') - assert.equal(Meteor.roles.findOne({ _id: 'test2' })._id, 'test2') - assert.equal(Meteor.roles.findOne(role2Id)._id, 'test2') + const role2Id = await Roles.createRoleAsync('test2') + const test2a = await Meteor.roles.findOneAsync({ _id: 'test2' }) + const test2b = await Meteor.roles.findOneAsync(role2Id) + assert.equal(test2a._id, 'test2') + assert.equal(test2b._id, 'test2') - assert.equal(Meteor.roles.find().count(), 2) + assert.equal(await Meteor.roles.countDocuments(), 2) - Roles.deleteRole('test1') - assert.equal(typeof Meteor.roles.findOne({ _id: 'test1' }), 'undefined') + await Roles.deleteRoleAsync('test1') + const undefinedTest = await Meteor.roles.findOneAsync({ _id: 'test1' }) + assert.equal(typeof undefinedTest, 'undefined') - Roles.deleteRole('test2') - assert.equal(typeof Meteor.roles.findOne(), 'undefined') + await Roles.deleteRoleAsync('test2') + const undefinedTest2 = await Meteor.roles.findOneAsync() + assert.equal(typeof undefinedTest2, 'undefined') }) - it('can try to remove non-existing roles without crashing', function () { - Roles.deleteRole('non-existing-role') + it('can try to remove non-existing roles without crashing', async function () { + try { + await Roles.deleteRoleAsync('non-existing-role') + } catch (e) { + assert.notExists(e) + } + // Roles.deleteRoleAsync('non-existing-role').should.be.fulfilled }) - it('can\'t create duplicate roles', function () { - Roles.createRole('test1') - assert.throws(function () { Roles.createRole('test1') }) - assert.isNull(Roles.createRole('test1', { unlessExists: true })) + it('can\'t create duplicate roles', async function () { + try { + await Roles.createRoleAsync('test1') + } catch (e) { + assert.notExists(e) + } + // assert.eventually.throws(Roles.createRoleAsync('test1')) + try { + await Roles.createRoleAsync('test1') + } catch (e) { + assert.exists(e) + } + assert.isNull(await Roles.createRoleAsync('test1', { unlessExists: true })) }) - it('can\'t create role with empty names', function () { - assert.throws(function () { - Roles.createRole('') - }, /Invalid role name/) - assert.throws(function () { - Roles.createRole(null) - }, /Invalid role name/) - assert.throws(function () { - Roles.createRole(' ') - }, /Invalid role name/) - assert.throws(function () { - Roles.createRole(' foobar') - }, /Invalid role name/) - assert.throws(function () { - Roles.createRole(' foobar ') - }, /Invalid role name/) + it('can\'t create role with empty names', async function () { + assert.isRejected(Roles.createRoleAsync(''), /Invalid role name/) + assert.isRejected(Roles.createRoleAsync(null), /Invalid role name/) + assert.isRejected(Roles.createRoleAsync(' '), /Invalid role name/) + assert.isRejected(Roles.createRoleAsync(' foobar'), /Invalid role name/) + assert.isRejected(Roles.createRoleAsync(' foobar '), /Invalid role name/) }) - it('can\'t use invalid scope names', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') - Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') - - assert.throws(function () { - Roles.addUsersToRoles(users.eve, ['admin', 'user'], '') - }, /Invalid scope name/) - assert.throws(function () { - Roles.addUsersToRoles(users.eve, ['admin', 'user'], ' ') - }, /Invalid scope name/) - assert.throws(function () { - Roles.addUsersToRoles(users.eve, ['admin', 'user'], ' foobar') - }, /Invalid scope name/) - assert.throws(function () { - Roles.addUsersToRoles(users.eve, ['admin', 'user'], ' foobar ') - }, /Invalid scope name/) - assert.throws(function () { - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 42) - }, /Invalid scope name/) + it('can\'t use invalid scope names', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') + + assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ''), /Invalid scope name/) + assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' '), /Invalid scope name/) + assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' foobar'), /Invalid scope name/) + assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' foobar '), /Invalid scope name/) + assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 42), /Invalid scope name/) }) - it('can check if user is in role', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.addUsersToRoles(users.eve, ['admin', 'user']) + it('can check if user is in role', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) - testUser('eve', ['admin', 'user']) + await testUser('eve', ['admin', 'user']) }) - it('can check if user is in role by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') - Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + it('can check if user is in role by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') testUser('eve', ['admin', 'user'], 'scope1') testUser('eve', ['editor'], 'scope2') - assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope2')) - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], 'scope2')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'], 'scope1')) - assert.isTrue(Roles.userIsInRole(users.eve, ['admin', 'user'], { anyScope: true })) - assert.isTrue(Roles.userIsInRole(users.eve, ['editor'], { anyScope: true })) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], { anyScope: true })) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['editor'], { anyScope: true })) }) - it('can check if user is in role by scope through options', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], { scope: 'scope1' }) - Roles.addUsersToRoles(users.eve, ['editor'], { scope: 'scope2' }) + it('can check if user is in role by scope through options', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], { scope: 'scope1' }) + await Roles.addUsersToRolesAsync(users.eve, ['editor'], { scope: 'scope2' }) - testUser('eve', ['admin', 'user'], { scope: 'scope1' }) - testUser('eve', ['editor'], { scope: 'scope2' }) + await testUser('eve', ['admin', 'user'], { scope: 'scope1' }) + await testUser('eve', ['editor'], { scope: 'scope2' }) }) - it('can check if user is in role by scope with global role', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') - Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') - Roles.addUsersToRoles(users.eve, ['admin']) - - assert.isTrue(Roles.userIsInRole(users.eve, ['user'], 'scope1')) - assert.isTrue(Roles.userIsInRole(users.eve, ['editor'], 'scope2')) - - assert.isFalse(Roles.userIsInRole(users.eve, ['user'])) - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'])) - assert.isFalse(Roles.userIsInRole(users.eve, ['user'], null)) - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], null)) - - assert.isFalse(Roles.userIsInRole(users.eve, ['user'], 'scope2')) - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], 'scope1')) - - assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], 'scope2')) - assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], 'scope1')) - assert.isTrue(Roles.userIsInRole(users.eve, ['admin'])) - assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], null)) - }) + // it('can check if user is in role by scope with global role', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') + // Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') + // Roles.addUsersToRolesAsync(users.eve, ['admin']) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['user'], 'scope1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['editor'], 'scope2')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['user'])) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['editor'])) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['user'], null)) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['editor'], null)) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['user'], 'scope2')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['editor'], 'scope1')) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'], 'scope2')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'], 'scope1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'])) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'], null)) + // }) - it('renaming scopes', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') - Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + it('renaming scopes', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('eve', ['editor'], 'scope2') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('eve', ['editor'], 'scope2') - Roles.renameScope('scope1', 'scope3') + await Roles.renameScopeAsync('scope1', 'scope3') - testUser('eve', ['admin', 'user'], 'scope3') - testUser('eve', ['editor'], 'scope2') + await testUser('eve', ['admin', 'user'], 'scope3') + await testUser('eve', ['editor'], 'scope2') - assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope1')) - assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope2')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], 'scope2')) - assert.throws(function () { - Roles.renameScope('scope3') - }, /Invalid scope name/) + assert.isRejected(Roles.renameScopeAsync('scope3'), /Invalid scope name/) - Roles.renameScope('scope3', null) + await Roles.renameScopeAsync('scope3', null) - testUser('eve', ['admin', 'user', 'editor'], 'scope2') + await testUser('eve', ['admin', 'user', 'editor'], 'scope2') - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'])) - assert.isTrue(Roles.userIsInRole(users.eve, ['admin'])) - assert.isTrue(Roles.userIsInRole(users.eve, ['user'])) - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], null)) - assert.isTrue(Roles.userIsInRole(users.eve, ['admin'], null)) - assert.isTrue(Roles.userIsInRole(users.eve, ['user'], null)) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'])) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['admin'])) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['user'])) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'], null)) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['admin'], null)) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['user'], null)) - Roles.renameScope(null, 'scope2') + await Roles.renameScopeAsync(null, 'scope2') - testUser('eve', ['admin', 'user', 'editor'], 'scope2') + await testUser('eve', ['admin', 'user', 'editor'], 'scope2') - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'])) - assert.isFalse(Roles.userIsInRole(users.eve, ['admin'])) - assert.isFalse(Roles.userIsInRole(users.eve, ['user'])) - assert.isFalse(Roles.userIsInRole(users.eve, ['editor'], null)) - assert.isFalse(Roles.userIsInRole(users.eve, ['admin'], null)) - assert.isFalse(Roles.userIsInRole(users.eve, ['user'], null)) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'])) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin'])) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['user'])) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'], null)) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin'], null)) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['user'], null)) }) - it('removing scopes', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') - Roles.addUsersToRoles(users.eve, ['editor'], 'scope2') + it('removing scopes', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('eve', ['editor'], 'scope2') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('eve', ['editor'], 'scope2') - Roles.removeScope('scope1') + await Roles.removeScopeAsync('scope1') - testUser('eve', ['editor'], 'scope2') + await testUser('eve', ['editor'], 'scope2') - assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope1')) - assert.isFalse(Roles.userIsInRole(users.eve, ['admin', 'user'], 'scope2')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], 'scope2')) }) - it('can check if non-existant user is in role', function () { - assert.isFalse(Roles.userIsInRole('1', 'admin')) + it('can check if non-existant user is in role', async function () { + assert.isFalse(await Roles.userIsInRoleAsync('1', 'admin')) }) - it('can check if null user is in role', function () { - assert.isFalse(Roles.userIsInRole(null, 'admin')) + it('can check if null user is in role', async function () { + assert.isFalse(await Roles.userIsInRoleAsync(null, 'admin')) }) - it('can check user against several roles at once', function () { - Roles.createRole('admin') - Roles.createRole('user') + it('can check user against several roles at once', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') - Roles.addUsersToRoles(users.eve, ['admin', 'user']) - const user = Meteor.users.findOne({ _id: users.eve }) + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) + const user = await Meteor.users.findOneAsync({ _id: users.eve }) // we can check the non-existing role - assert.isTrue(Roles.userIsInRole(user, ['editor', 'admin'])) + assert.isTrue(await Roles.userIsInRoleAsync(user, ['editor', 'admin'])) }) - it('can\'t add non-existent user to role', function () { - Roles.createRole('admin') + it('can\'t add non-existent user to role', async function () { + await Roles.createRoleAsync('admin') - Roles.addUsersToRoles(['1'], ['admin']) - assert.equal(Meteor.users.findOne({ _id: '1' }), undefined) + await Roles.addUsersToRolesAsync(['1'], ['admin']) + assert.equal(await Meteor.users.findOneAsync({ _id: '1' }), undefined) }) - it('can\'t add user to non-existent role', function () { - assert.throws(function () { - Roles.addUsersToRoles(users.eve, ['admin']) - }, /Role 'admin' does not exist/) - Roles.addUsersToRoles(users.eve, ['admin'], { ifExists: true }) + it('can\'t add user to non-existent role', async function () { + assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin']), /Role 'admin' does not exist/) + await Roles.addUsersToRolesAsync(users.eve, ['admin'], { ifExists: true }) }) - it('can\'t set non-existent user to role', function () { - Roles.createRole('admin') + it('can\'t set non-existent user to role', async function () { + await Roles.createRoleAsync('admin') - Roles.setUserRoles(['1'], ['admin']) - assert.equal(Meteor.users.findOne({ _id: '1' }), undefined) + await Roles.setUserRolesAsync(['1'], ['admin']) + assert.equal(await Meteor.users.findOneAsync({ _id: '1' }), undefined) }) - it('can\'t set user to non-existent role', function () { - assert.throws(function () { - Roles.setUserRoles(users.eve, ['admin']) - }, /Role 'admin' does not exist/) - Roles.setUserRoles(users.eve, ['admin'], { ifExists: true }) + it('can\'t set user to non-existent role', async function () { + assert.isRejected(Roles.setUserRolesAsync(users.eve, ['admin']), /Role 'admin' does not exist/) + await Roles.setUserRolesAsync(users.eve, ['admin'], { ifExists: true }) }) - it('can add individual users to roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can add individual users to roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user']) + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) - testUser('eve', ['admin', 'user']) - testUser('bob', []) - testUser('joe', []) + await testUser('eve', ['admin', 'user']) + await testUser('bob', []) + await testUser('joe', []) - Roles.addUsersToRoles(users.joe, ['editor', 'user']) + await Roles.addUsersToRolesAsync(users.joe, ['editor', 'user']) - testUser('eve', ['admin', 'user']) - testUser('bob', []) - testUser('joe', ['editor', 'user']) + await testUser('eve', ['admin', 'user']) + await testUser('bob', []) + await testUser('joe', ['editor', 'user']) }) - it('can add individual users to roles by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can add individual users to roles by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('bob', [], 'scope1') - testUser('joe', [], 'scope1') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('bob', [], 'scope1') + await testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', [], 'scope2') - testUser('joe', [], 'scope2') + await testUser('eve', [], 'scope2') + await testUser('bob', [], 'scope2') + await testUser('joe', [], 'scope2') - Roles.addUsersToRoles(users.joe, ['editor', 'user'], 'scope1') - Roles.addUsersToRoles(users.bob, ['editor', 'user'], 'scope2') + await Roles.addUsersToRolesAsync(users.joe, ['editor', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.bob, ['editor', 'user'], 'scope2') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('bob', [], 'scope1') - testUser('joe', ['editor', 'user'], 'scope1') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('bob', [], 'scope1') + await testUser('joe', ['editor', 'user'], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['editor', 'user'], 'scope2') - testUser('joe', [], 'scope2') + await testUser('eve', [], 'scope2') + await testUser('bob', ['editor', 'user'], 'scope2') + await testUser('joe', [], 'scope2') }) - it('can add user to roles via user object', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can add user to roles via user object', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - const eve = Meteor.users.findOne({ _id: users.eve }) - const bob = Meteor.users.findOne({ _id: users.bob }) + const eve = await Meteor.users.findOneAsync({ _id: users.eve }) + const bob = await Meteor.users.findOneAsync({ _id: users.bob }) - Roles.addUsersToRoles(eve, ['admin', 'user']) + await Roles.addUsersToRolesAsync(eve, ['admin', 'user']) - testUser('eve', ['admin', 'user']) - testUser('bob', []) - testUser('joe', []) + await testUser('eve', ['admin', 'user']) + await testUser('bob', []) + await testUser('joe', []) - Roles.addUsersToRoles(bob, ['editor']) + await Roles.addUsersToRolesAsync(bob, ['editor']) - testUser('eve', ['admin', 'user']) - testUser('bob', ['editor']) - testUser('joe', []) + await testUser('eve', ['admin', 'user']) + await testUser('bob', ['editor']) + await testUser('joe', []) }) - it('can add user to roles multiple times', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can add user to roles multiple times', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user']) - Roles.addUsersToRoles(users.eve, ['admin', 'user']) + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) - testUser('eve', ['admin', 'user']) - testUser('bob', []) - testUser('joe', []) + await testUser('eve', ['admin', 'user']) + await testUser('bob', []) + await testUser('joe', []) - Roles.addUsersToRoles(users.bob, ['admin']) - Roles.addUsersToRoles(users.bob, ['editor']) + await Roles.addUsersToRolesAsync(users.bob, ['admin']) + await Roles.addUsersToRolesAsync(users.bob, ['editor']) - testUser('eve', ['admin', 'user']) - testUser('bob', ['admin', 'editor']) - testUser('joe', []) + await testUser('eve', ['admin', 'user']) + await testUser('bob', ['admin', 'editor']) + await testUser('joe', []) }) - it('can add user to roles multiple times by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can add user to roles multiple times by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') - Roles.addUsersToRoles(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('bob', [], 'scope1') - testUser('joe', [], 'scope1') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('bob', [], 'scope1') + await testUser('joe', [], 'scope1') - Roles.addUsersToRoles(users.bob, ['admin'], 'scope1') - Roles.addUsersToRoles(users.bob, ['editor'], 'scope1') + await Roles.addUsersToRolesAsync(users.bob, ['admin'], 'scope1') + await Roles.addUsersToRolesAsync(users.bob, ['editor'], 'scope1') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('bob', ['admin', 'editor'], 'scope1') - testUser('joe', [], 'scope1') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('bob', ['admin', 'editor'], 'scope1') + await testUser('joe', [], 'scope1') }) - it('can add multiple users to roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can add multiple users to roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - Roles.addUsersToRoles([users.eve, users.bob], ['admin', 'user']) + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['admin', 'user']) - testUser('eve', ['admin', 'user']) - testUser('bob', ['admin', 'user']) - testUser('joe', []) + await testUser('eve', ['admin', 'user']) + await testUser('bob', ['admin', 'user']) + await testUser('joe', []) - Roles.addUsersToRoles([users.bob, users.joe], ['editor', 'user']) + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['editor', 'user']) - testUser('eve', ['admin', 'user']) - testUser('bob', ['admin', 'editor', 'user']) - testUser('joe', ['editor', 'user']) + await testUser('eve', ['admin', 'user']) + await testUser('bob', ['admin', 'editor', 'user']) + await testUser('joe', ['editor', 'user']) }) - it('can add multiple users to roles by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can add multiple users to roles by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - Roles.addUsersToRoles([users.eve, users.bob], ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['admin', 'user'], 'scope1') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('bob', ['admin', 'user'], 'scope1') - testUser('joe', [], 'scope1') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('bob', ['admin', 'user'], 'scope1') + await testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', [], 'scope2') - testUser('joe', [], 'scope2') + await testUser('eve', [], 'scope2') + await testUser('bob', [], 'scope2') + await testUser('joe', [], 'scope2') - Roles.addUsersToRoles([users.bob, users.joe], ['editor', 'user'], 'scope1') - Roles.addUsersToRoles([users.bob, users.joe], ['editor', 'user'], 'scope2') + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['editor', 'user'], 'scope1') + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['editor', 'user'], 'scope2') - testUser('eve', ['admin', 'user'], 'scope1') - testUser('bob', ['admin', 'editor', 'user'], 'scope1') - testUser('joe', ['editor', 'user'], 'scope1') + await testUser('eve', ['admin', 'user'], 'scope1') + await testUser('bob', ['admin', 'editor', 'user'], 'scope1') + await testUser('joe', ['editor', 'user'], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['editor', 'user'], 'scope2') - testUser('joe', ['editor', 'user'], 'scope2') + await testUser('eve', [], 'scope2') + await testUser('bob', ['editor', 'user'], 'scope2') + await testUser('joe', ['editor', 'user'], 'scope2') }) - it('can remove individual users from roles', function () { - Roles.createRole('user') - Roles.createRole('editor') + it('can remove individual users from roles', async function () { + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') // remove user role - one user - Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user']) - testUser('eve', ['editor', 'user']) - testUser('bob', ['editor', 'user']) - Roles.removeUsersFromRoles(users.eve, ['user']) - testUser('eve', ['editor']) - testUser('bob', ['editor', 'user']) + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['editor', 'user']) + await testUser('eve', ['editor', 'user']) + await testUser('bob', ['editor', 'user']) + await Roles.removeUsersFromRolesAsync(users.eve, ['user']) + await testUser('eve', ['editor']) + await testUser('bob', ['editor', 'user']) }) - it('can remove user from roles multiple times', function () { - Roles.createRole('user') - Roles.createRole('editor') + it('can remove user from roles multiple times', async function () { + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') // remove user role - one user - Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user']) - testUser('eve', ['editor', 'user']) - testUser('bob', ['editor', 'user']) - Roles.removeUsersFromRoles(users.eve, ['user']) - testUser('eve', ['editor']) - testUser('bob', ['editor', 'user']) + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['editor', 'user']) + await testUser('eve', ['editor', 'user']) + await testUser('bob', ['editor', 'user']) + await Roles.removeUsersFromRolesAsync(users.eve, ['user']) + await testUser('eve', ['editor']) + await testUser('bob', ['editor', 'user']) // try remove again - Roles.removeUsersFromRoles(users.eve, ['user']) - testUser('eve', ['editor']) + await Roles.removeUsersFromRolesAsync(users.eve, ['user']) + await testUser('eve', ['editor']) }) - it('can remove users from roles via user object', function () { - Roles.createRole('user') - Roles.createRole('editor') + it('can remove users from roles via user object', async function () { + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - const eve = Meteor.users.findOne({ _id: users.eve }) - const bob = Meteor.users.findOne({ _id: users.bob }) + const eve = await Meteor.users.findOneAsync({ _id: users.eve }) + const bob = await Meteor.users.findOneAsync({ _id: users.bob }) // remove user role - one user - Roles.addUsersToRoles([eve, bob], ['editor', 'user']) - testUser('eve', ['editor', 'user']) - testUser('bob', ['editor', 'user']) - Roles.removeUsersFromRoles(eve, ['user']) - testUser('eve', ['editor']) - testUser('bob', ['editor', 'user']) + await Roles.addUsersToRolesAsync([eve, bob], ['editor', 'user']) + await testUser('eve', ['editor', 'user']) + await testUser('bob', ['editor', 'user']) + await Roles.removeUsersFromRolesAsync(eve, ['user']) + await testUser('eve', ['editor']) + await testUser('bob', ['editor', 'user']) }) - it('can remove individual users from roles by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can remove individual users from roles by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') // remove user role - one user - Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') - Roles.addUsersToRoles([users.joe, users.bob], ['admin'], 'scope2') - testUser('eve', ['editor', 'user'], 'scope1') - testUser('bob', ['editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope2') - - Roles.removeUsersFromRoles(users.eve, ['user'], 'scope1') - testUser('eve', ['editor'], 'scope1') - testUser('bob', ['editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope2') - }) - - it('can remove individual users from roles by scope through options', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['editor', 'user'], 'scope1') + await Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], 'scope2') + await testUser('eve', ['editor', 'user'], 'scope1') + await testUser('bob', ['editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope2') + + await Roles.removeUsersFromRolesAsync(users.eve, ['user'], 'scope1') + await testUser('eve', ['editor'], 'scope1') + await testUser('bob', ['editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope2') + }) + + it('can remove individual users from roles by scope through options', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') // remove user role - one user - Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], { scope: 'scope1' }) - Roles.addUsersToRoles([users.joe, users.bob], ['admin'], { scope: 'scope2' }) - testUser('eve', ['editor', 'user'], 'scope1') - testUser('bob', ['editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope2') - - Roles.removeUsersFromRoles(users.eve, ['user'], { scope: 'scope1' }) - testUser('eve', ['editor'], 'scope1') - testUser('bob', ['editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope2') - }) - - it('can remove multiple users from roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['editor', 'user'], { scope: 'scope1' }) + await Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], { scope: 'scope2' }) + await testUser('eve', ['editor', 'user'], 'scope1') + await testUser('bob', ['editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope2') + + await Roles.removeUsersFromRolesAsync(users.eve, ['user'], { scope: 'scope1' }) + await testUser('eve', ['editor'], 'scope1') + await testUser('bob', ['editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope2') + }) + + it('can remove multiple users from roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') // remove user role - two users - Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user']) - testUser('eve', ['editor', 'user']) - testUser('bob', ['editor', 'user']) - - assert.isFalse(Roles.userIsInRole(users.joe, 'admin')) - Roles.addUsersToRoles([users.bob, users.joe], ['admin', 'user']) - testUser('bob', ['admin', 'user', 'editor']) - testUser('joe', ['admin', 'user']) - Roles.removeUsersFromRoles([users.bob, users.joe], ['admin']) - testUser('bob', ['user', 'editor']) - testUser('joe', ['user']) - }) - - it('can remove multiple users from roles by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['editor', 'user']) + await testUser('eve', ['editor', 'user']) + await testUser('bob', ['editor', 'user']) - // remove user role - one user - Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') - Roles.addUsersToRoles([users.joe, users.bob], ['admin'], 'scope2') - testUser('eve', ['editor', 'user'], 'scope1') - testUser('bob', ['editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope2') - - Roles.removeUsersFromRoles([users.eve, users.bob], ['user'], 'scope1') - testUser('eve', ['editor'], 'scope1') - testUser('bob', ['editor'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope2') - - Roles.removeUsersFromRoles([users.joe, users.bob], ['admin'], 'scope2') - testUser('eve', [], 'scope2') - testUser('bob', [], 'scope2') - testUser('joe', [], 'scope2') + assert.isFalse(await Roles.userIsInRoleAsync(users.joe, 'admin')) + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin', 'user']) + await testUser('bob', ['admin', 'user', 'editor']) + await testUser('joe', ['admin', 'user']) + await Roles.removeUsersFromRolesAsync([users.bob, users.joe], ['admin']) + await testUser('bob', ['user', 'editor']) + await testUser('joe', ['user']) }) - it('can remove multiple users from roles of any scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + it('can remove multiple users from roles by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') // remove user role - one user - Roles.addUsersToRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') - Roles.addUsersToRoles([users.joe, users.bob], ['user'], 'scope2') - testUser('eve', ['editor', 'user'], 'scope1') - testUser('bob', ['editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['user'], 'scope2') - testUser('joe', ['user'], 'scope2') - - Roles.removeUsersFromRoles([users.eve, users.bob], ['user'], { anyScope: true }) - testUser('eve', ['editor'], 'scope1') - testUser('bob', ['editor'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', [], 'scope2') - testUser('joe', ['user'], 'scope2') - }) - - it('can set user roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['editor', 'user'], 'scope1') + await Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], 'scope2') + await testUser('eve', ['editor', 'user'], 'scope1') + await testUser('bob', ['editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope2') + + await Roles.removeUsersFromRolesAsync([users.eve, users.bob], ['user'], 'scope1') + await testUser('eve', ['editor'], 'scope1') + await testUser('bob', ['editor'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope2') + + await Roles.removeUsersFromRolesAsync([users.joe, users.bob], ['admin'], 'scope2') + await testUser('eve', [], 'scope2') + await testUser('bob', [], 'scope2') + await testUser('joe', [], 'scope2') + }) + + it('can remove multiple users from roles of any scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') - const eve = Meteor.users.findOne({ _id: users.eve }) - const bob = Meteor.users.findOne({ _id: users.bob }) - - Roles.setUserRoles([users.eve, bob], ['editor', 'user']) - testUser('eve', ['editor', 'user']) - testUser('bob', ['editor', 'user']) - testUser('joe', []) + // remove user role - one user + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['editor', 'user'], 'scope1') + await Roles.addUsersToRolesAsync([users.joe, users.bob], ['user'], 'scope2') + await testUser('eve', ['editor', 'user'], 'scope1') + await testUser('bob', ['editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['user'], 'scope2') + await testUser('joe', ['user'], 'scope2') + + await Roles.removeUsersFromRolesAsync([users.eve, users.bob], ['user'], { anyScope: true }) + await testUser('eve', ['editor'], 'scope1') + await testUser('bob', ['editor'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', [], 'scope2') + await testUser('joe', ['user'], 'scope2') + }) + + it('can set user roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + const eve = await Meteor.users.findOneAsync({ _id: users.eve }) + const bob = await Meteor.users.findOneAsync({ _id: users.bob }) + + await Roles.setUserRolesAsync([users.eve, bob], ['editor', 'user']) + await testUser('eve', ['editor', 'user']) + await testUser('bob', ['editor', 'user']) + await testUser('joe', []) // use addUsersToRoles add some roles - Roles.addUsersToRoles([bob, users.joe], ['admin']) - testUser('eve', ['editor', 'user']) - testUser('bob', ['admin', 'editor', 'user']) - testUser('joe', ['admin']) - - Roles.setUserRoles([eve, bob], ['user']) - testUser('eve', ['user']) - testUser('bob', ['user']) - testUser('joe', ['admin']) - - Roles.setUserRoles(bob, 'editor') - testUser('eve', ['user']) - testUser('bob', ['editor']) - testUser('joe', ['admin']) - - Roles.setUserRoles([users.joe, users.bob], []) - testUser('eve', ['user']) - testUser('bob', []) - testUser('joe', []) - }) - - it('can set user roles by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - - const eve = Meteor.users.findOne({ _id: users.eve }) - const bob = Meteor.users.findOne({ _id: users.bob }) - const joe = Meteor.users.findOne({ _id: users.joe }) - - Roles.setUserRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') - Roles.setUserRoles([users.bob, users.joe], ['admin'], 'scope2') - testUser('eve', ['editor', 'user'], 'scope1') - testUser('bob', ['editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope2') + await Roles.addUsersToRolesAsync([bob, users.joe], ['admin']) + await testUser('eve', ['editor', 'user']) + await testUser('bob', ['admin', 'editor', 'user']) + await testUser('joe', ['admin']) + + await Roles.setUserRolesAsync([eve, bob], ['user']) + await testUser('eve', ['user']) + await testUser('bob', ['user']) + await testUser('joe', ['admin']) + + await Roles.setUserRolesAsync(bob, 'editor') + await testUser('eve', ['user']) + await testUser('bob', ['editor']) + await testUser('joe', ['admin']) + + await Roles.setUserRolesAsync([users.joe, users.bob], []) + await testUser('eve', ['user']) + await testUser('bob', []) + await testUser('joe', []) + }) + + it('can set user roles by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + const eve = await Meteor.users.findOneAsync({ _id: users.eve }) + const bob = await Meteor.users.findOneAsync({ _id: users.bob }) + const joe = await Meteor.users.findOneAsync({ _id: users.joe }) + + await Roles.setUserRolesAsync([users.eve, users.bob], ['editor', 'user'], 'scope1') + await Roles.setUserRolesAsync([users.bob, users.joe], ['admin'], 'scope2') + await testUser('eve', ['editor', 'user'], 'scope1') + await testUser('bob', ['editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope2') // use addUsersToRoles add some roles - Roles.addUsersToRoles([users.eve, users.bob], ['admin'], 'scope1') - Roles.addUsersToRoles([users.bob, users.joe], ['editor'], 'scope2') - testUser('eve', ['admin', 'editor', 'user'], 'scope1') - testUser('bob', ['admin', 'editor', 'user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', [], 'scope2') - testUser('bob', ['admin', 'editor'], 'scope2') - testUser('joe', ['admin', 'editor'], 'scope2') - - Roles.setUserRoles([eve, bob], ['user'], 'scope1') - Roles.setUserRoles([eve, joe], ['editor'], 'scope2') - testUser('eve', ['user'], 'scope1') - testUser('bob', ['user'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', ['editor'], 'scope2') - testUser('bob', ['admin', 'editor'], 'scope2') - testUser('joe', ['editor'], 'scope2') - - Roles.setUserRoles(bob, 'editor', 'scope1') - testUser('eve', ['user'], 'scope1') - testUser('bob', ['editor'], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', ['editor'], 'scope2') - testUser('bob', ['admin', 'editor'], 'scope2') - testUser('joe', ['editor'], 'scope2') - - assert.isTrue(Roles.getRolesForUser(users.bob, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) - assert.isFalse(Roles.getRolesForUser(users.joe, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) - - Roles.setUserRoles([bob, users.joe], [], 'scope1') - testUser('eve', ['user'], 'scope1') - testUser('bob', [], 'scope1') - testUser('joe', [], 'scope1') - testUser('eve', ['editor'], 'scope2') - testUser('bob', ['admin', 'editor'], 'scope2') - testUser('joe', ['editor'], 'scope2') + await Roles.addUsersToRolesAsync([users.eve, users.bob], ['admin'], 'scope1') + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['editor'], 'scope2') + await testUser('eve', ['admin', 'editor', 'user'], 'scope1') + await testUser('bob', ['admin', 'editor', 'user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', [], 'scope2') + await testUser('bob', ['admin', 'editor'], 'scope2') + await testUser('joe', ['admin', 'editor'], 'scope2') + + await Roles.setUserRolesAsync([eve, bob], ['user'], 'scope1') + await Roles.setUserRolesAsync([eve, joe], ['editor'], 'scope2') + await testUser('eve', ['user'], 'scope1') + await testUser('bob', ['user'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', ['editor'], 'scope2') + await testUser('bob', ['admin', 'editor'], 'scope2') + await testUser('joe', ['editor'], 'scope2') + + await Roles.setUserRolesAsync(bob, 'editor', 'scope1') + await testUser('eve', ['user'], 'scope1') + await testUser('bob', ['editor'], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', ['editor'], 'scope2') + await testUser('bob', ['admin', 'editor'], 'scope2') + await testUser('joe', ['editor'], 'scope2') + + const bobRoles1 = await Roles.getRolesForUserAsync(users.bob, { anyScope: true, fullObjects: true }) + const joeRoles1 = await Roles.getRolesForUserAsync(users.joe, { anyScope: true, fullObjects: true }) + assert.isTrue(bobRoles1.map(r => r.scope).includes('scope1')) + assert.isFalse(joeRoles1.map(r => r.scope).includes('scope1')) + + await Roles.setUserRolesAsync([bob, users.joe], [], 'scope1') + await testUser('eve', ['user'], 'scope1') + await testUser('bob', [], 'scope1') + await testUser('joe', [], 'scope1') + await testUser('eve', ['editor'], 'scope2') + await testUser('bob', ['admin', 'editor'], 'scope2') + await testUser('joe', ['editor'], 'scope2') // When roles in a given scope are removed, we do not want any dangling database content for that scope. - assert.isFalse(Roles.getRolesForUser(users.bob, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) - assert.isFalse(Roles.getRolesForUser(users.joe, { anyScope: true, fullObjects: true }).map(r => r.scope).includes('scope1')) + const bobRoles2 = await Roles.getRolesForUserAsync(users.bob, { anyScope: true, fullObjects: true }) + const joeRoles2 = await Roles.getRolesForUserAsync(users.joe, { anyScope: true, fullObjects: true }) + assert.isFalse(bobRoles2.map(r => r.scope).includes('scope1')) + assert.isFalse(joeRoles2.map(r => r.scope).includes('scope1')) }) - it('can set user roles by scope including GLOBAL_SCOPE', function () { - Roles.createRole('admin') - Roles.createRole('editor') + it('can set user roles by scope including GLOBAL_SCOPE', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('editor') - const eve = Meteor.users.findOne({ _id: users.eve }) + const eve = await Meteor.users.findOneAsync({ _id: users.eve }) - Roles.addUsersToRoles(eve, 'admin', Roles.GLOBAL_SCOPE) - testUser('eve', ['admin'], 'scope1') - testUser('eve', ['admin']) + await Roles.addUsersToRolesAsync(eve, 'admin', Roles.GLOBAL_SCOPE) + await testUser('eve', ['admin'], 'scope1') + await testUser('eve', ['admin']) - Roles.setUserRoles(eve, 'editor', Roles.GLOBAL_SCOPE) - testUser('eve', ['editor'], 'scope2') - testUser('eve', ['editor']) + await Roles.setUserRolesAsync(eve, 'editor', Roles.GLOBAL_SCOPE) + await testUser('eve', ['editor'], 'scope2') + await testUser('eve', ['editor']) }) - it('can set user roles by scope and anyScope', function () { - Roles.createRole('admin') - Roles.createRole('editor') + it('can set user roles by scope and anyScope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('editor') - const eve = Meteor.users.findOne({ _id: users.eve }) + const eve = await Meteor.users.findOneAsync({ _id: users.eve }) - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + const eveRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(eveRoles.map(obj => { delete obj._id; return obj }), []) - Roles.addUsersToRoles(eve, 'admin') + await Roles.addUsersToRolesAsync(eve, 'admin') - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + const eveRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(eveRoles2.map(obj => { delete obj._id; return obj }), [{ role: { _id: 'admin' }, scope: null, user: { _id: users.eve }, inheritedRoles: [{ _id: 'admin' }] }]) - Roles.setUserRoles(eve, 'editor', { anyScope: true, scope: 'scope2' }) + await Roles.setUserRolesAsync(eve, 'editor', { anyScope: true, scope: 'scope2' }) - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + const eveRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(eveRoles3.map(obj => { delete obj._id; return obj }), [{ role: { _id: 'editor' }, scope: 'scope2', user: { _id: users.eve }, @@ -773,10 +774,10 @@ describe('roles async', async function () { }]) }) - it('can get all roles', function () { - roles.forEach(function (role) { - Roles.createRole(role) - }) + it('can get all roles', async function () { + for (const role of roles) { + await Roles.createRoleAsync(role) + } // compare roles, sorted alphabetically const expected = roles @@ -787,1494 +788,1494 @@ describe('roles async', async function () { assert.sameMembers(Roles.getAllRoles({ sort: { _id: -1 } }).fetch().map(r => r._id), expected.reverse()) }) - it('get an empty list of roles for an empty user', function () { - assert.sameMembers(Roles.getRolesForUser(undefined), []) - assert.sameMembers(Roles.getRolesForUser(null), []) - assert.sameMembers(Roles.getRolesForUser({}), []) - }) - - it('get an empty list of roles for non-existant user', function () { - assert.sameMembers(Roles.getRolesForUser('1'), []) - assert.sameMembers(Roles.getRolesForUser('1', 'scope1'), []) - }) - - it('can get all roles for user', function () { - Roles.createRole('admin') - Roles.createRole('user') - - const userId = users.eve - let userObj - - // by userId - assert.sameMembers(Roles.getRolesForUser(userId), []) - - // by user object - userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getRolesForUser(userObj), []) - - Roles.addUsersToRoles(userId, ['admin', 'user']) - - // by userId - assert.sameMembers(Roles.getRolesForUser(userId), ['admin', 'user']) - - // by user object - userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getRolesForUser(userObj), ['admin', 'user']) - - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: null, - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }, { - role: { _id: 'user' }, - scope: null, - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }] - }]) - }) - - it('can get all roles for user by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - - const userId = users.eve - let userObj - - // by userId - assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), []) - - // by user object - userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), []) - - // add roles - Roles.addUsersToRoles(userId, ['admin', 'user'], 'scope1') - Roles.addUsersToRoles(userId, ['admin'], 'scope2') - - // by userId - assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), ['admin', 'user']) - assert.sameMembers(Roles.getRolesForUser(userId, 'scope2'), ['admin']) - assert.sameMembers(Roles.getRolesForUser(userId), []) - - // by user object - userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), ['admin', 'user']) - assert.sameMembers(Roles.getRolesForUser(userObj, 'scope2'), ['admin']) - assert.sameMembers(Roles.getRolesForUser(userObj), []) - - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }, { - role: { _id: 'user' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }] - }]) - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope2', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }]) - - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }, { - role: { _id: 'user' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }] - }, { - role: { _id: 'admin' }, - scope: 'scope2', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }]) - - Roles.createRole('PERMISSION') - Roles.addRolesToParent('PERMISSION', 'user') - - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }, { - role: { _id: 'user' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - }]) - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope2', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }]) - assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope1' }), ['admin', 'user', 'PERMISSION']) - assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope2' }), ['admin']) - - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }, { - role: { _id: 'user' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - }, { - role: { _id: 'admin' }, - scope: 'scope2', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }]) - assert.sameMembers(Roles.getRolesForUser(userId, { anyScope: true }), ['admin', 'user', 'PERMISSION']) - - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope1', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }, { - role: { _id: 'user' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - }]) - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, scope: 'scope2', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope2', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }]) - assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope1', onlyAssigned: true }), ['admin', 'user']) - assert.sameMembers(Roles.getRolesForUser(userId, { scope: 'scope2', onlyAssigned: true }), ['admin']) - - assert.sameDeepMembers(Roles.getRolesForUser(userId, { fullObjects: true, anyScope: true, onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }, { - role: { _id: 'user' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - }, { - role: { _id: 'admin' }, - scope: 'scope2', - user: { _id: userId }, - inheritedRoles: [{ _id: 'admin' }] - }]) - assert.sameMembers(Roles.getRolesForUser(userId, { anyScope: true, onlyAssigned: true }), ['admin', 'user']) - }) - - it('can get only scoped roles for user', function () { - Roles.createRole('admin') - Roles.createRole('user') - - const userId = users.eve - - // add roles - Roles.addUsersToRoles(userId, ['user'], 'scope1') - Roles.addUsersToRoles(userId, ['admin']) - - Roles.createRole('PERMISSION') - Roles.addRolesToParent('PERMISSION', 'user') - - assert.sameMembers(Roles.getRolesForUser(userId, { onlyScoped: true, scope: 'scope1' }), ['user', 'PERMISSION']) - assert.sameMembers(Roles.getRolesForUser(userId, { onlyScoped: true, onlyAssigned: true, scope: 'scope1' }), ['user']) - assert.sameDeepMembers(Roles.getRolesForUser(userId, { onlyScoped: true, fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: 'scope1', - user: { _id: userId }, - inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - }]) - }) - - it('can get all roles for user by scope with periods in name', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles(users.joe, ['admin'], 'example.k12.va.us') - - assert.sameMembers(Roles.getRolesForUser(users.joe, 'example.k12.va.us'), ['admin']) - }) - - it('can get all roles for user by scope including Roles.GLOBAL_SCOPE', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - - const userId = users.eve - - Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) - Roles.addUsersToRoles([users.eve], ['admin', 'user'], 'scope1') - - // by userId - assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), ['editor', 'admin', 'user']) - assert.sameMembers(Roles.getRolesForUser(userId), ['editor']) - - // by user object - const userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), ['editor', 'admin', 'user']) - assert.sameMembers(Roles.getRolesForUser(userObj), ['editor']) - }) - - it('getRolesForUser should not return null entries if user has no roles for scope', function () { - Roles.createRole('editor') - - const userId = users.eve - let userObj - - // by userId - assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), []) - assert.sameMembers(Roles.getRolesForUser(userId), []) - - // by user object - userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), []) - assert.sameMembers(Roles.getRolesForUser(userObj), []) - - Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) - - // by userId - assert.sameMembers(Roles.getRolesForUser(userId, 'scope1'), ['editor']) - assert.sameMembers(Roles.getRolesForUser(userId), ['editor']) - - // by user object - userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getRolesForUser(userObj, 'scope1'), ['editor']) - assert.sameMembers(Roles.getRolesForUser(userObj), ['editor']) - }) - - it('getRolesForUser should not fail during a call of addUsersToRoles', function () { - Roles.createRole('editor') - - const userId = users.eve - const promises = [] - const interval = setInterval(() => { - promises.push(Promise.resolve().then(() => { Roles.getRolesForUser(userId) })) - }, 0) - - Roles.addUsersToRoles([users.eve], ['editor'], Roles.GLOBAL_SCOPE) - clearInterval(interval) - - return Promise.all(promises) - }) - - it('returns an empty list of scopes for null as user-id', function () { - assert.sameMembers(Roles.getScopesForUser(undefined), []) - assert.sameMembers(Roles.getScopesForUser(null), []) - assert.sameMembers(Roles.getScopesForUser('foo'), []) - assert.sameMembers(Roles.getScopesForUser({}), []) - assert.sameMembers(Roles.getScopesForUser({ _id: 'foo' }), []) - }) - - it('can get all scopes for user', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - - const userId = users.eve - - Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') - Roles.addUsersToRoles([users.eve], ['admin', 'user'], 'scope2') - - // by userId - assert.sameMembers(Roles.getScopesForUser(userId), ['scope1', 'scope2']) - - // by user object - const userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getScopesForUser(userObj), ['scope1', 'scope2']) - }) - - it('can get all scopes for user by role', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - - const userId = users.eve - - Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') - Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'scope2') - - // by userId - assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) - assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) - assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) - - // by user object - const userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) - assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) - assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) - }) - - it('getScopesForUser returns [] when not using scopes', function () { - Roles.createRole('user') - Roles.createRole('editor') - - const userId = users.eve - - Roles.addUsersToRoles([users.eve], ['editor', 'user']) - - // by userId - assert.sameMembers(Roles.getScopesForUser(userId), []) - assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), []) - assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), []) - assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), []) - - // by user object - const userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getScopesForUser(userObj), []) - assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), []) - assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), []) - assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), []) - }) - - it('can get all groups for user by role array', function () { - const userId = users.eve - - Roles.createRole('user') - Roles.createRole('editor') - Roles.createRole('moderator') - Roles.createRole('admin') - - Roles.addUsersToRoles([users.eve], ['editor'], 'group1') - Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'group2') - Roles.addUsersToRoles([users.eve], ['moderator'], 'group3') - - // by userId, one role - assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['group2']) - assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['group1', 'group2']) - assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) - - // by userId, multiple roles - assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), ['group1', 'group2']) - assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'moderator']), ['group1', 'group2', 'group3']) - assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'moderator']), ['group2', 'group3']) - - // by user object, one role - const userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['group2']) - assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['group1', 'group2']) - assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) - - // by user object, multiple roles - assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), ['group1', 'group2']) - assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'moderator']), ['group1', 'group2', 'group3']) - assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'moderator']), ['group2', 'group3']) - }) - - it('getting all scopes for user does not include GLOBAL_SCOPE', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - - const userId = users.eve - - Roles.addUsersToRoles([users.eve], ['editor'], 'scope1') - Roles.addUsersToRoles([users.eve], ['editor', 'user'], 'scope2') - Roles.addUsersToRoles([users.eve], ['editor', 'user', 'admin'], Roles.GLOBAL_SCOPE) - - // by userId - assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) - assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) - assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) - assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['scope2']) - assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['scope1', 'scope2']) - assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) - assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'editor', 'admin']), ['scope1', 'scope2']) - - // by user object - const userObj = Meteor.users.findOne({ _id: userId }) - assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) - assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) - assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) - assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['scope2']) - assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['scope1', 'scope2']) - assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) - assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'editor', 'admin']), ['scope1', 'scope2']) - }) - - it('can get all users in role', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - - Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user']) - Roles.addUsersToRoles([users.bob, users.joe], ['editor']) - - const expected = [users.eve, users.joe] - const actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - - assert.sameMembers(actual, expected) - }) - - it('can get all users in role by scope', function () { - Roles.createRole('admin') - Roles.createRole('user') - - Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user'], 'scope1') - Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') - - let expected = [users.eve, users.joe] - let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) - - assert.sameMembers(actual, expected) - - expected = [users.eve, users.joe] - actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) - assert.sameMembers(actual, expected) - - expected = [users.eve, users.bob, users.joe] - actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) - assert.sameMembers(actual, expected) - - actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - assert.sameMembers(actual, []) - }) - - it('can get all users in role by scope including Roles.GLOBAL_SCOPE', function () { - Roles.createRole('admin') - Roles.createRole('user') - - Roles.addUsersToRoles([users.eve], ['admin', 'user'], Roles.GLOBAL_SCOPE) - Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') - - let expected = [users.eve] - let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) - - assert.sameMembers(actual, expected) - - expected = [users.eve, users.bob, users.joe] - actual = Roles.getUsersInRole('admin', 'scope2').fetch().map(r => r._id) - - assert.sameMembers(actual, expected) - - expected = [users.eve] - actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - - assert.sameMembers(actual, expected) - - expected = [users.eve, users.bob, users.joe] - actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) - - assert.sameMembers(actual, expected) - }) - - it('can get all users in role by scope excluding Roles.GLOBAL_SCOPE', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles([users.eve], ['admin'], Roles.GLOBAL_SCOPE) - Roles.addUsersToRoles([users.bob], ['admin'], 'scope1') - - let expected = [users.eve] - let actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - assert.sameMembers(actual, expected) - - expected = [users.eve, users.bob] - actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) - assert.sameMembers(actual, expected) - - expected = [users.bob] - actual = Roles.getUsersInRole('admin', { scope: 'scope1', onlyScoped: true }).fetch().map(r => r._id) - assert.sameMembers(actual, expected) - }) - - it('can get all users in role by scope and passes through mongo query arguments', function () { - Roles.createRole('admin') - Roles.createRole('user') - - Roles.addUsersToRoles([users.eve, users.joe], ['admin', 'user'], 'scope1') - Roles.addUsersToRoles([users.bob, users.joe], ['admin'], 'scope2') - - const results = Roles.getUsersInRole('admin', 'scope1', { fields: { username: 0 }, limit: 1 }).fetch() + it('get an empty list of roles for an empty user', async function () { + assert.sameMembers(await Roles.getRolesForUserAsync(undefined), []) + assert.sameMembers(await Roles.getRolesForUserAsync(null), []) + assert.sameMembers(await Roles.getRolesForUserAsync({}), []) + }) + + it('get an empty list of roles for non-existant user', async function () { + assert.sameMembers(await Roles.getRolesForUserAsync('1'), []) + assert.sameMembers(await Roles.getRolesForUserAsync('1', 'scope1'), []) + }) + + // it('can get all roles for user', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // + // const userId = users.eve + // let userObj + // + // // by userId + // assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) + // + // // by user object + // userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) + // + // Roles.addUsersToRolesAsync(userId, ['admin', 'user']) + // + // // by userId + // assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['admin', 'user']) + // + // // by user object + // userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['admin', 'user']) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: null, + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }, { + // role: { _id: 'user' }, + // scope: null, + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }] + // }]) + // }) + // + // it('can get all roles for user by scope', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // + // const userId = users.eve + // let userObj + // + // // by userId + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), []) + // + // // by user object + // userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), []) + // + // // add roles + // Roles.addUsersToRolesAsync(userId, ['admin', 'user'], 'scope1') + // Roles.addUsersToRolesAsync(userId, ['admin'], 'scope2') + // + // // by userId + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['admin', 'user']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope2'), ['admin']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) + // + // // by user object + // userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['admin', 'user']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope2'), ['admin']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }, { + // role: { _id: 'user' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }] + // }]) + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope2', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }, { + // role: { _id: 'user' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }] + // }, { + // role: { _id: 'admin' }, + // scope: 'scope2', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // + // Roles.createRoleAsync('PERMISSION') + // Roles.addRolesToParent('PERMISSION', 'user') + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }, { + // role: { _id: 'user' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + // }]) + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope2', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope1' }), ['admin', 'user', 'PERMISSION']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope2' }), ['admin']) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }, { + // role: { _id: 'user' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + // }, { + // role: { _id: 'admin' }, + // scope: 'scope2', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { anyScope: true }), ['admin', 'user', 'PERMISSION']) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }, { + // role: { _id: 'user' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + // }]) + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope2', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope1', onlyAssigned: true }), ['admin', 'user']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope2', onlyAssigned: true }), ['admin']) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true, onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }, { + // role: { _id: 'user' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + // }, { + // role: { _id: 'admin' }, + // scope: 'scope2', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { anyScope: true, onlyAssigned: true }), ['admin', 'user']) + // }) + // + // it('can get only scoped roles for user', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // + // const userId = users.eve + // + // // add roles + // Roles.addUsersToRolesAsync(userId, ['user'], 'scope1') + // Roles.addUsersToRolesAsync(userId, ['admin']) + // + // Roles.createRoleAsync('PERMISSION') + // Roles.addRolesToParent('PERMISSION', 'user') + // + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, scope: 'scope1' }), ['user', 'PERMISSION']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, onlyAssigned: true, scope: 'scope1' }), ['user']) + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: 'scope1', + // user: { _id: userId }, + // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + // }]) + // }) + // + // it('can get all roles for user by scope with periods in name', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.k12.va.us') + // + // assert.sameMembers(await Roles.getRolesForUserAsync(users.joe, 'example.k12.va.us'), ['admin']) + // }) + // + // it('can get all roles for user by scope including Roles.GLOBAL_SCOPE', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // + // const userId = users.eve + // + // Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + // Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], 'scope1') + // + // // by userId + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['editor', 'admin', 'user']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['editor']) + // + // // by user object + // const userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['editor', 'admin', 'user']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['editor']) + // }) + // + // it('getRolesForUser should not return null entries if user has no roles for scope', function () { + // Roles.createRoleAsync('editor') + // + // const userId = users.eve + // let userObj + // + // // by userId + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), []) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) + // + // // by user object + // userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), []) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) + // + // Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + // + // // by userId + // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['editor']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['editor']) + // + // // by user object + // userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['editor']) + // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['editor']) + // }) + // + // it('getRolesForUser should not fail during a call of addUsersToRoles', function () { + // Roles.createRoleAsync('editor') + // + // const userId = users.eve + // const promises = [] + // const interval = setInterval(() => { + // promises.push(Promise.resolve().then(() => { await Roles.getRolesForUserAsync(userId) })) + // }, 0) + // + // Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + // clearInterval(interval) + // + // return Promise.all(promises) + // }) + // + // it('returns an empty list of scopes for null as user-id', function () { + // assert.sameMembers(Roles.getScopesForUser(undefined), []) + // assert.sameMembers(Roles.getScopesForUser(null), []) + // assert.sameMembers(Roles.getScopesForUser('foo'), []) + // assert.sameMembers(Roles.getScopesForUser({}), []) + // assert.sameMembers(Roles.getScopesForUser({ _id: 'foo' }), []) + // }) + // + // it('can get all scopes for user', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // + // const userId = users.eve + // + // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') + // Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], 'scope2') + // + // // by userId + // assert.sameMembers(Roles.getScopesForUser(userId), ['scope1', 'scope2']) + // + // // by user object + // const userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(Roles.getScopesForUser(userObj), ['scope1', 'scope2']) + // }) + // + // it('can get all scopes for user by role', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // + // const userId = users.eve + // + // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') + // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'scope2') + // + // // by userId + // assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) + // assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) + // assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) + // + // // by user object + // const userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) + // }) + // + // it('getScopesForUser returns [] when not using scopes', function () { + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // + // const userId = users.eve + // + // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user']) + // + // // by userId + // assert.sameMembers(Roles.getScopesForUser(userId), []) + // assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), []) + // assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), []) + // assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), []) + // + // // by user object + // const userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(Roles.getScopesForUser(userObj), []) + // assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), []) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), []) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), []) + // }) + // + // it('can get all groups for user by role array', function () { + // const userId = users.eve + // + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // Roles.createRoleAsync('moderator') + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'group1') + // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'group2') + // Roles.addUsersToRolesAsync([users.eve], ['moderator'], 'group3') + // + // // by userId, one role + // assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['group2']) + // assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['group1', 'group2']) + // assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) + // + // // by userId, multiple roles + // assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), ['group1', 'group2']) + // assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'moderator']), ['group1', 'group2', 'group3']) + // assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'moderator']), ['group2', 'group3']) + // + // // by user object, one role + // const userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['group2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['group1', 'group2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) + // + // // by user object, multiple roles + // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), ['group1', 'group2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'moderator']), ['group1', 'group2', 'group3']) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'moderator']), ['group2', 'group3']) + // }) + // + // it('getting all scopes for user does not include GLOBAL_SCOPE', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // + // const userId = users.eve + // + // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') + // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'scope2') + // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user', 'admin'], Roles.GLOBAL_SCOPE) + // + // // by userId + // assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) + // assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) + // assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) + // assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['scope2']) + // assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['scope1', 'scope2']) + // assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) + // assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'editor', 'admin']), ['scope1', 'scope2']) + // + // // by user object + // const userObj = Meteor.users.findOneAsync({ _id: userId }) + // assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['scope2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['scope1', 'scope2']) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) + // assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'editor', 'admin']), ['scope1', 'scope2']) + // }) + // + // it('can get all users in role', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // + // Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user']) + // Roles.addUsersToRolesAsync([users.bob, users.joe], ['editor']) + // + // const expected = [users.eve, users.joe] + // const actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + // + // assert.sameMembers(actual, expected) + // }) + // + // it('can get all users in role by scope', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // + // Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user'], 'scope1') + // Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') + // + // let expected = [users.eve, users.joe] + // let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) + // + // assert.sameMembers(actual, expected) + // + // expected = [users.eve, users.joe] + // actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) + // assert.sameMembers(actual, expected) + // + // expected = [users.eve, users.bob, users.joe] + // actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) + // assert.sameMembers(actual, expected) + // + // actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + // assert.sameMembers(actual, []) + // }) + // + // it('can get all users in role by scope including Roles.GLOBAL_SCOPE', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // + // Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], Roles.GLOBAL_SCOPE) + // Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') + // + // let expected = [users.eve] + // let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) + // + // assert.sameMembers(actual, expected) + // + // expected = [users.eve, users.bob, users.joe] + // actual = Roles.getUsersInRole('admin', 'scope2').fetch().map(r => r._id) + // + // assert.sameMembers(actual, expected) + // + // expected = [users.eve] + // actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + // + // assert.sameMembers(actual, expected) + // + // expected = [users.eve, users.bob, users.joe] + // actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) + // + // assert.sameMembers(actual, expected) + // }) + // + // it('can get all users in role by scope excluding Roles.GLOBAL_SCOPE', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync([users.eve], ['admin'], Roles.GLOBAL_SCOPE) + // Roles.addUsersToRolesAsync([users.bob], ['admin'], 'scope1') + // + // let expected = [users.eve] + // let actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) + // assert.sameMembers(actual, expected) + // + // expected = [users.eve, users.bob] + // actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) + // assert.sameMembers(actual, expected) + // + // expected = [users.bob] + // actual = Roles.getUsersInRole('admin', { scope: 'scope1', onlyScoped: true }).fetch().map(r => r._id) + // assert.sameMembers(actual, expected) + // }) + + it('can get all users in role by scope and passes through mongo query arguments', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + + await Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') + + const results = await Roles.getUsersInRole('admin', 'scope1', { fields: { username: 0 }, limit: 1 }).fetch() assert.equal(1, results.length) assert.isTrue(hasProp(results[0], '_id')) assert.isFalse(hasProp(results[0], 'username')) }) - it('can use Roles.GLOBAL_SCOPE to assign blanket roles', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) - - testUser('eve', [], 'scope1') - testUser('joe', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope1') - testUser('bob', ['admin'], 'scope2') - testUser('bob', ['admin'], 'scope1') - - Roles.removeUsersFromRoles(users.joe, ['admin'], Roles.GLOBAL_SCOPE) - - testUser('eve', [], 'scope1') - testUser('joe', [], 'scope2') - testUser('joe', [], 'scope1') - testUser('bob', ['admin'], 'scope2') - testUser('bob', ['admin'], 'scope1') - }) - - it('Roles.GLOBAL_SCOPE is independent of other scopes', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles([users.joe, users.bob], ['admin'], 'scope5') - Roles.addUsersToRoles([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) - - testUser('eve', [], 'scope1') - testUser('joe', ['admin'], 'scope5') - testUser('joe', ['admin'], 'scope2') - testUser('joe', ['admin'], 'scope1') - testUser('bob', ['admin'], 'scope5') - testUser('bob', ['admin'], 'scope2') - testUser('bob', ['admin'], 'scope1') - - Roles.removeUsersFromRoles(users.joe, ['admin'], Roles.GLOBAL_SCOPE) - - testUser('eve', [], 'scope1') - testUser('joe', ['admin'], 'scope5') - testUser('joe', [], 'scope2') - testUser('joe', [], 'scope1') - testUser('bob', ['admin'], 'scope5') - testUser('bob', ['admin'], 'scope2') - testUser('bob', ['admin'], 'scope1') - }) - - it('Roles.GLOBAL_SCOPE also checked when scope not specified', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles(users.joe, 'admin', Roles.GLOBAL_SCOPE) - - testUser('joe', ['admin']) - - Roles.removeUsersFromRoles(users.joe, 'admin', Roles.GLOBAL_SCOPE) - - testUser('joe', []) - }) - - it('can use \'.\' in scope name', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles(users.joe, ['admin'], 'example.com') - testUser('joe', ['admin'], 'example.com') - }) - - it('can use multiple periods in scope name', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles(users.joe, ['admin'], 'example.k12.va.us') - testUser('joe', ['admin'], 'example.k12.va.us') - }) - - it('renaming of roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - - Roles.setUserRoles([users.eve, users.bob], ['editor', 'user'], 'scope1') - Roles.setUserRoles([users.bob, users.joe], ['user', 'admin'], 'scope2') - - assert.isTrue(Roles.userIsInRole(users.eve, 'editor', 'scope1')) - assert.isFalse(Roles.userIsInRole(users.eve, 'editor', 'scope2')) - - assert.isFalse(Roles.userIsInRole(users.joe, 'admin', 'scope1')) - assert.isTrue(Roles.userIsInRole(users.joe, 'admin', 'scope2')) - - assert.isTrue(Roles.userIsInRole(users.eve, 'user', 'scope1')) - assert.isTrue(Roles.userIsInRole(users.bob, 'user', 'scope1')) - assert.isFalse(Roles.userIsInRole(users.joe, 'user', 'scope1')) - - assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope2')) - assert.isTrue(Roles.userIsInRole(users.bob, 'user', 'scope2')) - assert.isTrue(Roles.userIsInRole(users.joe, 'user', 'scope2')) - - assert.isFalse(Roles.userIsInRole(users.eve, 'user2', 'scope1')) - assert.isFalse(Roles.userIsInRole(users.eve, 'user2', 'scope2')) - - Roles.renameRole('user', 'user2') - - assert.isTrue(Roles.userIsInRole(users.eve, 'editor', 'scope1')) - assert.isFalse(Roles.userIsInRole(users.eve, 'editor', 'scope2')) - - assert.isFalse(Roles.userIsInRole(users.joe, 'admin', 'scope1')) - assert.isTrue(Roles.userIsInRole(users.joe, 'admin', 'scope2')) - - assert.isTrue(Roles.userIsInRole(users.eve, 'user2', 'scope1')) - assert.isTrue(Roles.userIsInRole(users.bob, 'user2', 'scope1')) - assert.isFalse(Roles.userIsInRole(users.joe, 'user2', 'scope1')) - - assert.isFalse(Roles.userIsInRole(users.eve, 'user2', 'scope2')) - assert.isTrue(Roles.userIsInRole(users.bob, 'user2', 'scope2')) - assert.isTrue(Roles.userIsInRole(users.joe, 'user2', 'scope2')) - - assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope1')) - assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope2')) - }) - - it('migration without global groups (to v2)', function () { - assert.isOk(Meteor.roles.insert({ name: 'admin' })) - assert.isOk(Meteor.roles.insert({ name: 'editor' })) - assert.isOk(Meteor.roles.insert({ name: 'user' })) - - assert.isOk(Meteor.users.update(users.eve, { $set: { roles: ['admin', 'editor'] } })) - assert.isOk(Meteor.users.update(users.bob, { $set: { roles: [] } })) - assert.isOk(Meteor.users.update(users.joe, { $set: { roles: ['user'] } })) - - Roles._forwardMigrate() - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'admin', - scope: null, - assigned: true - }, { - _id: 'editor', - scope: null, - assigned: true - }] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'user', - scope: null, - assigned: true - }] - }) - - assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - _id: 'admin', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - _id: 'editor', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - _id: 'user', - children: [] - }) - - Roles._backwardMigrate(null, null, false) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: ['admin', 'editor'] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: ['user'] - }) - - assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { - name: 'admin' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { - name: 'editor' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { - name: 'user' - }) - }) - - it('migration without global groups (to v3)') - - it('migration with global groups (to v2)', function () { - assert.isOk(Meteor.roles.insert({ name: 'admin' })) - assert.isOk(Meteor.roles.insert({ name: 'editor' })) - assert.isOk(Meteor.roles.insert({ name: 'user' })) - - assert.isOk(Meteor.users.update(users.eve, { $set: { roles: { __global_roles__: ['admin', 'editor'], foo_bla: ['user'] } } })) - assert.isOk(Meteor.users.update(users.bob, { $set: { roles: { } } })) - assert.isOk(Meteor.users.update(users.joe, { $set: { roles: { __global_roles__: ['user'], foo_bla: ['user'] } } })) - - Roles._forwardMigrate(null, null, false) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'admin', - scope: null, - assigned: true - }, { - _id: 'editor', - scope: null, - assigned: true - }, { - _id: 'user', - scope: 'foo_bla', - assigned: true - }] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'user', - scope: null, - assigned: true - }, { - _id: 'user', - scope: 'foo_bla', - assigned: true - }] - }) - - assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - _id: 'admin', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - _id: 'editor', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - _id: 'user', - children: [] - }) - - Roles._backwardMigrate(null, null, true) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: { - __global_roles__: ['admin', 'editor'], - foo_bla: ['user'] - } - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: {} - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: { - __global_roles__: ['user'], - foo_bla: ['user'] - } - }) - - assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { - name: 'admin' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { - name: 'editor' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { - name: 'user' - }) - - Roles._forwardMigrate(null, null, true) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'admin', - scope: null, - assigned: true - }, { - _id: 'editor', - scope: null, - assigned: true - }, { - _id: 'user', - scope: 'foo.bla', - assigned: true - }] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'user', - scope: null, - assigned: true - }, { - _id: 'user', - scope: 'foo.bla', - assigned: true - }] - }) - - assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - _id: 'admin', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - _id: 'editor', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - _id: 'user', - children: [] - }) - }) - - it('migration with global groups (to v3)') - - it('_addUserToRole', function () { - Roles.createRole('admin') - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) - - assert.include( - Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), - 'insertedId' - ) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'admin' }] - }]) - - assert.notInclude( - Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), - 'insertedId' - ) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'admin' }] - }]) - }) - - it('_removeUserFromRole', function () { - Roles.createRole('admin') - - Roles.addUsersToRoles(users.eve, 'admin') - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'admin' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'admin' }] - }]) - - Roles._removeUserFromRole(users.eve, 'admin', { scope: null }) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) - }) - - it('keep assigned roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('ALL_PERMISSIONS') - Roles.createRole('VIEW_PERMISSION') - Roles.createRole('EDIT_PERMISSION') - Roles.createRole('DELETE_PERMISSION') - Roles.addRolesToParent('ALL_PERMISSIONS', 'user') - Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') - Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') - Roles.addRolesToParent('DELETE_PERMISSION', 'admin') - - Roles.addUsersToRoles(users.eve, ['user']) - - assert.isTrue(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' }, - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' } - ] - }]) - - Roles.addUsersToRoles(users.eve, 'VIEW_PERMISSION') - - assert.isTrue(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' }, - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' } - ] - }, { - role: { _id: 'VIEW_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'VIEW_PERMISSION' } - ] - }]) - - Roles.removeUsersFromRoles(users.eve, 'user') - - assert.isTrue(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'VIEW_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'VIEW_PERMISSION' } - ] - }]) - - Roles.removeUsersFromRoles(users.eve, 'VIEW_PERMISSION') - - assert.isFalse(Roles.userIsInRole(users.eve, 'VIEW_PERMISSION')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) - }) - - it('adds children of the added role to the assignments', function () { - Roles.createRole('admin') - Roles.createRole('ALBUM.ADMIN') - Roles.createRole('ALBUM.VIEW') - Roles.createRole('TRACK.ADMIN') - Roles.createRole('TRACK.VIEW') - - Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') - Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') - - Roles.addRolesToParent('ALBUM.ADMIN', 'admin') - - Roles.addUsersToRoles(users.eve, ['admin']) - - assert.isFalse(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) - - Roles.addRolesToParent('TRACK.ADMIN', 'admin') - - assert.isTrue(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) - }) - - it('removes children of the removed role from the assignments', function () { - Roles.createRole('admin') - Roles.createRole('ALBUM.ADMIN') - Roles.createRole('ALBUM.VIEW') - Roles.createRole('TRACK.ADMIN') - Roles.createRole('TRACK.VIEW') - - Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') - Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') - - Roles.addRolesToParent('ALBUM.ADMIN', 'admin') - Roles.addRolesToParent('TRACK.ADMIN', 'admin') - - Roles.addUsersToRoles(users.eve, ['admin']) - - assert.isTrue(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) - - Roles.removeRolesFromParent('TRACK.ADMIN', 'admin') - - assert.isFalse(Roles.userIsInRole(users.eve, 'TRACK.VIEW')) - }) - - it('modify assigned hierarchical roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('ALL_PERMISSIONS') - Roles.createRole('VIEW_PERMISSION') - Roles.createRole('EDIT_PERMISSION') - Roles.createRole('DELETE_PERMISSION') - Roles.addRolesToParent('ALL_PERMISSIONS', 'user') - Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') - Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') - Roles.addRolesToParent('DELETE_PERMISSION', 'admin') - - Roles.addUsersToRoles(users.eve, ['user']) - Roles.addUsersToRoles(users.eve, ['ALL_PERMISSIONS'], 'scope') - - assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION', 'scope')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' }, - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' } - ] - }, { - role: { _id: 'ALL_PERMISSIONS' }, - scope: 'scope', - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' } - ] - }]) - - Roles.createRole('MODERATE_PERMISSION') - - Roles.addRolesToParent('MODERATE_PERMISSION', 'ALL_PERMISSIONS') - - assert.isTrue(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION')) - assert.isTrue(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION', 'scope')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' }, - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' } - ] - }, { - role: { _id: 'ALL_PERMISSIONS' }, - scope: 'scope', - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' } - ] - }]) - - Roles.addUsersToRoles(users.eve, ['admin']) - - assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) - assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' }, - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' } - ] - }, { - role: { _id: 'ALL_PERMISSIONS' }, - scope: 'scope', - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' } - ] - }, { - role: { _id: 'admin' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'admin' }, - { _id: 'DELETE_PERMISSION' } - ] - }]) - - Roles.addRolesToParent('DELETE_PERMISSION', 'ALL_PERMISSIONS') - - assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) - assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' }, - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' }, - { _id: 'DELETE_PERMISSION' } - ] - }, { - role: { _id: 'ALL_PERMISSIONS' }, - scope: 'scope', - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' }, - { _id: 'DELETE_PERMISSION' } - ] - }, { - role: { _id: 'admin' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'admin' }, - { _id: 'DELETE_PERMISSION' } - ] - }]) - - Roles.removeUsersFromRoles(users.eve, ['admin']) - - assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) - assert.isTrue(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' }, - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' }, - { _id: 'DELETE_PERMISSION' } - ] - }, { - role: { _id: 'ALL_PERMISSIONS' }, - scope: 'scope', - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'ALL_PERMISSIONS' }, - { _id: 'EDIT_PERMISSION' }, - { _id: 'VIEW_PERMISSION' }, - { _id: 'MODERATE_PERMISSION' }, - { _id: 'DELETE_PERMISSION' } - ] - }]) - - Roles.deleteRole('ALL_PERMISSIONS') - - assert.isFalse(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'DELETE_PERMISSION', 'scope')) - - assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'MODERATE_PERMISSION', 'scope')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'user' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'user' } - ] - }]) - }) - - it('delete role with overlapping hierarchical roles', function () { - Roles.createRole('role1') - Roles.createRole('role2') - Roles.createRole('COMMON_PERMISSION_1') - Roles.createRole('COMMON_PERMISSION_2') - Roles.createRole('COMMON_PERMISSION_3') - Roles.createRole('EXTRA_PERMISSION_ROLE_1') - Roles.createRole('EXTRA_PERMISSION_ROLE_2') - - Roles.addRolesToParent('COMMON_PERMISSION_1', 'role1') - Roles.addRolesToParent('COMMON_PERMISSION_2', 'role1') - Roles.addRolesToParent('COMMON_PERMISSION_3', 'role1') - Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_1', 'role1') - - Roles.addRolesToParent('COMMON_PERMISSION_1', 'role2') - Roles.addRolesToParent('COMMON_PERMISSION_2', 'role2') - Roles.addRolesToParent('COMMON_PERMISSION_3', 'role2') - Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_2', 'role2') - - Roles.addUsersToRoles(users.eve, 'role1') - Roles.addUsersToRoles(users.eve, 'role2') - - assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) - assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'role1' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'role1' }, - { _id: 'COMMON_PERMISSION_1' }, - { _id: 'COMMON_PERMISSION_2' }, - { _id: 'COMMON_PERMISSION_3' }, - { _id: 'EXTRA_PERMISSION_ROLE_1' } - ] - }, { - role: { _id: 'role2' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'role2' }, - { _id: 'COMMON_PERMISSION_1' }, - { _id: 'COMMON_PERMISSION_2' }, - { _id: 'COMMON_PERMISSION_3' }, - { _id: 'EXTRA_PERMISSION_ROLE_2' } - ] - }]) - - Roles.removeUsersFromRoles(users.eve, 'role2') - - assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) - assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - assert.isFalse(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'role1' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'role1' }, - { _id: 'COMMON_PERMISSION_1' }, - { _id: 'COMMON_PERMISSION_2' }, - { _id: 'COMMON_PERMISSION_3' }, - { _id: 'EXTRA_PERMISSION_ROLE_1' } - ] - }]) - - Roles.addUsersToRoles(users.eve, 'role2') - - assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) - assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'role1' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'role1' }, - { _id: 'COMMON_PERMISSION_1' }, - { _id: 'COMMON_PERMISSION_2' }, - { _id: 'COMMON_PERMISSION_3' }, - { _id: 'EXTRA_PERMISSION_ROLE_1' } - ] - }, { - role: { _id: 'role2' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'role2' }, - { _id: 'COMMON_PERMISSION_1' }, - { _id: 'COMMON_PERMISSION_2' }, - { _id: 'COMMON_PERMISSION_3' }, - { _id: 'EXTRA_PERMISSION_ROLE_2' } - ] - }]) - - Roles.deleteRole('role2') - - assert.isTrue(Roles.userIsInRole(users.eve, 'COMMON_PERMISSION_1')) - assert.isTrue(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - assert.isFalse(Roles.userIsInRole(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'role1' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [ - { _id: 'role1' }, - { _id: 'COMMON_PERMISSION_1' }, - { _id: 'COMMON_PERMISSION_2' }, - { _id: 'COMMON_PERMISSION_3' }, - { _id: 'EXTRA_PERMISSION_ROLE_1' } - ] - }]) - }) - - it('set parent on assigned role', function () { - Roles.createRole('admin') - Roles.createRole('EDIT_PERMISSION') - - Roles.addUsersToRoles(users.eve, 'EDIT_PERMISSION') - - assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'EDIT_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - }]) - - Roles.addRolesToParent('EDIT_PERMISSION', 'admin') - - assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'EDIT_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - }]) - }) - - it('remove parent on assigned role', function () { - Roles.createRole('admin') - Roles.createRole('EDIT_PERMISSION') - - Roles.addRolesToParent('EDIT_PERMISSION', 'admin') - - Roles.addUsersToRoles(users.eve, 'EDIT_PERMISSION') - - assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'EDIT_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - }]) - - Roles.removeRolesFromParent('EDIT_PERMISSION', 'admin') - - assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'EDIT_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - }]) - }) - - it('adding and removing extra role parents', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('EDIT_PERMISSION') - - Roles.addRolesToParent('EDIT_PERMISSION', 'admin') - - Roles.addUsersToRoles(users.eve, 'EDIT_PERMISSION') - - assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'EDIT_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - }]) - - Roles.addRolesToParent('EDIT_PERMISSION', 'user') - - assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'EDIT_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - }]) - - Roles.removeRolesFromParent('EDIT_PERMISSION', 'user') - - assert.isTrue(Roles.userIsInRole(users.eve, 'EDIT_PERMISSION')) - assert.isFalse(Roles.userIsInRole(users.eve, 'admin')) - - assert.sameDeepMembers(Roles.getRolesForUser(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - role: { _id: 'EDIT_PERMISSION' }, - scope: null, - user: { _id: users.eve }, - inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - }]) - }) - - it('cyclic roles', function () { - Roles.createRole('admin') - Roles.createRole('editor') - Roles.createRole('user') - - Roles.addRolesToParent('editor', 'admin') - Roles.addRolesToParent('user', 'editor') - - assert.throws(function () { - Roles.addRolesToParent('admin', 'user') - }, /form a cycle/) - }) - - it('userIsInRole returns false for unknown roles', function () { - Roles.createRole('admin') - Roles.createRole('user') - Roles.createRole('editor') - Roles.addUsersToRoles(users.eve, ['admin', 'user']) - Roles.addUsersToRoles(users.eve, ['editor']) - - assert.isFalse(Roles.userIsInRole(users.eve, 'unknown')) - assert.isFalse(Roles.userIsInRole(users.eve, [])) - assert.isFalse(Roles.userIsInRole(users.eve, null)) - assert.isFalse(Roles.userIsInRole(users.eve, undefined)) - - assert.isFalse(Roles.userIsInRole(users.eve, 'unknown', { anyScope: true })) - assert.isFalse(Roles.userIsInRole(users.eve, [], { anyScope: true })) - assert.isFalse(Roles.userIsInRole(users.eve, null, { anyScope: true })) - assert.isFalse(Roles.userIsInRole(users.eve, undefined, { anyScope: true })) - - assert.isFalse(Roles.userIsInRole(users.eve, ['Role1', 'Role2', undefined], 'GroupName')) - }) - - it('userIsInRole returns false if user is a function', function () { - Roles.createRole('admin') - Roles.addUsersToRoles(users.eve, ['admin']) - - assert.isFalse(Roles.userIsInRole(() => {}, 'admin')) - }) - - describe('isParentOf', function () { - it('returns false for unknown roles', function () { - Roles.createRole('admin') - - assert.isFalse(Roles.isParentOf('admin', 'unknown')) - assert.isFalse(Roles.isParentOf('admin', null)) - assert.isFalse(Roles.isParentOf('admin', undefined)) - - assert.isFalse(Roles.isParentOf('unknown', 'admin')) - assert.isFalse(Roles.isParentOf(null, 'admin')) - assert.isFalse(Roles.isParentOf(undefined, 'admin')) - }) - - it('returns false if role is not parent of', function () { - Roles.createRole('admin') - Roles.createRole('editor') - Roles.createRole('user') - Roles.addRolesToParent(['editor'], 'admin') - Roles.addRolesToParent(['user'], 'editor') - - assert.isFalse(Roles.isParentOf('user', 'admin')) - assert.isFalse(Roles.isParentOf('editor', 'admin')) - }) - - it('returns true if role is parent of the demanded role', function () { - Roles.createRole('admin') - Roles.createRole('editor') - Roles.createRole('user') - Roles.addRolesToParent(['editor'], 'admin') - Roles.addRolesToParent(['user'], 'editor') - - assert.isTrue(Roles.isParentOf('admin', 'user')) - assert.isTrue(Roles.isParentOf('editor', 'user')) - assert.isTrue(Roles.isParentOf('admin', 'editor')) - - assert.isTrue(Roles.isParentOf('admin', 'admin')) - assert.isTrue(Roles.isParentOf('editor', 'editor')) - assert.isTrue(Roles.isParentOf('user', 'user')) - }) - }) + // it('can use Roles.GLOBAL_SCOPE to assign blanket roles', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) + // + // testUser('eve', [], 'scope1') + // testUser('joe', ['admin'], 'scope2') + // testUser('joe', ['admin'], 'scope1') + // testUser('bob', ['admin'], 'scope2') + // testUser('bob', ['admin'], 'scope1') + // + // Roles.removeUsersFromRolesAsync(users.joe, ['admin'], Roles.GLOBAL_SCOPE) + // + // testUser('eve', [], 'scope1') + // testUser('joe', [], 'scope2') + // testUser('joe', [], 'scope1') + // testUser('bob', ['admin'], 'scope2') + // testUser('bob', ['admin'], 'scope1') + // }) + // + // it('Roles.GLOBAL_SCOPE is independent of other scopes', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], 'scope5') + // Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) + // + // testUser('eve', [], 'scope1') + // testUser('joe', ['admin'], 'scope5') + // testUser('joe', ['admin'], 'scope2') + // testUser('joe', ['admin'], 'scope1') + // testUser('bob', ['admin'], 'scope5') + // testUser('bob', ['admin'], 'scope2') + // testUser('bob', ['admin'], 'scope1') + // + // Roles.removeUsersFromRolesAsync(users.joe, ['admin'], Roles.GLOBAL_SCOPE) + // + // testUser('eve', [], 'scope1') + // testUser('joe', ['admin'], 'scope5') + // testUser('joe', [], 'scope2') + // testUser('joe', [], 'scope1') + // testUser('bob', ['admin'], 'scope5') + // testUser('bob', ['admin'], 'scope2') + // testUser('bob', ['admin'], 'scope1') + // }) + // + // it('Roles.GLOBAL_SCOPE also checked when scope not specified', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync(users.joe, 'admin', Roles.GLOBAL_SCOPE) + // + // testUser('joe', ['admin']) + // + // Roles.removeUsersFromRolesAsync(users.joe, 'admin', Roles.GLOBAL_SCOPE) + // + // testUser('joe', []) + // }) + // + // it('can use \'.\' in scope name', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.com') + // testUser('joe', ['admin'], 'example.com') + // }) + // + // it('can use multiple periods in scope name', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.k12.va.us') + // testUser('joe', ['admin'], 'example.k12.va.us') + // }) + // + // it('renaming of roles', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // + // await Roles.setUserRolesAsync([users.eve, users.bob], ['editor', 'user'], 'scope1') + // await Roles.setUserRolesAsync([users.bob, users.joe], ['user', 'admin'], 'scope2') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope2')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope2')) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'user', 'scope1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user', 'scope1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'user', 'scope1')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user', 'scope2')) + // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user', 'scope2')) + // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'user', 'scope2')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope2')) + // + // Roles.renameRole('user', 'user2') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope2')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope2')) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user2', 'scope1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'user2', 'scope1')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope2')) + // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user2', 'scope2')) + // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'user2', 'scope2')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user', 'scope1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user', 'scope2')) + // }) + // + // it('migration without global groups (to v2)', function () { + // assert.isOk(Meteor.roles.insert({ name: 'admin' })) + // assert.isOk(Meteor.roles.insert({ name: 'editor' })) + // assert.isOk(Meteor.roles.insert({ name: 'user' })) + // + // assert.isOk(Meteor.users.update(users.eve, { $set: { roles: ['admin', 'editor'] } })) + // assert.isOk(Meteor.users.update(users.bob, { $set: { roles: [] } })) + // assert.isOk(Meteor.users.update(users.joe, { $set: { roles: ['user'] } })) + // + // Roles._forwardMigrate() + // + // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { + // roles: [{ + // _id: 'admin', + // scope: null, + // assigned: true + // }, { + // _id: 'editor', + // scope: null, + // assigned: true + // }] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { + // roles: [] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { + // roles: [{ + // _id: 'user', + // scope: null, + // assigned: true + // }] + // }) + // + // assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { + // _id: 'admin', + // children: [] + // }) + // assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { + // _id: 'editor', + // children: [] + // }) + // assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { + // _id: 'user', + // children: [] + // }) + // + // Roles._backwardMigrate(null, null, false) + // + // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { + // roles: ['admin', 'editor'] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { + // roles: [] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { + // roles: ['user'] + // }) + // + // assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { + // name: 'admin' + // }) + // assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { + // name: 'editor' + // }) + // assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { + // name: 'user' + // }) + // }) + // + // it('migration without global groups (to v3)') + // + // it('migration with global groups (to v2)', function () { + // assert.isOk(Meteor.roles.insert({ name: 'admin' })) + // assert.isOk(Meteor.roles.insert({ name: 'editor' })) + // assert.isOk(Meteor.roles.insert({ name: 'user' })) + // + // assert.isOk(Meteor.users.update(users.eve, { $set: { roles: { __global_roles__: ['admin', 'editor'], foo_bla: ['user'] } } })) + // assert.isOk(Meteor.users.update(users.bob, { $set: { roles: { } } })) + // assert.isOk(Meteor.users.update(users.joe, { $set: { roles: { __global_roles__: ['user'], foo_bla: ['user'] } } })) + // + // Roles._forwardMigrate(null, null, false) + // + // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { + // roles: [{ + // _id: 'admin', + // scope: null, + // assigned: true + // }, { + // _id: 'editor', + // scope: null, + // assigned: true + // }, { + // _id: 'user', + // scope: 'foo_bla', + // assigned: true + // }] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { + // roles: [] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { + // roles: [{ + // _id: 'user', + // scope: null, + // assigned: true + // }, { + // _id: 'user', + // scope: 'foo_bla', + // assigned: true + // }] + // }) + // + // assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { + // _id: 'admin', + // children: [] + // }) + // assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { + // _id: 'editor', + // children: [] + // }) + // assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { + // _id: 'user', + // children: [] + // }) + // + // Roles._backwardMigrate(null, null, true) + // + // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { + // roles: { + // __global_roles__: ['admin', 'editor'], + // foo_bla: ['user'] + // } + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { + // roles: {} + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { + // roles: { + // __global_roles__: ['user'], + // foo_bla: ['user'] + // } + // }) + // + // assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { + // name: 'admin' + // }) + // assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { + // name: 'editor' + // }) + // assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { + // name: 'user' + // }) + // + // Roles._forwardMigrate(null, null, true) + // + // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { + // roles: [{ + // _id: 'admin', + // scope: null, + // assigned: true + // }, { + // _id: 'editor', + // scope: null, + // assigned: true + // }, { + // _id: 'user', + // scope: 'foo.bla', + // assigned: true + // }] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { + // roles: [] + // }) + // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { + // roles: [{ + // _id: 'user', + // scope: null, + // assigned: true + // }, { + // _id: 'user', + // scope: 'foo.bla', + // assigned: true + // }] + // }) + // + // assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { + // _id: 'admin', + // children: [] + // }) + // assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { + // _id: 'editor', + // children: [] + // }) + // assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { + // _id: 'user', + // children: [] + // }) + // }) + // + // it('migration with global groups (to v3)') + // + // it('_addUserToRole', function () { + // Roles.createRoleAsync('admin') + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + // + // assert.include( + // Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), + // 'insertedId' + // ) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // + // assert.notInclude( + // Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), + // 'insertedId' + // ) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // }) + // + // it('_removeUserFromRole', function () { + // Roles.createRoleAsync('admin') + // + // Roles.addUsersToRolesAsync(users.eve, 'admin') + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'admin' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'admin' }] + // }]) + // + // Roles._removeUserFromRole(users.eve, 'admin', { scope: null }) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + // }) + // + // it('keep assigned roles', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('ALL_PERMISSIONS') + // Roles.createRoleAsync('VIEW_PERMISSION') + // Roles.createRoleAsync('EDIT_PERMISSION') + // Roles.createRoleAsync('DELETE_PERMISSION') + // Roles.addRolesToParent('ALL_PERMISSIONS', 'user') + // Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') + // Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') + // Roles.addRolesToParent('DELETE_PERMISSION', 'admin') + // + // Roles.addUsersToRolesAsync(users.eve, ['user']) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' }, + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' } + // ] + // }]) + // + // Roles.addUsersToRolesAsync(users.eve, 'VIEW_PERMISSION') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' }, + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' } + // ] + // }, { + // role: { _id: 'VIEW_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'VIEW_PERMISSION' } + // ] + // }]) + // + // Roles.removeUsersFromRolesAsync(users.eve, 'user') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'VIEW_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'VIEW_PERMISSION' } + // ] + // }]) + // + // Roles.removeUsersFromRolesAsync(users.eve, 'VIEW_PERMISSION') + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) + // }) + // + // it('adds children of the added role to the assignments', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('ALBUM.ADMIN') + // Roles.createRoleAsync('ALBUM.VIEW') + // Roles.createRoleAsync('TRACK.ADMIN') + // Roles.createRoleAsync('TRACK.VIEW') + // + // Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') + // Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') + // + // Roles.addRolesToParent('ALBUM.ADMIN', 'admin') + // + // Roles.addUsersToRolesAsync(users.eve, ['admin']) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + // + // Roles.addRolesToParent('TRACK.ADMIN', 'admin') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + // }) + // + // it('removes children of the removed role from the assignments', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('ALBUM.ADMIN') + // Roles.createRoleAsync('ALBUM.VIEW') + // Roles.createRoleAsync('TRACK.ADMIN') + // Roles.createRoleAsync('TRACK.VIEW') + // + // Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') + // Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') + // + // Roles.addRolesToParent('ALBUM.ADMIN', 'admin') + // Roles.addRolesToParent('TRACK.ADMIN', 'admin') + // + // Roles.addUsersToRolesAsync(users.eve, ['admin']) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + // + // Roles.removeRolesFromParent('TRACK.ADMIN', 'admin') + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + // }) + // + // it('modify assigned hierarchical roles', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('ALL_PERMISSIONS') + // Roles.createRoleAsync('VIEW_PERMISSION') + // Roles.createRoleAsync('EDIT_PERMISSION') + // Roles.createRoleAsync('DELETE_PERMISSION') + // Roles.addRolesToParent('ALL_PERMISSIONS', 'user') + // Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') + // Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') + // Roles.addRolesToParent('DELETE_PERMISSION', 'admin') + // + // Roles.addUsersToRolesAsync(users.eve, ['user']) + // Roles.addUsersToRolesAsync(users.eve, ['ALL_PERMISSIONS'], 'scope') + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' }, + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' } + // ] + // }, { + // role: { _id: 'ALL_PERMISSIONS' }, + // scope: 'scope', + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' } + // ] + // }]) + // + // Roles.createRoleAsync('MODERATE_PERMISSION') + // + // Roles.addRolesToParent('MODERATE_PERMISSION', 'ALL_PERMISSIONS') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' }, + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' } + // ] + // }, { + // role: { _id: 'ALL_PERMISSIONS' }, + // scope: 'scope', + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' } + // ] + // }]) + // + // Roles.addUsersToRolesAsync(users.eve, ['admin']) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' }, + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' } + // ] + // }, { + // role: { _id: 'ALL_PERMISSIONS' }, + // scope: 'scope', + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' } + // ] + // }, { + // role: { _id: 'admin' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'admin' }, + // { _id: 'DELETE_PERMISSION' } + // ] + // }]) + // + // Roles.addRolesToParent('DELETE_PERMISSION', 'ALL_PERMISSIONS') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' }, + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' }, + // { _id: 'DELETE_PERMISSION' } + // ] + // }, { + // role: { _id: 'ALL_PERMISSIONS' }, + // scope: 'scope', + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' }, + // { _id: 'DELETE_PERMISSION' } + // ] + // }, { + // role: { _id: 'admin' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'admin' }, + // { _id: 'DELETE_PERMISSION' } + // ] + // }]) + // + // Roles.removeUsersFromRolesAsync(users.eve, ['admin']) + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' }, + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' }, + // { _id: 'DELETE_PERMISSION' } + // ] + // }, { + // role: { _id: 'ALL_PERMISSIONS' }, + // scope: 'scope', + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'ALL_PERMISSIONS' }, + // { _id: 'EDIT_PERMISSION' }, + // { _id: 'VIEW_PERMISSION' }, + // { _id: 'MODERATE_PERMISSION' }, + // { _id: 'DELETE_PERMISSION' } + // ] + // }]) + // + // Roles.deleteRole('ALL_PERMISSIONS') + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'user' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'user' } + // ] + // }]) + // }) + // + // it('delete role with overlapping hierarchical roles', function () { + // Roles.createRoleAsync('role1') + // Roles.createRoleAsync('role2') + // Roles.createRoleAsync('COMMON_PERMISSION_1') + // Roles.createRoleAsync('COMMON_PERMISSION_2') + // Roles.createRoleAsync('COMMON_PERMISSION_3') + // Roles.createRoleAsync('EXTRA_PERMISSION_ROLE_1') + // Roles.createRoleAsync('EXTRA_PERMISSION_ROLE_2') + // + // Roles.addRolesToParent('COMMON_PERMISSION_1', 'role1') + // Roles.addRolesToParent('COMMON_PERMISSION_2', 'role1') + // Roles.addRolesToParent('COMMON_PERMISSION_3', 'role1') + // Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_1', 'role1') + // + // Roles.addRolesToParent('COMMON_PERMISSION_1', 'role2') + // Roles.addRolesToParent('COMMON_PERMISSION_2', 'role2') + // Roles.addRolesToParent('COMMON_PERMISSION_3', 'role2') + // Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_2', 'role2') + // + // Roles.addUsersToRolesAsync(users.eve, 'role1') + // Roles.addUsersToRolesAsync(users.eve, 'role2') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'role1' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'role1' }, + // { _id: 'COMMON_PERMISSION_1' }, + // { _id: 'COMMON_PERMISSION_2' }, + // { _id: 'COMMON_PERMISSION_3' }, + // { _id: 'EXTRA_PERMISSION_ROLE_1' } + // ] + // }, { + // role: { _id: 'role2' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'role2' }, + // { _id: 'COMMON_PERMISSION_1' }, + // { _id: 'COMMON_PERMISSION_2' }, + // { _id: 'COMMON_PERMISSION_3' }, + // { _id: 'EXTRA_PERMISSION_ROLE_2' } + // ] + // }]) + // + // Roles.removeUsersFromRolesAsync(users.eve, 'role2') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'role1' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'role1' }, + // { _id: 'COMMON_PERMISSION_1' }, + // { _id: 'COMMON_PERMISSION_2' }, + // { _id: 'COMMON_PERMISSION_3' }, + // { _id: 'EXTRA_PERMISSION_ROLE_1' } + // ] + // }]) + // + // Roles.addUsersToRolesAsync(users.eve, 'role2') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'role1' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'role1' }, + // { _id: 'COMMON_PERMISSION_1' }, + // { _id: 'COMMON_PERMISSION_2' }, + // { _id: 'COMMON_PERMISSION_3' }, + // { _id: 'EXTRA_PERMISSION_ROLE_1' } + // ] + // }, { + // role: { _id: 'role2' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'role2' }, + // { _id: 'COMMON_PERMISSION_1' }, + // { _id: 'COMMON_PERMISSION_2' }, + // { _id: 'COMMON_PERMISSION_3' }, + // { _id: 'EXTRA_PERMISSION_ROLE_2' } + // ] + // }]) + // + // Roles.deleteRole('role2') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'role1' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [ + // { _id: 'role1' }, + // { _id: 'COMMON_PERMISSION_1' }, + // { _id: 'COMMON_PERMISSION_2' }, + // { _id: 'COMMON_PERMISSION_3' }, + // { _id: 'EXTRA_PERMISSION_ROLE_1' } + // ] + // }]) + // }) + // + // it('set parent on assigned role', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('EDIT_PERMISSION') + // + // Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'EDIT_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + // }]) + // + // Roles.addRolesToParent('EDIT_PERMISSION', 'admin') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'EDIT_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + // }]) + // }) + // + // it('remove parent on assigned role', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('EDIT_PERMISSION') + // + // Roles.addRolesToParent('EDIT_PERMISSION', 'admin') + // + // Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'EDIT_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + // }]) + // + // Roles.removeRolesFromParent('EDIT_PERMISSION', 'admin') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'EDIT_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + // }]) + // }) + // + // it('adding and removing extra role parents', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('EDIT_PERMISSION') + // + // Roles.addRolesToParent('EDIT_PERMISSION', 'admin') + // + // Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'EDIT_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + // }]) + // + // Roles.addRolesToParent('EDIT_PERMISSION', 'user') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'EDIT_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + // }]) + // + // Roles.removeRolesFromParent('EDIT_PERMISSION', 'user') + // + // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) + // + // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ + // role: { _id: 'EDIT_PERMISSION' }, + // scope: null, + // user: { _id: users.eve }, + // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + // }]) + // }) + // + // it('cyclic roles', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('editor') + // Roles.createRoleAsync('user') + // + // Roles.addRolesToParent('editor', 'admin') + // Roles.addRolesToParent('user', 'editor') + // + // assert.throws(function () { + // Roles.addRolesToParent('admin', 'user') + // }, /form a cycle/) + // }) + // + // it('userIsInRole returns false for unknown roles', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('user') + // Roles.createRoleAsync('editor') + // Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) + // Roles.addUsersToRolesAsync(users.eve, ['editor']) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'unknown')) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, [])) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, null)) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, undefined)) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'unknown', { anyScope: true })) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, [], { anyScope: true })) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, null, { anyScope: true })) + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, undefined, { anyScope: true })) + // + // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['Role1', 'Role2', undefined], 'GroupName')) + // }) + // + // it('userIsInRole returns false if user is a function', function () { + // Roles.createRoleAsync('admin') + // Roles.addUsersToRolesAsync(users.eve, ['admin']) + // + // assert.isFalse(Roles.userIsInRoleAsync(() => {}, 'admin')) + // }) + // + // describe('isParentOf', function () { + // it('returns false for unknown roles', function () { + // Roles.createRoleAsync('admin') + // + // assert.isFalse(Roles.isParentOf('admin', 'unknown')) + // assert.isFalse(Roles.isParentOf('admin', null)) + // assert.isFalse(Roles.isParentOf('admin', undefined)) + // + // assert.isFalse(Roles.isParentOf('unknown', 'admin')) + // assert.isFalse(Roles.isParentOf(null, 'admin')) + // assert.isFalse(Roles.isParentOf(undefined, 'admin')) + // }) + // + // it('returns false if role is not parent of', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('editor') + // Roles.createRoleAsync('user') + // Roles.addRolesToParent(['editor'], 'admin') + // Roles.addRolesToParent(['user'], 'editor') + // + // assert.isFalse(Roles.isParentOf('user', 'admin')) + // assert.isFalse(Roles.isParentOf('editor', 'admin')) + // }) + // + // it('returns true if role is parent of the demanded role', function () { + // Roles.createRoleAsync('admin') + // Roles.createRoleAsync('editor') + // Roles.createRoleAsync('user') + // Roles.addRolesToParent(['editor'], 'admin') + // Roles.addRolesToParent(['user'], 'editor') + // + // assert.isTrue(Roles.isParentOf('admin', 'user')) + // assert.isTrue(Roles.isParentOf('editor', 'user')) + // assert.isTrue(Roles.isParentOf('admin', 'editor')) + // + // assert.isTrue(Roles.isParentOf('admin', 'admin')) + // assert.isTrue(Roles.isParentOf('editor', 'editor')) + // assert.isTrue(Roles.isParentOf('user', 'user')) + // }) + // }) }) diff --git a/testapp/.meteor/packages b/testapp/.meteor/packages index 63f32aa2..45d8f396 100644 --- a/testapp/.meteor/packages +++ b/testapp/.meteor/packages @@ -4,7 +4,7 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -meteor@1.11.2 # Shared foundation for all Meteor packages +meteor@1.11.3 # Shared foundation for all Meteor packages static-html@1.3.2 # Define static page content in .html files standard-minifier-css@1.9.2 # CSS minifier run for production mode standard-minifier-js@2.8.1 # JS minifier run for production mode diff --git a/testapp/.meteor/release b/testapp/.meteor/release index e8cfc7ec..6641d047 100644 --- a/testapp/.meteor/release +++ b/testapp/.meteor/release @@ -1 +1 @@ -METEOR@2.12 +METEOR@2.13.3 diff --git a/testapp/.meteor/versions b/testapp/.meteor/versions index 24b50021..e0abc760 100644 --- a/testapp/.meteor/versions +++ b/testapp/.meteor/versions @@ -11,7 +11,7 @@ check@1.3.2 ddp@1.4.1 ddp-client@2.6.1 ddp-common@1.4.0 -ddp-server@2.6.1 +ddp-server@2.6.2 diff-sequence@1.1.2 dynamic-import@0.7.3 ecmascript@0.16.7 @@ -25,14 +25,10 @@ hot-code-push@1.0.4 hot-module-replacement@0.5.3 html-tools@1.1.3 htmljs@1.1.1 -http@1.0.10 id-map@1.1.1 inter-process-messaging@0.1.1 logging@1.3.2 -meteor@1.11.2 -meteortesting:browser-tests@1.4.2 -meteortesting:mocha@2.1.0 -meteortesting:mocha-core@8.0.1 +meteor@1.11.3 minifier-css@1.6.4 minifier-js@2.7.5 modern-browsers@0.1.9 @@ -57,6 +53,5 @@ templating-tools@1.2.2 tracker@1.3.2 typescript@4.9.4 underscore@1.0.13 -url@1.3.2 webapp@1.13.5 webapp-hashing@1.1.1 From 3a429bf95c7918716cd8992cd9f0bafa737eeed5 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sun, 24 Sep 2023 16:28:14 +0200 Subject: [PATCH 48/53] Finish server tests for async --- roles/roles_common.js | 2 +- roles/roles_common_async.js | 47 +- roles/tests/serverAsync.js | 2808 +++++++++++++++++------------------ 3 files changed, 1349 insertions(+), 1508 deletions(-) diff --git a/roles/roles_common.js b/roles/roles_common.js index f05d6206..3dfcefe3 100644 --- a/roles/roles_common.js +++ b/roles/roles_common.js @@ -706,7 +706,7 @@ Object.assign(Roles, { * - `onlyAssigned`: return only assigned roles and not automatically inferred (like subroles) * - `fullObjects`: return full roles objects (`true`) or just names (`false`) (`onlyAssigned` option is ignored) (default `false`) * If you have a use-case for this option, please file a feature-request. You shouldn't need to use it as it's - * result strongly dependant on the internal data structure of this plugin. + * result strongly dependent on the internal data structure of this plugin. * * Alternatively, it can be a scope name string. * @return {Array} Array of user's roles, unsorted. diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index ad9c0fcd..93d7bec8 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -583,6 +583,21 @@ Object.assign(Roles, { } // This might create duplicates, because we don't have a unique index, but that's all right. In case there are two, withdrawing the role will effectively kill them both. + // TODO revisit this + /* const res = await Meteor.roleAssignment.upsertAsync( + { + "user._id": userId, + "role._id": roleName, + scope: options.scope, + }, + { + $setOnInsert: { + user: { _id: userId }, + role: { _id: roleName }, + scope: options.scope, + }, + } + ); */ const existingAssignment = await Meteor.roleAssignment.findOneAsync({ 'user._id': userId, 'role._id': roleName, @@ -608,20 +623,6 @@ Object.assign(Roles, { scope: options.scope }) } - /* const res = await Meteor.roleAssignment.upsertAsync( - { - "user._id": userId, - "role._id": roleName, - scope: options.scope, - }, - { - $setOnInsert: { - user: { _id: userId }, - role: { _id: roleName }, - scope: options.scope, - }, - } - ); */ if (insertedId) { await Meteor.roleAssignment.updateAsync( @@ -638,6 +639,7 @@ Object.assign(Roles, { res = await Meteor.roleAssignment.findOneAsync({ _id: insertedId }) } + res.insertedId = insertedId // For backward compatibility return res }, @@ -876,7 +878,7 @@ Object.assign(Roles, { * - `onlyAssigned`: return only assigned roles and not automatically inferred (like subroles) * - `fullObjects`: return full roles objects (`true`) or just names (`false`) (`onlyAssigned` option is ignored) (default `false`) * If you have a use-case for this option, please file a feature-request. You shouldn't need to use it as it's - * result strongly dependant on the internal data structure of this plugin. + * result strongly dependent on the internal data structure of this plugin. * * Alternatively, it can be a scope name string. * @return {Promise} Array of user's roles, unsorted. @@ -889,15 +891,12 @@ Object.assign(Roles, { Roles._checkScopeName(options.scope) - options = Object.assign( - { - fullObjects: false, - onlyAssigned: false, - anyScope: false, - onlyScoped: false - }, - options - ) + options = Object.assign({ + fullObjects: false, + onlyAssigned: false, + anyScope: false, + onlyScoped: false + }, options) if (user && typeof user === 'object') { id = user._id diff --git a/roles/tests/serverAsync.js b/roles/tests/serverAsync.js index 5b4fda6f..9fc3a6ab 100644 --- a/roles/tests/serverAsync.js +++ b/roles/tests/serverAsync.js @@ -126,11 +126,11 @@ describe('roles async', async function () { }) it('can\'t create role with empty names', async function () { - assert.isRejected(Roles.createRoleAsync(''), /Invalid role name/) - assert.isRejected(Roles.createRoleAsync(null), /Invalid role name/) - assert.isRejected(Roles.createRoleAsync(' '), /Invalid role name/) - assert.isRejected(Roles.createRoleAsync(' foobar'), /Invalid role name/) - assert.isRejected(Roles.createRoleAsync(' foobar '), /Invalid role name/) + await assert.isRejected(Roles.createRoleAsync(''), /Invalid role name/) + await assert.isRejected(Roles.createRoleAsync(null), /Invalid role name/) + await assert.isRejected(Roles.createRoleAsync(' '), /Invalid role name/) + await assert.isRejected(Roles.createRoleAsync(' foobar'), /Invalid role name/) + await assert.isRejected(Roles.createRoleAsync(' foobar '), /Invalid role name/) }) it('can\'t use invalid scope names', async function () { @@ -140,11 +140,11 @@ describe('roles async', async function () { await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') await Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') - assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ''), /Invalid scope name/) - assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' '), /Invalid scope name/) - assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' foobar'), /Invalid scope name/) - assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' foobar '), /Invalid scope name/) - assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 42), /Invalid scope name/) + await assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ''), /Invalid scope name/) + await assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' '), /Invalid scope name/) + await assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' foobar'), /Invalid scope name/) + await assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], ' foobar '), /Invalid scope name/) + await assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 42), /Invalid scope name/) }) it('can check if user is in role', async function () { @@ -183,30 +183,30 @@ describe('roles async', async function () { await testUser('eve', ['editor'], { scope: 'scope2' }) }) - // it('can check if user is in role by scope with global role', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') - // Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') - // Roles.addUsersToRolesAsync(users.eve, ['admin']) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['user'], 'scope1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['editor'], 'scope2')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['user'])) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['editor'])) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['user'], null)) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['editor'], null)) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['user'], 'scope2')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['editor'], 'scope1')) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'], 'scope2')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'], 'scope1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'])) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, ['admin'], null)) - // }) + it('can check if user is in role by scope with global role', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(users.eve, ['editor'], 'scope2') + await Roles.addUsersToRolesAsync(users.eve, ['admin']) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['user'], 'scope1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['editor'], 'scope2')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['user'])) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'])) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['user'], null)) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'], null)) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['user'], 'scope2')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['editor'], 'scope1')) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['admin'], 'scope2')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['admin'], 'scope1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['admin'])) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, ['admin'], null)) + }) it('renaming scopes', async function () { await Roles.createRoleAsync('admin') @@ -226,7 +226,7 @@ describe('roles async', async function () { assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], 'scope1')) assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['admin', 'user'], 'scope2')) - assert.isRejected(Roles.renameScopeAsync('scope3'), /Invalid scope name/) + await assert.isRejected(Roles.renameScopeAsync('scope3'), /Invalid scope name/) await Roles.renameScopeAsync('scope3', null) @@ -296,7 +296,7 @@ describe('roles async', async function () { }) it('can\'t add user to non-existent role', async function () { - assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin']), /Role 'admin' does not exist/) + await assert.isRejected(Roles.addUsersToRolesAsync(users.eve, ['admin']), /Role 'admin' does not exist/) await Roles.addUsersToRolesAsync(users.eve, ['admin'], { ifExists: true }) }) @@ -308,7 +308,7 @@ describe('roles async', async function () { }) it('can\'t set user to non-existent role', async function () { - assert.isRejected(Roles.setUserRolesAsync(users.eve, ['admin']), /Role 'admin' does not exist/) + await assert.isRejected(Roles.setUserRolesAsync(users.eve, ['admin']), /Role 'admin' does not exist/) await Roles.setUserRolesAsync(users.eve, ['admin'], { ifExists: true }) }) @@ -799,497 +799,517 @@ describe('roles async', async function () { assert.sameMembers(await Roles.getRolesForUserAsync('1', 'scope1'), []) }) - // it('can get all roles for user', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // - // const userId = users.eve - // let userObj - // - // // by userId - // assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) - // - // // by user object - // userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) - // - // Roles.addUsersToRolesAsync(userId, ['admin', 'user']) - // - // // by userId - // assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['admin', 'user']) - // - // // by user object - // userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['admin', 'user']) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: null, - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }, { - // role: { _id: 'user' }, - // scope: null, - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }] - // }]) - // }) - // - // it('can get all roles for user by scope', function () { + it('can get all roles for user', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + + const userId = users.eve + let userObj + + // by userId + assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) + + // by user object + userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) + + await Roles.addUsersToRolesAsync(userId, ['admin', 'user']) + + // by userId + assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['admin', 'user']) + + // by user object + userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['admin', 'user']) + + const userRoles = await Roles.getRolesForUserAsync(userId, { fullObjects: true }) + assert.sameDeepMembers(userRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: null, + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }] + }]) + }) + + it('can get all roles for user by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + + const userId = users.eve + let userObj + + // by userId + assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), []) + + // by user object + userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), []) + + // add roles + await Roles.addUsersToRolesAsync(userId, ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync(userId, ['admin'], 'scope2') + + // by userId + assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['admin', 'user']) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope2'), ['admin']) + assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) + + // by user object + userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['admin', 'user']) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope2'), ['admin']) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) + + const userRoles = await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1' }) + assert.sameDeepMembers(userRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }] + }]) + const userRoles2 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2' }) + assert.sameDeepMembers(userRoles2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + const userRoles3 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true }) + assert.sameDeepMembers(userRoles3.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }] + }, { + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + await Roles.createRoleAsync('PERMISSION') + await Roles.addRolesToParentAsync('PERMISSION', 'user') + + const userRoles4 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1' }) + assert.sameDeepMembers(userRoles4.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }]) + const userRoles5 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2' }) + assert.sameDeepMembers(userRoles5.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope1' }), ['admin', 'user', 'PERMISSION']) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope2' }), ['admin']) + + const userRoles6 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true }) + assert.sameDeepMembers(userRoles6.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }, { + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { anyScope: true }), ['admin', 'user', 'PERMISSION']) + + const userRoles7 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1', onlyAssigned: true }) + assert.sameDeepMembers(userRoles7.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }]) + const userRoles8 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2', onlyAssigned: true }) + assert.sameDeepMembers(userRoles8.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope1', onlyAssigned: true }), ['admin', 'user']) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope2', onlyAssigned: true }), ['admin']) + + const userRoles9 = await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true, onlyAssigned: true }) + assert.sameDeepMembers(userRoles9.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }, { + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }, { + role: { _id: 'admin' }, + scope: 'scope2', + user: { _id: userId }, + inheritedRoles: [{ _id: 'admin' }] + }]) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { anyScope: true, onlyAssigned: true }), ['admin', 'user']) + }) + + it('can get only scoped roles for user', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + + const userId = users.eve + + // add roles + await Roles.addUsersToRolesAsync(userId, ['user'], 'scope1') + await Roles.addUsersToRolesAsync(userId, ['admin']) + + await Roles.createRoleAsync('PERMISSION') + await Roles.addRolesToParentAsync('PERMISSION', 'user') + + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, scope: 'scope1' }), ['user', 'PERMISSION']) + assert.sameMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, onlyAssigned: true, scope: 'scope1' }), ['user']) + const userRoles = await Roles.getRolesForUserAsync(userId, { onlyScoped: true, fullObjects: true, scope: 'scope1' }) + assert.sameDeepMembers(userRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: 'scope1', + user: { _id: userId }, + inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] + }]) + }) + + it('can get all roles for user by scope with periods in name', async function () { + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.k12.va.us') + + assert.sameMembers(await Roles.getRolesForUserAsync(users.joe, 'example.k12.va.us'), ['admin']) + }) + + it('can get all roles for user by scope including Roles.GLOBAL_SCOPE', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + const userId = users.eve + + await Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + await Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], 'scope1') + + // by userId + assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['editor', 'admin', 'user']) + assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['editor']) + + // by user object + const userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['editor', 'admin', 'user']) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['editor']) + }) + + describe('getRolesForUser', function () { + it('should not return null entries if user has no roles for scope', async function () { + await Roles.createRoleAsync('editor') + + const userId = users.eve + let userObj + + // by userId + assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), []) + assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) + + // by user object + userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), []) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) + + await Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + + // by userId + assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['editor']) + assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['editor']) + + // by user object + userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['editor']) + assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['editor']) + }) + + it('should not fail during a call of addUsersToRoles', async function () { + await Roles.createRoleAsync('editor') + + const userId = users.eve + const promises = [] + const interval = setInterval(() => { + promises.push(Promise.resolve().then(async () => { + await Roles.getRolesForUserAsync(userId) + })) + }, 0) + + await Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) + clearInterval(interval) + + return Promise.all(promises) + }) + }) + + it('returns an empty list of scopes for null as user-id', async function () { + assert.sameMembers(await Roles.getScopesForUserAsync(undefined), []) + assert.sameMembers(await Roles.getScopesForUserAsync(null), []) + assert.sameMembers(await Roles.getScopesForUserAsync('foo'), []) + assert.sameMembers(await Roles.getScopesForUserAsync({}), []) + assert.sameMembers(await Roles.getScopesForUserAsync({ _id: 'foo' }), []) + }) + + it('can get all scopes for user', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + const userId = users.eve + + await Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') + await Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], 'scope2') + + // by userId + assert.sameMembers(await Roles.getScopesForUserAsync(userId), ['scope1', 'scope2']) + + // by user object + const userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj), ['scope1', 'scope2']) + }) + + it('can get all scopes for user by role', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + const userId = users.eve + + await Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') + await Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'scope2') + + // by userId + assert.sameMembers(await Roles.getScopesForUserAsync(userId, 'user'), ['scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, 'admin'), []) + + // by user object + const userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, 'user'), ['scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, 'admin'), []) + }) + + it('getScopesForUser returns [] when not using scopes', async function () { + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + const userId = users.eve + + await Roles.addUsersToRolesAsync([users.eve], ['editor', 'user']) + + // by userId + assert.sameMembers(await Roles.getScopesForUserAsync(userId), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, 'editor'), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['editor']), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['editor', 'user']), []) + + // by user object + const userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, 'editor'), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['editor']), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['editor', 'user']), []) + }) + + it('can get all groups for user by role array', async function () { + const userId = users.eve + + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.createRoleAsync('moderator') + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync([users.eve], ['editor'], 'group1') + await Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'group2') + await Roles.addUsersToRolesAsync([users.eve], ['moderator'], 'group3') + + // by userId, one role + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['user']), ['group2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['editor']), ['group1', 'group2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['admin']), []) + + // by userId, multiple roles + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['editor', 'user']), ['group1', 'group2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['editor', 'moderator']), ['group1', 'group2', 'group3']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['user', 'moderator']), ['group2', 'group3']) + + // by user object, one role + const userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['user']), ['group2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['editor']), ['group1', 'group2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['admin']), []) + + // by user object, multiple roles + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['editor', 'user']), ['group1', 'group2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['editor', 'moderator']), ['group1', 'group2', 'group3']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['user', 'moderator']), ['group2', 'group3']) + }) + + it('getting all scopes for user does not include GLOBAL_SCOPE', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + const userId = users.eve + + await Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') + await Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'scope2') + await Roles.addUsersToRolesAsync([users.eve], ['editor', 'user', 'admin'], Roles.GLOBAL_SCOPE) + + // by userId + assert.sameMembers(await Roles.getScopesForUserAsync(userId, 'user'), ['scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, 'admin'), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['user']), ['scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['editor']), ['scope1', 'scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['admin']), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userId, ['user', 'editor', 'admin']), ['scope1', 'scope2']) + + // by user object + const userObj = await Meteor.users.findOneAsync({ _id: userId }) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, 'user'), ['scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, 'editor'), ['scope1', 'scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, 'admin'), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['user']), ['scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['editor']), ['scope1', 'scope2']) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['admin']), []) + assert.sameMembers(await Roles.getScopesForUserAsync(userObj, ['user', 'editor', 'admin']), ['scope1', 'scope2']) + }) + + it('can get all users in role', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + await Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user']) + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['editor']) + + const expected = [users.eve, users.joe] + const cursor = await Roles.getUsersInRoleAsync('admin') + const actual = cursor.fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + }) + + it('can get all users in role by scope', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + + await Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user'], 'scope1') + await Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') + + let expected = [users.eve, users.joe] + const cursor1 = await Roles.getUsersInRoleAsync('admin', 'scope1') + let actual = cursor1.fetch().map(r => r._id) + + assert.sameMembers(actual, expected) + + expected = [users.eve, users.joe] + const cursor2 = await Roles.getUsersInRoleAsync('admin', { scope: 'scope1' }) + actual = cursor2.fetch().map(r => r._id) + assert.sameMembers(actual, expected) + + expected = [users.eve, users.bob, users.joe] + const cursor3 = await Roles.getUsersInRoleAsync('admin', { anyScope: true }) + actual = cursor3.fetch().map(r => r._id) + assert.sameMembers(actual, expected) + + const cursor4 = await Roles.getUsersInRoleAsync('admin') + actual = cursor4.fetch().map(r => r._id) + assert.sameMembers(actual, []) + }) + + // it('can get all users in role by scope including Roles.GLOBAL_SCOPE', function () { // Roles.createRoleAsync('admin') // Roles.createRoleAsync('user') // - // const userId = users.eve - // let userObj - // - // // by userId - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), []) - // - // // by user object - // userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), []) - // - // // add roles - // Roles.addUsersToRolesAsync(userId, ['admin', 'user'], 'scope1') - // Roles.addUsersToRolesAsync(userId, ['admin'], 'scope2') - // - // // by userId - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['admin', 'user']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope2'), ['admin']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) + // Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], Roles.GLOBAL_SCOPE) + // Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') // - // // by user object - // userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['admin', 'user']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope2'), ['admin']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) + // let expected = [users.eve] + // let actual = await Roles.getUsersInRoleAsync('admin', 'scope1').fetch().map(r => r._id) // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }, { - // role: { _id: 'user' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }] - // }]) - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope2', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) + // assert.sameMembers(actual, expected) // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }, { - // role: { _id: 'user' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }] - // }, { - // role: { _id: 'admin' }, - // scope: 'scope2', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) + // expected = [users.eve, users.bob, users.joe] + // actual = await Roles.getUsersInRoleAsync('admin', 'scope2').fetch().map(r => r._id) // - // Roles.createRoleAsync('PERMISSION') - // Roles.addRolesToParent('PERMISSION', 'user') + // assert.sameMembers(actual, expected) // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }, { - // role: { _id: 'user' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - // }]) - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2' }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope2', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope1' }), ['admin', 'user', 'PERMISSION']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope2' }), ['admin']) + // expected = [users.eve] + // actual = await Roles.getUsersInRoleAsync('admin').fetch().map(r => r._id) // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }, { - // role: { _id: 'user' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - // }, { - // role: { _id: 'admin' }, - // scope: 'scope2', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { anyScope: true }), ['admin', 'user', 'PERMISSION']) + // assert.sameMembers(actual, expected) // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope1', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }, { - // role: { _id: 'user' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - // }]) - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, scope: 'scope2', onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope2', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope1', onlyAssigned: true }), ['admin', 'user']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { scope: 'scope2', onlyAssigned: true }), ['admin']) + // expected = [users.eve, users.bob, users.joe] + // actual = await Roles.getUsersInRoleAsync('admin', { anyScope: true }).fetch().map(r => r._id) // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { fullObjects: true, anyScope: true, onlyAssigned: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }, { - // role: { _id: 'user' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - // }, { - // role: { _id: 'admin' }, - // scope: 'scope2', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { anyScope: true, onlyAssigned: true }), ['admin', 'user']) + // assert.sameMembers(actual, expected) // }) // - // it('can get only scoped roles for user', function () { + // it('can get all users in role by scope excluding Roles.GLOBAL_SCOPE', function () { // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') // - // const userId = users.eve - // - // // add roles - // Roles.addUsersToRolesAsync(userId, ['user'], 'scope1') - // Roles.addUsersToRolesAsync(userId, ['admin']) - // - // Roles.createRoleAsync('PERMISSION') - // Roles.addRolesToParent('PERMISSION', 'user') - // - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, scope: 'scope1' }), ['user', 'PERMISSION']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, onlyAssigned: true, scope: 'scope1' }), ['user']) - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(userId, { onlyScoped: true, fullObjects: true, scope: 'scope1' }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: 'scope1', - // user: { _id: userId }, - // inheritedRoles: [{ _id: 'user' }, { _id: 'PERMISSION' }] - // }]) - // }) + // Roles.addUsersToRolesAsync([users.eve], ['admin'], Roles.GLOBAL_SCOPE) + // Roles.addUsersToRolesAsync([users.bob], ['admin'], 'scope1') // - // it('can get all roles for user by scope with periods in name', function () { - // Roles.createRoleAsync('admin') + // let expected = [users.eve] + // let actual = await Roles.getUsersInRoleAsync('admin').fetch().map(r => r._id) + // assert.sameMembers(actual, expected) // - // Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.k12.va.us') + // expected = [users.eve, users.bob] + // actual = await Roles.getUsersInRoleAsync('admin', { scope: 'scope1' }).fetch().map(r => r._id) + // assert.sameMembers(actual, expected) // - // assert.sameMembers(await Roles.getRolesForUserAsync(users.joe, 'example.k12.va.us'), ['admin']) - // }) - // - // it('can get all roles for user by scope including Roles.GLOBAL_SCOPE', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // - // const userId = users.eve - // - // Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) - // Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], 'scope1') - // - // // by userId - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['editor', 'admin', 'user']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['editor']) - // - // // by user object - // const userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['editor', 'admin', 'user']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['editor']) - // }) - // - // it('getRolesForUser should not return null entries if user has no roles for scope', function () { - // Roles.createRoleAsync('editor') - // - // const userId = users.eve - // let userObj - // - // // by userId - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), []) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId), []) - // - // // by user object - // userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), []) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), []) - // - // Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) - // - // // by userId - // assert.sameMembers(await Roles.getRolesForUserAsync(userId, 'scope1'), ['editor']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userId), ['editor']) - // - // // by user object - // userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj, 'scope1'), ['editor']) - // assert.sameMembers(await Roles.getRolesForUserAsync(userObj), ['editor']) - // }) - // - // it('getRolesForUser should not fail during a call of addUsersToRoles', function () { - // Roles.createRoleAsync('editor') - // - // const userId = users.eve - // const promises = [] - // const interval = setInterval(() => { - // promises.push(Promise.resolve().then(() => { await Roles.getRolesForUserAsync(userId) })) - // }, 0) - // - // Roles.addUsersToRolesAsync([users.eve], ['editor'], Roles.GLOBAL_SCOPE) - // clearInterval(interval) - // - // return Promise.all(promises) - // }) - // - // it('returns an empty list of scopes for null as user-id', function () { - // assert.sameMembers(Roles.getScopesForUser(undefined), []) - // assert.sameMembers(Roles.getScopesForUser(null), []) - // assert.sameMembers(Roles.getScopesForUser('foo'), []) - // assert.sameMembers(Roles.getScopesForUser({}), []) - // assert.sameMembers(Roles.getScopesForUser({ _id: 'foo' }), []) - // }) - // - // it('can get all scopes for user', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // - // const userId = users.eve - // - // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') - // Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], 'scope2') - // - // // by userId - // assert.sameMembers(Roles.getScopesForUser(userId), ['scope1', 'scope2']) - // - // // by user object - // const userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(Roles.getScopesForUser(userObj), ['scope1', 'scope2']) - // }) - // - // it('can get all scopes for user by role', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // - // const userId = users.eve - // - // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') - // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'scope2') - // - // // by userId - // assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) - // assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) - // assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) - // - // // by user object - // const userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) - // }) - // - // it('getScopesForUser returns [] when not using scopes', function () { - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // - // const userId = users.eve - // - // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user']) - // - // // by userId - // assert.sameMembers(Roles.getScopesForUser(userId), []) - // assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), []) - // assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), []) - // assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), []) - // - // // by user object - // const userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(Roles.getScopesForUser(userObj), []) - // assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), []) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), []) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), []) - // }) - // - // it('can get all groups for user by role array', function () { - // const userId = users.eve - // - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // Roles.createRoleAsync('moderator') - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'group1') - // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'group2') - // Roles.addUsersToRolesAsync([users.eve], ['moderator'], 'group3') - // - // // by userId, one role - // assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['group2']) - // assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['group1', 'group2']) - // assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) - // - // // by userId, multiple roles - // assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'user']), ['group1', 'group2']) - // assert.sameMembers(Roles.getScopesForUser(userId, ['editor', 'moderator']), ['group1', 'group2', 'group3']) - // assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'moderator']), ['group2', 'group3']) - // - // // by user object, one role - // const userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['group2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['group1', 'group2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) - // - // // by user object, multiple roles - // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'user']), ['group1', 'group2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor', 'moderator']), ['group1', 'group2', 'group3']) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'moderator']), ['group2', 'group3']) - // }) - // - // it('getting all scopes for user does not include GLOBAL_SCOPE', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // - // const userId = users.eve - // - // Roles.addUsersToRolesAsync([users.eve], ['editor'], 'scope1') - // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user'], 'scope2') - // Roles.addUsersToRolesAsync([users.eve], ['editor', 'user', 'admin'], Roles.GLOBAL_SCOPE) - // - // // by userId - // assert.sameMembers(Roles.getScopesForUser(userId, 'user'), ['scope2']) - // assert.sameMembers(Roles.getScopesForUser(userId, 'editor'), ['scope1', 'scope2']) - // assert.sameMembers(Roles.getScopesForUser(userId, 'admin'), []) - // assert.sameMembers(Roles.getScopesForUser(userId, ['user']), ['scope2']) - // assert.sameMembers(Roles.getScopesForUser(userId, ['editor']), ['scope1', 'scope2']) - // assert.sameMembers(Roles.getScopesForUser(userId, ['admin']), []) - // assert.sameMembers(Roles.getScopesForUser(userId, ['user', 'editor', 'admin']), ['scope1', 'scope2']) - // - // // by user object - // const userObj = Meteor.users.findOneAsync({ _id: userId }) - // assert.sameMembers(Roles.getScopesForUser(userObj, 'user'), ['scope2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, 'editor'), ['scope1', 'scope2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, 'admin'), []) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['user']), ['scope2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['editor']), ['scope1', 'scope2']) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['admin']), []) - // assert.sameMembers(Roles.getScopesForUser(userObj, ['user', 'editor', 'admin']), ['scope1', 'scope2']) - // }) - // - // it('can get all users in role', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // - // Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user']) - // Roles.addUsersToRolesAsync([users.bob, users.joe], ['editor']) - // - // const expected = [users.eve, users.joe] - // const actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - // - // assert.sameMembers(actual, expected) - // }) - // - // it('can get all users in role by scope', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // - // Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user'], 'scope1') - // Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') - // - // let expected = [users.eve, users.joe] - // let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) - // - // assert.sameMembers(actual, expected) - // - // expected = [users.eve, users.joe] - // actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) - // assert.sameMembers(actual, expected) - // - // expected = [users.eve, users.bob, users.joe] - // actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) - // assert.sameMembers(actual, expected) - // - // actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - // assert.sameMembers(actual, []) - // }) - // - // it('can get all users in role by scope including Roles.GLOBAL_SCOPE', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // - // Roles.addUsersToRolesAsync([users.eve], ['admin', 'user'], Roles.GLOBAL_SCOPE) - // Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') - // - // let expected = [users.eve] - // let actual = Roles.getUsersInRole('admin', 'scope1').fetch().map(r => r._id) - // - // assert.sameMembers(actual, expected) - // - // expected = [users.eve, users.bob, users.joe] - // actual = Roles.getUsersInRole('admin', 'scope2').fetch().map(r => r._id) - // - // assert.sameMembers(actual, expected) - // - // expected = [users.eve] - // actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - // - // assert.sameMembers(actual, expected) - // - // expected = [users.eve, users.bob, users.joe] - // actual = Roles.getUsersInRole('admin', { anyScope: true }).fetch().map(r => r._id) - // - // assert.sameMembers(actual, expected) - // }) - // - // it('can get all users in role by scope excluding Roles.GLOBAL_SCOPE', function () { - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync([users.eve], ['admin'], Roles.GLOBAL_SCOPE) - // Roles.addUsersToRolesAsync([users.bob], ['admin'], 'scope1') - // - // let expected = [users.eve] - // let actual = Roles.getUsersInRole('admin').fetch().map(r => r._id) - // assert.sameMembers(actual, expected) - // - // expected = [users.eve, users.bob] - // actual = Roles.getUsersInRole('admin', { scope: 'scope1' }).fetch().map(r => r._id) - // assert.sameMembers(actual, expected) - // - // expected = [users.bob] - // actual = Roles.getUsersInRole('admin', { scope: 'scope1', onlyScoped: true }).fetch().map(r => r._id) - // assert.sameMembers(actual, expected) + // expected = [users.bob] + // actual = await Roles.getUsersInRoleAsync('admin', { scope: 'scope1', onlyScoped: true }).fetch().map(r => r._id) + // assert.sameMembers(actual, expected) // }) it('can get all users in role by scope and passes through mongo query arguments', async function () { @@ -1299,983 +1319,805 @@ describe('roles async', async function () { await Roles.addUsersToRolesAsync([users.eve, users.joe], ['admin', 'user'], 'scope1') await Roles.addUsersToRolesAsync([users.bob, users.joe], ['admin'], 'scope2') - const results = await Roles.getUsersInRole('admin', 'scope1', { fields: { username: 0 }, limit: 1 }).fetch() + const cursor = await Roles.getUsersInRoleAsync('admin', 'scope1', { fields: { username: 0 }, limit: 1 }) + const results = cursor.fetch() assert.equal(1, results.length) assert.isTrue(hasProp(results[0], '_id')) assert.isFalse(hasProp(results[0], 'username')) }) - // it('can use Roles.GLOBAL_SCOPE to assign blanket roles', function () { - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) - // - // testUser('eve', [], 'scope1') - // testUser('joe', ['admin'], 'scope2') - // testUser('joe', ['admin'], 'scope1') - // testUser('bob', ['admin'], 'scope2') - // testUser('bob', ['admin'], 'scope1') - // - // Roles.removeUsersFromRolesAsync(users.joe, ['admin'], Roles.GLOBAL_SCOPE) - // - // testUser('eve', [], 'scope1') - // testUser('joe', [], 'scope2') - // testUser('joe', [], 'scope1') - // testUser('bob', ['admin'], 'scope2') - // testUser('bob', ['admin'], 'scope1') - // }) - // - // it('Roles.GLOBAL_SCOPE is independent of other scopes', function () { - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], 'scope5') - // Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) - // - // testUser('eve', [], 'scope1') - // testUser('joe', ['admin'], 'scope5') - // testUser('joe', ['admin'], 'scope2') - // testUser('joe', ['admin'], 'scope1') - // testUser('bob', ['admin'], 'scope5') - // testUser('bob', ['admin'], 'scope2') - // testUser('bob', ['admin'], 'scope1') - // - // Roles.removeUsersFromRolesAsync(users.joe, ['admin'], Roles.GLOBAL_SCOPE) - // - // testUser('eve', [], 'scope1') - // testUser('joe', ['admin'], 'scope5') - // testUser('joe', [], 'scope2') - // testUser('joe', [], 'scope1') - // testUser('bob', ['admin'], 'scope5') - // testUser('bob', ['admin'], 'scope2') - // testUser('bob', ['admin'], 'scope1') - // }) - // - // it('Roles.GLOBAL_SCOPE also checked when scope not specified', function () { - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync(users.joe, 'admin', Roles.GLOBAL_SCOPE) - // - // testUser('joe', ['admin']) - // - // Roles.removeUsersFromRolesAsync(users.joe, 'admin', Roles.GLOBAL_SCOPE) - // - // testUser('joe', []) - // }) - // - // it('can use \'.\' in scope name', function () { - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.com') - // testUser('joe', ['admin'], 'example.com') - // }) - // - // it('can use multiple periods in scope name', function () { - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.k12.va.us') - // testUser('joe', ['admin'], 'example.k12.va.us') - // }) - // - // it('renaming of roles', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // - // await Roles.setUserRolesAsync([users.eve, users.bob], ['editor', 'user'], 'scope1') - // await Roles.setUserRolesAsync([users.bob, users.joe], ['user', 'admin'], 'scope2') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope2')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope2')) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'user', 'scope1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user', 'scope1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'user', 'scope1')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user', 'scope2')) - // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user', 'scope2')) - // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'user', 'scope2')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope2')) - // - // Roles.renameRole('user', 'user2') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'editor', 'scope2')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'admin', 'scope2')) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user2', 'scope1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.joe, 'user2', 'scope1')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user2', 'scope2')) - // assert.isTrue(Roles.userIsInRoleAsync(users.bob, 'user2', 'scope2')) - // assert.isTrue(Roles.userIsInRoleAsync(users.joe, 'user2', 'scope2')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user', 'scope1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'user', 'scope2')) - // }) - // - // it('migration without global groups (to v2)', function () { - // assert.isOk(Meteor.roles.insert({ name: 'admin' })) - // assert.isOk(Meteor.roles.insert({ name: 'editor' })) - // assert.isOk(Meteor.roles.insert({ name: 'user' })) - // - // assert.isOk(Meteor.users.update(users.eve, { $set: { roles: ['admin', 'editor'] } })) - // assert.isOk(Meteor.users.update(users.bob, { $set: { roles: [] } })) - // assert.isOk(Meteor.users.update(users.joe, { $set: { roles: ['user'] } })) - // - // Roles._forwardMigrate() - // - // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { - // roles: [{ - // _id: 'admin', - // scope: null, - // assigned: true - // }, { - // _id: 'editor', - // scope: null, - // assigned: true - // }] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { - // roles: [] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { - // roles: [{ - // _id: 'user', - // scope: null, - // assigned: true - // }] - // }) - // - // assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - // _id: 'admin', - // children: [] - // }) - // assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - // _id: 'editor', - // children: [] - // }) - // assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - // _id: 'user', - // children: [] - // }) - // - // Roles._backwardMigrate(null, null, false) - // - // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { - // roles: ['admin', 'editor'] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { - // roles: [] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { - // roles: ['user'] - // }) - // - // assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { - // name: 'admin' - // }) - // assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { - // name: 'editor' - // }) - // assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { - // name: 'user' - // }) - // }) - // - // it('migration without global groups (to v3)') - // - // it('migration with global groups (to v2)', function () { - // assert.isOk(Meteor.roles.insert({ name: 'admin' })) - // assert.isOk(Meteor.roles.insert({ name: 'editor' })) - // assert.isOk(Meteor.roles.insert({ name: 'user' })) - // - // assert.isOk(Meteor.users.update(users.eve, { $set: { roles: { __global_roles__: ['admin', 'editor'], foo_bla: ['user'] } } })) - // assert.isOk(Meteor.users.update(users.bob, { $set: { roles: { } } })) - // assert.isOk(Meteor.users.update(users.joe, { $set: { roles: { __global_roles__: ['user'], foo_bla: ['user'] } } })) - // - // Roles._forwardMigrate(null, null, false) - // - // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { - // roles: [{ - // _id: 'admin', - // scope: null, - // assigned: true - // }, { - // _id: 'editor', - // scope: null, - // assigned: true - // }, { - // _id: 'user', - // scope: 'foo_bla', - // assigned: true - // }] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { - // roles: [] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { - // roles: [{ - // _id: 'user', - // scope: null, - // assigned: true - // }, { - // _id: 'user', - // scope: 'foo_bla', - // assigned: true - // }] - // }) - // - // assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - // _id: 'admin', - // children: [] - // }) - // assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - // _id: 'editor', - // children: [] - // }) - // assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - // _id: 'user', - // children: [] - // }) - // - // Roles._backwardMigrate(null, null, true) - // - // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { - // roles: { - // __global_roles__: ['admin', 'editor'], - // foo_bla: ['user'] - // } - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { - // roles: {} - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { - // roles: { - // __global_roles__: ['user'], - // foo_bla: ['user'] - // } - // }) - // - // assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { - // name: 'admin' - // }) - // assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { - // name: 'editor' - // }) - // assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { - // name: 'user' - // }) - // - // Roles._forwardMigrate(null, null, true) - // - // assert.deepEqual(Meteor.users.findOneAsync(users.eve, { fields: { roles: 1, _id: 0 } }), { - // roles: [{ - // _id: 'admin', - // scope: null, - // assigned: true - // }, { - // _id: 'editor', - // scope: null, - // assigned: true - // }, { - // _id: 'user', - // scope: 'foo.bla', - // assigned: true - // }] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.bob, { fields: { roles: 1, _id: 0 } }), { - // roles: [] - // }) - // assert.deepEqual(Meteor.users.findOneAsync(users.joe, { fields: { roles: 1, _id: 0 } }), { - // roles: [{ - // _id: 'user', - // scope: null, - // assigned: true - // }, { - // _id: 'user', - // scope: 'foo.bla', - // assigned: true - // }] - // }) - // - // assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - // _id: 'admin', - // children: [] - // }) - // assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - // _id: 'editor', - // children: [] - // }) - // assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - // _id: 'user', - // children: [] - // }) - // }) - // - // it('migration with global groups (to v3)') - // - // it('_addUserToRole', function () { - // Roles.createRoleAsync('admin') - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) - // - // assert.include( - // Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), - // 'insertedId' - // ) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) - // - // assert.notInclude( - // Object.keys(Roles._addUserToRole(users.eve, 'admin', { scope: null, ifExists: false })), - // 'insertedId' - // ) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) - // }) - // - // it('_removeUserFromRole', function () { - // Roles.createRoleAsync('admin') - // - // Roles.addUsersToRolesAsync(users.eve, 'admin') - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'admin' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'admin' }] - // }]) - // - // Roles._removeUserFromRole(users.eve, 'admin', { scope: null }) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) - // }) - // - // it('keep assigned roles', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('ALL_PERMISSIONS') - // Roles.createRoleAsync('VIEW_PERMISSION') - // Roles.createRoleAsync('EDIT_PERMISSION') - // Roles.createRoleAsync('DELETE_PERMISSION') - // Roles.addRolesToParent('ALL_PERMISSIONS', 'user') - // Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') - // Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') - // Roles.addRolesToParent('DELETE_PERMISSION', 'admin') - // - // Roles.addUsersToRolesAsync(users.eve, ['user']) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' }, - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' } - // ] - // }]) - // - // Roles.addUsersToRolesAsync(users.eve, 'VIEW_PERMISSION') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' }, - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' } - // ] - // }, { - // role: { _id: 'VIEW_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'VIEW_PERMISSION' } - // ] - // }]) - // - // Roles.removeUsersFromRolesAsync(users.eve, 'user') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'VIEW_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'VIEW_PERMISSION' } - // ] - // }]) - // - // Roles.removeUsersFromRolesAsync(users.eve, 'VIEW_PERMISSION') - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), []) - // }) - // - // it('adds children of the added role to the assignments', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('ALBUM.ADMIN') - // Roles.createRoleAsync('ALBUM.VIEW') - // Roles.createRoleAsync('TRACK.ADMIN') - // Roles.createRoleAsync('TRACK.VIEW') - // - // Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') - // Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') - // - // Roles.addRolesToParent('ALBUM.ADMIN', 'admin') - // - // Roles.addUsersToRolesAsync(users.eve, ['admin']) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) - // - // Roles.addRolesToParent('TRACK.ADMIN', 'admin') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) - // }) - // - // it('removes children of the removed role from the assignments', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('ALBUM.ADMIN') - // Roles.createRoleAsync('ALBUM.VIEW') - // Roles.createRoleAsync('TRACK.ADMIN') - // Roles.createRoleAsync('TRACK.VIEW') - // - // Roles.addRolesToParent('ALBUM.VIEW', 'ALBUM.ADMIN') - // Roles.addRolesToParent('TRACK.VIEW', 'TRACK.ADMIN') - // - // Roles.addRolesToParent('ALBUM.ADMIN', 'admin') - // Roles.addRolesToParent('TRACK.ADMIN', 'admin') - // - // Roles.addUsersToRolesAsync(users.eve, ['admin']) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) - // - // Roles.removeRolesFromParent('TRACK.ADMIN', 'admin') - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) - // }) - // - // it('modify assigned hierarchical roles', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('ALL_PERMISSIONS') - // Roles.createRoleAsync('VIEW_PERMISSION') - // Roles.createRoleAsync('EDIT_PERMISSION') - // Roles.createRoleAsync('DELETE_PERMISSION') - // Roles.addRolesToParent('ALL_PERMISSIONS', 'user') - // Roles.addRolesToParent('EDIT_PERMISSION', 'ALL_PERMISSIONS') - // Roles.addRolesToParent('VIEW_PERMISSION', 'ALL_PERMISSIONS') - // Roles.addRolesToParent('DELETE_PERMISSION', 'admin') - // - // Roles.addUsersToRolesAsync(users.eve, ['user']) - // Roles.addUsersToRolesAsync(users.eve, ['ALL_PERMISSIONS'], 'scope') - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' }, - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' } - // ] - // }, { - // role: { _id: 'ALL_PERMISSIONS' }, - // scope: 'scope', - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' } - // ] - // }]) - // - // Roles.createRoleAsync('MODERATE_PERMISSION') - // - // Roles.addRolesToParent('MODERATE_PERMISSION', 'ALL_PERMISSIONS') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' }, - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' } - // ] - // }, { - // role: { _id: 'ALL_PERMISSIONS' }, - // scope: 'scope', - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' } - // ] - // }]) - // - // Roles.addUsersToRolesAsync(users.eve, ['admin']) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' }, - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' } - // ] - // }, { - // role: { _id: 'ALL_PERMISSIONS' }, - // scope: 'scope', - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' } - // ] - // }, { - // role: { _id: 'admin' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'admin' }, - // { _id: 'DELETE_PERMISSION' } - // ] - // }]) - // - // Roles.addRolesToParent('DELETE_PERMISSION', 'ALL_PERMISSIONS') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' }, - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' }, - // { _id: 'DELETE_PERMISSION' } - // ] - // }, { - // role: { _id: 'ALL_PERMISSIONS' }, - // scope: 'scope', - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' }, - // { _id: 'DELETE_PERMISSION' } - // ] - // }, { - // role: { _id: 'admin' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'admin' }, - // { _id: 'DELETE_PERMISSION' } - // ] - // }]) - // - // Roles.removeUsersFromRolesAsync(users.eve, ['admin']) - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' }, - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' }, - // { _id: 'DELETE_PERMISSION' } - // ] - // }, { - // role: { _id: 'ALL_PERMISSIONS' }, - // scope: 'scope', - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'ALL_PERMISSIONS' }, - // { _id: 'EDIT_PERMISSION' }, - // { _id: 'VIEW_PERMISSION' }, - // { _id: 'MODERATE_PERMISSION' }, - // { _id: 'DELETE_PERMISSION' } - // ] - // }]) - // - // Roles.deleteRole('ALL_PERMISSIONS') - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'user' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'user' } - // ] - // }]) - // }) - // - // it('delete role with overlapping hierarchical roles', function () { - // Roles.createRoleAsync('role1') - // Roles.createRoleAsync('role2') - // Roles.createRoleAsync('COMMON_PERMISSION_1') - // Roles.createRoleAsync('COMMON_PERMISSION_2') - // Roles.createRoleAsync('COMMON_PERMISSION_3') - // Roles.createRoleAsync('EXTRA_PERMISSION_ROLE_1') - // Roles.createRoleAsync('EXTRA_PERMISSION_ROLE_2') - // - // Roles.addRolesToParent('COMMON_PERMISSION_1', 'role1') - // Roles.addRolesToParent('COMMON_PERMISSION_2', 'role1') - // Roles.addRolesToParent('COMMON_PERMISSION_3', 'role1') - // Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_1', 'role1') - // - // Roles.addRolesToParent('COMMON_PERMISSION_1', 'role2') - // Roles.addRolesToParent('COMMON_PERMISSION_2', 'role2') - // Roles.addRolesToParent('COMMON_PERMISSION_3', 'role2') - // Roles.addRolesToParent('EXTRA_PERMISSION_ROLE_2', 'role2') - // - // Roles.addUsersToRolesAsync(users.eve, 'role1') - // Roles.addUsersToRolesAsync(users.eve, 'role2') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'role1' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'role1' }, - // { _id: 'COMMON_PERMISSION_1' }, - // { _id: 'COMMON_PERMISSION_2' }, - // { _id: 'COMMON_PERMISSION_3' }, - // { _id: 'EXTRA_PERMISSION_ROLE_1' } - // ] - // }, { - // role: { _id: 'role2' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'role2' }, - // { _id: 'COMMON_PERMISSION_1' }, - // { _id: 'COMMON_PERMISSION_2' }, - // { _id: 'COMMON_PERMISSION_3' }, - // { _id: 'EXTRA_PERMISSION_ROLE_2' } - // ] - // }]) - // - // Roles.removeUsersFromRolesAsync(users.eve, 'role2') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'role1' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'role1' }, - // { _id: 'COMMON_PERMISSION_1' }, - // { _id: 'COMMON_PERMISSION_2' }, - // { _id: 'COMMON_PERMISSION_3' }, - // { _id: 'EXTRA_PERMISSION_ROLE_1' } - // ] - // }]) - // - // Roles.addUsersToRolesAsync(users.eve, 'role2') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'role1' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'role1' }, - // { _id: 'COMMON_PERMISSION_1' }, - // { _id: 'COMMON_PERMISSION_2' }, - // { _id: 'COMMON_PERMISSION_3' }, - // { _id: 'EXTRA_PERMISSION_ROLE_1' } - // ] - // }, { - // role: { _id: 'role2' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'role2' }, - // { _id: 'COMMON_PERMISSION_1' }, - // { _id: 'COMMON_PERMISSION_2' }, - // { _id: 'COMMON_PERMISSION_3' }, - // { _id: 'EXTRA_PERMISSION_ROLE_2' } - // ] - // }]) - // - // Roles.deleteRole('role2') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'role1' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [ - // { _id: 'role1' }, - // { _id: 'COMMON_PERMISSION_1' }, - // { _id: 'COMMON_PERMISSION_2' }, - // { _id: 'COMMON_PERMISSION_3' }, - // { _id: 'EXTRA_PERMISSION_ROLE_1' } - // ] - // }]) - // }) - // - // it('set parent on assigned role', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('EDIT_PERMISSION') - // - // Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'EDIT_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - // }]) - // - // Roles.addRolesToParent('EDIT_PERMISSION', 'admin') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'EDIT_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - // }]) - // }) - // - // it('remove parent on assigned role', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('EDIT_PERMISSION') - // - // Roles.addRolesToParent('EDIT_PERMISSION', 'admin') - // - // Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'EDIT_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - // }]) - // - // Roles.removeRolesFromParent('EDIT_PERMISSION', 'admin') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'EDIT_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - // }]) - // }) - // - // it('adding and removing extra role parents', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('EDIT_PERMISSION') - // - // Roles.addRolesToParent('EDIT_PERMISSION', 'admin') - // - // Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'EDIT_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - // }]) - // - // Roles.addRolesToParent('EDIT_PERMISSION', 'user') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'EDIT_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - // }]) - // - // Roles.removeRolesFromParent('EDIT_PERMISSION', 'user') - // - // assert.isTrue(Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'admin')) - // - // assert.sameDeepMembers(await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }).map(obj => { delete obj._id; return obj }), [{ - // role: { _id: 'EDIT_PERMISSION' }, - // scope: null, - // user: { _id: users.eve }, - // inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] - // }]) - // }) - // - // it('cyclic roles', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('editor') - // Roles.createRoleAsync('user') - // - // Roles.addRolesToParent('editor', 'admin') - // Roles.addRolesToParent('user', 'editor') - // - // assert.throws(function () { - // Roles.addRolesToParent('admin', 'user') - // }, /form a cycle/) - // }) - // - // it('userIsInRole returns false for unknown roles', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('user') - // Roles.createRoleAsync('editor') - // Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) - // Roles.addUsersToRolesAsync(users.eve, ['editor']) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'unknown')) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, [])) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, null)) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, undefined)) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, 'unknown', { anyScope: true })) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, [], { anyScope: true })) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, null, { anyScope: true })) - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, undefined, { anyScope: true })) - // - // assert.isFalse(Roles.userIsInRoleAsync(users.eve, ['Role1', 'Role2', undefined], 'GroupName')) - // }) - // - // it('userIsInRole returns false if user is a function', function () { - // Roles.createRoleAsync('admin') - // Roles.addUsersToRolesAsync(users.eve, ['admin']) - // - // assert.isFalse(Roles.userIsInRoleAsync(() => {}, 'admin')) - // }) - // - // describe('isParentOf', function () { - // it('returns false for unknown roles', function () { - // Roles.createRoleAsync('admin') - // - // assert.isFalse(Roles.isParentOf('admin', 'unknown')) - // assert.isFalse(Roles.isParentOf('admin', null)) - // assert.isFalse(Roles.isParentOf('admin', undefined)) - // - // assert.isFalse(Roles.isParentOf('unknown', 'admin')) - // assert.isFalse(Roles.isParentOf(null, 'admin')) - // assert.isFalse(Roles.isParentOf(undefined, 'admin')) - // }) - // - // it('returns false if role is not parent of', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('editor') - // Roles.createRoleAsync('user') - // Roles.addRolesToParent(['editor'], 'admin') - // Roles.addRolesToParent(['user'], 'editor') - // - // assert.isFalse(Roles.isParentOf('user', 'admin')) - // assert.isFalse(Roles.isParentOf('editor', 'admin')) - // }) - // - // it('returns true if role is parent of the demanded role', function () { - // Roles.createRoleAsync('admin') - // Roles.createRoleAsync('editor') - // Roles.createRoleAsync('user') - // Roles.addRolesToParent(['editor'], 'admin') - // Roles.addRolesToParent(['user'], 'editor') - // - // assert.isTrue(Roles.isParentOf('admin', 'user')) - // assert.isTrue(Roles.isParentOf('editor', 'user')) - // assert.isTrue(Roles.isParentOf('admin', 'editor')) - // - // assert.isTrue(Roles.isParentOf('admin', 'admin')) - // assert.isTrue(Roles.isParentOf('editor', 'editor')) - // assert.isTrue(Roles.isParentOf('user', 'user')) - // }) - // }) + it('can use Roles.GLOBAL_SCOPE to assign blanket roles', async function () { + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) + + await testUser('eve', [], 'scope1') + await testUser('joe', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope1') + await testUser('bob', ['admin'], 'scope2') + await testUser('bob', ['admin'], 'scope1') + + await Roles.removeUsersFromRolesAsync(users.joe, ['admin'], Roles.GLOBAL_SCOPE) + + await testUser('eve', [], 'scope1') + await testUser('joe', [], 'scope2') + await testUser('joe', [], 'scope1') + await testUser('bob', ['admin'], 'scope2') + await testUser('bob', ['admin'], 'scope1') + }) + + it('Roles.GLOBAL_SCOPE is independent of other scopes', async function () { + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], 'scope5') + await Roles.addUsersToRolesAsync([users.joe, users.bob], ['admin'], Roles.GLOBAL_SCOPE) + + await testUser('eve', [], 'scope1') + await testUser('joe', ['admin'], 'scope5') + await testUser('joe', ['admin'], 'scope2') + await testUser('joe', ['admin'], 'scope1') + await testUser('bob', ['admin'], 'scope5') + await testUser('bob', ['admin'], 'scope2') + await testUser('bob', ['admin'], 'scope1') + + await Roles.removeUsersFromRolesAsync(users.joe, ['admin'], Roles.GLOBAL_SCOPE) + + await testUser('eve', [], 'scope1') + await testUser('joe', ['admin'], 'scope5') + await testUser('joe', [], 'scope2') + await testUser('joe', [], 'scope1') + await testUser('bob', ['admin'], 'scope5') + await testUser('bob', ['admin'], 'scope2') + await testUser('bob', ['admin'], 'scope1') + }) + + it('Roles.GLOBAL_SCOPE also checked when scope not specified', async function () { + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync(users.joe, 'admin', Roles.GLOBAL_SCOPE) + + await testUser('joe', ['admin']) + + await Roles.removeUsersFromRolesAsync(users.joe, 'admin', Roles.GLOBAL_SCOPE) + + await testUser('joe', []) + }) + + it('can use \'.\' in scope name', async function () { + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.com') + await testUser('joe', ['admin'], 'example.com') + }) + + it('can use multiple periods in scope name', async function () { + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync(users.joe, ['admin'], 'example.k12.va.us') + await testUser('joe', ['admin'], 'example.k12.va.us') + }) + + it('renaming of roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + + await Roles.setUserRolesAsync([users.eve, users.bob], ['editor', 'user'], 'scope1') + await Roles.setUserRolesAsync([users.bob, users.joe], ['user', 'admin'], 'scope2') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'editor', 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'editor', 'scope2')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.joe, 'admin', 'scope1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.joe, 'admin', 'scope2')) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'user', 'scope1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.bob, 'user', 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.joe, 'user', 'scope1')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'user', 'scope2')) + assert.isTrue(await Roles.userIsInRoleAsync(users.bob, 'user', 'scope2')) + assert.isTrue(await Roles.userIsInRoleAsync(users.joe, 'user', 'scope2')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'user2', 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'user2', 'scope2')) + + await Roles.renameRoleAsync('user', 'user2') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'editor', 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'editor', 'scope2')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.joe, 'admin', 'scope1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.joe, 'admin', 'scope2')) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'user2', 'scope1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.bob, 'user2', 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.joe, 'user2', 'scope1')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'user2', 'scope2')) + assert.isTrue(await Roles.userIsInRoleAsync(users.bob, 'user2', 'scope2')) + assert.isTrue(await Roles.userIsInRoleAsync(users.joe, 'user2', 'scope2')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'user', 'scope1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'user', 'scope2')) + }) + + it('_addUserToRole', async function () { + await Roles.createRoleAsync('admin') + + const userRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(userRoles.map(obj => { delete obj._id; return obj }), []) + + const roles = await Roles._addUserToRoleAsync(users.eve, 'admin', { scope: null, ifExists: false }) + assert.hasAnyKeys(roles, 'insertedId') + + const userRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(userRoles2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + const roles2 = await Roles._addUserToRoleAsync(users.eve, 'admin', { scope: null, ifExists: false }) + assert.hasAnyKeys(roles2, 'insertedId') + + const roles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(roles3.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'admin' }] + }]) + }) + + it('_removeUserFromRole', async function () { + await Roles.createRoleAsync('admin') + + await Roles.addUsersToRolesAsync(users.eve, 'admin') + + const rolesForUser = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(rolesForUser.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'admin' }] + }]) + + Roles._removeUserFromRole(users.eve, 'admin', { scope: null }) + + const rolesForUser2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(rolesForUser2.map(obj => { delete obj._id; return obj }), []) + }) + + it('keep assigned roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('ALL_PERMISSIONS') + await Roles.createRoleAsync('VIEW_PERMISSION') + await Roles.createRoleAsync('EDIT_PERMISSION') + await Roles.createRoleAsync('DELETE_PERMISSION') + await Roles.addRolesToParentAsync('ALL_PERMISSIONS', 'user') + await Roles.addRolesToParentAsync('EDIT_PERMISSION', 'ALL_PERMISSIONS') + await Roles.addRolesToParentAsync('VIEW_PERMISSION', 'ALL_PERMISSIONS') + await Roles.addRolesToParentAsync('DELETE_PERMISSION', 'admin') + + await Roles.addUsersToRolesAsync(users.eve, ['user']) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + + const rolesForUser = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(rolesForUser.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }]) + + await Roles.addUsersToRolesAsync(users.eve, 'VIEW_PERMISSION') + + assert.eventually.isTrue(Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + + const rolesForUser2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(rolesForUser2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }, { + role: { _id: 'VIEW_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'VIEW_PERMISSION' } + ] + }]) + + await Roles.removeUsersFromRolesAsync(users.eve, 'user') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + + const rolesForUser3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(rolesForUser3.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'VIEW_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'VIEW_PERMISSION' } + ] + }]) + + await Roles.removeUsersFromRolesAsync(users.eve, 'VIEW_PERMISSION') + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) + + const rolesForUser4 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(rolesForUser4.map(obj => { delete obj._id; return obj }), []) + }) + + it('adds children of the added role to the assignments', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('ALBUM.ADMIN') + await Roles.createRoleAsync('ALBUM.VIEW') + await Roles.createRoleAsync('TRACK.ADMIN') + await Roles.createRoleAsync('TRACK.VIEW') + + await Roles.addRolesToParentAsync('ALBUM.VIEW', 'ALBUM.ADMIN') + await Roles.addRolesToParentAsync('TRACK.VIEW', 'TRACK.ADMIN') + + await Roles.addRolesToParentAsync('ALBUM.ADMIN', 'admin') + + await Roles.addUsersToRolesAsync(users.eve, ['admin']) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + + await Roles.addRolesToParentAsync('TRACK.ADMIN', 'admin') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + }) + + it('removes children of the removed role from the assignments', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('ALBUM.ADMIN') + await Roles.createRoleAsync('ALBUM.VIEW') + await Roles.createRoleAsync('TRACK.ADMIN') + await Roles.createRoleAsync('TRACK.VIEW') + + await Roles.addRolesToParentAsync('ALBUM.VIEW', 'ALBUM.ADMIN') + await Roles.addRolesToParentAsync('TRACK.VIEW', 'TRACK.ADMIN') + + await Roles.addRolesToParentAsync('ALBUM.ADMIN', 'admin') + await Roles.addRolesToParentAsync('TRACK.ADMIN', 'admin') + + await Roles.addUsersToRolesAsync(users.eve, ['admin']) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + + await Roles.removeRolesFromParentAsync('TRACK.ADMIN', 'admin') + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'TRACK.VIEW')) + }) + + it('modify assigned hierarchical roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('ALL_PERMISSIONS') + await Roles.createRoleAsync('VIEW_PERMISSION') + await Roles.createRoleAsync('EDIT_PERMISSION') + await Roles.createRoleAsync('DELETE_PERMISSION') + await Roles.addRolesToParentAsync('ALL_PERMISSIONS', 'user') + await Roles.addRolesToParentAsync('EDIT_PERMISSION', 'ALL_PERMISSIONS') + await Roles.addRolesToParentAsync('VIEW_PERMISSION', 'ALL_PERMISSIONS') + await Roles.addRolesToParentAsync('DELETE_PERMISSION', 'admin') + + await Roles.addUsersToRolesAsync(users.eve, ['user']) + await Roles.addUsersToRolesAsync(users.eve, ['ALL_PERMISSIONS'], 'scope') + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) + + const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' } + ] + }]) + + await Roles.createRoleAsync('MODERATE_PERMISSION') + + await Roles.addRolesToParentAsync('MODERATE_PERMISSION', 'ALL_PERMISSIONS') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) + + const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }]) + + await Roles.addUsersToRolesAsync(users.eve, ['admin']) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + + const usersRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles3.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' } + ] + }, { + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'admin' }, + { _id: 'DELETE_PERMISSION' } + ] + }]) + + await Roles.addRolesToParentAsync('DELETE_PERMISSION', 'ALL_PERMISSIONS') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + + const usersRoles4 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles4.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }, { + role: { _id: 'admin' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'admin' }, + { _id: 'DELETE_PERMISSION' } + ] + }]) + + await Roles.removeUsersFromRolesAsync(users.eve, ['admin']) + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + + const usersRoles5 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles5.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' }, + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }, { + role: { _id: 'ALL_PERMISSIONS' }, + scope: 'scope', + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'ALL_PERMISSIONS' }, + { _id: 'EDIT_PERMISSION' }, + { _id: 'VIEW_PERMISSION' }, + { _id: 'MODERATE_PERMISSION' }, + { _id: 'DELETE_PERMISSION' } + ] + }]) + + await await Roles.deleteRoleAsync('ALL_PERMISSIONS') + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'DELETE_PERMISSION', 'scope')) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'MODERATE_PERMISSION', 'scope')) + + const usersRoles6 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles6.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'user' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'user' } + ] + }]) + }) + + it('delete role with overlapping hierarchical roles', async function () { + await Roles.createRoleAsync('role1') + await Roles.createRoleAsync('role2') + await Roles.createRoleAsync('COMMON_PERMISSION_1') + await Roles.createRoleAsync('COMMON_PERMISSION_2') + await Roles.createRoleAsync('COMMON_PERMISSION_3') + await Roles.createRoleAsync('EXTRA_PERMISSION_ROLE_1') + await Roles.createRoleAsync('EXTRA_PERMISSION_ROLE_2') + + await Roles.addRolesToParentAsync('COMMON_PERMISSION_1', 'role1') + await Roles.addRolesToParentAsync('COMMON_PERMISSION_2', 'role1') + await Roles.addRolesToParentAsync('COMMON_PERMISSION_3', 'role1') + await Roles.addRolesToParentAsync('EXTRA_PERMISSION_ROLE_1', 'role1') + + await Roles.addRolesToParentAsync('COMMON_PERMISSION_1', 'role2') + await Roles.addRolesToParentAsync('COMMON_PERMISSION_2', 'role2') + await Roles.addRolesToParentAsync('COMMON_PERMISSION_3', 'role2') + await Roles.addRolesToParentAsync('EXTRA_PERMISSION_ROLE_2', 'role2') + + await Roles.addUsersToRolesAsync(users.eve, 'role1') + await Roles.addUsersToRolesAsync(users.eve, 'role2') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }, { + role: { _id: 'role2' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role2' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_2' } + ] + }]) + + await Roles.removeUsersFromRolesAsync(users.eve, 'role2') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }]) + + await Roles.addUsersToRolesAsync(users.eve, 'role2') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + const usersRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles3.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }, { + role: { _id: 'role2' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role2' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_2' } + ] + }]) + + await Roles.deleteRoleAsync('role2') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'COMMON_PERMISSION_1')) + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_1')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'EXTRA_PERMISSION_ROLE_2')) + + const usersRoles4 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles4.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'role1' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [ + { _id: 'role1' }, + { _id: 'COMMON_PERMISSION_1' }, + { _id: 'COMMON_PERMISSION_2' }, + { _id: 'COMMON_PERMISSION_3' }, + { _id: 'EXTRA_PERMISSION_ROLE_1' } + ] + }]) + }) + + it('set parent on assigned role', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('EDIT_PERMISSION') + + await Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'admin')) + + const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + await Roles.addRolesToParentAsync('EDIT_PERMISSION', 'admin') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'admin')) + + const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + }) + + it('remove parent on assigned role', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('EDIT_PERMISSION') + + await Roles.addRolesToParentAsync('EDIT_PERMISSION', 'admin') + + await Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'admin')) + + const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + await Roles.removeRolesFromParentAsync('EDIT_PERMISSION', 'admin') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'admin')) + + const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + }) + + it('adding and removing extra role parents', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('EDIT_PERMISSION') + + await Roles.addRolesToParentAsync('EDIT_PERMISSION', 'admin') + + await Roles.addUsersToRolesAsync(users.eve, 'EDIT_PERMISSION') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'admin')) + + const usersRoles = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + await Roles.addRolesToParentAsync('EDIT_PERMISSION', 'user') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'admin')) + + const usersRoles2 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles2.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + + await Roles.removeRolesFromParentAsync('EDIT_PERMISSION', 'user') + + assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'EDIT_PERMISSION')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'admin')) + + const usersRoles3 = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + assert.sameDeepMembers(usersRoles3.map(obj => { delete obj._id; return obj }), [{ + role: { _id: 'EDIT_PERMISSION' }, + scope: null, + user: { _id: users.eve }, + inheritedRoles: [{ _id: 'EDIT_PERMISSION' }] + }]) + }) + + it('cyclic roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('editor') + await Roles.createRoleAsync('user') + + await Roles.addRolesToParentAsync('editor', 'admin') + await Roles.addRolesToParentAsync('user', 'editor') + + await assert.isRejected(Roles.addRolesToParentAsync('admin', 'user'), /form a cycle/) + }) + + describe('userIsInRole', function () { + it('userIsInRole returns false for unknown roles', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('user') + await Roles.createRoleAsync('editor') + await Roles.addUsersToRolesAsync(users.eve, ['admin', 'user']) + await Roles.addUsersToRolesAsync(users.eve, ['editor']) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'unknown')) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, [])) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, null)) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, undefined)) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, 'unknown', { anyScope: true })) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, [], { anyScope: true })) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, null, { anyScope: true })) + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, undefined, { anyScope: true })) + + assert.isFalse(await Roles.userIsInRoleAsync(users.eve, ['Role1', 'Role2', undefined], 'GroupName')) + }) + + it('userIsInRole returns false if user is a function', async function () { + await Roles.createRoleAsync('admin') + await Roles.addUsersToRolesAsync(users.eve, ['admin']) + + assert.isFalse(await Roles.userIsInRoleAsync(() => {}, 'admin')) + }) + }) + + describe('isParentOf', function () { + it('returns false for unknown roles', async function () { + await Roles.createRoleAsync('admin') + + assert.isFalse(await Roles.isParentOfAsync('admin', 'unknown')) + assert.isFalse(await Roles.isParentOfAsync('admin', null)) + assert.isFalse(await Roles.isParentOfAsync('admin', undefined)) + + assert.isFalse(await Roles.isParentOfAsync('unknown', 'admin')) + assert.isFalse(await Roles.isParentOfAsync(null, 'admin')) + assert.isFalse(await Roles.isParentOfAsync(undefined, 'admin')) + }) + + it('returns false if role is not parent of', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('editor') + await Roles.createRoleAsync('user') + await Roles.addRolesToParentAsync(['editor'], 'admin') + await Roles.addRolesToParentAsync(['user'], 'editor') + + assert.isFalse(await Roles.isParentOfAsync('user', 'admin')) + assert.isFalse(await Roles.isParentOfAsync('editor', 'admin')) + }) + + it('returns true if role is parent of the demanded role', async function () { + await Roles.createRoleAsync('admin') + await Roles.createRoleAsync('editor') + await Roles.createRoleAsync('user') + await Roles.addRolesToParentAsync(['editor'], 'admin') + await Roles.addRolesToParentAsync(['user'], 'editor') + + assert.isTrue(await Roles.isParentOfAsync('admin', 'user')) + assert.isTrue(await Roles.isParentOfAsync('editor', 'user')) + assert.isTrue(await Roles.isParentOfAsync('admin', 'editor')) + + assert.isTrue(await Roles.isParentOfAsync('admin', 'admin')) + assert.isTrue(await Roles.isParentOfAsync('editor', 'editor')) + assert.isTrue(await Roles.isParentOfAsync('user', 'user')) + }) + }) }) From 281f019634a45241b2abb34ae602a1f4088e0e82 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sun, 24 Sep 2023 16:31:56 +0200 Subject: [PATCH 49/53] Better categorization for migration tests --- roles/tests/server.js | 377 +++++++++++++++++++++--------------------- 1 file changed, 191 insertions(+), 186 deletions(-) diff --git a/roles/tests/server.js b/roles/tests/server.js index b3fb854d..d49750c3 100644 --- a/roles/tests/server.js +++ b/roles/tests/server.js @@ -1418,206 +1418,211 @@ describe('roles', function () { assert.isFalse(Roles.userIsInRole(users.eve, 'user', 'scope2')) }) - it('migration without global groups (to v2)', function () { - assert.isOk(Meteor.roles.insert({ name: 'admin' })) - assert.isOk(Meteor.roles.insert({ name: 'editor' })) - assert.isOk(Meteor.roles.insert({ name: 'user' })) - - assert.isOk(Meteor.users.update(users.eve, { $set: { roles: ['admin', 'editor'] } })) - assert.isOk(Meteor.users.update(users.bob, { $set: { roles: [] } })) - assert.isOk(Meteor.users.update(users.joe, { $set: { roles: ['user'] } })) - - Roles._forwardMigrate() - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: [{ + describe('v2 migration', function () { + it('migration without global groups (to v2)', function () { + assert.isOk(Meteor.roles.insert({ name: 'admin' })) + assert.isOk(Meteor.roles.insert({ name: 'editor' })) + assert.isOk(Meteor.roles.insert({ name: 'user' })) + + assert.isOk(Meteor.users.update(users.eve, { $set: { roles: ['admin', 'editor'] } })) + assert.isOk(Meteor.users.update(users.bob, { $set: { roles: [] } })) + assert.isOk(Meteor.users.update(users.joe, { $set: { roles: ['user'] } })) + + Roles._forwardMigrate() + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'admin', + scope: null, + assigned: true + }, { + _id: 'editor', + scope: null, + assigned: true + }] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'user', + scope: null, + assigned: true + }] + }) + + assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { _id: 'admin', - scope: null, - assigned: true - }, { + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { _id: 'editor', - scope: null, - assigned: true - }] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: [{ + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { _id: 'user', - scope: null, - assigned: true - }] - }) - - assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - _id: 'admin', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - _id: 'editor', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - _id: 'user', - children: [] - }) - - Roles._backwardMigrate(null, null, false) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: ['admin', 'editor'] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: ['user'] + children: [] + }) + + Roles._backwardMigrate(null, null, false) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: ['admin', 'editor'] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: ['user'] + }) + + assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { + name: 'admin' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { + name: 'editor' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { + name: 'user' + }) }) - assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { - name: 'admin' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { - name: 'editor' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { - name: 'user' - }) - }) - - it('migration without global groups (to v3)') - - it('migration with global groups (to v2)', function () { - assert.isOk(Meteor.roles.insert({ name: 'admin' })) - assert.isOk(Meteor.roles.insert({ name: 'editor' })) - assert.isOk(Meteor.roles.insert({ name: 'user' })) - - assert.isOk(Meteor.users.update(users.eve, { $set: { roles: { __global_roles__: ['admin', 'editor'], foo_bla: ['user'] } } })) - assert.isOk(Meteor.users.update(users.bob, { $set: { roles: { } } })) - assert.isOk(Meteor.users.update(users.joe, { $set: { roles: { __global_roles__: ['user'], foo_bla: ['user'] } } })) - - Roles._forwardMigrate(null, null, false) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: [{ + it('migration with global groups (to v2)', function () { + assert.isOk(Meteor.roles.insert({ name: 'admin' })) + assert.isOk(Meteor.roles.insert({ name: 'editor' })) + assert.isOk(Meteor.roles.insert({ name: 'user' })) + + assert.isOk(Meteor.users.update(users.eve, { $set: { roles: { __global_roles__: ['admin', 'editor'], foo_bla: ['user'] } } })) + assert.isOk(Meteor.users.update(users.bob, { $set: { roles: { } } })) + assert.isOk(Meteor.users.update(users.joe, { $set: { roles: { __global_roles__: ['user'], foo_bla: ['user'] } } })) + + Roles._forwardMigrate(null, null, false) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'admin', + scope: null, + assigned: true + }, { + _id: 'editor', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo_bla', + assigned: true + }] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'user', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo_bla', + assigned: true + }] + }) + + assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { _id: 'admin', - scope: null, - assigned: true - }, { + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { _id: 'editor', - scope: null, - assigned: true - }, { + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { _id: 'user', - scope: 'foo_bla', - assigned: true - }] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'user', - scope: null, - assigned: true - }, { - _id: 'user', - scope: 'foo_bla', - assigned: true - }] - }) - - assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - _id: 'admin', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - _id: 'editor', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - _id: 'user', - children: [] - }) - - Roles._backwardMigrate(null, null, true) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: { - __global_roles__: ['admin', 'editor'], - foo_bla: ['user'] - } - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: {} - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: { - __global_roles__: ['user'], - foo_bla: ['user'] - } - }) - - assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { - name: 'admin' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { - name: 'editor' - }) - assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { - name: 'user' - }) - - Roles._forwardMigrate(null, null, true) - - assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { - roles: [{ + children: [] + }) + + Roles._backwardMigrate(null, null, true) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: { + __global_roles__: ['admin', 'editor'], + foo_bla: ['user'] + } + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: {} + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: { + __global_roles__: ['user'], + foo_bla: ['user'] + } + }) + + assert.deepEqual(Meteor.roles.findOne({ name: 'admin' }, { fields: { _id: 0 } }), { + name: 'admin' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'editor' }, { fields: { _id: 0 } }), { + name: 'editor' + }) + assert.deepEqual(Meteor.roles.findOne({ name: 'user' }, { fields: { _id: 0 } }), { + name: 'user' + }) + + Roles._forwardMigrate(null, null, true) + + assert.deepEqual(Meteor.users.findOne(users.eve, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'admin', + scope: null, + assigned: true + }, { + _id: 'editor', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo.bla', + assigned: true + }] + }) + assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { + roles: [] + }) + assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { + roles: [{ + _id: 'user', + scope: null, + assigned: true + }, { + _id: 'user', + scope: 'foo.bla', + assigned: true + }] + }) + + assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { _id: 'admin', - scope: null, - assigned: true - }, { + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { _id: 'editor', - scope: null, - assigned: true - }, { - _id: 'user', - scope: 'foo.bla', - assigned: true - }] - }) - assert.deepEqual(Meteor.users.findOne(users.bob, { fields: { roles: 1, _id: 0 } }), { - roles: [] - }) - assert.deepEqual(Meteor.users.findOne(users.joe, { fields: { roles: 1, _id: 0 } }), { - roles: [{ - _id: 'user', - scope: null, - assigned: true - }, { + children: [] + }) + assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { _id: 'user', - scope: 'foo.bla', - assigned: true - }] - }) - - assert.deepEqual(Meteor.roles.findOne({ _id: 'admin' }), { - _id: 'admin', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'editor' }), { - _id: 'editor', - children: [] - }) - assert.deepEqual(Meteor.roles.findOne({ _id: 'user' }), { - _id: 'user', - children: [] + children: [] + }) }) }) - it('migration with global groups (to v3)') + + describe('v3 migration', function () { + it('migration without global groups (to v3)') + + it('migration with global groups (to v3)') + }) it('_addUserToRole', function () { Roles.createRole('admin') From 9a213287271edf2bb18680cd7bcea144c6d3c47e Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Sun, 24 Sep 2023 18:23:40 +0200 Subject: [PATCH 50/53] fixing tests --- roles/roles_common_async.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 93d7bec8..0e97f799 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -692,7 +692,7 @@ Object.assign(Roles, { const inheritedRoles = new Set() const nestedRoles = new Set([role]) - for (const r in nestedRoles) { + for (const r of nestedRoles) { const roles = await Meteor.roles .find( { _id: { $in: r.children.map((r) => r._id) } }, From fb2ecb19a8c2f8677ed64db91d3e75581d0eff17 Mon Sep 17 00:00:00 2001 From: bratelefant <59534030+bratelefant@users.noreply.github.com> Date: Sun, 24 Sep 2023 18:27:12 +0200 Subject: [PATCH 51/53] lint fix --- roles/tests/server.js | 1 - roles/tests/serverAsync.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/roles/tests/server.js b/roles/tests/server.js index d49750c3..5ed65b56 100644 --- a/roles/tests/server.js +++ b/roles/tests/server.js @@ -1617,7 +1617,6 @@ describe('roles', function () { }) }) - describe('v3 migration', function () { it('migration without global groups (to v3)') diff --git a/roles/tests/serverAsync.js b/roles/tests/serverAsync.js index 9fc3a6ab..8d118aef 100644 --- a/roles/tests/serverAsync.js +++ b/roles/tests/serverAsync.js @@ -1507,7 +1507,7 @@ describe('roles async', async function () { assert.isTrue(await Roles.userIsInRoleAsync(users.eve, 'VIEW_PERMISSION')) - const rolesForUser = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) + const rolesForUser = await Roles.getRolesForUserAsync(users.eve, { anyScope: true, fullObjects: true }) assert.sameDeepMembers(rolesForUser.map(obj => { delete obj._id; return obj }), [{ role: { _id: 'user' }, scope: null, From e9506878e8f1fbdca0461a5f6c65c70c33741c1f Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sat, 14 Oct 2023 11:14:08 +0200 Subject: [PATCH 52/53] Try client side test async --- .github/workflows/testsuite.yml | 2 +- package.js | 2 +- roles/roles_common_async.js | 2 +- roles/tests/clientAsync.js | 5 ++++- testapp/package-lock.json | 6 +++--- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index aa1ff189..ffce9b1b 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -37,7 +37,7 @@ jobs: matrix: meteorRelease: - '2.8.0' - - '2.13' + - '2.13.3' # Latest version steps: - name: Checkout code diff --git a/package.js b/package.js index f362cf22..eef959fd 100644 --- a/package.js +++ b/package.js @@ -44,7 +44,7 @@ Package.onTest(function (api) { 'meteortesting:mocha@2.1.0' ]) - api.versionsFrom('2.3') + api.versionsFrom(['2.3', '2.8.1']) const both = ['client', 'server'] diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 0e97f799..7d3369ca 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -313,7 +313,7 @@ Object.assign(Roles, { ) // if there was no change, parent role might not exist, or role is - // already a subrole; in any case we do not have anything more to do + // already a sub-role; in any case we do not have anything more to do if (!count) return await Meteor.roleAssignment.updateAsync( diff --git a/roles/tests/clientAsync.js b/roles/tests/clientAsync.js index c931896c..0f606b78 100644 --- a/roles/tests/clientAsync.js +++ b/roles/tests/clientAsync.js @@ -2,7 +2,10 @@ /* global Roles */ import { Meteor } from 'meteor/meteor' -import { assert } from 'chai' +import chai, { assert } from 'chai' +import chaiAsPromised from 'chai-as-promised' + +chai.use(chaiAsPromised) // To ensure that the files are loaded for coverage import '../roles_common' diff --git a/testapp/package-lock.json b/testapp/package-lock.json index 0d1ed7dd..ca5c8cc2 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -200,9 +200,9 @@ "dev": true }, "@babel/runtime": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", - "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "requires": { "regenerator-runtime": "^0.14.0" } From 249eb0b6852ff8f8837d52b0674c49bfb1ee6c68 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sat, 14 Oct 2023 12:26:26 +0200 Subject: [PATCH 53/53] Fix lint issues --- roles/tests/clientAsync.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/tests/clientAsync.js b/roles/tests/clientAsync.js index 0f606b78..ce1575e4 100644 --- a/roles/tests/clientAsync.js +++ b/roles/tests/clientAsync.js @@ -5,11 +5,11 @@ import { Meteor } from 'meteor/meteor' import chai, { assert } from 'chai' import chaiAsPromised from 'chai-as-promised' -chai.use(chaiAsPromised) - // To ensure that the files are loaded for coverage import '../roles_common' +chai.use(chaiAsPromised) + const safeInsert = async (collection, data) => { try { await collection.insertAsync(data)