diff --git a/.smooai-logs/output.ansi b/.smooai-logs/output.ansi index 078a1b7d..032ac884 100644 --- a/.smooai-logs/output.ansi +++ b/.smooai-logs/output.ansi @@ -1800,3 +1800,228 @@ ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------- +{ + "msg": "An API error occurred: Status: 400 (undefined); Message: Bad Request", + "time": "2026-06-13T21:11:57.830Z", + "error": "Bad Request", + "errorDetails": [ + { + "message": "Bad Request", + "name": "Error", + "stack": "Error: Bad Request\n at /Users/brentrager/dev/smooai/utils/src/api/sqsHandler.spec.ts:51:22\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:103:11\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:595:26\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:877:20\n at new Promise ()\n at runWithTimeout (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:850:10)\n at runTest (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1345:12)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)", + "status": 400 + } + ], + "@message": "An API error occurred: Status: 400 (undefined); Message: Bad Request", + "@requestId": "test-request-id", + "@timestamp": "2026-06-13T21:11:57.830Z", + "LogLevel": "error", + "callerContext": { + "loggerName": "AwsServerLogger", + "stack": [ + "/Users/brentrager/dev/smooai/utils/src/api/sqsHandler.ts:21:20", + "processTicksAndRejections (node:internal/process/task_queues:105:5)" + ] + }, + "correlationId": "6ae1ca49-a00d-460c-889a-adec39f06ff1", + "http": { + "request": { + } + }, + "lambda": { + "requestId": "test-request-id" + }, + "level": 50, + "name": "AwsServerLogger", + "nodeEnv": "test", + "queue": { + "messageApproximateReceiveCount": "1", + "messageId": "msg1" + }, + "requestId": "6ae1ca49-a00d-460c-889a-adec39f06ff1", + "traceId": "6ae1ca49-a00d-460c-889a-adec39f06ff1" +} +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +{ + "msg": "A schema validation error occurred: Invalid schema at \"test\"", + "time": "2026-06-13T21:11:57.834Z", + "error": "Invalid schema at \"test\"", + "errorDetails": [ + { + "message": "Invalid schema at \"test\"", + "name": "HumanReadableSchemaError", + "schemaError": { + "issues": [ + { + "message": "Invalid schema", + "path": [ + "test" + ] + } + ], + "message": "Invalid schema", + "name": "SchemaError", + "stack": "SchemaError: Invalid schema\n at /Users/brentrager/dev/smooai/utils/src/api/sqsHandler.spec.ts:62:25\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:103:11\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:595:26\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:877:20\n at new Promise ()\n at runWithTimeout (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:850:10)\n at runTest (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1345:12)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)" + }, + "stack": "HumanReadableSchemaError: Invalid schema at \"test\"\n at /Users/brentrager/dev/smooai/utils/src/api/sqsHandler.spec.ts:63:32\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:103:11\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:595:26\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:877:20\n at new Promise ()\n at runWithTimeout (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:850:10)\n at runTest (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1345:12)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)" + } + ], + "@message": "A schema validation error occurred: Invalid schema at \"test\"", + "@requestId": "test-request-id", + "@timestamp": "2026-06-13T21:11:57.834Z", + "LogLevel": "error", + "callerContext": { + "loggerName": "AwsServerLogger", + "stack": [ + "/Users/brentrager/dev/smooai/utils/src/api/sqsHandler.ts:23:20", + "processTicksAndRejections (node:internal/process/task_queues:105:5)" + ] + }, + "correlationId": "652fcde5-fa91-4850-92ae-09c594d75b77", + "http": { + "request": { + } + }, + "lambda": { + "requestId": "test-request-id" + }, + "level": 50, + "name": "AwsServerLogger", + "nodeEnv": "test", + "queue": { + "messageApproximateReceiveCount": "1", + "messageId": "msg1" + }, + "requestId": "652fcde5-fa91-4850-92ae-09c594d75b77", + "traceId": "652fcde5-fa91-4850-92ae-09c594d75b77" +} +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +{ + "msg": "A validation error occurred: ✖ Expected string, received number\n → at name", + "time": "2026-06-13T21:11:57.835Z", + "@message": "A validation error occurred: ✖ Expected string, received number\n → at name", + "@requestId": "test-request-id", + "@timestamp": "2026-06-13T21:11:57.835Z", + "LogLevel": "error", + "callerContext": { + "loggerName": "AwsServerLogger", + "stack": [ + "/Users/brentrager/dev/smooai/utils/src/api/sqsHandler.ts:26:20", + "processTicksAndRejections (node:internal/process/task_queues:105:5)" + ] + }, + "context": { + "message": "[\n {\n \"code\": \"invalid_type\",\n \"expected\": \"string\",\n \"path\": [\n \"name\"\n ],\n \"message\": \"Expected string, received number\"\n }\n]", + "name": "ZodError" + }, + "correlationId": "72e526da-f048-40a7-93d9-2ae3abd64493", + "http": { + "request": { + } + }, + "lambda": { + "requestId": "test-request-id" + }, + "level": 50, + "name": "AwsServerLogger", + "nodeEnv": "test", + "queue": { + "messageApproximateReceiveCount": "1", + "messageId": "msg1" + }, + "requestId": "72e526da-f048-40a7-93d9-2ae3abd64493", + "traceId": "72e526da-f048-40a7-93d9-2ae3abd64493" +} +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +{ + "msg": "An unexpected error occurred: General error", + "time": "2026-06-13T21:11:57.835Z", + "error": "General error", + "errorDetails": [ + { + "message": "General error", + "name": "Error", + "stack": "Error: General error\n at /Users/brentrager/dev/smooai/utils/src/api/sqsHandler.spec.ts:92:19\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:103:11\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:595:26\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:877:20\n at new Promise ()\n at runWithTimeout (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:850:10)\n at runTest (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1345:12)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)" + } + ], + "@message": "An unexpected error occurred: General error", + "@requestId": "test-request-id", + "@timestamp": "2026-06-13T21:11:57.835Z", + "LogLevel": "error", + "callerContext": { + "loggerName": "AwsServerLogger", + "stack": [ + "/Users/brentrager/dev/smooai/utils/src/api/sqsHandler.ts:28:20", + "processTicksAndRejections (node:internal/process/task_queues:105:5)" + ] + }, + "correlationId": "e6e48613-95b8-466a-bcd8-64e221db78bb", + "http": { + "request": { + } + }, + "lambda": { + "requestId": "test-request-id" + }, + "level": 50, + "name": "AwsServerLogger", + "nodeEnv": "test", + "queue": { + "messageApproximateReceiveCount": "1", + "messageId": "msg1" + }, + "requestId": "e6e48613-95b8-466a-bcd8-64e221db78bb", + "traceId": "e6e48613-95b8-466a-bcd8-64e221db78bb" +} +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +{ + "msg": "An unexpected error occurred: Failed", + "time": "2026-06-13T21:11:57.837Z", + "error": "Failed", + "errorDetails": [ + { + "message": "Failed", + "name": "Error", + "stack": "Error: Failed\n at /Users/brentrager/dev/smooai/utils/src/api/sqsHandler.spec.ts:117:69\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:103:11\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:595:26\n at file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:877:20\n at new Promise ()\n at runWithTimeout (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:850:10)\n at runTest (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1345:12)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)\n at runSuite (file:///Users/brentrager/dev/smooai/utils/node_modules/.pnpm/@vitest+runner@3.1.1/node_modules/@vitest/runner/dist/index.js:1491:8)" + } + ], + "@message": "An unexpected error occurred: Failed", + "@requestId": "test-request-id", + "@timestamp": "2026-06-13T21:11:57.837Z", + "LogLevel": "error", + "callerContext": { + "loggerName": "AwsServerLogger", + "stack": [ + "/Users/brentrager/dev/smooai/utils/src/api/sqsHandler.ts:28:20", + "processTicksAndRejections (node:internal/process/task_queues:105:5)" + ] + }, + "correlationId": "24e653fa-d93d-4ee0-b30a-eb28d1678d6c", + "http": { + "request": { + } + }, + "lambda": { + "requestId": "test-request-id" + }, + "level": 50, + "name": "AwsServerLogger", + "nodeEnv": "test", + "queue": { + "messageApproximateReceiveCount": "1", + "messageId": "msg2" + }, + "requestId": "24e653fa-d93d-4ee0-b30a-eb28d1678d6c", + "traceId": "24e653fa-d93d-4ee0-b30a-eb28d1678d6c" +} +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- diff --git a/README.md b/README.md index c183e2bb..9ebe1157 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,62 @@ - - - - - - - - -
- - - - -## About SmooAI - -SmooAI is an AI-powered platform for helping businesses multiply their customer, employee, and developer experience. - -Learn more on [smoo.ai](https://smoo.ai) - -## SmooAI Packages - -Check out other SmooAI packages at [npmjs.com/org/smooai](https://www.npmjs.com/org/smooai) - -## About @smooai/utils +

