npm package: @strong-together/shared
Description: Shared TypeScript library for the Strong Together ecosystem.
Latest version: 1.0.6

# @strong-together/shared (v1.0.6)

Shared TypeScript library for the Strong Together ecosystem.

It centralizes:

- `zod` request/response schemas
- API contract types inferred from schemas
- DTOs and entity interfaces
- barrel exports for all modules

## Modules

The library currently exports these module groups from [`src/index.ts`](./src/index.ts):

- `aerobics`
- `analytics`
- `auth`
- `bootstrap`
- `exercises`
- `messages`
- `oauth`
- `push`
- `user`
- `video-analysis`
- `web-sockets`
- `workout`

## Structure

Most modules follow this shape:

```text
src/modules/<module>
├─ index.ts
├─ <module>.schemas.ts
├─ <module>.contracts.ts
├─ <module>.dtos.ts
└─ <module>.entities.ts
```

Nested modules also expose submodule barrels:

```text
src/modules/<module>/<submodule>
├─ index.ts
├─ <submodule>.schemas.ts
├─ <submodule>.contracts.ts
├─ <submodule>.dtos.ts
└─ <submodule>.entities.ts
```

## Install

```bash
npm install @strong-together/shared
```

## Build

```bash
npm run build
```

Build output is generated into `dist/`:

- `dist/index.js`
- `dist/index.mjs`
- `dist/index.d.ts`
- `dist/index.d.mts`

## Development

```bash
npm run dev
```

## Usage

Import from the package root:

```ts
import { loginRequest, type LoginRequestBody, updateUserRequest, type UpdateUserBody } from '@strong-together/shared';
```

Validate runtime payloads with `zod` schemas:

```ts
const parsed = loginRequest.parse({
  body: {
    identifier: 'demo@example.com',
    password: 'secret123',
  },
});
```

Use inferred contracts for compile-time safety:

```ts
const payload: UpdateUserBody = {
  username: 'new_username',
};
```

## Type System

This library separates its exported TypeScript shapes into a few clear layers.

The core design principle is:

- define runtime schemas first with `zod`
- infer contract types from those schemas
- compose DTOs and entities around those inferred contracts

### `schemas`

`*.schemas.ts` files contain runtime validators built with `zod`.

Use schemas when you need to:

- validate incoming HTTP request payloads
- validate service responses
- infer TypeScript types from a single runtime source of truth

Typical examples:

- `loginRequest`
- `updateUserRequest`
- `bootstrapResponseSchema`
- `exerciseTrackingAndStatsSchema`

Example:

```ts
import { loginRequest } from '@strong-together/shared';

type LoginBody = typeof loginRequest.shape.body;
```

### Zod-First Contracts

This package follows a `zod-first` approach.

That means the schema is the primary source of truth, and the TypeScript contract is derived from it instead of being written separately by hand.

Typical flow:

```ts
export const updateUserRequest = z.object({
  body: z.object({
    username: z.string().optional(),
  }),
});

export type UpdateUserBody = z.infer<typeof updateUserRequest.shape.body>;
```

Why this matters:

- runtime validation and TypeScript types stay aligned
- changing a schema automatically updates the inferred contract
- there is less duplication between validation logic and type declarations
- request and response types are safer at API boundaries

In this library, the usual pattern is:

1. define a `zod` schema in `*.schemas.ts`
2. infer request or response types in `*.contracts.ts`
3. compose richer internal structures in `*.dtos.ts`
4. reuse domain fields from `*.entities.ts`

Common examples:

```ts
export type LoginRequestBody = z.infer<typeof loginRequest.shape.body>;
export type GetWholeUserWorkoutPlanResponse = z.infer<typeof getWholeUserWorkoutPlanResponseSchema>;
export type GenerateTicketResponse = z.infer<typeof generateTicketResponseSchema>;
```

Use `contracts` when you want the typed shape of an API boundary.

Use `schemas` when you need to parse or validate data at runtime.

### `contracts`

`*.contracts.ts` files expose public request and response types, usually via `z.infer<typeof ...>`.

