@smartsoft001/users

Two interfaces that describe who is acting, shared by the authentication, repository and CRUD packages so they all mean the same thing by "user".


Install

npm install @smartsoft001/users

What it is

The packages in this workspace pass a user around constantly: repositories stamp it onto the records they write, the permission service reads its roles, and the JWT strategy produces it from a token. If each of them declared its own shape, none of them could be combined without an adapter, so the shape lives here instead, in a package that depends on nothing.

There is no runtime code at all. IUser and IUserCredentials are interfaces, erased when TypeScript compiles, so the dependency exists at build time and disappears from the bundle. That also means there is nothing here to test in the usual sense: what the example below checks is that the declarations resolve and that a value written against them typechecks.

Usage

import { IUser, IUserCredentials } from '@smartsoft001/users';

/**
 * The identity contract shared by auth, repositories and CRUD.
 * `permissions` holds the role names that PermissionService matches against
 * the lists configured on SharedModule, and `scope` separates tenants.
 */
export const adminUser: IUser = {
  username: 'admin@example.com',
  permissions: ['admin', 'user'],
  scope: 'my-app',
};

/** The payload sent to the token endpoint. */
export const credentials: IUserCredentials = {
  username: adminUser.username,
  password: 'change-me',
};

The fixture is the whole surface. adminUser is what a request handler receives once a token has been validated, and credentials is what a client posts to obtain that token in the first place.

Its spec asserts the permission names, the scope and that the credentials sign in under the same username, and it declares both fixtures against the interfaces a second time inside the test. Those assertions are cheap on purpose. The proof they carry is the compilation itself: the example imports from @smartsoft001/users through the published entry point, so if the interfaces were renamed, dropped from the package index or given different members, the example would stop building before any assertion ran.

API

IUser

The identity every other package accepts.

PropertyTypeRequiredWhat it holds
usernamestringyesThe identifier the user signs in with. The JWT strategy fills it from the sub claim of the token.
permissionsArray<string>yesThe role names this user holds. PermissionService matches them against the lists configured on SharedModule.
scopestringnoAn optional tenant or application scope, used to keep the records of separate deployments apart when they share one database.

IUserCredentials

The sign-in payload, and nothing more. It has no relation to IUser in the type system, so a credentials object is never accidentally accepted where an identity is expected.

PropertyTypeRequiredWhat it holds
usernamestringyesThe same identifier that ends up on IUser.username.
passwordstringyesThe plain password, sent once to exchange it for a token.

Where the interfaces are consumed

ConsumerHow it uses IUser
PermissionService.valid(type, user)Reads permissions and throws when none of them appears in the list configured for that operation.
@User() param decoratorReturns the user the JWT strategy attached to the request, typed as IUser by the handler that declares it.
IItemRepository write methodsTake the acting user so the implementation can record who created or changed a record.