+ Smoo AI +

-**The foundation that eliminates boilerplate** - Battle-tested utilities that handle the repetitive tasks so you can focus on building features, not infrastructure. +

@smooai/utils

-![NPM Version](https://img.shields.io/npm/v/%40smooai%2Futils?style=for-the-badge) -![NPM Downloads](https://img.shields.io/npm/dw/%40smooai%2Futils?style=for-the-badge) -![NPM Last Update](https://img.shields.io/npm/last-update/%40smooai%2Futils?style=for-the-badge) +

+ Battle-tested TypeScript utilities that eliminate the boilerplate — Lambda handlers, human-readable validation, case-insensitive collections, and more. +

-![GitHub License](https://img.shields.io/github/license/SmooAI/utils?style=for-the-badge) -![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/SmooAI/utils/release.yml?style=for-the-badge) -![GitHub Repo stars](https://img.shields.io/github/stars/SmooAI/utils?style=for-the-badge) +

+ npm + downloads + Smoo AI + license + TypeScript +

-### Why @smooai/utils? +

+ Features · + Install · + Usage · + Platform +

-Ever found yourself writing the same error handler for the 50th time? Debugging Lambda functions without proper request tracking? Wrestling with phone number validation that works everywhere except production? You're not alone. +--- -**We built @smooai/utils because we were tired of:** +> 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. -- 🔁 Copy-pasting the same utility functions across projects -- 🐛 Inconsistent error handling breaking production deploys -- 🔍 Losing request context across AWS services -- 📱 Phone numbers failing validation in different formats -- 🗺️ HTTP headers losing their case-sensitivity battles -- 🎯 Writing custom validators for every data type +## ✨ Features -**Now, with one package, you get:** +Stop copy-pasting the same utility functions across projects. One package gives you: -- ✅ Production-tested utilities used across all SmooAI services +- ✅ 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 team will thank you for -- ✅ Zero configuration needed - sensible defaults out of the box +- ✅ Human-readable error messages your support team will thank you for +- ✅ Sensible defaults out of the box — no configuration required -### Install +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. + +## 📦 Install ```sh pnpm add @smooai/utils ``` -## Real-World Solutions +## 🚀 Usage -### 🚀 Lambda Error Handling That Actually Works +#### 🚀 Lambda error handling -Stop writing try-catch blocks in every Lambda function. Our battle-tested `apiHandler` does it all: +Stop writing try-catch blocks in every Lambda function. The `apiHandler` wrapper handles parsing, validation, error handling, logging, and response formatting: ```typescript import { apiHandler } from '@smooai/utils'; -// Before: Boilerplate everywhere +// Before: boilerplate everywhere export const handler = async (event, context) => { try { // Parse body @@ -100,17 +69,17 @@ export const handler = async (event, context) => { } }; -// After: Focus on your logic +// After: focus on your logic export const handler = apiHandler(async (event, context) => { const user = await createUser(event.body); return { statusCode: 201, body: user }; }); -// Automatic error handling, logging, and response formatting ✨ +// Automatic error handling, logging, and response formatting ``` -### 🎯 Validation With Human-Readable Errors +#### 🎯 Validation with human-readable errors -Your users (and your support team) deserve better than "ValidationError at path[0].nested.field": +Your users — and your support team — deserve better than `ValidationError at path[0].nested.field`: ```typescript import { handleSchemaValidation, HumanReadableSchemaError } from '@smooai/utils'; @@ -132,7 +101,7 @@ try { } ``` -### 🔍 Case-Insensitive Collections for HTTP Headers +#### 🔍 Case-insensitive collections for HTTP headers Because `Content-Type`, `content-type`, and `CONTENT-TYPE` should all just work: @@ -144,14 +113,14 @@ const headers = new CaseInsensitiveMap([ ['X-API-KEY', 'secret'], ]); -headers.get('content-type'); // 'application/json' ✅ -headers.has('X-Api-Key'); // true ✅ -headers.get('CONTENT-TYPE'); // 'application/json' ✅ +headers.get('content-type'); // 'application/json' +headers.has('X-Api-Key'); // true +headers.get('CONTENT-TYPE'); // 'application/json' ``` -### 🏭 Production-Ready Hono Apps for Lambda +#### 🏭 Production-ready Hono apps for Lambda -Set up a fully-configured API with one line: +Set up a fully configured API in one line: ```typescript import { createAwsLambdaHonoApp } from '@smooai/utils'; @@ -171,7 +140,7 @@ app.post('/users', async (c) => { export const handler = handle(app); ``` -### 📁 Smart File Discovery +#### 📁 Smart file discovery Find configuration files without hardcoding paths: @@ -188,7 +157,7 @@ const packageJson = await findFile('package.json'); // - Locating test fixtures ``` -### 🌍 Environment Detection Made Simple +#### 🌍 Environment detection ```typescript import { isRunningInProd, isRunningLocally } from '@smooai/utils'; @@ -206,9 +175,7 @@ if (isRunningInProd()) { } ``` -## More Powerful Examples - -### 🛡️ Type-Safe Error Handling +#### 🛡️ Type-safe error handling Transform cryptic errors into actionable messages: @@ -233,7 +200,7 @@ const processPayment = errorHandler( ); ``` -### ⏱️ Smart Async Utilities +#### ⏱️ Async utilities ```typescript import { sleep } from '@smooai/utils'; @@ -257,7 +224,7 @@ async function retryWithBackoff(fn, attempts = 3) { } ``` -### 📞 Phone Number Validation That Works Globally +#### 📞 Global phone-number validation ```typescript import { validateAndTransformPhoneNumber } from '@smooai/utils'; @@ -268,46 +235,57 @@ const phoneSchema = z.object({ }); phoneSchema.parse({ phone: '(212) 555-1234' }); -// ✅ { phone: '+12125551234' } +// { phone: '+12125551234' } phoneSchema.parse({ phone: '+44 20 7946 0958' }); -// ✅ { phone: '+442079460958' } +// { phone: '+442079460958' } phoneSchema.parse({ phone: '555-1234' }); -// ❌ Throws: "Phone must be a valid phone number" +// Throws: "Phone must be a valid phone number" ``` -## Built for Production +## 🔧 Built for production 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 SmooAI -- 📚 **Well-documented** - Clear examples and use cases -- 🔄 **Maintained** - Regular updates and improvements +- 🔒 **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 -

(back to top)

- -### Testing +#### Testing ```sh pnpm test ``` -### Linting +#### Linting ```sh pnpm lint ``` -## Contributing +## 🧩 Part of Smoo AI + +@smooai/utils is part of the [Smoo AI](https://smoo.ai) platform — an AI-powered business platform with AI built into every product. It's the shared foundation under our open-source packages. -We're currently developing our contribution processes. If you're interested in contributing to this package or have questions, please reach out to us through the contact information below. +- [@smooai/logger](https://github.com/SmooAI/logger) — contextual structured logging +- [@smooai/fetch](https://github.com/SmooAI/fetch) — typed HTTP with retries +- [@smooai/file](https://github.com/SmooAI/file) — stream-first file ops with magic-byte validation +- [@smooai/config](https://github.com/SmooAI/config) — typed config, secrets, and feature flags - +Browse the rest at [npmjs.com/org/smooai](https://www.npmjs.com/org/smooai) and [github.com/SmooAI](https://github.com/SmooAI). -## Contact +## 🤝 Contributing + +We're still developing our contribution processes. If you'd like to contribute or have questions, reach out through the contact information below. + +## 📄 License + +MIT — see [LICENSE](./LICENSE). + +## 📬 Contact Brent Rager @@ -317,29 +295,12 @@ Brent Rager - [TikTok](https://www.tiktok.com/@brentragertech) - [Instagram](https://www.instagram.com/brentragertech/) -Smoo Github: [https://github.com/SmooAI](https://github.com/SmooAI) +Smoo GitHub: [https://github.com/SmooAI](https://github.com/SmooAI)

(back to top)

- - - -[sst.dev-url]: https://reactjs.org/ -[sst]: https://img.shields.io/badge/sst-EDE1DA?style=for-the-badge&logo=sst&logoColor=E27152 -[sst-url]: https://sst.dev/ -[next]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white -[next-url]: https://nextjs.org/ -[aws]: https://img.shields.io/badge/aws-232F3E?style=for-the-badge&logo=amazonaws&logoColor=white -[aws-url]: https://tailwindcss.com/ -[tailwindcss]: https://img.shields.io/badge/tailwind%20css-0B1120?style=for-the-badge&logo=tailwindcss&logoColor=#06B6D4 -[tailwindcss-url]: https://tailwindcss.com/ -[zod]: https://img.shields.io/badge/zod-3E67B1?style=for-the-badge&logoColor=3E67B1 -[zod-url]: https://zod.dev/ -[sanity]: https://img.shields.io/badge/sanity-F36458?style=for-the-badge -[sanity-url]: https://www.sanity.io/ -[vitest]: https://img.shields.io/badge/vitest-1E1E20?style=for-the-badge&logo=vitest&logoColor=#6E9F18 -[vitest-url]: https://vitest.dev/ -[pnpm]: https://img.shields.io/badge/pnpm-F69220?style=for-the-badge&logo=pnpm&logoColor=white -[pnpm-url]: https://pnpm.io/ -[turborepo]: https://img.shields.io/badge/turborepo-000000?style=for-the-badge&logo=turborepo&logoColor=#EF4444 -[turborepo-url]: https://turbo.build/ +--- + +

+ Built by Smoo AI — AI built into every product. +