These are the types you will usually import in controllers, clients, SDK adapters, and service boundaries when you want compile-time safety without re-declaring the shape.

Typical contract naming patterns:

- `SomethingBody`
- `SomethingQuery`
- `SomethingParams`
- `SomethingResponse`

Examples from the library:

- `LoginRequestBody`
- `LoginResponse`
- `UpdateUserBody`
- `GetWholeUserWorkoutPlanResponse`
- `GenerateTicketResponse`

Example:

```ts
import { type LoginRequestBody, type LoginResponse } from '@strong-together/shared';

async function login(body: LoginRequestBody): Promise<LoginResponse> {
  // implementation
}
```

### `dtos`

`*.dtos.ts` files describe transport or application-level shapes that are useful inside the codebase but are not always direct API contracts.

DTOs usually model:

- transformed query results
- service payloads
- nested response structures
- message queue payloads
- helper objects shared across modules

Examples:

- `WorkoutSplitsMap`
- `ExerciseTrackingAndStats`
- `AnalyzeVideoPayload`
- `MessageAfterSendResponse`

DTOs are especially useful when:

- database rows do not match the final shape you want to expose
- one feature composes data from multiple entities
- internal service flows need typed payloads not directly tied to one endpoint

### `entities`

`*.entities.ts` files represent core domain or persistence-level records.

These usually map closely to database tables or canonical stored models.

Examples:

- `UserEntity`
- `ExerciseEntity`
- `WorkoutPlanEntity`
- `MessageEntity`
- `ExerciseTrackingEntity`

Entities are often used as the building blocks for DTOs and contracts through `Pick`, `Omit`, intersections, and nested composition.

Example:

```ts
type PublicUserPreview = Pick<UserEntity, 'id' | 'username' | 'name'>;
```

## Common Type Patterns

The library uses a few recurring patterns worth knowing.

### Infer request and response types from schemas

```ts
export type UpdateUserBody = z.infer<typeof updateUserRequest.shape.body>;
export type LoginResponse = z.infer<typeof loginResponseSchema>;
```

This keeps runtime validation and compile-time typing aligned.

### Build DTOs from entities

```ts
export type DeletedMessage = Pick<MessageEntity, 'id'>;
```

This avoids duplicating primitive field definitions and keeps model changes centralized.

### Compose nested feature shapes

```ts
export interface ExerciseTrackingAndStats {
  exerciseTrackingAnalysis: ExerciseTrackingAnalysis;
  exerciseTrackingMaps: {
    byDate: Record<string, Array<Omit<TrackingMapItem, 'workoutdate'>>>;
  };
}
```

This pattern is used in feature-heavy modules like `workout`, `analytics`, and `messages`.

## Exported Type Reference

Below is a practical reference of the main exported types and what they represent.

### `aerobics`

- `AddUserAerobicsBody`
  Request body for adding aerobic records.
- `GetUserAerobicsQuery`
  Query parameters for fetching aerobics data.
- `UserAerobicsResponse`
  Full API response for user aerobics history/statistics.
- `AddAerobicInput`
  Single aerobic record payload extracted from the request body.
- `AerobicsDailyRecord`
  Normalized daily aerobics entry.
- `AerobicsWeeklyRecord`
  Weekly aggregation shape for aerobics data.
- `WeeklyData`
  Wrapper shape for grouped weekly output.
- `AerobicEntity`
  Canonical persistence/domain representation of an aerobic record.

### `analytics`

- `GetAnalyticsResponse`
  Public analytics response contract.
- `WorkoutRMRecord`
  Per-exercise record describing best lifts or RM-related metrics.
- `WorkoutRMsResponse`
  Map of workout RM records keyed by exercise identifier.
- `AdherenceExerciseStats`
  Per-exercise adherence statistics.
- `GoalAdherenceResponse`
  Aggregated adherence result keyed by exercise or grouping field.

### `auth`

#### `auth` root

- `UserByIndetifier`
  User lookup result for login and identity checks.

#### `auth/password`

- `SendChangePassEmailBody`
  Request body for sending a password reset/change email.
- `ResetPasswordBody`
  Request body for submitting a new password.
