Skip to main content

patterns

Reference for Outfitter Dev Kit conventions including Result types, Handler contract, Error taxonomy, and transport-agnostic patterns. Use when learning the stack, looking up patterns, understanding @outfitter/* packages, or when "Result", "Handler", "error taxonomy", or "OutfitterError" are mentioned.

معلومات المصدر

المستودع
outfitter-dev/outfitter
آخر نشاط في المصدر
١٧ مارس ٢٠٢٦ في ١٧:٢٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٦
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
4 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
patterns
version
0.1.0
description
Reference for Outfitter Dev Kit conventions including Result types, Handler contract, Error taxonomy, and transport-agnostic patterns. Use when learning the stack, looking up patterns, understanding @outfitter/* packages, or when "Result", "Handler", "error taxonomy", or "OutfitterError" are mentioned.
allowed-tools
Read Grep Glob
# Outfitter Dev Kit Patterns Primary reference for @outfitter/\* package conventions. ## Handler Contract Handlers are pure functions that: - Accept typed input and context - Return `Result<TOutput, TError>` - Know nothing about transport (CLI flags, HTTP headers, MCP tool schemas) ```typescript type Handler<TInput, TOutput, TError extends OutfitterError> = ( input: TInput, ctx: HandlerContext ) => Promise<Result<TOutput, TError>>; ``` ### Example ```typescript import { Result, NotFoundError, type Handler } from "@outfitter/contracts"; export const getUser: Handler<{ id: string }, User, NotFoundError> = async ( input, ctx ) => { ctx.logger.debug("Fetching user", { userId: input.id }); const user = await db.users.findById(input.id); if (!user) { return Result.err(NotFoundError.create("user", input.id)); } return Result.ok(user); }; ``` **Why?** Testability (just call the function), reusability (same handler for CLI/MCP/HTTP), type safety (explicit types), composability (handlers wrap handlers). ## Result Types Uses `Result<T, E>` from `better-result` for explicit error handling. ```typescript import { NotFoundError, Result } from "@outfitter/contracts"; // Create const ok = Result.ok({ name: "Alice" }); const err = Result.err(NotFoundError.create("user", "123")); // Check if (result.isOk()) { console.log(result.value); // TypeScript knows T } else { console.log(result.error); // TypeScript knows E } // Pattern match const message = result.match({ ok: (user) => `Found ${user.name}`, err: (error) => `Error: ${error.message}`, }); // Combine const combined = combine2(result1, result2); // tuple or first error ``` ## Error Taxonomy Ten categories map to exit codes and HTTP status: | Category | Exit | HTTP | When to Use | | ------------ | ---- | ---- | -------------------------------- | | `validation` | 1 | 400 | Invalid input, schema failures | | `not_found` | 2 | 404 | Resource doesn't exist | | `conflict` | 3 | 409 | Already exists, version mismatch | | `permission` | 4 | 403 | Forbidden action | | `timeout` | 5 | 504 | Operation took too long | | `rate_limit` | 6 | 429 | Too many requests | | `network` | 7 | 502 | Connection failures | | `internal` | 8 | 500 | Unexpected errors, bugs | | `auth` | 9 | 401 | Authentication required | | `cancelled` | 130 | 499 | User interrupted (Ctrl+C) | ```typescript import { ValidationError, NotFoundError, getExitCode, } from "@outfitter/contracts"; ValidationError.create("email", "invalid"); NotFoundError.create("user", "user-123"); getExitCode(error.category); // 2 for not_found getStatusCode(error.category); // 404 for not_found ``` ## Validation Use Zod with `createValidator` for type-safe validation returning Results: ```typescript import { createValidator } from "@outfitter/contracts"; import { z } from "zod"; const InputSchema = z.object({ name: z.string().min(1), email: z.string().email(), }); const validateInput = createValidator(InputSchema); // In handler const inputResult = validateInput(rawInput); if (inputResult.isErr()) return inputResult; const input = inputResult.value; // typed as z.infer<typeof InputSchema> ``` ## Context `HandlerContext` carries cross-cutting concerns: ```typescript import { createContext } from "@outfitter/contracts"; const ctx = createContext({ logger: myLogger, // structured logger config: resolvedConfig, // merged configuration signal: controller.signal, // cancellation workspaceRoot: "/project", }); // ctx.requestId is auto-generated UUIDv7 for tracing ``` | Field | Type | Description | | --------------- | ---------------- | --------------------- | | `requestId` | `string` | Auto-generated UUIDv7 | | `logger` | `Logger` | Structured logger | | `config` | `ResolvedConfig` | Merged config | | `signal` | `AbortSignal` | Cancellation signal | | `workspaceRoot` | `string` | Project root | | `cwd` | `string` | Current directory | ## Bun-First APIs Prefer Bun-native APIs: | Need | Bun API | | ------------ | -------------------- | | Hashing | `Bun.hash()` | | Globbing | `Bun.Glob` | | Semver | `Bun.semver` | | Shell | `Bun.$` | | Colors | `Bun.color()` | | String width | `Bun.stringWidth()` | | SQLite | `bun:sqlite` | | UUID v7 | `Bun.randomUUIDv7()` | ## References - [Handler Contract](references/handler-contract.md) - [Error Taxonomy](references/error-taxonomy.md) - [Result Utilities](references/result-utilities.md)
عرض على GitHub