spaps-types
v1.1.3
Published
Shared TypeScript types for SPAPS ecosystem
Maintainers
Readme
spaps-types
Shared TypeScript types, runtime guards, and schema helpers for SPAPS packages.
Examples in this README use placeholders such as [email protected]. Replace them with values from your own application data where needed.
Install
npm install spaps-typesAlternative package managers:
pnpm add spaps-types
yarn add spaps-typesWhen It Fits
| Need | Package gives you |
| --- | --- |
| One source of truth for app contracts | Shared auth, payment, entitlement, issue-reporting, and user shapes |
| Lightweight runtime checks | Guards for roles, permissions, severities, and chain types |
| Structured validation | Zod-backed secure-message schema helpers |
| Docs tooling contracts | Types for docs/manifest.json style metadata |
Quick Example
import type { ApiResponse, User } from "spaps-types";
import { isAdminRole, isValidPermission } from "spaps-types";
const user: User = {
id: "123",
email: "[email protected]",
role: "user",
};
const response: ApiResponse<User> = {
success: true,
data: user,
};
console.log(response.data?.email);
console.log(isAdminRole("admin"));
console.log(isValidPermission("manage_products"));Schema Helpers
import { z } from "zod";
import {
createSecureMessageRequestSchema,
secureMessageSchema,
} from "spaps-types";
const metadataSchema = z.object({
urgency: z.enum(["low", "high"]),
tags: z.array(z.string()).optional(),
});
const requestSchema = createSecureMessageRequestSchema(metadataSchema);
const messageSchema = secureMessageSchema(metadataSchema);
requestSchema.parse({
patientId: "3d6f0a51-8d77-4b38-8248-2d1b2f1f6c7f",
practitionerId: "a3d7f431-6c9d-4cbc-9f78-4e5b6a7c8d9e",
content: "Hello",
metadata: { urgency: "low" },
});
messageSchema.parse({
id: "msg-123",
application_id: "app-456",
patient_id: "3d6f0a51-8d77-4b38-8248-2d1b2f1f6c7f",
practitioner_id: "a3d7f431-6c9d-4cbc-9f78-4e5b6a7c8d9e",
content: "Hello",
metadata: { urgency: "high" },
created_at: new Date().toISOString(),
});Export Groups
| Group | Examples |
| --- | --- |
| Core models | Application, User, UserProfile, UserWallet |
| Auth and sessions | TokenPayload, RefreshTokenPayload, TokenPair, AuthResponse |
| Payments | CheckoutSession, Subscription, Product, Price, UsageBalance |
| Entitlements | Entitlement, ResourceType |
| Issue reporting | IssueReport, IssueReportTarget, IssueReportListResult |
| Secure messages | SecureMessage, CreateSecureMessageRequest, schema helpers |
| Docs tooling | DocsManifest, DocsManifestEndpoint, related manifest types |
Runtime Guards
Common helpers include:
isAdminRoleisValidPermissionisValidSeverityisValidAlertSeverityisValidChainType
Validation
cd packages/types
npm run build
npm run typecheck
npm run test:typesTroubleshooting
Types are drifting between packages
Move the shared shape into spaps-types instead of copying it into each package.
I need runtime validation, not just TypeScript
Use the exported guards and Zod schema helpers.
tsd fails after I change exports
Re-run npm run test:types and update the assertions in test/ alongside the public API.
Limitations
- This package is a contract layer, not a full validation framework for every endpoint.
- Some server-only types still live in
src/server.ts. - Downstream packages still decide how strict they want runtime validation to be.
FAQ
Is this useful from plain JavaScript?
Yes, especially for the runtime guards and schema helpers, though most value comes from the shared TypeScript surface.
Does it include Express request extensions?
Yes. Server-specific request extension types live in src/server.ts.
Does it depend on Zod?
Yes. The secure-message schema helpers use Zod.
Should apps duplicate these shapes locally?
No. Prefer importing them from spaps-types.
How do I verify exported type behavior?
Run npm run test:types.
About Contributions
About Contributions: Please don't take this the wrong way, but I do not accept outside contributions for any of my projects. I simply don't have the mental bandwidth to review anything, and it's my name on the thing, so I'm responsible for any problems it causes; thus, the risk-reward is highly asymmetric from my perspective. I'd also have to worry about other "stakeholders," which seems unwise for tools I mostly make for myself for free. Feel free to submit issues, and even PRs if you want to illustrate a proposed fix, but know I won't merge them directly. Instead, I'll have Claude or Codex review submissions via
ghand independently decide whether and how to address them. Bug reports in particular are welcome. Sorry if this offends, but I want to avoid wasted time and hurt feelings. I understand this isn't in sync with the prevailing open-source ethos that seeks community contributions, but it's the only way I can move at this velocity and keep my sanity.
License
UNLICENSED