- `ResetPasswordQuery`
  Query params used when validating a reset flow.
- `ResetPasswordResponse`
  Response returned after a password reset action.
- `ForgotPasswordPayload`
  Internal token/email payload used in the forgot-password flow.

#### `auth/session`

- `LoginRequestBody`
  Login request payload.
- `LoginResponse`
  Login success response including auth tokens and user metadata.
- `RefreshTokenResponse`
  Response returned when refreshing an authenticated session.
- `LogOutResponse`
  Response returned after logout completes successfully.
- `AccessTokenPayload`
  JWT payload stored in access tokens.
- `UserAfterBump`
  User shape after token-version or auth-state refresh logic.
- `TokenVersionResult`
  Result used when comparing or bumping token versions.

#### `auth/verification`

- `VerifyUserAccountQuery`
  Query params for account verification callbacks.
- `SendVerifcationMailBody`
  Request body for sending verification email.
- `ChangeEmailAndVerifyBody`
  Request body for email change plus verification.
- `CheckUserVerifyQuery`
  Query params used to check verification state.
- `EmailVerifyPayload`
  Internal payload carried in verification tokens.

### `bootstrap`

- `BootstrapRequestQuery`
  Query params for the bootstrap endpoint.
- `BootstrapResponse`
  Aggregated startup payload combining user, workout, tracking, messages, and aerobics data.

### `exercises`

- `GetAllExercisesResponse`
  Public response contract for the exercise catalog.
- `GetAllExercisesExercise`
  Single exercise item in the catalog response.
- `ExercisesMapByMuscle`
  Exercise collection grouped by target muscle.
- `QueryGetExerciseMapByMuscleRow`
  Query/result row shape used to build grouped exercise maps.
- `ExerciseEntity`
  Canonical exercise record.

### `messages`

- `GetAllUserMessagesQuery`
  Query params for listing user messages.
- `GetAllUserMessagesResponse`
  Full response for all user messages.
- `MarkMessageAsReadParams`
  Route params for marking a message as read.
- `MarkMessageAsReadResponse`
  Response after marking a message as read.
- `DeleteMessageParams`
  Route params for deleting a message.
- `DeleteMessageResponse`
  Response after deleting a message.
- `AllUserMessages`
  DTO representing a message item in user-facing listings.
- `MessageAfterSendResponse`
  Internal or service-layer message shape after send.
- `MessageAsRead`
  Minimal updated shape for read-state mutations.
- `DeletedMessage`
  Minimal response shape for delete mutations.
- `MessageEntity`
  Canonical stored message record.

### `oauth`

- `OAuthLoginResponse`
  Shared response for OAuth login flows.

#### `oauth/apple`

- `AppleOAuthBody`
  Request body for Apple sign-in.
- `AppleTokenVerificationResult`
  Result of Apple token validation.

#### `oauth/google`

- `GoogleOAuthBody`
  Request body for Google sign-in.
- `GoogleTokenVerificationResult`
  Result of Google token validation.

### `user`

#### `user` root

- `UserEntity`
  Canonical stored user record.

#### `user/create`

- `CreateUserBody`
  Request body for creating a user.
- `CreateUserResponse`
  Response returned after successful user creation.

#### `user/push-tokens`

- `SaveUserPushTokenBody`
  Request body for storing or updating a user push token.

#### `user/update`

- `UpdateUserBody`
  Partial update payload for editable user profile fields.
- `UpdateAuthenticatedUserResponse`
  Response returned after updating the authenticated user.
- `UserDataResponse`
  Response wrapper containing user data.
- `GetAuthenticatedUserByIdResponse`
  Direct user lookup response for an authenticated user.
- `DeleteUserProfilePicBody`
  Request body for removing a profile image.
- `SetProfilePicAndUpdateDBResponse`
  Response after setting profile picture storage path and database state.
- `ChangeEmailTokenPayload`
  Internal token payload for secure email-change flows.
- `AuthenticatedUserForUpdate`
  Derived update-safe user payload type.

### `video-analysis`

- `GetPresignedUrlFromS3Body`
  Request body for generating an upload URL.
