@smartsoft001/auth-shell-dtos
One class, two required fields: the credentials model the auth family renders as a login form.
Install
npm install @smartsoft001/auth-shell-dtos @smartsoft001/models reflect-metadata
The manifest declares @smartsoft001/models as a peer dependency, and reflect-metadata has to be installed alongside it as well. LoginDto carries @Model and @Field from the models package, and those decorators write their metadata through reflect-metadata. There is no NestJS dependency, no database and no HTTP client here.
What it is
The package exports a single class and nothing else. LoginDto is a @Model({}) with username and password, both marked @Field({ required: true }), and username additionally marked focused: true.
It is not a validation schema in the class-validator sense, and no ValidationPipe is involved anywhere in this family. What the decorators buy is metadata that the framework reads at runtime: a form can be generated from the class, the still-empty required fields can be reported before anything is sent, and the object can be trimmed to the fields a given operation may touch. focused: true tells a generated form which control takes the cursor.
Nothing inside the workspace imports it. The token endpoint in @smartsoft001/auth-shell-nestjs takes an IAuthTokenRequest, not a LoginDto, so this class exists for the client side of the exchange: the screen that collects the two values before they become a password grant.
Usage
import { ItemChangedData, UserDto } from '@smartsoft001/crud-shell-dtos';
import { getInvalidFields } from '@smartsoft001/models';
/**
* `UserDto` marks `username` and `password` as required, so the same metadata
* check the CRUD service runs before an insert can be reused on the caller
* side. It is the `@smartsoft001/models` metadata API, not class-validator.
*/
export function missingCredentials(dto: UserDto): string[] {
return getInvalidFields(dto, 'create', []);
}
/**
* Turns one entry of the change feed returned by `CrudService.changes(...)`
* into a log line. The feed is a discriminated union, so the `type` field
* narrows the payload: only an update carries `removedFields` and
* `updatedFields`.
*/
export function toChangeMessage(change: ItemChangedData): string {
switch (change.type) {
case 'create':
return `${change.id} created`;
case 'update': {
const changed = Object.keys(change.data.updatedFields).length;
const removed = change.data.removedFields.length;
return `${change.id} updated: ${changed} changed, ${removed} removed`;
}
case 'delete':
return `${change.id} deleted`;
default:
return 'unknown change';
}
}
The example is the shared one, written against UserDto from @smartsoft001/crud-shell-dtos, and it applies to LoginDto unchanged. The two classes are identical field for field: the same two string properties, the same required: true on both, the same focused: true on username. Swap the import and the type annotation and every line behaves the same way.
The half that matters here is missingCredentials. It runs getInvalidFields(dto, 'create', []) over the model and gets back the names of the required fields that are still empty, in declaration order, which is the same check the server runs before it accepts a record. Doing it on the caller's side is how a login form refuses to submit an incomplete pair. The spec proves both ends of it: an empty instance reports ['username', 'password'], and a filled one reports nothing.
The rest of the region, toChangeMessage and the change-feed union it switches on, belongs to the CRUD package and has no counterpart here. This package has no feed and no interfaces, only the model.
API
LoginDto
A @Model({}) class with two string properties.
| Field | Decorator | What it means |
|---|---|---|
username | @Field({ required: true, focused: true }) | Mandatory in every mode. focused marks it as the control a generated form focuses first. |
password | @Field({ required: true }) | Mandatory in every mode. A property named password defaults to FieldType.password, so no explicit type is needed. |
That is the entire public surface. The barrel re-exports ./lib/login.dto and nothing more: no provider array, no interfaces, no constants.
Related packages
@smartsoft001/modelssupplies the two decorators and the metadata readers the example calls.@smartsoft001/crud-shell-dtosexportsUserDto, the identical model the shared example is written against.@smartsoft001/auth-domaindefinesIAuthTokenRequestPassword, the shape these two fields become on the wire.@smartsoft001/auth-shell-nestjsis the endpoint that receives them.