
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@outfitter/contracts
Advanced tools
Core contracts for building type-safe applications, including Result, AppError, and domain types.
Core contracts for building type-safe applications, including Result, AppError, and domain types.
npm install @outfitter/contracts
# or
pnpm add @outfitter/contracts
This package provides essential TypeScript utilities that form the foundation of type-safe development:
Handle errors explicitly without throwing exceptions:
import {
Result,
success,
failure,
isSuccess,
isFailure,
} from '@outfitter/contracts';
function divide(a: number, b: number): Result<number, AppError> {
if (b === 0) {
return failure(makeError('VALIDATION_ERROR', 'Division by zero'));
}
return success(a / b);
}
// Usage
const result = divide(10, 2);
if (isSuccess(result)) {
console.log(result.data); // 5
} else {
console.error(result.error.message);
}
Structured errors with rich context:
import { makeError, AppError } from '@outfitter/contracts';
const error = makeError(
'VALIDATION_ERROR',
'Invalid email format',
{ field: 'email', value: 'not-an-email' },
originalError // Optional: wrap caught errors
);
// Error structure
interface AppError {
code: string;
message: string;
details?: unknown;
cause?: Error;
stack?: string;
}
Type-safe environment variable handling with Zod. This is available via a sub-path import to keep the core package dependency-free.
import { validateEnv } from '@outfitter/contracts-zod';
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'production', 'test']),
PORT: z.string().regex(/^\d+$/).transform(Number),
API_KEY: z.string().min(1),
ENABLE_FEATURE: z
.string()
.transform(val => val === 'true')
.optional(),
});
const envResult = validateEnv(process.env, envSchema);
if (isSuccess(envResult)) {
const env = envResult.data;
// env is fully typed: { NODE_ENV: 'development' | 'production' | 'test', PORT: number, ... }
} else {
console.error('Environment validation failed:', envResult.error);
process.exit(1);
}
Advanced TypeScript utility types:
import type {
DeepReadonly,
DeepPartial,
Nullable,
Brand,
UnionToIntersection,
} from '@outfitter/contracts';
// Brand types for type safety
type UserId = Brand<string, 'UserId'>;
type Email = Brand<string, 'Email'>;
// Deep type transformations
type Config = {
server: {
port: number;
host: string;
};
};
type ReadonlyConfig = DeepReadonly<Config>;
type PartialConfig = DeepPartial<Config>;
Runtime validation with type narrowing:
import { assert, assertDefined, assertNever } from '@outfitter/contracts';
// assert: Ensures condition is true
function processPositive(value: number) {
assert(value > 0, 'Value must be positive');
// TypeScript knows value > 0 here
}
// assertDefined: Ensures value is not null/undefined
function processUser(user: User | null) {
assertDefined(user, 'User is required');
// TypeScript knows user is User here
}
// assertNever: Exhaustive checking
type Status = 'pending' | 'approved' | 'rejected';
function handleStatus(status: Status) {
switch (status) {
case 'pending':
return 'waiting';
case 'approved':
return 'success';
case 'rejected':
return 'failed';
default:
assertNever(status); // Compile error if cases missed
}
}
Create nominal types from primitives to prevent accidental misuse of values like IDs or tokens.
import type { Branded } from '@outfitter/contracts';
type UserId = Branded<string, 'UserId'>;
const createUserId = (id: string): UserId => id as UserId;
const userId = createUserId('user-123');
// const otherString: string = 'abc';
// const otherUserId: UserId = otherString; // Fails to compile
success<T>(data: T): Success<T>
- Create a success resultfailure<E>(error: E): Failure<E>
- Create a failure resultisSuccess<T, E>(result: Result<T, E>): result is Success<T>
- Type guard for
successisFailure<T, E>(result: Result<T, E>): result is Failure<E>
- Type guard for
failuremapResult<T, U, E>(result: Result<T, E>, fn: (data: T) => U): Result<U, E>
-
Transform success valueflatMapResult<T, U, E>(result: Result<T, E>, fn: (data: T) => Result<U, E>): Result<U, E>
-
Chain resultsmakeError(code: string, message: string, details?: unknown, cause?: Error): AppError
-
Create structured errorisAppError(error: unknown): error is AppError
- Type guard for AppError@outfitter/contracts-zod
)validateEnv<T>(env: unknown, schema: ZodSchema<T>): Result<T, AppError>
-
Validate environment variablesfromZod(error: ZodError): AppError
- Convert a Zod error to an AppErrorisObject(value: unknown): value is Record<string, unknown>
- Check if value
is objectisString(value: unknown): value is string
- Check if value is stringisNumber(value: unknown): value is number
- Check if value is numberisBoolean(value: unknown): value is boolean
- Check if value is boolean// ❌ Don't throw in library functions
function parseConfig(json: string): Config {
return JSON.parse(json); // Throws on invalid JSON
}
// ✅ Return Result instead
function parseConfig(json: string): Result<Config, AppError> {
try {
return success(JSON.parse(json));
} catch (error) {
return failure(
makeError('PARSE_ERROR', 'Invalid config format', { json }, error)
);
}
}
// ❌ Primitive types allow mixing up parameters
function sendEmail(to: string, from: string, subject: string) {}
// ✅ Branded types prevent errors
type Email = Brand<string, 'Email'>;
type Subject = Brand<string, 'Subject'>;
function sendEmail(to: Email, from: Email, subject: Subject) {}
// Validate external data immediately
const configResult = validateEnv(process.env, configSchema);
if (isFailure(configResult)) {
console.error('Invalid configuration:', configResult.error);
process.exit(1);
}
const config = configResult.data; // Fully typed and validated
This package has zero runtime dependencies in its core entry point.
The standalone @outfitter/contracts-zod
package has a dependency on zod
.
This package is part of the @outfitter/monorepo monorepo.
# Install dependencies
pnpm install
# Run tests
pnpm test
# Build the package
pnpm build
# Type check
pnpm type-check
MIT
FAQs
Core contracts for building type-safe applications, including Result, AppError, and domain types.
The npm package @outfitter/contracts receives a total of 3 weekly downloads. As such, @outfitter/contracts popularity was classified as not popular.
We found that @outfitter/contracts demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.