- `GetPresignedUrlFromS3Response`
  Response containing the generated S3 presigned URL details.
- `EnqueueAanalyzeVideoParams`
  Queue/job parameters used when scheduling analysis.
- `AnalyzeVideoPayload`
  Worker/job payload for video analysis execution.
- `SquatRepetition`
  Single detected squat repetition shape.
- `AnalyzeVideoResultPayload<T>`
  Generic wrapper for analysis results returned by the processor.

### `web-sockets`

- `GenerateTicketBody`
  Request body for creating a websocket/session ticket.
- `GenerateTicketResponse`
  Response returned after generating a websocket ticket.

### `workout`

#### `workout/plan`

- `GetWholeUserWorkoutPlanQuery`
  Query params for fetching a user's full workout plan.
- `GetWholeUserWorkoutPlanResponse`
  Full workout-plan response contract.
- `AddWorkoutBody`
  Request payload for creating or replacing workout plan data.
- `AddWorkoutResponse`
  Response after workout-plan creation/update.
- `ExerciseInPlan`
  DTO describing an exercise nested inside a workout plan.
- `ExerciseMetadata`
  Small shared exercise metadata subset used in plan composition.
- `WholeUserWorkoutPlan`
  DTO representing the complete nested workout plan structure.
- `AddWorkoutSplitPayload`
  Input shape grouped by split for creating workout splits.
- `WorkoutSplitsMap`
  Normalized map of split names to exercises.
- `WorkoutPlanEntity`
  Canonical workout plan record.
- `WorkoutSplitEntity`
  Canonical workout split record.
- `ExerciseToWorkoutSplitEntity`
  Join entity connecting exercises to workout splits.

#### `workout/tracking`

- `GetExerciseTrackingQuery`
  Query params for fetching exercise tracking/statistics.
- `GetExerciseTrackingResponse`
  Response contract for workout tracking data.
- `FinishUserWorkoutBody`
  Request body sent when finishing a workout.
- `FinishUserWorkoutResponse`
  Response returned after completing a workout.
- `ExerciseTrackingAnalysis`
  Aggregated analysis of exercise history and PR-related stats.
- `TrackingMapItem`
  Normalized single tracking row with joined workout and exercise metadata.
- `ExerciseTrackingAndStats`
  Main DTO returned by tracking flows, combining analysis and grouped maps.
- `FinishedWorkoutEntry`
  Single finished exercise entry submitted at workout completion.
- `ExerciseTrackingEntity`
  Canonical stored exercise-tracking record.
- `WorkoutSummaryEntity`
  Canonical workout summary/session record.

## How To Choose What To Import

- Import a `schema` when you need runtime validation.
- Import a `contract` when you need a public request or response type.
- Import a `dto` when you need a composed internal data shape.
- Import an `entity` when you need a canonical domain record or want to derive another type from it.

As a rule of thumb:

- API boundary: prefer `schemas` and `contracts`
- business logic: prefer `dtos`
- storage/domain modeling: prefer `entities`

## Example Workflow

A typical endpoint flow can look like this:

1. Validate the incoming payload with a schema such as `updateUserRequest`.
2. Use the inferred contract type such as `UpdateUserBody` in the controller/service signature.
3. Read or write persistence data using entity types such as `UserEntity`.
4. Transform data into a DTO or response contract such as `UserDataResponse`.

That gives you:

- runtime validation
- strongly typed controller and service interfaces
- reusable shared domain shapes
- minimal duplication between validation and typing

## Design Notes

- `*.schemas.ts` contains runtime validation schemas.
- `*.contracts.ts` contains exported request/response types, usually inferred from schemas.
- `*.dtos.ts` contains internal transport or service-layer shapes.
- `*.entities.ts` contains entity-style interfaces representing stored/domain objects.
- Each module and submodule exposes an `index.ts` barrel for simple imports.

## Scripts

```json
{
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
  "dev": "tsup src/index.ts --format cjs,esm --watch --dts"
}
```

## Requirements

- Node.js
- npm

## Notes

- The package depends on [`zod`](https://github.com/colinhacks/zod).
- The project is compiled with TypeScript and bundled with `tsup`.