{"_id":"@astrotech-sh/nuvicms-api-sdk","_rev":"6-492455be3e1bb724b15cd01ac384947f","name":"@astrotech-sh/nuvicms-api-sdk","dist-tags":{"latest":"0.3.1"},"versions":{"0.1.0":{"name":"@astrotech-sh/nuvicms-api-sdk","version":"0.1.0","_id":"@astrotech-sh/nuvicms-api-sdk@0.1.0","maintainers":[{"name":"dersonsena","email":"dersonsena@gmail.com"}],"homepage":"https://github.com/astrotechsh/nuvicms-api-sdk#readme","bugs":{"url":"https://github.com/astrotechsh/nuvicms-api-sdk/issues"},"dist":{"shasum":"0e4a68994ed955d6e14af3db2acaa0e4172f96a9","tarball":"https://registry.npmjs.org/@astrotech-sh/nuvicms-api-sdk/-/nuvicms-api-sdk-0.1.0.tgz","fileCount":154,"integrity":"sha512-vkcy6lotVYxWi4cf+blAYQAp4yxy168Ty3D7SmBlBSwmKVWDFkLw7qlwbKe9HCVF0QVsrmBAh5wyKEavgHua3Q==","signatures":[{"sig":"MEYCIQDHb1SwITdPjFz0sjT9e8HPiDxqqFEsyojQ/1d2thIjvAIhAIiIG1KPr1QJNVxfBlTQuZlHEZOVzM9xFMNQR0XDJsoF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":325685},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./content":{"types":"./dist/content-types.d.ts","import":"./dist/content-types.js"}},"gitHead":"3ea367362f68cb37d307734e2e84b6f365ba32b4","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json"},"_npmUser":{"name":"dersonsena","email":"dersonsena@gmail.com"},"repository":{"url":"git+https://github.com/astrotechsh/nuvicms-api-sdk.git","type":"git"},"_npmVersion":"10.8.2","description":"TypeScript HTTP client (ports-and-adapters) for the NuviCMS public API.","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.9","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/nuvicms-api-sdk_0.1.0_1785953923327_0.38526924220750547","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@astrotech-sh/nuvicms-api-sdk","version":"0.1.1","_id":"@astrotech-sh/nuvicms-api-sdk@0.1.1","maintainers":[{"name":"dersonsena","email":"dersonsena@gmail.com"}],"homepage":"https://github.com/astrotech-sh/nuvicms-api-sdk#readme","bugs":{"url":"https://github.com/astrotech-sh/nuvicms-api-sdk/issues"},"dist":{"shasum":"9fe237cf4f994342c073357fed173b230a705684","tarball":"https://registry.npmjs.org/@astrotech-sh/nuvicms-api-sdk/-/nuvicms-api-sdk-0.1.1.tgz","fileCount":226,"integrity":"sha512-fYydyslrQ52a+ZW5tOArG5hCe3P0m575RYsbTVQFD2Sn6FVCigzcI0mSnBy0ZMUNMtQs4pEYW4jLIFsXPG1F4w==","signatures":[{"sig":"MEUCICYd3g/bvwtCZZyD5thI9/Xs39C1zaFRyxlNl5cCM0ehAiEA3+r93ebXlpMcjuMU4TjnVknyj7lYKCvMid8wncOEUu0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":508817},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./content":{"types":"./dist/content-types.d.ts","import":"./dist/content-types.js"}},"gitHead":"8f5e9614e0975a8f57f5fedce3ff20c4e30f107b","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json"},"_npmUser":{"name":"dersonsena","email":"dersonsena@gmail.com"},"repository":{"url":"git+https://github.com/astrotech-sh/nuvicms-api-sdk.git","type":"git"},"_npmVersion":"10.8.2","description":"TypeScript HTTP client (ports-and-adapters) for the NuviCMS public API.","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.9","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/nuvicms-api-sdk_0.1.1_1786038314761_0.8721111660672785","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@astrotech-sh/nuvicms-api-sdk","version":"0.2.0","_id":"@astrotech-sh/nuvicms-api-sdk@0.2.0","maintainers":[{"name":"dersonsena","email":"dersonsena@gmail.com"}],"homepage":"https://github.com/astrotech-sh/nuvicms-api-sdk#readme","bugs":{"url":"https://github.com/astrotech-sh/nuvicms-api-sdk/issues"},"dist":{"shasum":"c957577c29353e9c5f8d4c614de4d24a78505424","tarball":"https://registry.npmjs.org/@astrotech-sh/nuvicms-api-sdk/-/nuvicms-api-sdk-0.2.0.tgz","fileCount":242,"integrity":"sha512-z+Ua7v3/Fyi2wWwZbN3Koy80R9RpQFHSJURmti0a1Rto2Vj7SzW1p02a7AdW/hPpYB4OxRSIzYbbtdI0lTQ3tA==","signatures":[{"sig":"MEQCIFe+JhghNN620nAiUyhC/1qsRRe/SCRAle7DZmKeZgyRAiAtfC5lCuUqs/pJ3di2i6Os6e+su5SUfzMAwNDuNFcBAg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":540260},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./content":{"types":"./dist/content-types.d.ts","import":"./dist/content-types.js"}},"gitHead":"8a2c60726f2052123f0d52057f0c9eb79055dfbf","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json"},"_npmUser":{"name":"dersonsena","email":"dersonsena@gmail.com"},"repository":{"url":"git+https://github.com/astrotech-sh/nuvicms-api-sdk.git","type":"git"},"_npmVersion":"10.8.2","description":"TypeScript HTTP client (ports-and-adapters) for the NuviCMS public API.","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.9","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/nuvicms-api-sdk_0.2.0_1786631533490_0.7692999699731877","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@astrotech-sh/nuvicms-api-sdk","version":"0.3.0","_id":"@astrotech-sh/nuvicms-api-sdk@0.3.0","maintainers":[{"name":"dersonsena","email":"dersonsena@gmail.com"}],"homepage":"https://github.com/astrotech-sh/nuvicms-api-sdk#readme","bugs":{"url":"https://github.com/astrotech-sh/nuvicms-api-sdk/issues"},"dist":{"shasum":"c4aacb6dc9997bbdb36b23c5c507e39e312b75c5","tarball":"https://registry.npmjs.org/@astrotech-sh/nuvicms-api-sdk/-/nuvicms-api-sdk-0.3.0.tgz","fileCount":242,"integrity":"sha512-6vj5tbHDKJW/0PBOu4ArYXqO18a9cCq+V3ybdpmnWb62j2nC6iOP7/D4SkvcIYmVbIhCQr+YjxubkAA44GgyHw==","signatures":[{"sig":"MEQCIEMCUUYc+AGbn7wmgg7VopNEZxIW1jB6gHNIUeQmLmXNAiAX+vHGYmMtsqPJme2Z5TD88L5+64fRMM82oIuMnomz5A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":540260},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./content":{"types":"./dist/content-types.d.ts","import":"./dist/content-types.js"}},"gitHead":"ea2c9c1818772729bbf6e29319962249bfaccbe2","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json"},"_npmUser":{"name":"dersonsena","email":"dersonsena@gmail.com"},"repository":{"url":"git+https://github.com/astrotech-sh/nuvicms-api-sdk.git","type":"git"},"_npmVersion":"10.8.2","description":"TypeScript HTTP client (ports-and-adapters) for the NuviCMS public API.","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.9","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/nuvicms-api-sdk_0.3.0_1786725569040_0.15159948424723058","host":"s3://npm-registry-packages-npm-production"},"deprecated":"This version was published with a stale build and does not contain the mapWebsiteInfo/mapPage/mapSitemap/mapServiceCategories fixes despite the CHANGELOG. Use 0.3.1 or later."},"0.3.1":{"name":"@astrotech-sh/nuvicms-api-sdk","version":"0.3.1","_id":"@astrotech-sh/nuvicms-api-sdk@0.3.1","maintainers":[{"name":"dersonsena","email":"dersonsena@gmail.com"}],"homepage":"https://github.com/astrotech-sh/nuvicms-api-sdk#readme","bugs":{"url":"https://github.com/astrotech-sh/nuvicms-api-sdk/issues"},"dist":{"shasum":"16e6fea1acb26b87d31bde63ead373fe2b6d3ad3","tarball":"https://registry.npmjs.org/@astrotech-sh/nuvicms-api-sdk/-/nuvicms-api-sdk-0.3.1.tgz","fileCount":242,"integrity":"sha512-Qm7+8xIeexsCGpCl4Zu3w4D6GIat7D7kJ4nmXJCm1LlY6oW0cJp/BHmO3gOqM4Mm3aMSb3dpXnpBIn9BcnwWsg==","signatures":[{"sig":"MEYCIQDMuXzG9ITs5kCiTBcBTTpNFAlFPjXH/RorOQxgJeCEagIhANq184BY0xlnwMvVMpdJiDHO3PJh9pmz/DLui8CEbI1T","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":544338},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./content":{"types":"./dist/content-types.d.ts","import":"./dist/content-types.js"}},"gitHead":"810c9eae6102aeab6385b77f5fb27146dcc62e10","scripts":{"test":"vitest run","build":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"dersonsena","email":"dersonsena@gmail.com"},"repository":{"url":"git+https://github.com/astrotech-sh/nuvicms-api-sdk.git","type":"git"},"_npmVersion":"10.8.2","description":"TypeScript HTTP client (ports-and-adapters) for the NuviCMS public API.","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.1.9","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/nuvicms-api-sdk_0.3.1_1786735323718_0.06500914035101779","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-08-05T18:18:43.225Z","modified":"2026-08-14T19:22:16.879Z","0.1.0":"2026-08-05T18:18:43.493Z","0.1.1":"2026-08-06T17:45:14.917Z","0.2.0":"2026-08-13T14:32:13.642Z","0.3.0":"2026-08-14T16:39:29.235Z","0.3.1":"2026-08-14T19:22:03.863Z"},"bugs":{"url":"https://github.com/astrotech-sh/nuvicms-api-sdk/issues"},"homepage":"https://github.com/astrotech-sh/nuvicms-api-sdk#readme","repository":{"url":"git+https://github.com/astrotech-sh/nuvicms-api-sdk.git","type":"git"},"description":"TypeScript HTTP client (ports-and-adapters) for the NuviCMS public API.","maintainers":[{"name":"dersonsena","email":"dersonsena@gmail.com"}],"readme":"# nuvicms-api-sdk\n\nTypeScript HTTP client for the [NuviCMS](https://api.nuvicms.com.br/docs/api/public/openapi.json) public API, built with a ports-and-adapters (hexagonal) architecture — zero runtime dependencies, DOM-free core, fully injectable I/O.\n\nExtracted from `vape-shop-022-site` (originally `nuvicms-client`) for reuse across multiple client projects.\n\n## Status\n\nPublished to the [public npm registry](https://www.npmjs.com/package/@astrotech-sh/nuvicms-api-sdk) as `@astrotech-sh/nuvicms-api-sdk` version 0.1.0.\n\n## Installation\n\nThe SDK is published to the public npm registry — no custom registry configuration needed:\n\n```bash\nnpm install @astrotech-sh/nuvicms-api-sdk\n```\n\nContent/CMS-shape types (pages, products, posts, etc.) are available from the `./content` subpath and are type-only:\n\n```ts\nimport type { CmsPage, CmsProduct } from \"@astrotech-sh/nuvicms-api-sdk/content\";\n```\n\n## Quick Start\n\n```ts\nimport { createNuviCmsClient } from \"@astrotech-sh/nuvicms-api-sdk\";\n\n// Create a client with configuration\nconst client = createNuviCmsClient({\n  apiBaseUrl: \"https://api.nuvicms.com.br/api/public\",\n  siteKey: \"your-site-key\",\n});\n\n// Read store configuration\nconst config = await client.store.fetchConfig();\nif (!config) {\n  console.error(\"Store not configured\");\n  return;\n}\n\n// Validate a coupon\nconst validationResult = await client.coupons.validate(\"DISCOUNT10\");\nif (validationResult.valid) {\n  console.log(`Discount: ${validationResult.coupon?.discountValue}`);\n}\n\n// Create an order\ntry {\n  const order = await client.orders.create({\n    customerRef: \"customer-123\",\n    items: [\n      { productId: \"prod-1\", quantity: 2 },\n    ],\n    delivery: { kind: \"pickup\" },\n    payment: { method: \"pix\" },\n  });\n  console.log(`Order created: ${order.id}`);\n} catch (error) {\n  if (error instanceof NuviCmsConfigError) {\n    console.error(\"Client not configured with apiBaseUrl\");\n  }\n}\n```\n\n## Public Surface\n\n| Export | Type | Purpose | Documentation |\n|--------|------|---------|----------------|\n| `createNuviCmsClient(config, ports?)` | Factory | Creates a client instance | [getting-started](./docs/getting-started.md) |\n| **Configuration** | | | |\n| `NuviCmsConfig` | Type | Client config shape | [configuration](./docs/reference/configuration.md) |\n| `NormalizedNuviCmsConfig` | Type | Internal normalized shape | [configuration](./docs/reference/configuration.md) |\n| **Errors** | | | |\n| `NuviCmsError` | Class | Base error type | [errors](./docs/reference/errors.md) |\n| `NuviCmsHttpError` | Class | Non-2xx HTTP response | [errors](./docs/reference/errors.md) |\n| `NuviCmsEnvelopeError` | Class | Malformed API envelope | [errors](./docs/reference/errors.md) |\n| `NuviCmsTransportError` | Class | Network/CORS/abort error | [errors](./docs/reference/errors.md) |\n| `NuviCmsParseError` | Class | JSON parse error | [errors](./docs/reference/errors.md) |\n| `NuviCmsConfigError` | Class | Missing apiBaseUrl | [errors](./docs/reference/errors.md) |\n| **Ports** | | | |\n| `NuviCmsPorts` | Type | Complete port set | [ports](./docs/reference/ports.md) |\n| `HttpPort`, `StoragePort`, `LoggerPort`, etc. | Types | Individual port contracts | [ports](./docs/reference/ports.md) |\n| `AbortSignalLike` | Type | Cancellation signal | [ports](./docs/reference/ports.md) |\n| **Store Configuration** | | | |\n| `client.store.fetchConfig()` | Method | Fetch store/catalog config | [store-config](./docs/api/store-config.md) |\n| `client.store.trackFilterEvents()` | Method | Send filter/search telemetry | [filter-events](./docs/api/filter-events.md) |\n| `StoreConfig`, `StoreConfigPix` | Types | Store shape | [configuration](./docs/reference/configuration.md) |\n| **Coupons** | | | |\n| `client.coupons.validate(code, context?)` | Method | Validate a coupon code | [coupons](./docs/api/coupons.md) |\n| `CouponValidationResult`, `ValidatedCoupon` | Types | Result types | [coupons](./docs/api/coupons.md) |\n| **Customers** | | | |\n| `client.customers.getByClientRef(ref)` | Method | Look up customer by ref | [customers](./docs/api/customers.md) |\n| `client.customers.upsert(payload)` | Method | Create or update customer | [customers](./docs/api/customers.md) |\n| `CustomerData`, `CustomerAddress` | Types | Customer shape | [customers](./docs/api/customers.md) |\n| **Orders** | | | |\n| `client.orders.create(request)` | Method | Create an order | [orders](./docs/api/orders.md) |\n| `OrderRequest`, `OrderResponse` | Types | Order shape | [orders](./docs/api/orders.md) |\n| **Forms** | | | |\n| `client.forms.getBySlug(slug)` | Method | Fetch a form by slug | [forms](./docs/api/forms.md) |\n| `client.forms.submit(slug, values)` | Method | Submit form values | [forms](./docs/api/forms.md) |\n| `CmsForm`, `CmsFormField`, `CmsFormValues` | Types | Form shape | [forms](./docs/api/forms.md) |\n| `validateFieldValue`, `validateFormValues` | Functions | Client-side validation | [forms](./docs/api/forms.md) |\n| `FormValidationCode`, `FormValidationResult` | Types | Validation result | [forms](./docs/api/forms.md) |\n| **Pages** | | | |\n| `client.pages.getBySlug(slug, options?)` | Method | Fetch a page by slug | [pages](./docs/api/pages.md) |\n| `Page`, `PageSection`, `PageModule`, `PageModuleData` | Types | Page shape | [pages](./docs/api/pages.md) |\n| `PageSeo`, `PageFaqModuleData`, `PageFormModuleData`, ... | Types | Module and SEO types (15+ types) | [pages](./docs/api/pages.md) |\n| **SEO & Public Content** | | | |\n| `client.sitemap.get()` | Method | Fetch sitemap entries | [sitemap](./docs/api/sitemap.md) |\n| `client.robots.get()` | Method | Fetch robots.txt directives | [robots](./docs/api/robots.md) |\n| `client.website.get()` | Method | Fetch website configuration | [website](./docs/api/website.md) |\n| `SitemapEntry`, `Robots`, `RobotsUserAgentGroup` | Types | Sitemap and robots shape | [sitemap](./docs/api/sitemap.md), [robots](./docs/api/robots.md) |\n| `WebsiteInfo`, `WebsiteAddress`, `WebsiteIntegrations`, ... | Types | Website info structure (20+ types) | [website](./docs/api/website.md) |\n| **Pricing** | | | |\n| `calculateDiscounts(cart, rules)` | Function | Compute order discounts | [pricing](./docs/reference/pricing.md) |\n| `resolveProductScopeIds(cart)` | Function | Extract product IDs for coupon scope | [pricing](./docs/reference/pricing.md) |\n| `DiscountCartItem`, `DiscountResult` | Types | Discount shapes | [pricing](./docs/reference/pricing.md) |\n| **Blog & Posts** | | | |\n| `client.posts.list(params?)` | Method | Paginated post list, optionally filtered by category | [posts](./docs/api/posts.md) |\n| `client.posts.getBySlug(slug, options?)` | Method | Fetch a single post by slug | [posts](./docs/api/posts.md) |\n| `client.posts.submitComment(slug, input, options?)` | Method | Submit a comment on a post | [posts](./docs/api/posts.md) |\n| `client.blog.getFeedInventory(options?)` | Method | Fetch the blog's RSS/feed inventory | [blog](./docs/api/blog.md) |\n| `Post`, `GetPostsParams`, `SubmitPostCommentInput` | Types | Post shape and inputs | [posts](./docs/api/posts.md) |\n| **Catalog (Products)** | | | |\n| `client.products.list(params)` | Method | Paginated product card list | [products](./docs/api/products.md) |\n| `client.products.getBySlug(slug, options?)` | Method | Fetch a single product by slug | [products](./docs/api/products.md) |\n| `client.products.listReviews(slug, params)` | Method | Paginated product review list | [products](./docs/api/products.md) |\n| `client.products.submitReview(productId, payload, options?)` | Method | Submit a product review | [products](./docs/api/products.md) |\n| `client.productCategories.list(options?)` | Method | Fetch all product categories | [product-categories](./docs/api/product-categories.md) |\n| `Product`, `ProductCard`, `ProductReview`, `ProductCategory` | Types | Catalog shapes | [products](./docs/api/products.md), [product-categories](./docs/api/product-categories.md) |\n| **Galleries** | | | |\n| `client.galleries.photos()` | Method | Fetch all photo galleries | [galleries](./docs/api/galleries.md) |\n| `client.galleries.videos()` | Method | Fetch all video galleries | [galleries](./docs/api/galleries.md) |\n| `PhotoGallery`, `GalleryPhoto`, `VideoGallery`, `GalleryVideo` | Types | Gallery shapes | [galleries](./docs/api/galleries.md) |\n| **Institutional** | | | |\n| `client.institutional.faq()` | Method | Fetch all FAQ items | [institutional](./docs/api/institutional.md) |\n| `client.institutional.team()` | Method | Fetch all team members | [institutional](./docs/api/institutional.md) |\n| `client.institutional.testimonials()` | Method | Fetch all testimonials | [institutional](./docs/api/institutional.md) |\n| `FaqItem`, `TeamMember`, `Testimonial` | Types | Institutional content shapes | [institutional](./docs/api/institutional.md) |\n| **Section Catalog** | | | |\n| `client.sectionCatalog.list()` | Method | Fetch the available page-section descriptors | [section-catalog](./docs/api/section-catalog.md) |\n| `SectionCatalogEntry` | Type | Section descriptor shape | [section-catalog](./docs/api/section-catalog.md) |\n| **Events** | | | |\n| `client.events.trackCta(event, idempotencyKey?)` | Method | Track a CTA click/impression | [events](./docs/api/events.md) |\n| `client.events.trackPost(event, idempotencyKey?)` | Method | Track a post interaction | [events](./docs/api/events.md) |\n| `CtaEvent`, `PostEvent` | Types | Event shapes | [events](./docs/api/events.md) |\n| **Payments** | | | |\n| `client.payments.getPublicKey(websiteExternalId)` | Method | Fetch the payment provider's publishable key | [payments](./docs/api/payments.md) |\n| `PaymentsPublicKey` | Type | Public key shape | [payments](./docs/api/payments.md) |\n| **Customers (extended)** | | | |\n| `client.customers.getByExternalId(externalId)` | Method | Look up customer by external ID | [customers](./docs/api/customers.md) |\n| **Post Categories** | | | |\n| `buildPostCategoryTree(categories)` | Function | Organize flat categories into a tree | [content-types](./docs/reference/content-types.md) |\n| `CmsPostCategory`, `CmsPostCategoryNode` | Types | Category tree shapes | [content-types](./docs/reference/content-types.md) |\n| **Browser Utilities** | | | |\n| `cookieClientRefPort` | Object | Browser session cookie adapter | [ports](./docs/reference/ports.md) |\n| `ensureAnonCookie()` | Function | Create anon session if needed | [ports](./docs/reference/ports.md) |\n\n**Type-only entry point**: `./content` exports only types and has no runtime code. Safe to import in type-only contexts and unbundled in tree-shaking.\n\n## Resources and Endpoints\n\n| Facade Method | HTTP Method + Path | Retried | Requires Config | Documentation |\n|---------------|-------------------|---------|-----------------|---------------|\n| `store.fetchConfig()` | GET `/store-config` | Yes | No | [store-config](./docs/api/store-config.md) |\n| `store.trackFilterEvents(events)` | POST `/filter-events` | No | No | [filter-events](./docs/api/filter-events.md) |\n| `coupons.validate(code, context?)` | GET `/coupons/:code/validate` | Yes | No | [coupons](./docs/api/coupons.md) |\n| `customers.getByClientRef(ref)` | GET `/customers/:ref` | Yes | No | [customers](./docs/api/customers.md) |\n| `customers.upsert(payload)` | POST `/customers` | No | Yes | [customers](./docs/api/customers.md) |\n| `orders.create(request)` | POST `/orders` | No | Yes | [orders](./docs/api/orders.md) |\n| `forms.getBySlug(slug)` | GET `/forms/:slug` | Yes | No | [forms](./docs/api/forms.md) |\n| `forms.submit(slug, values)` | POST `/forms/:slug/submit` | No | Yes | [forms](./docs/api/forms.md) |\n| `pages.getBySlug(slug, options?)` | GET `/pages/:slug` | Yes | No | [pages](./docs/api/pages.md) |\n| `sitemap.get()` | GET `/sitemap` | Yes | No | [sitemap](./docs/api/sitemap.md) |\n| `robots.get()` | GET `/robots` | Yes | No | [robots](./docs/api/robots.md) |\n| `website.get()` | GET `/website` | Yes | No | [website](./docs/api/website.md) |\n| `posts.list(params?)` | GET `/posts` | Yes | No | [posts](./docs/api/posts.md) |\n| `posts.getBySlug(slug, options?)` | GET `/posts/:slug` | Yes | No | [posts](./docs/api/posts.md) |\n| `posts.submitComment(slug, input, options?)` | POST `/posts/:slug/comments` | No | Yes | [posts](./docs/api/posts.md) |\n| `blog.getFeedInventory(options?)` | GET `/blog/feed-inventory` | Yes | No | [blog](./docs/api/blog.md) |\n| `products.list(params)` | GET `/products` | Yes | No | [products](./docs/api/products.md) |\n| `products.getBySlug(slug, options?)` | GET `/products/:slug` | Yes | No | [products](./docs/api/products.md) |\n| `products.listReviews(slug, params)` | GET `/products/:slug/reviews` | Yes | No | [products](./docs/api/products.md) |\n| `products.submitReview(productId, payload, options?)` | POST `/products/:productId/reviews` | No | Yes | [products](./docs/api/products.md) |\n| `productCategories.list(options?)` | GET `/product-categories` | Yes | No | [product-categories](./docs/api/product-categories.md) |\n| `galleries.photos()` | GET `/galleries/photos` | Yes | No | [galleries](./docs/api/galleries.md) |\n| `galleries.videos()` | GET `/galleries/videos` | Yes | No | [galleries](./docs/api/galleries.md) |\n| `institutional.faq()` | GET `/faq` | Yes | No | [institutional](./docs/api/institutional.md) |\n| `institutional.team()` | GET `/team` | Yes | No | [institutional](./docs/api/institutional.md) |\n| `institutional.testimonials()` | GET `/testimonials` | Yes | No | [institutional](./docs/api/institutional.md) |\n| `sectionCatalog.list()` | GET `/section-catalog` | Yes | No | [section-catalog](./docs/api/section-catalog.md) |\n| `events.trackCta(event, idempotencyKey?)` | POST `/cta-events` | No | Yes | [events](./docs/api/events.md) |\n| `events.trackPost(event, idempotencyKey?)` | POST `/post-events` | No | Yes | [events](./docs/api/events.md) |\n| `payments.getPublicKey(websiteExternalId)` | GET `/websites/:id/payments/public-key` | Yes | No | [payments](./docs/api/payments.md) |\n| `customers.getByExternalId(externalId)` | GET `/customers/:externalId` | Yes | No | [customers](./docs/api/customers.md) |\n\n**Retry policy**: Only idempotent GETs are retried on transient failures. POST (state-changing) and telemetry calls are never retried. **Requires Config**: Mutations (`orders.create`, `customers.upsert`, `forms.submit`) throw `NuviCmsConfigError` if `apiBaseUrl` is missing; reads silently return null or skip the call. SEO endpoints (`sitemap.get()`, `robots.get()`, `website.get()`) are best-effort and return empty/null on failure without throwing.\n\n## Error Handling\n\nAll errors inherit from `NuviCmsError` and can be caught with `instanceof`:\n\n```ts\nimport {\n  NuviCmsError,\n  NuviCmsHttpError,\n  NuviCmsConfigError,\n} from \"@astrotech-sh/nuvicms-api-sdk\";\n\ntry {\n  const order = await client.orders.create(request);\n} catch (error) {\n  if (error instanceof NuviCmsConfigError) {\n    // Client not configured; silent for reads, loud for mutations\n    console.error(\"Orders require apiBaseUrl\");\n  } else if (error instanceof NuviCmsHttpError) {\n    // Non-2xx response\n    console.error(`API error ${error.status}:`, error.body);\n  } else if (error instanceof NuviCmsError) {\n    // Other SDK error (transport, parse, envelope)\n    console.error(\"SDK error:\", error.message);\n  }\n}\n```\n\nSee [Error Handling](./docs/reference/errors.md) for the complete hierarchy and contract.\n\n## Testing with Fake Ports\n\nInject fake I/O adapters in tests:\n\n```ts\nimport { createNuviCmsClient } from \"@astrotech-sh/nuvicms-api-sdk\";\n\nconst fakeHttp = {\n  async send(request) {\n    if (request.path.includes(\"/store-config\")) {\n      return {\n        status: 200,\n        body: JSON.stringify({\n          status: \"success\",\n          data: { currency: \"BRL\", methods: [\"pix\"] },\n        }),\n      };\n    }\n    return { status: 404, body: \"Not found\" };\n  },\n};\n\nconst client = createNuviCmsClient(\n  { apiBaseUrl: \"https://api.test\", siteKey: \"test-key\" },\n  { http: fakeHttp } // Override the HTTP port\n);\n\nconst config = await client.store.fetchConfig();\n// config is { currency: \"BRL\", methods: [\"pix\"] }\n```\n\nSee [Ports](./docs/reference/ports.md) for the full port interface and [Testing](./docs/getting-started.md#testing) for browser vs. Node patterns.\n\n## Architecture\n\n```\ncreateNuviCmsClient(config, ports)\n  |\n  +-- client.ts (facade)\n       |\n       +-- resources/*.ts (store, coupons, customers, orders, forms)\n            |\n            +-- transport/request.ts:sendRequest() [single HTTP call site]\n                 |\n                 +-- ports/http.ts (injected; default: adapters/browser.ts)\n                 +-- mappers/*.ts (pure raw -> domain translation)\n```\n\nThe client is shaped as a facade over per-resource modules. Every network call funnels through a single HTTP port, which by default uses `fetch`. Config is resolved once at construction and never re-read. Every side-effecting capability (`fetch`, `sessionStorage`, `document`, `crypto`, cookies) lives in `adapters/browser.ts` — the only place ambient DOM/runtime globals are allowed. Tests or non-browser contexts inject their own I/O ports.\n\nThe read/telemetry asymmetry is intentional: `store.fetchConfig()` and `trackFilterEvents()` silently no-op and return `{ kind: \"skipped\" }` if `apiBaseUrl` is missing; mutations (`orders.create`, `customers.upsert`, `forms.submit`) throw `NuviCmsConfigError` instead. A dropped read is recoverable; a dropped order or customer record is not.\n\n## Development\n\nInstall dependencies, build, and test:\n\n```bash\nnpm install\nnpm run build   # TypeScript compilation (tsconfig.build.json)\nnpm test        # Vitest\n```\n\n## Architecture Invariants\n\nThree invariants are enforced by boundary tests (`src/tests/boundary.test.ts` and `src/tests/dom-free.node.test.ts`):\n\n- **No outbound imports**: No file under `src/` imports outside `src/`.\n- **No ambient globals outside adapters**: No `fetch`, `sessionStorage`, `document`, `console`, `crypto`, or other DOM/Node globals outside `src/adapters/` and test files.\n- **Zero runtime dependencies**: The SDK has no production npm dependencies; only dev dependencies (TypeScript, Vitest).\n\n## Documentation\n\n- **[Getting Started](./docs/getting-started.md)** — Install, configure, and walk through a real flow\n- **[Architecture](./docs/architecture.md)** — Hexagonal design, layers, and invariants\n- **[API Reference](./docs/api/)** — Per-resource endpoint documentation\n- **[Configuration Reference](./docs/reference/configuration.md)** — Config options and normalization\n- **[Error Reference](./docs/reference/errors.md)** — Error hierarchy and handling\n- **[Ports Reference](./docs/reference/ports.md)** — I/O port contracts and browser adapters\n- **[LLM Context](./docs/llm-context.md)** — Dense, self-contained reference for LLM/agent ingestion\n","readmeFilename":"README.md"}