Features · Install · Usage · Platform
The foundation utilities that power every Smoo AI service. They handle the repetitive infrastructure work — error handling, request tracking, validation, environment detection — so you focus on features. Type-safe, production-tested, zero configuration.
Stop copy-pasting the same utility functions across projects. One package gives you:
- ✅ Production-tested utilities used across every Smoo AI service
- ✅ Type-safe implementations with full TypeScript support
- ✅ AWS Lambda integration that just works
- ✅ Human-readable error messages your support team will thank you for
- ✅ Sensible defaults out of the box — no configuration required
Concretely, that means a battle-tested Lambda apiHandler, schema validation that produces human-readable errors, case-insensitive collections for HTTP headers, production-ready Hono apps for Lambda, file discovery, environment detection, type-safe error handling, async helpers, and global phone-number validation.
pnpm add @smooai/utilsStop writing try-catch blocks in every Lambda function. The apiHandler wrapper handles parsing, validation, error handling, logging, and response formatting:
import{apiHandler}from'@smooai/utils';// Before: boilerplate everywhereexportconsthandler=async(event,context)=>{try{// Parse body// Validate input// Handle errors// Format response// Log everything}catch(error){// More error handling}};// After: focus on your logicexportconsthandler=apiHandler(async(event,context)=>{constuser=awaitcreateUser(event.body);return{statusCode: 201,body: user};});// Automatic error handling, logging, and response formattingYour users — and your support team — deserve better than ValidationError at path[0].nested.field:
import{handleSchemaValidation,HumanReadableSchemaError}from'@smooai/utils';constuserSchema=z.object({email: z.string().email(),phone: validateAndTransformPhoneNumber,age: z.number().min(18),});try{constuser=handleSchemaValidation(userSchema,data);// user.phone is guaranteed to be E.164 format: +12125551234}catch(error){if(errorinstanceofHumanReadableSchemaError){console.log(error.humanReadableMessage);// "Email must be a valid email address. Phone must be a valid phone number. Age must be at least 18."}}Because Content-Type, content-type, and CONTENT-TYPE should all just work:
import{CaseInsensitiveMap}from'@smooai/utils';constheaders=newCaseInsensitiveMap([['Content-Type','application/json'],['X-API-KEY','secret'],]);headers.get('content-type');// 'application/json'headers.has('X-Api-Key');// trueheaders.get('CONTENT-TYPE');// 'application/json'Set up a fully configured API in one line:
import{createAwsLambdaHonoApp}from'@smooai/utils';constapp=createAwsLambdaHonoApp();app.get('/health',(c)=>c.json({status: 'healthy'}));app.post('/users',async(c)=>{// Automatic request ID tracking// Built-in error handling// Pretty JSON in developmentconstuser=awaitcreateUser(awaitc.req.json());returnc.json(user,201);});exportconsthandler=handle(app);Find configuration files without hardcoding paths:
import{findFile}from'@smooai/utils';// Searches up the directory tree until it finds the fileconstconfigPath=awaitfindFile('smoo.config.json');constpackageJson=awaitfindFile('package.json');// Perfect for:// - Finding project root// - Loading environment-specific configs// - Locating test fixturesimport{isRunningInProd,isRunningLocally}from'@smooai/utils';if(isRunningLocally()){// Enable debug logging// Use local database// Show detailed errors}if(isRunningInProd()){// Use production services// Enable monitoring// Sanitize error messages}Transform cryptic errors into actionable messages:
import{ApiError,errorHandler}from'@smooai/utils';constprocessPayment=errorHandler(async(orderId: string)=>{// Throws ApiError with 404 statusif(!order)thrownewApiError('Order not found',404);// Validation errors become 400s with detailsconstvalidated=handleSchemaValidation(schema,data);// Unexpected errors are logged and sanitizedreturnawaitchargeCard(order);},{logger: console,onError: (error)=>notifyOps(error),},);import{sleep}from'@smooai/utils';// Rate limiting made easyfor(constbatchofbatches){awaitprocessBatch(batch);awaitsleep(1000);// Wait 1 second between batches}// Retry with exponential backoffasyncfunctionretryWithBackoff(fn,attempts=3){for(leti=0;i<attempts;i++){try{returnawaitfn();}catch(error){if(i===attempts-1)throwerror;awaitsleep(Math.pow(2,i)*1000);}}}import{validateAndTransformPhoneNumber}from'@smooai/utils';// Accepts multiple formats, outputs E.164constphoneSchema=z.object({phone: validateAndTransformPhoneNumber,});phoneSchema.parse({phone: '(212) 555-1234'});// { phone: '+12125551234' }phoneSchema.parse({phone: '+44 20 7946 0958'});// { phone: '+442079460958' }phoneSchema.parse({phone: '555-1234'});// Throws: "Phone must be a valid phone number"Every utility in this package is:
- 🔒 Type-safe — full TypeScript support with strict types
- ⚡ Performance tested — optimized for real-world usage
- 📊 Battle-tested — used in production at Smoo AI
- 📚 Well-documented — clear examples and use cases
- 🔄 Maintained — regular updates and improvements
pnpm testpnpm lint@smooai/utils is built and open-sourced by Smoo AI — the AI-powered business platform with AI built into every product: CRM, customer support, campaigns, field service, observability, and developer tools.
- 🧰 More open source from Smoo AI — smoo.ai/open-source
- 🧩 Sibling packages — @smooai/logger, @smooai/fetch, @smooai/file, @smooai/config
We're still developing our contribution processes. If you'd like to contribute or have questions, reach out through the contact information below.
MIT — see LICENSE.
Brent Rager
Smoo GitHub: https://github.com/SmooAI
Built by Smoo AI — AI built into every product.
