diff --git a/meteor-roles/meteor-roles-tests.ts b/meteor-roles/meteor-roles-tests.ts
new file mode 100644
index 0000000000..dae900800c
--- /dev/null
+++ b/meteor-roles/meteor-roles-tests.ts
@@ -0,0 +1,150 @@
+///
+///
+///
+
+/**
+ * All code below was copied from the examples at https://github.com/alanning/meteor-roles/.
+ * When necessary, code was added to make the examples work (e.g. declaring a variable
+ * that was assumed to have been declared earlier)
+ */
+
+var joesUserId = '1234';
+Roles.addUsersToRoles(joesUserId, ['manage-team','schedule-game'], 'manchester-united.com')
+Roles.addUsersToRoles(joesUserId, ['player','goalie'], 'real-madrid.com')
+
+Roles.userIsInRole(joesUserId, 'manage-team', 'manchester-united.com') // => true
+Roles.userIsInRole(joesUserId, 'manage-team', 'real-madrid.com') // => false
+
+Roles.addUsersToRoles(joesUserId, 'super-admin', Roles.GLOBAL_GROUP)
+
+var bobsUserId = '1234';
+Roles.addUsersToRoles(bobsUserId, ['manage-team','schedule-game'])
+// internal representation - no groups
+// user.roles = ['manage-team','schedule-game']
+
+Roles.addUsersToRoles(joesUserId, ['manage-team','schedule-game'], 'manchester-united.com')
+Roles.addUsersToRoles(joesUserId, ['player','goalie'], 'real-madrid.com')
+// internal representation - groups
+// NOTE: MongoDB uses periods to represent hierarchy so periods in group names
+// are converted to underscores.
+//
+// user.roles = {
+// 'manchester-united_com': ['manage-team','schedule-game'],
+// 'real-madrid_com': ['player','goalie']
+// }
+
+Meteor.roles.find({});
+
+
+
+var users = [
+ {name:"Normal User",email:"normal@example.com",roles:[]},
+ {name:"View-Secrets User",email:"view@example.com",roles:['view-secrets']},
+ {name:"Manage-Users User",email:"manage@example.com",roles:['manage-users']},
+ {name:"Admin User",email:"admin@example.com",roles:['admin']}
+];
+
+_.each(users, function (user) {
+ var id : string;
+
+ id = Accounts.createUser({
+ email: user.email,
+ password: "apple1",
+ profile: { name: user.name }
+ });
+
+ if (user.roles.length > 0) {
+ // Need _id of existing user record so this call must come
+ // after `Accounts.createUser` or `Accounts.onCreate`
+ Roles.addUsersToRoles(id, user.roles, 'default-group');
+ }
+
+});
+
+
+
+// server/publish.js
+
+// Give authorized users access to sensitive data by group
+Meteor.publish('secrets', function (group : string) {
+ if (Roles.userIsInRole(this.userId, ['view-secrets','admin'], group)) {
+
+// return Meteor.secrets.find({group: group});
+
+ } else {
+
+ // user not authorized. do not publish secrets
+ this.stop();
+ return;
+
+ }
+});
+
+
+Accounts.validateNewUser(function (user : Meteor.User) {
+ var loggedInUser = Meteor.user();
+
+ if (Roles.userIsInRole(loggedInUser, ['admin','manage-users'])) {
+ // NOTE: This example assumes the user is not using groups.
+ return true;
+ }
+
+ throw new Meteor.Error('403', "Not authorized to create new users");
+});
+
+
+// server/userMethods.js
+
+Meteor.methods({
+ /**
+ * delete a user from a specific group
+ *
+ * @method deleteUser
+ * @param {String} targetUserId _id of user to delete
+ * @param {String} group Company to update permissions for
+ */
+ deleteUser: function (targetUserId : string, group : string) {
+ var loggedInUser = Meteor.user()
+
+ if (!loggedInUser ||
+ !Roles.userIsInRole(loggedInUser,
+ ['manage-users', 'support-staff'], group)) {
+ throw new Meteor.Error('403', "Access denied")
+ }
+
+ // remove permissions for target group
+ Roles.setUserRoles(targetUserId, [], group)
+
+ // do other actions required when a user is removed...
+ }
+})
+
+
+
+// server/userMethods.js
+
+Meteor.methods({
+ /**
+ * update a user's permissions
+ *
+ * @param {Object} targetUserId Id of user to update
+ * @param {Array} roles User's new permissions
+ * @param {String} group Company to update permissions for
+ */
+ updateRoles: function (targetUserId : string, roles : string[], group : string) {
+ var loggedInUser = Meteor.user()
+
+ if (!loggedInUser ||
+ !Roles.userIsInRole(loggedInUser,
+ ['manage-users', 'support-staff'], group)) {
+ throw new Meteor.Error('403', "Access denied")
+ }
+
+ Roles.setUserRoles(targetUserId, roles, group)
+ }
+})
+
+
+
+
+
diff --git a/meteor-roles/meteor-roles.d.ts b/meteor-roles/meteor-roles.d.ts
new file mode 100644
index 0000000000..95e4223ac1
--- /dev/null
+++ b/meteor-roles/meteor-roles.d.ts
@@ -0,0 +1,264 @@
+///
+
+// Type definitions for Meteor Roles 1.2.14
+// Project: https://github.com/alanning/meteor-roles/
+// Definitions by: Robbie Van Gorkom
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+/**
+ * Provides functions related to user authorization. Compatible with built-in Meteor accounts packages.
+ *
+ * @module Roles
+ */
+declare module Roles {
+ /**
+ * Constant used to reference the special 'global' group that
+ * can be used to apply blanket permissions across all groups.
+ *
+ * @example
+ * Roles.addUsersToRoles(user, 'admin', Roles.GLOBAL_GROUP)
+ * Roles.userIsInRole(user, 'admin') // => true
+ *
+ * Roles.setUserRoles(user, 'support-staff', Roles.GLOBAL_GROUP)
+ * Roles.userIsInRole(user, 'support-staff') // => true
+ * Roles.userIsInRole(user, 'admin') // => false
+ *
+ * @property GLOBAL_GROUP
+ * @type String
+ * @static
+ * @final
+ */
+ var GLOBAL_GROUP : string;
+
+ /**
+ * Subscription handle for the currently logged in user's permissions.
+ *
+ * NOTE: The corresponding publish function, `_roles`, depends on
+ * `this.userId` so it will automatically re-run when the currently
+ * logged-in user changes.
+ *
+ * @example
+ *
+ * `Roles.subscription.ready()` // => `true` if user roles have been loaded
+ *
+ * @property subscription
+ * @type Object
+ * @for Roles
+ */
+ var subscription : Subscription;
+
+ /**
+ * Add users to roles. Will create roles as needed.
+ *
+ * NOTE: Mixing grouped and non-grouped roles for the same user
+ * is not supported and will throw an error.
+ *
+ * Makes 2 calls to database:
+ * 1. retrieve list of all existing roles
+ * 2. update users' roles
+ *
+ * @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.addUsersToRoles(userId, 'admin', Roles.GLOBAL_GROUP)
+ *
+ * @method addUsersToRoles
+ * @param {Array|String} users User id(s) or object(s) with an _id field
+ * @param {Array|String} roles Name(s) of roles/permissions to add users to
+ * @param {String} [group] Optional group name. If supplied, roles will be
+ * specific to that group.
+ * Group names can not start with '$' or numbers.
+ * Periods in names '.' are automatically converted
+ * to underscores.
+ * The special group Roles.GLOBAL_GROUP provides
+ * a convenient way to assign blanket roles/permissions
+ * across all groups. The roles/permissions in the
+ * Roles.GLOBAL_GROUP group will be automatically
+ * included in checks for any group.
+ */
+ function addUsersToRoles(
+ user : string|string[]|Object|Object[],
+ roles : string|string[],
+ group? : string
+ ) : void;
+
+ /**
+ * Create a new role. Whitespace will be trimmed.
+ *
+ * @method createRole
+ * @param {String} role Name of role
+ * @return {String} id of new role
+ */
+ function createRole(role : string) : string;
+
+ /**
+ * Delete an existing role. Will throw "Role in use" error if any users
+ * are currently assigned to the target role.
+ *
+ * @method deleteRole
+ * @param {String} role Name of role
+ */
+ function deleteRole (role : string) : void;
+
+ /**
+ * Retrieve set of all existing roles
+ *
+ * @method getAllRoles
+ * @return {Cursor} cursor of existing roles
+ */
+ function getAllRoles() : Mongo.Cursor;
+
+ /**
+ * Retrieve users groups, if any
+ *
+ * @method getGroupsForUser
+ * @param {String|Object} user User Id or actual user object
+ * @param {String} [role] Optional name of roles to restrict groups to.
+ *
+ * @return {Array} Array of user's groups, unsorted. Roles.GLOBAL_GROUP will be omitted
+ */
+ function getGroupsForUser(
+ user : string|Object,
+ role? : string
+ ) : string[];
+
+ /**
+ * Retrieve users roles
+ *
+ * @method getRolesForUser
+ * @param {String|Object} user User Id or actual user object
+ * @param {String} [group] Optional name of group to restrict roles to.
+ * User's Roles.GLOBAL_GROUP will also be included.
+ * @return {Array} Array of user's roles, unsorted.
+ */
+ function getRolesForUser(
+ user : string|Object,
+ group? : string
+ ) : Role[];
+
+ /**
+ * Retrieve all users who are in target role.
+ *
+ * NOTE: This is an expensive query; it performs a full collection scan
+ * on the users collection since there is no index set on the 'roles' field.
+ * This is by design as most queries will specify an _id so the _id index is
+ * used automatically.
+ *
+ * @method getUsersInRole
+ * @param {Array|String} role Name of role/permission. If array, users
+ * returned will have at least one of the roles
+ * specified but need not have _all_ roles.
+ * @param {String} [group] Optional name of group to restrict roles to.
+ * User's Roles.GLOBAL_GROUP will also be checked.
+ * @param {Object} [options] Optional options which are passed directly
+ * through to `Meteor.users.find(query, options)`
+ * @return {Cursor} cursor of users in role
+ */
+ function getUsersInRole(
+ role : string|string[],
+ group? : string,
+ options? : {
+ sort?: Mongo.SortSpecifier;
+ skip?: number;
+ limit?: number;
+ fields?: Mongo.FieldSpecifier;
+ reactive?: boolean;
+ transform?: Function;
+ }) : Mongo.Cursor;
+
+ /**
+ * Remove users from roles
+ *
+ * @example
+ * Roles.removeUsersFromRoles(users.bob, 'admin')
+ * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor'])
+ * Roles.removeUsersFromRoles([users.bob, users.joe], ['editor', 'user'])
+ * Roles.removeUsersFromRoles(users.eve, ['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 add users to
+ * @param {String} [group] Optional. Group name. If supplied, only that
+ * group will have roles removed.
+ */
+ function removeUsersFromRoles(
+ user : string|string[]|Object|Object[],
+ roles? : string[],
+ group? : string
+ ) : void;
+
+ /**
+ * Set a users roles/permissions.
+ *
+ * @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')
+ * Roles.setUserRoles(userId, 'admin', Roles.GLOBAL_GROUP)
+ *
+ * @method setUserRoles
+ * @param {Array|String} users User id(s) or object(s) with an _id field
+ * @param {Array|String} roles Name(s) of roles/permissions to add users to
+ * @param {String} [group] Optional group name. If supplied, roles will be
+ * specific to that group.
+ * Group names can not start with '$'.
+ * Periods in names '.' are automatically converted
+ * to underscores.
+ * The special group Roles.GLOBAL_GROUP provides
+ * a convenient way to assign blanket roles/permissions
+ * across all groups. The roles/permissions in the
+ * Roles.GLOBAL_GROUP group will be automatically
+ * included in checks for any group.
+ */
+ function setUserRoles (
+ user : string|string[]|Object|Object[],
+ roles : string|string[],
+ group? : string
+ ) : void;
+
+ /**
+ * Check if user has specified permissions/roles
+ *
+ * @example
+ * // non-group usage
+ * Roles.userIsInRole(user, 'admin')
+ * Roles.userIsInRole(user, ['admin','editor'])
+ * Roles.userIsInRole(userId, 'admin')
+ * Roles.userIsInRole(userId, ['admin','editor'])
+ *
+ * // per-group usage
+ * Roles.userIsInRole(user, ['admin','editor'], 'group1')
+ * Roles.userIsInRole(userId, ['admin','editor'], 'group1')
+ * Roles.userIsInRole(userId, ['admin','editor'], Roles.GLOBAL_GROUP)
+ *
+ * // this format can also be used as short-hand for Roles.GLOBAL_GROUP
+ * Roles.userIsInRole(user, 'admin')
+ *
+ * @method userIsInRole
+ * @param {String|Object} user User Id or actual user object
+ * @param {String|Array} roles Name of role/permission or Array of
+ * roles/permissions to check against. If array,
+ * will return true if user is in _any_ role.
+ * @param {String} [group] Optional. Name of group. If supplied, limits check
+ * to just that group.
+ * The user's Roles.GLOBAL_GROUP will always be checked
+ * whether group is specified or not.
+ * @return {Boolean} true if user is in _any_ of the target roles
+ */
+ function userIsInRole(
+ user : string|string[]|Object|Object[],
+ roles : string|string[],
+ group? : string
+ ) : boolean;
+
+ interface Role {
+ name : string;
+ }
+} // module
+
+declare module Meteor {
+ var roles : Mongo.Collection;
+}