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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] =?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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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 c890d44f946e0142c255f67294533b250bd51dd7 Mon Sep 17 00:00:00 2001 From: Timo Frionnet Date: Sun, 24 Sep 2023 21:19:14 +0200 Subject: [PATCH 52/66] Updated readme, contributing, security and issue templates --- .github/CONTRIBUTING.MD | 104 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 37 ++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 24 +++++ .github/SECURITY.MD | 26 ++++++ README.md | 52 ++++++----- 5 files changed, 221 insertions(+), 22 deletions(-) create mode 100644 .github/CONTRIBUTING.MD create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/SECURITY.MD diff --git a/.github/CONTRIBUTING.MD b/.github/CONTRIBUTING.MD new file mode 100644 index 00000000..de40874f --- /dev/null +++ b/.github/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/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..ad1babd0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** + +A clear and concise description of what the bug is. + +**To Reproduce** + +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** + +A clear and concise description of what you expected to happen. + +**Screenshots** + +If applicable, add screenshots to help explain your problem. + +**Versions (please complete the following information):** + - Meteor version: [e.g. 1.8.2] + - Browser: [e.g. Firefox, Chrome, Safari] + - Version: [e.g. 1.0.0] + +**Additional context** + +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..a294cc20 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,24 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** + +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** + +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** + +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** + +Add any other context or screenshots about the feature request here. diff --git a/.github/SECURITY.MD b/.github/SECURITY.MD new file mode 100644 index 00000000..a1d37606 --- /dev/null +++ b/.github/SECURITY.MD @@ -0,0 +1,26 @@ +# Security Policy + +## Supported Versions + +Unless otherwise noted, MCP packages and projects support the latest version of Meteor. +As of the time of writing this in September 2023 it is Meteor 2.13 and, in general the 2.x series. +Support for Meteor 1.x is not guaranteed and at best can include Meteor 1.12.1. +At the present time, we are also preparing to support Meteor 3.0 which is in development. + +| Meteor Version | Supported | +| -------------- | ------------------ | +| 3.0 | 🚧 | +| > 2.0 | ✅ | +| < 1.12 | ❌ | + +## Reporting a Vulnerability + +We are not providing support for Meteor itself. See their [SECURITY](https://github.com/meteor/meteor/blob/devel/SECURITY.md) for more information. + +Any security concerns should be first raised in the repository of the affected package. +If you want to report a vulnerability privately, please contact the maintainer of the package directly. +If you are not sure who that is, you can contact one of the following people, and they will take it from there: + +Jan Dvorak +hello+mcp-security@jandvorak.me + diff --git a/README.md b/README.md index 97424b9d..87593ef2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ meteor-roles v3 =============== +[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) +![GitHub](https://img.shields.io/github/license/Meteor-Community-Packages/meteor-roles) +[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) +![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/Meteor-Community-Packages/meteor-roles?label=latest&sort=semver) +[![](https://img.shields.io/badge/semver-2.0.0-success)](http://semver.org/spec/v2.0.0.html) Authorization package for Meteor - compatible with built-in accounts package. @@ -11,17 +16,20 @@ There are also older versions of this package: ### Table of Contents -* [Contributors](#roles-contributors) -* [Authorization](#roles-authorization) -* [Permissions vs roles](#roles-naming) -* [What are "scopes"?](#roles-scopes) -* [Changes to default Meteor](#roles-changes) -* [Installation](#roles-installing) -* [Migration to 3.0](#roles-migration) -* [Usage examples](#roles-usage) -* [Online API docs](#roles-docs) -* [Example apps](#roles-example-apps) -* [Running tests](#roles-contributions-development-and-tests) +- [meteor-roles v3](#meteor-roles-v3) + - [Table of Contents](#table-of-contents) + - [Contributors](#contributors) + - [Authorization](#authorization) + - [Permissions vs roles (or What's in a name...)](#permissions-vs-roles--or-whats-in-a-name) + - [What are "scopes"?](#what-are-scopes) + - [Changes to default Meteor behavior](#changes-to-default-meteor-behavior) + - [Installing](#installing) + - [Migration to 3.0](#migration-to-30) + - [Changes between 2.x and 3.0](#changes-between-2x-and-30) + - [Usage Examples](#usage-examples) + - [API Docs](#api-docs) + - [Example Apps](#example-apps) + - [Contributions, development and tests](#contributions-development-and-tests)
@@ -53,7 +61,7 @@ Thanks to: ### Authorization -This package lets you attach roles to a user which you can then check against later when deciding whether to grant +This package lets you attach roles to a user, which you can then check against later when deciding whether to grant access to Meteor methods or publish data. The core concept is very simple, essentially you are creating an assignment of roles to a user and then checking for the existence of those roles later. This package provides helper methods to make the process of adding, removing, and verifying those roles easier. @@ -99,13 +107,13 @@ Roles.addRolesToParent('POST_EDIT', 'user'); ### What are "scopes"? Sometimes it is useful to let a user have independent sets of roles. The `roles` package calls these independent -sets "scopes" for lack of a better term. You can use them to represent various communities inside of your +sets "scopes" for lack of a better term. You can use them to represent various communities inside your application. Or maybe your application supports [multiple tenants](https://en.wikipedia.org/wiki/Multitenancy). You can put each of those tenants into their own scope. Alternatively, you can use scopes to represent various resources you have. Users can have both scope roles assigned, and global roles. Global roles are in effect for all scopes. -But scopes are independent from each other. Users can have one set of roles in scope A and another set +But scopes are independent of each other. Users can have one set of roles in scope A and another set of roles in scope B. Let's go through an example of this using soccer/football teams as scopes. ```javascript @@ -116,7 +124,7 @@ Roles.userIsInRole(joesUserId, 'manage-team', 'manchester-united.com'); // true Roles.userIsInRole(joesUserId, 'manage-team', 'real-madrid.com'); // false ``` -In this example we can see that Joe manages Manchester United and plays for Real Madrid. By using scopes, we can +In this example, we can see that Joe manages Manchester United and plays for Real Madrid. By using scopes, we can assign roles independently and make sure that they don't get mixed up between scopes. Now, let's take a look at how to use the global roles. Say we want to give Joe permission to do something across @@ -136,7 +144,7 @@ if (Roles.userIsInRole(joesUserId, ['manage-team', 'super-admin'], 'real-madrid. ### Changes to default Meteor behavior - 1. A new collection `Meteor.roleAssignment` contains the information which role has been assigned to which user. + 1. A new collection `Meteor.roleAssignment` contains the information about which role has been assigned to which user. 1. A new collection `Meteor.roles` contains a global list of defined role names. 1. All existing roles are automatically published to the client. @@ -185,7 +193,7 @@ meteor shell > Package['alanning:roles'].Roles._forwardMigrate2() ``` -In case something fails, there is also a script available for rolling back the changes. But be warned that a backward migration takes a magnitude longer than a foward migration. To migrate the database back to the old schema, run `Meteor._backwardMigrate2()` on the server: +In case something fails, there is also a script available for rolling back the changes. But be warned that a backward migration takes a magnitude longer than a forward migration. To migrate the database back to the old schema, run `Meteor._backwardMigrate2()` on the server: ```bash meteor shell @@ -197,7 +205,7 @@ meteor shell Here is the list of important changes between meteor-roles 2.x and 3.0 to consider when migrating to 3.0: * Role assignments have been moved from the `users` documents to a separate collection called `role-assignment`, available at `Meteor.roleAssignment`. -* Role assignments are not published automatically. If you want all your role-assignments to be published automatically please include the following code: +* Role assignments are not published automatically. If you want all your role-assignments to be published automatically, please include the following code: ```js Meteor.publish(null, function () { if (this.userId) { @@ -378,7 +386,7 @@ Meteor.methods({ -- **Client** -- -Client javascript does not by default have access to all the same Roles functions as the server unless you publish +Client JavaScript does not by default have access to all the same Roles functions as the server unless you publish these role-assignments. In addition, Blaze will have the addition of a `isInRole` handlebars helper which is automatically registered by the Roles package. @@ -388,10 +396,10 @@ for latency compensation during Meteor method calls. Roles functions which modif called directly, but inside the Meteor methods. NOTE: Any sensitive data needs to be controlled server-side to prevent unwanted disclosure. To be clear, Meteor sends -all templates, client-side javascript, and published data to the client's browser. This is by design and is a good thing. +all templates, client-side JavaScript, and published data to the client's browser. This is by design and is a good thing. The following example is just sugar to help improve the user experience for normal users. Those interested in seeing the 'admin_nav' template in the example below will still be able to do so by manually reading the bundled `client.js` -file. It won't be pretty but it is possible. But this is not a problem as long as the actual data is restricted server-side. +file. It won't be pretty, but it is possible. But this is not a problem as long as the actual data is restricted server-side. To check for global roles or when not using scopes: @@ -470,4 +478,4 @@ The `examples` directory contains Meteor apps which show off the following featu ### Contributions, development and tests Please read our [contribution guidelines](./CONTRIBUTING.md), -which also describe how to set up and run the linter and tests. +which also describes how to set up and run the linter and tests. From 206d4576522856c637393a0b4c74c3ea6d717544 Mon Sep 17 00:00:00 2001 From: Timo Frionnet Date: Sun, 24 Sep 2023 21:29:00 +0200 Subject: [PATCH 53/66] Updated headers in readme --- README.md | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 87593ef2..222ade9e 100644 --- a/README.md +++ b/README.md @@ -15,27 +15,27 @@ There are also older versions of this package:
-### Table of Contents +## Table of Contents - [meteor-roles v3](#meteor-roles-v3) - - [Table of Contents](#table-of-contents) - - [Contributors](#contributors) - - [Authorization](#authorization) - - [Permissions vs roles (or What's in a name...)](#permissions-vs-roles--or-whats-in-a-name) - - [What are "scopes"?](#what-are-scopes) - - [Changes to default Meteor behavior](#changes-to-default-meteor-behavior) - - [Installing](#installing) - - [Migration to 3.0](#migration-to-30) - - [Changes between 2.x and 3.0](#changes-between-2x-and-30) - - [Usage Examples](#usage-examples) - - [API Docs](#api-docs) - - [Example Apps](#example-apps) - - [Contributions, development and tests](#contributions-development-and-tests) + - [Table of Contents](#table-of-contents) + - [Contributors](#contributors) + - [Authorization](#authorization) + - [Permissions vs roles (or What's in a name...)](#permissions-vs-roles--or-whats-in-a-name) + - [What are "scopes"?](#what-are-scopes) + - [Changes to default Meteor behavior](#changes-to-default-meteor-behavior) + - [Installing](#installing) + - [Migration to 3.0](#migration-to-30) + - [Changes between 2.x and 3.0](#changes-between-2x-and-30) + - [Usage Examples](#usage-examples) + - [API Docs](#api-docs) + - [Example Apps](#example-apps) + - [Contributions, development and tests](#contributions-development-and-tests)
-### Contributors +## Contributors Thanks to: @@ -59,7 +59,7 @@ Thanks to: -### Authorization +## Authorization This package lets you attach roles to a user, which you can then check against later when deciding whether to grant access to Meteor methods or publish data. The core concept is very simple, essentially you are creating an assignment @@ -69,7 +69,7 @@ to make the process of adding, removing, and verifying those roles easier.
-### Permissions vs roles (or What's in a name...) +## Permissions vs roles (or What's in a name...) Although the name of this package is `roles`, you can define your **roles**, **scopes** or **permissions** however you like. They are essentially just tags that you assign to a user and which you can check upon later. @@ -104,7 +104,7 @@ Roles.addRolesToParent('POST_EDIT', 'user');
-### What are "scopes"? +## What are "scopes"? Sometimes it is useful to let a user have independent sets of roles. The `roles` package calls these independent sets "scopes" for lack of a better term. You can use them to represent various communities inside your @@ -142,7 +142,7 @@ if (Roles.userIsInRole(joesUserId, ['manage-team', 'super-admin'], 'real-madrid.
-### Changes to default Meteor behavior +## Changes to default Meteor behavior 1. A new collection `Meteor.roleAssignment` contains the information about which role has been assigned to which user. 1. A new collection `Meteor.roles` contains a global list of defined role names. @@ -151,7 +151,7 @@ if (Roles.userIsInRole(joesUserId, ['manage-team', 'super-admin'], 'real-madrid.
-### Installing +## Installing 1. Add one of the built-in accounts packages so the `Meteor.users` collection exists. From a command prompt: ```bash @@ -182,7 +182,7 @@ if (Roles.userIsInRole(joesUserId, ['manage-team', 'super-admin'], 'real-madrid.
-### Migration to 3.0 +## Migration to 3.0 If you are currently using this package in a version older than 2.x, please upgrade to 2.0 by running the migration script required there: https://github.com/Meteor-Community-Packages/meteor-roles/tree/v2#migration-to-20 @@ -200,7 +200,7 @@ meteor shell > Package['alanning:roles'].Roles._backwardMigrate2() ``` -#### Changes between 2.x and 3.0 +### Changes between 2.x and 3.0 Here is the list of important changes between meteor-roles 2.x and 3.0 to consider when migrating to 3.0: @@ -225,7 +225,7 @@ Meteor.publish(null, function () { -### Usage Examples +## Usage Examples
@@ -434,7 +434,7 @@ To check for roles when using scopes: -### API Docs +## API Docs Online API docs found here: https://meteor-community-packages.github.io/meteor-roles/ @@ -456,7 +456,7 @@ To serve documentation locally: -### Example Apps +## Example Apps The `examples` directory contains Meteor apps which show off the following features: * Server-side publishing with authorization to secure sensitive data @@ -475,7 +475,7 @@ The `examples` directory contains Meteor apps which show off the following featu -### Contributions, development and tests +## Contributions, development and tests Please read our [contribution guidelines](./CONTRIBUTING.md), which also describes how to set up and run the linter and tests. From 7be1e7c1cd14f73b90e017db6b0ac5dd5497b4c8 Mon Sep 17 00:00:00 2001 From: Timo Frionnet Date: Mon, 25 Sep 2023 23:35:15 +0200 Subject: [PATCH 54/66] Added github code quality badge to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 222ade9e..05247ecf 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ meteor-roles v3 [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) ![GitHub](https://img.shields.io/github/license/Meteor-Community-Packages/meteor-roles) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) +[![CodeQL](https://github.com/Meteor-Community-Packages/meteor-roles/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/Meteor-Community-Packages/meteor-roles/actions/workflows/github-code-scanning/codeql) ![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/Meteor-Community-Packages/meteor-roles?label=latest&sort=semver) [![](https://img.shields.io/badge/semver-2.0.0-success)](http://semver.org/spec/v2.0.0.html) From c2845979037a5e13358b4e837866fc473c9d5c94 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Tue, 26 Sep 2023 14:59:23 +0200 Subject: [PATCH 55/66] Adjust GitFlow branch names --- CONTRIBUTING.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index de40874f..9db04a00 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,13 +7,12 @@ Any contribution to this repository is highly appreciated! ### 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: +Branch names should follow the GitFlow standard and start with a descriptive prefix 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 +- `feature/` for features +- `fix/` for general fixes + +Then the name of the branch should describe the purpose of the branch and potentially reference the issue number it is solving. ```shell $ git clone git@github.com:Meteor-Community-Packages/meteor-roles.git From c80f55b7c60550fd1f3cd3b0c6e1b4ef097db2c9 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Tue, 26 Sep 2023 15:01:51 +0200 Subject: [PATCH 56/66] Adjust things in .github directory --- .github/{CONTRIBUTING.MD => CONTRIBUTING.md} | 11 +++++------ .github/{SECURITY.MD => SECURITY.md} | 0 2 files changed, 5 insertions(+), 6 deletions(-) rename .github/{CONTRIBUTING.MD => CONTRIBUTING.md} (89%) rename .github/{SECURITY.MD => SECURITY.md} (100%) diff --git a/.github/CONTRIBUTING.MD b/.github/CONTRIBUTING.md similarity index 89% rename from .github/CONTRIBUTING.MD rename to .github/CONTRIBUTING.md index de40874f..9db04a00 100644 --- a/.github/CONTRIBUTING.MD +++ b/.github/CONTRIBUTING.md @@ -7,13 +7,12 @@ Any contribution to this repository is highly appreciated! ### 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: +Branch names should follow the GitFlow standard and start with a descriptive prefix 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 +- `feature/` for features +- `fix/` for general fixes + +Then the name of the branch should describe the purpose of the branch and potentially reference the issue number it is solving. ```shell $ git clone git@github.com:Meteor-Community-Packages/meteor-roles.git diff --git a/.github/SECURITY.MD b/.github/SECURITY.md similarity index 100% rename from .github/SECURITY.MD rename to .github/SECURITY.md From 335636af1ab48f72ace8884e3a26ed17dd730889 Mon Sep 17 00:00:00 2001 From: Timo Frionnet Date: Wed, 27 Sep 2023 11:35:31 +0200 Subject: [PATCH 57/66] Fixed inconsistent branch naming in contributing docs --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9db04a00..153f301b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -17,7 +17,7 @@ Then the name of the branch should describe the purpose of the branch and potent ```shell $ git clone git@github.com:Meteor-Community-Packages/meteor-roles.git $ cd meteor-roles -$ git checkout -b fix-some-issue +$ git checkout -b fix/some-issue ``` ### Initialize test app From e1a9d8b87f134a0ba53f013d2b5a0716c3c92d3a Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sat, 14 Oct 2023 11:01:51 +0200 Subject: [PATCH 58/66] Update testapp dependencies --- testapp/.meteor/packages | 2 +- testapp/.meteor/release | 2 +- testapp/.meteor/versions | 4 +-- testapp/package-lock.json | 55 +++++++++++++++++++++------------------ testapp/package.json | 8 +++--- 5 files changed, 37 insertions(+), 34 deletions(-) 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..fa9f2a80 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 @@ -29,7 +29,7 @@ http@1.0.10 id-map@1.1.1 inter-process-messaging@0.1.1 logging@1.3.2 -meteor@1.11.2 +meteor@1.11.3 meteortesting:browser-tests@1.4.2 meteortesting:mocha@2.1.0 meteortesting:mocha-core@8.0.1 diff --git a/testapp/package-lock.json b/testapp/package-lock.json index 4d42b56e..839665ed 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.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" } }, "@babel/template": { @@ -969,18 +969,18 @@ "dev": true }, "chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", "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", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" } }, "chalk": { @@ -995,10 +995,13 @@ } }, "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 + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "requires": { + "get-func-name": "^2.0.2" + } }, "chownr": { "version": "1.1.4", @@ -2231,9 +2234,9 @@ "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==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true }, "get-intrinsic": { @@ -2978,12 +2981,12 @@ } }, "loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "requires": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "lru-cache": { @@ -4408,9 +4411,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..0d2cc3c2 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -11,15 +11,15 @@ "lint:fix": "standard --fix ../" }, "dependencies": { - "@babel/runtime": "^7.17.9", - "meteor-node-stubs": "^1.2.1", + "@babel/runtime": "^7.23.2", + "meteor-node-stubs": "^1.2.5", "yuidocjs": "^0.10.2" }, "devDependencies": { "babel-plugin-istanbul": "^6.1.1", - "chai": "^4.3.7", + "chai": "^4.3.10", "nyc": "^15.1.0", - "puppeteer": "^19.4.0", + "puppeteer": "^19.11.1", "standard": "^17.1.0" }, "babel": { From e9506878e8f1fbdca0461a5f6c65c70c33741c1f Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sat, 14 Oct 2023 11:14:08 +0200 Subject: [PATCH 59/66] 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 60/66] 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) From f77cc8a1a203dce8aa8ad617e5bb94340c04a25b Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Mon, 16 Oct 2023 17:34:00 +0200 Subject: [PATCH 61/66] Update TS definitions --- definitions.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/definitions.d.ts b/definitions.d.ts index bc7b8b10..56da7377 100644 --- a/definitions.d.ts +++ b/definitions.d.ts @@ -357,6 +357,7 @@ declare namespace Roles { interface Role { _id: string name: string + children: { _id: string }[] } interface RoleAssignment { @@ -387,4 +388,5 @@ declare namespace Roles { declare namespace Meteor { var roles: Mongo.Collection + var roleAssignment: Mongo.Collection } From 6662f73fac9f0ac302384624bf80ccdcc82a66c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 15:24:15 +0000 Subject: [PATCH 62/66] build(deps-dev): bump @babel/traverse from 7.22.8 to 7.23.2 in /testapp Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.8 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] --- testapp/package-lock.json | 113 +++++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 19 deletions(-) diff --git a/testapp/package-lock.json b/testapp/package-lock.json index ca5c8cc2..d996f6f6 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -88,16 +88,6 @@ "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", @@ -219,21 +209,106 @@ } }, "@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==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "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/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@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", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + } + }, + "@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "dev": true, + "requires": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "dev": true + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/types": { From c7d7a96a04028b6530926260811d76a6f5da3a01 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Tue, 17 Oct 2023 17:31:21 +0200 Subject: [PATCH 63/66] Published alanning:roles@3.6.0 --- .versions | 22 +++++++++++----------- History.md | 6 ++++++ package-lock.json | 3 +++ package.js | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 package-lock.json diff --git a/.versions b/.versions index 06d249bb..2d09a9df 100644 --- a/.versions +++ b/.versions @@ -1,5 +1,5 @@ accounts-base@2.2.8 -alanning:roles@3.5.1 +alanning:roles@3.6.0 allow-deny@1.1.1 babel-compiler@7.10.4 babel-runtime@1.5.1 @@ -12,7 +12,7 @@ ddp@1.4.1 ddp-client@2.6.1 ddp-common@1.4.0 ddp-rate-limiter@1.2.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 @@ -22,28 +22,28 @@ ecmascript-runtime-server@0.11.0 ejson@1.1.3 fetch@0.1.3 geojson-utils@1.0.11 -http@1.4.2 +http@2.0.0 id-map@1.1.1 inter-process-messaging@0.1.1 -lmieulet:meteor-coverage@3.2.0 -lmieulet:meteor-packages-coverage@0.2.0 -local-test:alanning:roles@3.5.1 +lmieulet:meteor-coverage@4.1.0 +lmieulet:meteor-legacy-coverage@0.1.0 +local-test:alanning:roles@3.6.0 localstorage@1.2.0 logging@1.3.2 -meteor@1.11.2 -meteortesting:browser-tests@0.1.2 -meteortesting:mocha@0.4.4 +meteor@1.11.3 +meteortesting:browser-tests@1.4.2 +meteortesting:mocha@2.1.0 +meteortesting:mocha-core@8.0.1 minimongo@1.9.3 modern-browsers@0.1.9 modules@0.19.0 modules-runtime@0.13.1 -mongo@1.16.6 +mongo@1.16.7 mongo-decimal@0.1.3 mongo-dev-server@1.1.0 mongo-id@1.0.8 npm-mongo@4.16.0 ordered-dict@1.1.0 -practicalmeteor:mocha-core@1.0.1 promise@0.12.2 random@1.2.1 rate-limit@1.1.1 diff --git a/History.md b/History.md index 7242730e..0586e4b9 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,11 @@ # Changelog +## v3.6.0 + +* Added async versions of functions [#361](https://github.com/Meteor-Community-Packages/meteor-roles/pull/361) [#378](https://github.com/Meteor-Community-Packages/meteor-roles/pull/378) [@bratelefant](https://github.com/bratelefant) [@storytellercz](https://github.com/sponsors/StorytellerCZ) [@jankapunkt](https://github.com/sponsors/jankapunkt) +* Added missing types [#383](https://github.com/Meteor-Community-Packages/meteor-roles/pull/383) [@storytellercz](https://github.com/sponsors/StorytellerCZ) +* Add complete test suite [#375](https://github.com/Meteor-Community-Packages/meteor-roles/pull/375) [@jankapunkt](https://github.com/sponsors/jankapunkt) [#380](https://github.com/Meteor-Community-Packages/meteor-roles/pull/380) [@bratelefant](https://github.com/bratelefant) + ## v3.5.1 * Fix for index creation functions losing context [#371](https://github.com/Meteor-Community-Packages/meteor-roles/pull/371) [@copleykj](https://github.com/sponsors/copleykj) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..48e341a0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/package.js b/package.js index eef959fd..7f3ad490 100644 --- a/package.js +++ b/package.js @@ -2,7 +2,7 @@ Package.describe({ summary: 'Authorization package for Meteor', - version: '3.5.1', + version: '3.6.0', git: 'https://github.com/Meteor-Community-Packages/meteor-roles.git', name: 'alanning:roles' }) From 3fabfeedf5fe001948d6a6e9e92f2f4ffa697d94 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Mon, 18 Dec 2023 17:04:25 +0100 Subject: [PATCH 64/66] Types for async functions --- definitions.d.ts | 44 +++++++++++++++++++++++ roles/roles_common_async.js | 72 ++++++++++++++++++------------------- 2 files changed, 80 insertions(+), 36 deletions(-) diff --git a/definitions.d.ts b/definitions.d.ts index 56da7377..22775654 100644 --- a/definitions.d.ts +++ b/definitions.d.ts @@ -69,6 +69,11 @@ declare namespace Roles { roles: string | string[], options?: string | { scope?: string; ifExists?: boolean } ): void + function addUsersToRolesAsync( + users: string | string[] | Meteor.User | Meteor.User[], + roles: string | string[], + options?: string | { scope?: string; ifExists?: boolean } + ): Promise /** * Create a new role. @@ -80,6 +85,7 @@ declare namespace Roles { * @return {String} ID of the new role or null. */ function createRole(roleName: string, options?: { unlessExists: boolean }): string + function createRoleAsync(roleName: string, options?: { unlessExists: boolean }): Promise /** * Delete an existing role. @@ -90,6 +96,7 @@ declare namespace Roles { * @param {String} roleName Name of role. */ function deleteRole(roleName: string): void + function deleteRoleAsync(roleName: string): Promise /** * Rename an existing role. @@ -99,6 +106,7 @@ declare namespace Roles { * @param {String} newName New name of a role. */ function renameRole(oldName: string, newName: string): void + function renameRoleAsync(oldName: string, newName: string): Promise /** * Add role parent to roles. @@ -111,6 +119,7 @@ declare namespace Roles { * @param {String} parentName Name of parent role. */ function addRolesToParent(rolesNames: string | string[], parentName: string): void + function addRolesToParentAsync(rolesNames: string | string[], parentName: string): Promise /** * Remove role parent from roles. @@ -123,6 +132,7 @@ declare namespace Roles { * @param {String} parentName Name of parent role. */ function removeRolesFromParent(rolesNames: string | string[], parentName: string): void + function removeRolesFromParentAsync(rolesNames: string | string[], parentName: string): Promise /** * Retrieve cursor of all existing roles. @@ -144,6 +154,7 @@ declare namespace Roles { * @return {Array} Array of user's groups, unsorted. Roles.GLOBAL_GROUP will be omitted */ function getGroupsForUser(user: string | Meteor.User, role?: string): string[] + function getGroupsForUserAsync(user: string | Meteor.User, role?: string): Promise /** * Retrieve users scopes, if any. @@ -155,6 +166,7 @@ declare namespace Roles { * @return {Array} Array of user's scopes, unsorted. */ function getScopesForUser(user: string | Meteor.User, roles?: string | string[]): string[] + function getScopesForUserAsync(user: string | Meteor.User, roles?: string | string[]): Promise /** * Rename a scope. @@ -166,6 +178,7 @@ declare namespace Roles { * @param {String} newName New name of a scope. */ function renameScope(oldName: string, newName: string): void + function renameScopeAsync(oldName: string, newName: string): Promise /** * Remove a scope. @@ -177,6 +190,7 @@ declare namespace Roles { * */ function removeScope(name: String): void + function removeScopeAsync(name: String): Promise /** * Find out if a role is an ancestor of another role. @@ -189,6 +203,7 @@ declare namespace Roles { * @return {Boolean} */ function isParentOf(parentRoleName: string, childRoleName: string): boolean + function isParentOfAsync(parentRoleName: string, childRoleName: string): Promise /** * Retrieve user's roles. @@ -214,6 +229,13 @@ declare namespace Roles { onlyAssigned?: boolean; fullObjects?: boolean }): string[] + function getRolesForUserAsync(user: string | Meteor.User, options?: string | { + scope?: string; + anyScope?: boolean; + onlyScoped?: boolean; + onlyAssigned?: boolean; + fullObjects?: boolean + }): Promise /** * Retrieve all assignments of a user which are for the target role. @@ -269,6 +291,11 @@ declare namespace Roles { options?: string | { scope?: string; anyScope?: boolean; onlyScoped?: boolean; queryOptions?: QueryOptions }, queryOptions?: QueryOptions ): Mongo.Cursor + function getUsersInRoleAsync( + roles: string | string[], + options?: string | { scope?: string; anyScope?: boolean; onlyScoped?: boolean; queryOptions?: QueryOptions }, + queryOptions?: QueryOptions + ): Promise> /** * Remove users from assigned roles. @@ -292,6 +319,11 @@ declare namespace Roles { roles?: string | string[], options?: string | { scope?: string; anyScope?: boolean } ): void + function removeUsersFromRolesAsync( + users: string | string[] | Meteor.User | Meteor.User[], + roles?: string | string[], + options?: string | { scope?: string; anyScope?: boolean } + ): Promise /** * Set users' roles. @@ -319,6 +351,11 @@ declare namespace Roles { roles: string | string[], options?: string | { scope?: string; anyScope?: boolean; ifExists?: boolean } ): void + function setUserRolesAsync( + users: string | string[] | Meteor.User | Meteor.User[], + roles: string | string[], + options?: string | { scope?: string; anyScope?: boolean; ifExists?: boolean } + ): Promise /** * Check if user has specified roles. @@ -353,13 +390,20 @@ declare namespace Roles { roles: string | string[], options?: string | { scope?: string; anyScope?: boolean } ): boolean + function userIsInRoleAsync( + user: string | string[] | Meteor.User | Meteor.User[], + roles: string | string[], + options?: string | { scope?: string; anyScope?: boolean } + ): Promise + // The schema for the roles collection interface Role { _id: string name: string children: { _id: string }[] } + // The schema for the role-assignment collection interface RoleAssignment { _id: string user: { diff --git a/roles/roles_common_async.js b/roles/roles_common_async.js index 7d3369ca..6ca1a9f6 100644 --- a/roles/roles_common_async.js +++ b/roles/roles_common_async.js @@ -69,7 +69,7 @@ Object.assign(Roles, { /** * Create a new role. * - * @method createRole + * @method createRoleAsync * @param {String} roleName Name of role. * @param {Object} [options] Options: * - `unlessExists`: if `true`, exception will not be thrown in the role already exists @@ -116,7 +116,7 @@ Object.assign(Roles, { * * If the role is set for any user, it is automatically unset. * - * @method deleteRole + * @method deleteRoleAsync * @param {String} roleName Name of role. * @returns {Promise} * @static @@ -180,7 +180,7 @@ Object.assign(Roles, { /** * Rename an existing role. * - * @method renameRole + * @method renameRoleAsync * @param {String} oldName Old name of a role. * @param {String} newName New name of a role. * @returns {Promise} @@ -255,7 +255,7 @@ Object.assign(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 + * @method addRolesToParentAsync * @param {Array|String} rolesNames Name(s) of role(s). * @param {String} parentName Name of parent role. * @returns {Promise} @@ -271,7 +271,7 @@ Object.assign(Roles, { }, /** - * @method _addRoleToParent + * @method _addRoleToParentAsync * @param {String} roleName Name of role. * @param {String} parentName Name of parent role. * @returns {Promise} @@ -340,7 +340,7 @@ Object.assign(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 + * @method removeRolesFromParentAsync * @param {Array|String} rolesNames Name(s) of role(s). * @param {String} parentName Name of parent role. * @returns {Promise} @@ -356,7 +356,7 @@ Object.assign(Roles, { }, /** - * @method _removeRoleFromParent + * @method _removeRoleFromParentAsync * @param {String} roleName Name of role. * @param {String} parentName Name of parent role. * @returns {Promise} @@ -432,12 +432,12 @@ Object.assign(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') + * Roles.addUsersToRolesAsync(userId, 'admin') + * Roles.addUsersToRolesAsync(userId, ['view-secrets'], 'example.com') + * Roles.addUsersToRolesAsync([user1, user2], ['user','editor']) + * Roles.addUsersToRolesAsync([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') * - * @method addUsersToRoles + * @method addUsersToRolesAsync * @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: @@ -488,12 +488,12 @@ Object.assign(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') + * await Roles.setUserRolesAsync(userId, 'admin') + * await Roles.setUserRolesAsync(userId, ['view-secrets'], 'example.com') + * await Roles.setUserRolesAsync([user1, user2], ['user','editor']) + * await Roles.setUserRolesAsync([user1, user2], ['glorious-admin', 'perform-action'], 'example.org') * - * @method setUserRoles + * @method setUserRolesAsync * @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: @@ -713,11 +713,11 @@ Object.assign(Roles, { * Remove users from assigned roles. * * @example - * Roles.removeUsersFromRoles(userId, 'admin') - * Roles.removeUsersFromRoles([userId, user2], ['editor']) - * Roles.removeUsersFromRoles(userId, ['user'], 'group1') + * await Roles.removeUsersFromRolesAsync(userId, 'admin') + * await Roles.removeUsersFromRolesAsync([userId, user2], ['editor']) + * await Roles.removeUsersFromRolesAsync(userId, ['user'], 'group1') * - * @method removeUsersFromRoles + * @method removeUsersFromRolesAsync * @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: @@ -792,17 +792,17 @@ Object.assign(Roles, { * * @example * // global roles - * Roles.userIsInRole(user, 'admin') - * Roles.userIsInRole(user, ['admin','editor']) - * Roles.userIsInRole(userId, 'admin') - * Roles.userIsInRole(userId, ['admin','editor']) + * await Roles.userIsInRoleAsync(user, 'admin') + * await Roles.userIsInRoleAsync(user, ['admin','editor']) + * await Roles.userIsInRoleAsync(userId, 'admin') + * await Roles.userIsInRoleAsync(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'}) + * await Roles.userIsInRoleAsync(user, 'admin', 'group1') + * await Roles.userIsInRoleAsync(userId, ['admin','editor'], 'group1') + * await Roles.userIsInRoleAsync(userId, ['admin','editor'], {scope: 'group1'}) * - * @method userIsInRole + * @method userIsInRoleAsync * @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. @@ -869,7 +869,7 @@ Object.assign(Roles, { /** * Retrieve user's roles. * - * @method getRolesForUser + * @method getRolesForUserAsync * @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 @@ -971,7 +971,7 @@ Object.assign(Roles, { * * Options: * - * @method getUsersInRole + * @method getUsersInRoleAsync * @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. @@ -1095,7 +1095,7 @@ Object.assign(Roles, { /** * Deprecated. Use `getScopesForUser` instead. * - * @method getGroupsForUser + * @method getGroupsForUserAsync * @returns {Promise} * @static * @deprecated @@ -1115,7 +1115,7 @@ Object.assign(Roles, { /** * Retrieve users scopes, if any. * - * @method getScopesForUser + * @method getScopesForUserAsync * @param {String|Object} user User ID or an actual user object. * @param {Array|String} [roles] Name of roles to restrict scopes to. * @@ -1158,7 +1158,7 @@ Object.assign(Roles, { * * Roles assigned with a given scope are changed to be under the new scope. * - * @method renameScope + * @method renameScopeAsync * @param {String} oldName Old name of a scope. * @param {String} newName New name of a scope. * @returns {Promise} @@ -1192,7 +1192,7 @@ Object.assign(Roles, { * * Roles assigned with a given scope are removed. * - * @method removeScope + * @method removeScopeAsync * @param {String} name The name of a scope. * @returns {Promise} * @static @@ -1226,7 +1226,7 @@ Object.assign(Roles, { * * WARNING: If you check this on the client, please make sure all roles are published. * - * @method isParentOf + * @method isParentOfAsync * @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} From b09445bf95a1fbc306ee09c779ef75cd7716cb8e Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Mon, 18 Dec 2023 17:25:35 +0100 Subject: [PATCH 65/66] Update zodern:types and package version --- History.md | 6 ++++++ package.js | 4 ++-- yuidoc.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index 0586e4b9..cac88de0 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,11 @@ # Changelog +## v3.6.1 + +* Added types for async functions [#386](https://github.com/Meteor-Community-Packages/meteor-roles/pull/386) [@storytellercz](https://github.com/sponsors/StorytellerCZ) +* Updated docs with async functions [@storytellercz](https://github.com/sponsors/StorytellerCZ) +* Updated `zodern:types` to v1.0.10 + ## v3.6.0 * Added async versions of functions [#361](https://github.com/Meteor-Community-Packages/meteor-roles/pull/361) [#378](https://github.com/Meteor-Community-Packages/meteor-roles/pull/378) [@bratelefant](https://github.com/bratelefant) [@storytellercz](https://github.com/sponsors/StorytellerCZ) [@jankapunkt](https://github.com/sponsors/jankapunkt) diff --git a/package.js b/package.js index 7f3ad490..da41fa9a 100644 --- a/package.js +++ b/package.js @@ -2,7 +2,7 @@ Package.describe({ summary: 'Authorization package for Meteor', - version: '3.6.0', + version: '3.6.1', git: 'https://github.com/Meteor-Community-Packages/meteor-roles.git', name: 'alanning:roles' }) @@ -20,7 +20,7 @@ Package.onUse(function (api) { 'check' ], both) - api.use('zodern:types@1.0.9') + api.use('zodern:types@1.0.10') api.use(['blaze@2.7.1'], 'client', { weak: true }) diff --git a/yuidoc.json b/yuidoc.json index 18329a2a..de1aa908 100644 --- a/yuidoc.json +++ b/yuidoc.json @@ -1,7 +1,7 @@ { "name": "The meteor-roles API", "description": "The meteor-roles API: an authorization package for Meteor", - "version": "v3.4.0", + "version": "v3.6.0", "options": { "outdir": "./docs", "exclude": ".meteor,.build,tests", From d8c6eb63a5f969cdbeb779dce9578dc05a54ec5b Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Fri, 22 Dec 2023 00:24:11 +0100 Subject: [PATCH 66/66] Update CI & tests deps --- .github/workflows/testsuite.yml | 10 +++++----- testapp/.meteor/packages | 8 ++++---- testapp/.meteor/release | 2 +- testapp/.meteor/versions | 28 ++++++++++++++-------------- testapp/package-lock.json | 18 +++++++++--------- testapp/package.json | 6 +++--- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index ffce9b1b..410363ac 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -12,10 +12,10 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: setup node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 16 @@ -37,14 +37,14 @@ jobs: matrix: meteorRelease: - '2.8.0' - - '2.13.3' + - '2.14' # Latest version steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 16 diff --git a/testapp/.meteor/packages b/testapp/.meteor/packages index 45d8f396..0d165be5 100644 --- a/testapp/.meteor/packages +++ b/testapp/.meteor/packages @@ -4,15 +4,15 @@ # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -meteor@1.11.3 # Shared foundation for all Meteor packages +meteor@1.11.4 # 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 +ecmascript@0.16.8 # Enable ECMAScript2015+ syntax in app code +typescript@4.9.5 # 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 +webapp@1.13.6 # 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/release b/testapp/.meteor/release index 6641d047..c500c39d 100644 --- a/testapp/.meteor/release +++ b/testapp/.meteor/release @@ -1 +1 @@ -METEOR@2.13.3 +METEOR@2.14 diff --git a/testapp/.meteor/versions b/testapp/.meteor/versions index e0abc760..00869796 100644 --- a/testapp/.meteor/versions +++ b/testapp/.meteor/versions @@ -1,9 +1,9 @@ autoupdate@1.8.0 -babel-compiler@7.10.4 +babel-compiler@7.10.5 babel-runtime@1.5.1 base64@1.0.12 blaze-tools@1.1.3 -boilerplate-generator@1.7.1 +boilerplate-generator@1.7.2 caching-compiler@1.2.2 caching-html-compiler@1.2.1 callback-hook@1.5.1 @@ -11,47 +11,47 @@ check@1.3.2 ddp@1.4.1 ddp-client@2.6.1 ddp-common@1.4.0 -ddp-server@2.6.2 +ddp-server@2.7.0 diff-sequence@1.1.2 dynamic-import@0.7.3 -ecmascript@0.16.7 +ecmascript@0.16.8 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 +fetch@0.1.4 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.3 +logging@1.3.3 +meteor@1.11.4 minifier-css@1.6.4 minifier-js@2.7.5 -modern-browsers@0.1.9 -modules@0.19.0 +modern-browsers@0.1.10 +modules@0.20.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 +react-fast-refresh@0.2.8 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 +socket-stream-client@0.5.2 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 +tracker@1.3.3 +typescript@4.9.5 underscore@1.0.13 -webapp@1.13.5 +webapp@1.13.6 webapp-hashing@1.1.1 diff --git a/testapp/package-lock.json b/testapp/package-lock.json index d996f6f6..7cb48d5c 100644 --- a/testapp/package-lock.json +++ b/testapp/package-lock.json @@ -190,9 +190,9 @@ "dev": true }, "@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", "requires": { "regenerator-runtime": "^0.14.0" } @@ -3134,9 +3134,9 @@ "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==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.7.tgz", + "integrity": "sha512-20bAFUhEIOD/Cos2nmvhqf2NOKpTf63WVQ+nwuaX2OFj31sU6GL4KkNylkWum8McwsH0LsMr/F+UHhduTX7KRg==", "requires": { "assert": "^2.0.0", "browserify-zlib": "^0.2.0", @@ -4495,9 +4495,9 @@ } }, "regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "regexp.prototype.flags": { "version": "1.5.0", diff --git a/testapp/package.json b/testapp/package.json index b0227ca5..b1d84ef2 100644 --- a/testapp/package.json +++ b/testapp/package.json @@ -11,9 +11,9 @@ "lint:fix": "standard --fix ../" }, "dependencies": { - "@babel/runtime": "^7.23.2", - "meteor-node-stubs": "^1.2.5", - "yuidocjs": "^0.10.2" + "@babel/runtime": "7.23.6", + "meteor-node-stubs": "1.2.7", + "yuidocjs": "0.10.2" }, "devDependencies": { "babel-plugin-istanbul": "^6.1.1",