{"_id":"@bacano/sdk","_rev":"15-8a93ec410a979a9ae6c2bfacdb4ebab3","name":"@bacano/sdk","dist-tags":{"latest":"1.2.2"},"versions":{"1.0.0":{"name":"@bacano/sdk","version":"1.0.0","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.0.0","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/pulpo-labs/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/pulpo-labs/erp/issues"},"dist":{"shasum":"8a8ccbc13f892bba38da52bb4650cb3e4c8303d8","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.0.0.tgz","fileCount":32,"integrity":"sha512-3JHI/WyGr32G3lWNUuoFqEkYswUJwEtW7osSt95GtuyzJ1XOoDJCAIqHG7A+I8zujU7cYTLzbEEb9ae6DpgeCw==","signatures":[{"sig":"MEYCIQCnq6isiPZnm0S0l5ar1E7DF6fmJd0eVwO0jghO05dGPAIhAL7Od7MEHm+1yTq3sC0yRwc8KzpsZmV9FzX/THNE4Xcf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":825928},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"}},"gitHead":"780d63e8d64b8dc0c6a1b585834ecde8f1bf99b8","_npmUser":{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"},"repository":{"url":"git+https://github.com/pulpo-labs/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.12.1","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.0_1785700808704_0.5289575419443624","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@bacano/sdk","version":"1.0.1","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.0.1","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/pulpo-labs/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/pulpo-labs/erp/issues"},"dist":{"shasum":"9a19ce0a4a64e5bd543441f9e6b8db420580f3d1","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.0.1.tgz","fileCount":32,"integrity":"sha512-OdSDGULWe7SdvfRPAp9MNF56IPTaixZKZGFidhzakzRYgIS2hbHPihrfugGoHzZN7vyS3BA19BoMC4OM4enjtg==","signatures":[{"sig":"MEYCIQCkLyEDwoTjG0pMtgTEjBlum1oi1wjgzUGw2CFSg6zsLgIhALUPBon2kG/B1KZOTIh4gC4S0T5r0KRCFG2h1QkCMOZP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":825928},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"}},"gitHead":"ce32fe8a2c5b822fb196b7e8773eea94fb5a06f6","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a4d9d201-395a-471d-80d8-82cc4806ff31"}},"repository":{"url":"git+https://github.com/pulpo-labs/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.16.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.0.1_1785701856658_0.9740211067968827","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@bacano/sdk","version":"1.1.0","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.0","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs"},"dist":{"shasum":"7c4e7582460820dd4b04be4c0bc4681d8fd6bbbd","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.0.tgz","fileCount":72,"integrity":"sha512-I5nrIthXyD0hwceml86Rq/yhgYiNVuRHIofOO4s8PPXAf6zBbSjz53covJGwlgV0gZ1+dMch0QaBDbCGr+cAFQ==","signatures":[{"sig":"MEUCIQDUYvQHfGid8hdHjnBTJ9z40EoyNb/Hn53UYOTb21I0zwIgOXd6f2PUi6hN5c4VcggTEU9Y/2xPt8K54lvxUGrwNEc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1232711},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"}},"gitHead":"4cb3e7e3b1882027d2c4ed5ac087f11e3b64b03e","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.0_1786882805295_0.25137747517653186","host":"s3://npm-registry-packages-npm-production"}},"1.1.8":{"name":"@bacano/sdk","version":"1.1.8","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.8","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs"},"dist":{"shasum":"01c664bb39ed6cc8b2ab191c09394a37e86429af","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.8.tgz","fileCount":76,"integrity":"sha512-q1CCbiCXCvAWcx1PopFBT5tIXXewHqOYk7TFrtIxPDNesWjphsaL0x9WBUr+jcDHEeyDPyH6Qu/Oit49rvup5Q==","signatures":[{"sig":"MEUCIQDHoOmawLpYMZvl5+2fH74JlxMj3s8wfOzteBArHI7qegIgetGb6mAFBElAJRDydDz6RKHkWf2lViucP26b//cmM+Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1335604},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"}},"gitHead":"e082e1e3c915f1e9ca5d2af7f120b20d5681bc15","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.8_1787581403014_0.8772186447491377","host":"s3://npm-registry-packages-npm-production"}},"1.1.9":{"name":"@bacano/sdk","version":"1.1.9","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.9","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs"},"dist":{"shasum":"8b0d95aa45ccc7d2a0c39d7931aea9661f12b172","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.9.tgz","fileCount":76,"integrity":"sha512-lGSWA8Q39DYQcMk8oE+ZT/rv0QlSjv6PX11Q7bORoGZr0+TLdKEFbGLw2ui88c6gSmbD+vN5litwJDdo5i85LQ==","signatures":[{"sig":"MEUCIQCS3r0o9lRW/mKbqe/bnSvjjGOGaXjgZYICJsImRUdhQAIgBuYtvG85jiEKATw8WfG64vGC2YkpD7ShzE+Ry0Yn0OQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1335604},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"}},"gitHead":"e082e1e3c915f1e9ca5d2af7f120b20d5681bc15","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.9_1787585247845_0.30541514344166143","host":"s3://npm-registry-packages-npm-production"}},"1.1.10":{"name":"@bacano/sdk","version":"1.1.10","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.10","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"e210b6e1fa9db45ab1b72308cf5d9be524cea25c","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.10.tgz","fileCount":87,"integrity":"sha512-rgJwaAEVt3GLNe4vIoeEZrKeDLNySlYdAX7iKRPBB7nZbyZUTy+RjRJu3IvQsdqI9Sts7qU2TEUd65uROerIjw==","signatures":[{"sig":"MEUCIEe1x1G8zh7AqIVRbn0xMWgt0xTJzmbCQBSEXUfe2+0WAiEAurcPJ7AjLKvqgZTaUtXYqey3z4dUrXBOtbdB9OgKpI4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1375634},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"}},"gitHead":"36dff103ecbf41e29f309bd241679784d913c7fa","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.10_1787664667040_0.03930748469505674","host":"s3://npm-registry-packages-npm-production"}},"1.1.12":{"name":"@bacano/sdk","version":"1.1.12","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.12","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"d1b798e81b9f988593a63cb12b779e111b172221","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.12.tgz","fileCount":91,"integrity":"sha512-zZcEPtIXI42QLP4xc1HdQ6+eFxEpSD++bMuAXhbg762U8Nzn/yIurL6wGHFxC2/WvOPk9QBryqknikpB1zGyKQ==","signatures":[{"sig":"MEYCIQCeCsxWemBVWH/kJlNzlZueOFu1UlvK6evhFgyZh/vlSAIhAOeGFiN/d8fRe7CecuOJNS7zZA4U27uvet9GFFYpfm3b","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1397119},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"167e155e98671105797a6c9d0f172528bc1a3941","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.12_1787704076182_0.9938881426505233","host":"s3://npm-registry-packages-npm-production"}},"1.1.13":{"name":"@bacano/sdk","version":"1.1.13","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.13","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"a09e336fbc5a5e197e23000fec46119c699c6cf0","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.13.tgz","fileCount":93,"integrity":"sha512-u8xQX1HBv2VhDltUYhQZihNGpRd4ATjKlhJBiLpkoSz216FhC86U2taD0yvh1wYdLiO6KD8ke2rp5mDgtmUOnw==","signatures":[{"sig":"MEUCIQC6o6Ih9UL300w+zEK429YdHWXRJsSqdQqM3diiNY1gVQIgVJ8z9xqP/20S7cos+9Z1AaQVZeADXUt7I8TnlEuQ+WU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1423434},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"d9896245823ea378c84030b77c9392ed93f7009f","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.13_1787764533971_0.8782319675659687","host":"s3://npm-registry-packages-npm-production"}},"1.1.15":{"name":"@bacano/sdk","version":"1.1.15","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.15","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"a1a12d1e3b0c3b33e15d1d5525be3ad0d09fca0c","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.15.tgz","fileCount":94,"integrity":"sha512-UirhY/69AnZHCDWmHLgQGC0HQRl50w4DBGACjOEkY+PWG+BtaSvpOHbBwPkBlWnRTFzUifO/V8jaoXakc+p42Q==","signatures":[{"sig":"MEUCIQCktfdIF3Ij4pnj4qB0TtjUL2LNgCSNixVLROAxi9k2vgIgXCQoRbG3dpdm3nZQY52nwUAEk6EJ4/hc6Kfz6YIcOPg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1432504},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"91f1cddfb39218d733b8cdace294ea00b08390c6","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.15_1787781165491_0.730086841791082","host":"s3://npm-registry-packages-npm-production"}},"1.1.17":{"name":"@bacano/sdk","version":"1.1.17","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.17","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"71278dadf3bce4661c6cf3a876a1582492828f2e","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.17.tgz","fileCount":101,"integrity":"sha512-UrPdGXZupxtSoGOpD5I9kMfBMpReGobquMXV5g16G+3XVOGewzhNjYblLaZIY5eUkcosq+cdSE+6loLAb3MLnw==","signatures":[{"sig":"MEYCIQDJgAgaE095agRU7FzeDA71QkGoOkpbbUYFSwGHzbHN9gIhAKRk7bNEN9YWo78CSUsx/taVPGVmbjajTKJh7BNq9AM+","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1503853},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/forms":{"types":"./react/forms.d.ts","import":"./react/forms.js","require":"./react/forms.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"650b142ab857010c0c48982e2a027f71dd69e8ef","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.17_1787868450949_0.6171776627132681","host":"s3://npm-registry-packages-npm-production"}},"1.1.18":{"name":"@bacano/sdk","version":"1.1.18","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.18","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"39262c3ace5da3b706128e3c10ac79e8e801034d","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.18.tgz","fileCount":103,"integrity":"sha512-QRH4P/QlcnHGsP/LLrEhZdxSs6wn8hfADk1MObtLhEWHnZyd2vFpGiPuPYSvpoms/HnhqBjmAsTLKicsrecJWA==","signatures":[{"sig":"MEYCIQDsefKC8wR+EpZq7IKr2uhWIPYUgT2VWyDGNUYSbKRhuAIhAKiVAdvdrxQ8Myj0XDeu2iYXwcArYMLj6xUQwoUME8X4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1519639},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/forms":{"types":"./react/forms.d.ts","import":"./react/forms.js","require":"./react/forms.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"1ea3bcebbca0c36e6579c255167468d8715f6873","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.17.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.18_1788375087905_0.45728580498677074","host":"s3://npm-registry-packages-npm-production"}},"1.1.19":{"name":"@bacano/sdk","version":"1.1.19","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.19","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"d8b519d24c419be1c966e9099f3f209bf8115176","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.19.tgz","fileCount":105,"integrity":"sha512-DKox4R2nJsQxuC248JVC6dTSpxu7UE8TzvrL3tXqWyaBpe8wIgaRzYHoDNh/bUmQVki64O9ROwh1Zagy/9uJ2g==","signatures":[{"sig":"MEQCIDFY15cjVKyLswcLkAXmhkxjJF4wmiI0kQdjLQ1+6PdvAiAW8z88om1uqT6vhaWtb7WmlOzGPvfqVxYSBIb4axbYLw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1530466},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/forms":{"types":"./react/forms.d.ts","import":"./react/forms.js","require":"./react/forms.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"fd9943f85dae60ce3db0abd9a7cec6aa20937111","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.19.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.19_1788867399727_0.06143036577634842","host":"s3://npm-registry-packages-npm-production"}},"1.1.20":{"name":"@bacano/sdk","version":"1.1.20","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.1.20","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"a34496992718f5603640b23ca7eaee774f46906b","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.1.20.tgz","fileCount":105,"integrity":"sha512-sGUTaS/U+xuS8dlHgMcFR9E6GRGA04FvxEcmV2xOf54Dh42eWv2fuHtZ6kdWgnbju5D1yl3OAlNSCD02Uh0UIQ==","signatures":[{"sig":"MEYCIQCgfqIixQmhxcMjhhvjesPao6CoPJjLxtSeRFkQTxuXjwIhAMp19mSxhGhM1QvTJQc0JGNMNhWKGcoEJT4ps8wSAKH8","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1533186},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/forms":{"types":"./react/forms.d.ts","import":"./react/forms.js","require":"./react/forms.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"ef207746bcd52c37bf16cc92963e35f7669841b8","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.19.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.1.20_1788901651706_0.45452756107925807","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@bacano/sdk","version":"1.2.1","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"license":"MIT","_id":"@bacano/sdk@1.2.1","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"dist":{"shasum":"9267eba6e16784e78cfed44ce3dea5d67ad86750","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.2.1.tgz","fileCount":112,"integrity":"sha512-c476dx7OWOKRKJ0pxD7KBcenlgF+zvzvSGrLDQb4M/DyNMM1jcZh2gVR4u0DQQNOtUaOiqek7KfxQAIXC10Z+A==","signatures":[{"sig":"MEQCIFyPXjw/gg1047iDTlN9X/0SuunVp0beh8b8yuzyEY+rAiAC0YJK5vyrtVLmrC2lTPwmJF8gAVGNqTfuNa4ZcX/v4w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1587770},"main":"./index.cjs","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/forms":{"types":"./react/forms.d.ts","import":"./react/forms.js","require":"./react/forms.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"dd8f7548b851fff905cdf162215fa13addb28e48","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.19.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/sdk_1.2.1_1788920770531_0.17323279832019844","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"_id":"@bacano/sdk@1.2.2","bin":{"bacano-web":"skills/bacano-web/scripts/cli.mjs","bacano-figma-web":"skills/bacano-figma-web/scripts/cli.mjs"},"bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"dist":{"shasum":"2e713bdf0394f05fb06169480c4b012680e663af","tarball":"https://registry.npmjs.org/@bacano/sdk/-/sdk-1.2.2.tgz","fileCount":113,"integrity":"sha512-urOMO8OwnP1cuyaRMQUPMwUL1KjaIf+yeZBTVZPUjJODP1Wdu3NbNmYYkIvFISiEsMQJ5yOdsIsMAPoNos2HDQ==","signatures":[{"sig":"MEQCIEvriAf+ClMaDTLHea+37xTwDZ+bsAz/Wb6t0i7ihmM7AiBf9okkQ97eDX8A6+TafldY+qHN7qYdAEPymjKb75TrkA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIE6CRx/I+kdk9OLgwjdFvWL9k1N0glJiB+s+CJOyl5c1AiA4cPy8Q/Pd7yryz2kVoNssWuCy9WyHg3St+zKHdnUi9w=="}],"unpackedSize":1603174},"main":"./index.cjs","name":"@bacano/sdk","types":"./index.d.ts","module":"./index.js","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.cjs"},"./react":{"types":"./react.d.ts","import":"./react.js","require":"./react.cjs"},"./graphql":{"types":"./graphql.d.ts","import":"./graphql.js","require":"./graphql.cjs"},"./react/forms":{"types":"./react/forms.d.ts","import":"./react/forms.js","require":"./react/forms.cjs"},"./react/preview":{"types":"./react/preview.d.ts","import":"./react/preview.js","require":"./react/preview.cjs"},"./content-management":{"types":"./content-management.d.ts","import":"./content-management.js","require":"./content-management.cjs"}},"gitHead":"28ae84a29dac1a1cad427961a02a6542891e0644","license":"MIT","scripts":{"postinstall":"node ./skills/bacano-web/scripts/postinstall.mjs"},"version":"1.2.2","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3655e203-62d7-4491-b42e-ba3491d53561"}},"homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"_npmVersion":"11.19.0","description":"TypeScript SDK for building websites on the Bacano ERP","directories":{},"maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"sideEffects":false,"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"react":">=18.0.0"},"peerDependenciesMeta":{"react":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_1.2.2_1789418755313_0.927320115200639"}}},"time":{"created":"2026-08-02T20:00:08.515Z","modified":"2026-09-14T20:45:55.595Z","1.0.0":"2026-08-02T20:00:08.902Z","1.0.1":"2026-08-02T20:17:36.842Z","1.1.0":"2026-08-16T12:20:05.463Z","1.1.8":"2026-08-24T14:23:23.225Z","1.1.9":"2026-08-24T15:27:27.970Z","1.1.10":"2026-08-25T13:31:07.179Z","1.1.12":"2026-08-26T00:27:56.331Z","1.1.13":"2026-08-26T17:15:34.174Z","1.1.15":"2026-08-26T21:52:45.646Z","1.1.17":"2026-08-27T22:07:31.101Z","1.1.18":"2026-09-02T18:51:28.097Z","1.1.19":"2026-09-08T11:36:39.900Z","1.1.20":"2026-09-08T21:07:31.857Z","1.2.1":"2026-09-09T02:26:10.701Z","1.2.2":"2026-09-14T20:45:55.404Z"},"bugs":{"url":"https://github.com/bacano-erp/erp/issues"},"license":"MIT","homepage":"https://github.com/bacano-erp/erp/tree/main/libs/sdk#readme","keywords":["bacano","erp","website","sdk","graphql","ecommerce"],"repository":{"url":"git+https://github.com/bacano-erp/erp.git","type":"git","directory":"libs/sdk"},"description":"TypeScript SDK for building websites on the Bacano ERP","maintainers":[{"name":"tibiritabara","email":"ricardo.santos.diaz@gmail.com"}],"readme":"# @bacano/sdk\n\nTypeScript SDK for building e-commerce websites on the Bacano ERP. Zero runtime dependencies, optional React hooks, and full type safety.\n\nBuyer credentials are owned by each storefront's Clerk application. Read\n[`AUTHENTICATION.md`](./AUTHENTICATION.md) before implementing registration,\nsign-in, customer profiles, authenticated checkout, or order history. The guide\nships inside the npm package.\n\n## Installation\n\n```bash\nnpm install @bacano/sdk\n```\n\n```bash\npnpm add @bacano/sdk\n```\n\nReact hooks are available from `@bacano/sdk/react` and require `react >= 18`\nas a peer dependency. The core client has no runtime dependencies and works\nwithout React.\n\n### Gestión de Content y formularios para agentes\n\nUn agente autorizado puede consultar y mantener tipos, componentes, grupos,\nlistas de opciones, entradas y formularios con el entrypoint administrativo\n`@bacano/sdk/content-management`. Cada capacidad exige un scope explícito. El\nacceso se genera temporalmente desde Bacano, está limitado a una empresa y\nnunca debe incluirse en el storefront:\n\n```ts\nimport { createContentManagementClient } from \"@bacano/sdk/content-management\";\n```\n\nLee [`CONTENT_TYPE_MANAGEMENT.md`](./CONTENT_TYPE_MANAGEMENT.md) antes de usarlo.\nLa guía contiene el flujo de autorización, contratos de campos, entradas y\nmedia, estados, referencias, cambios destructivos y límites de seguridad. Con\nel scope `content_media:upload`, un agente puede buscar imágenes existentes y\ncargar JPEG, PNG o WebP mediante el contrato oficial; Bacano valida los bytes,\nnormaliza a WebP y registra el resultado en la biblioteca de la empresa.\n\n### Auditoría del storefront\n\nEl SDK incluye la skill oficial `bacano-web`. Instalarla al iniciar un\nstorefront y ejecutarla antes de publicar o después de un cambio relevante del\nSDK, hosting, autenticación, pagos o medición:\n\n```bash\npnpm add @bacano/sdk\npnpm exec bacano-web install --agent all\npnpm exec bacano-web check\n```\n\nDespués invocarla desde el agente elegido:\n\n- Codex: `$bacano-web`\n- Claude Code: `/bacano-web`\n- Antigravity: solicitar una auditoría Bacano Web o elegirla desde `/skills`\n\n`install` solo instala una copia canónica de la skill y sus enlaces de\ndescubrimiento. `check` confirma que está vigente. Ninguno ejecuta la auditoría,\nmodifica el storefront ni despliega; esa revisión comienza únicamente cuando\nel usuario o agente invoca la skill.\n\n### Implementación desde Figma\n\nEl SDK también incluye `bacano-figma-web`, la skill oficial para convertir un\ndiseño Figma en una web informativa, tienda o sitio híbrido que conserve el\ncascarón, Static First y contratos públicos de Bacano:\n\n```bash\npnpm exec bacano-figma-web install --agent all\npnpm exec bacano-figma-web check\npnpm exec bacano-figma-web doctor\n```\n\nDespués invocarla como `$bacano-figma-web` en Codex, `/bacano-figma-web` en\nClaude Code o solicitar “usar Bacano Figma Web” en Antigravity. La skill guía la\nconexión al MCP remoto oficial, MCP local oficial de Figma Desktop, Desktop\nBridge comunitario o REST autorizado. Prefiere siempre el MCP oficial y nunca\nguarda ni imprime tokens.\n\n`doctor` comprueba instalación, endpoint local, puertos del bridge y solamente\nla presencia del token REST. El OAuth del MCP remoto debe confirmarse dentro del\nagente con las herramientas de Figma. La extracción se conserva como snapshot\nnormalizado. Cuando el equipo de Content y desarrollo trabajan en tiempos\ndistintos, la skill genera un blueprint de entrega y permite fixtures locales\ncon el mismo contrato de los componentes. Con autorización temporal y scopes\nexplícitos, puede crear o ajustar tipos, componentes, grupos, listas y entradas\nmediante el entrypoint administrativo oficial. Las entradas nacen en borrador;\npublicar exige permiso y aprobación humana. Un fixture activo en producción\nbloquea la aprobación del sitio.\n\nEl snapshot puede validarse con:\n\n```bash\npnpm exec bacano-figma-web validate-snapshot .bacano/designs/<proyecto>/manifest.json\n```\n\nLas instrucciones completas viajan dentro de\n`skills/bacano-figma-web/references/`; no es necesario copiar documentación ni\ncrear integraciones particulares en cada storefront.\n\nEvery storefront must follow [`STOREFRONT_MARKETING.md`](./STOREFRONT_MARKETING.md)\nwhen instrumenting analytics, advertising signals, contact actions, ecommerce\nevents, attribution, or preview behavior. It is the canonical implementation\ncontract for storefront agents and ships inside the npm package.\n\nCommercial forms and newsletter subscriptions must follow\n[`STOREFRONT_LEADS.md`](./STOREFRONT_LEADS.md). Storefronts own the form UI;\nBacano owns consent evidence, identity resolution, attribution and idempotent\nlead capture through the SDK.\n\nWebsite forms defined and published from Bacano use the additive contract in\n[`STOREFRONT_FORMS.md`](./STOREFRONT_FORMS.md). Storefronts can mount the\nofficial `BacanoForm` renderer or consume the same typed definition through\n`useBacanoForm()` without GraphQL, HTML stored in the database or a rebuild\nafter each publication.\n\nEvery visible region sourced from a Bacano `ContentEntry` must expose the\nentry-level marker defined in\n[`STOREFRONT_CONTENT_LOCATOR.md`](./STOREFRONT_CONTENT_LOCATOR.md). Use\n`getContentEntryLocatorAttributes(entry)` on the outer section or card so an\nauthorized internal browser tool can show the entry name and open its Bacano\neditor. This contract identifies entries only; it does not expose field-level\nediting or grant backoffice access.\n\nStatic and hybrid stores must also follow\n[`STOREFRONT_PERFORMANCE.md`](./STOREFRONT_PERFORMANCE.md). It defines the\nofficial build bootstrap, live-state refresh, responsive media and request\nownership rules. It also documents the shared public-config bootstrap, deferred\nmarketing scripts and route-scoped authentication required for fast public\ncatalog pages.\n\nStorefronts that can be hidden temporarily must mount the runtime gate defined\nin [`STOREFRONT_CONSTRUCTION.md`](./STOREFRONT_CONSTRUCTION.md). It supports\nstatic SiteGround exports without rebuilding, responsive Bacano media and\nsigned temporary preview links.\n\nProduct detail pages and technical catalog filters must follow\n[`STOREFRONT_PRODUCT_SPECIFICATIONS.md`](./STOREFRONT_PRODUCT_SPECIFICATIONS.md).\n\nQuantity-based web pricing is documented in\n[`STOREFRONT_VOLUME_PRICING.md`](./STOREFRONT_VOLUME_PRICING.md). Bacano owns\nthe authoritative basket calculation; storefronts only render the effective\nprices and tier progress returned by the cart API.\nIt documents the additive specification contract, static publication and the\nstrict separation from commercial attributes and variants.\n\n#### Instalación y alcance de la skill\n\nEl paquete incluye `skills/bacano-web`, una skill portátil para que un agente\naudite el repositorio, build y dominio antes de producción. Primero confirma si\nel proyecto es una **web informativa** o una **tienda virtual** y aplica un\nchecklist distinto; no exige carrito, checkout o pagos a un sitio informativo.\n\nUbicaciones del proyecto después de instalar la skill:\n\n| Agente      | Ruta de descubrimiento      | Invocación                    |\n| ----------- | --------------------------- | ----------------------------- |\n| Codex       | `.codex/skills/bacano-web`  | `$bacano-web`                 |\n| Claude Code | `.claude/skills/bacano-web` | `/bacano-web`                 |\n| Antigravity | `.agents/skills/bacano-web` | Solicitud natural o `/skills` |\n\nPara instalarla solo para un agente puede indicarse explícitamente:\n\n```bash\npnpm exec bacano-web install --agent antigravity\n```\n\nTambién puede ejecutarse sin `--agent`; en una terminal interactiva pregunta si\nse usará Antigravity, Claude Code, Codex o todos. Mantiene una sola copia física\nen `.agents/skills/bacano-web` y crea enlaces de descubrimiento para los otros\nagentes seleccionados.\n\n```bash\npnpm exec bacano-web check\n```\n\nEl paquete incluye un aviso `postinstall` como ayuda adicional, aunque algunos\ngestores pueden ocultar su salida. El aviso nunca modifica el repositorio y\npuede desactivarse en entornos controlados con\n`BACANO_SDK_HIDE_SKILL_NOTICE=1`.\n\nLa skill realiza auditorías de solo lectura por defecto. Primero detecta las\ncapacidades realmente activas y separa gates de publicación (`P0`), calidad\nprofesional (`P1`) y mejoras (`P2`), para no bloquear una web por funciones\napagadas. Sus informes usan estados claros con emojis: `✅ APROBADO`,\n`⚠️ ADVERTENCIA`, `❌ FALLÓ`, `➖ NO APLICA` y `🧪 NO VERIFICADO`.\n\nAdemás audita explícitamente la arquitectura **Static First** y la vista previa\noficial. El informe incluye una sección “Arquitectura SDK y tráfico runtime” con\ninstancias del cliente/provider, operaciones GraphQL observadas, duplicados,\ndatos estáticos, actualizaciones vivas y evidencia de `noindex`, sitemap y cero\nmarketing en preview. Cuando no puede capturar un trace real, lo declara como\n`🧪 NO VERIFICADO` en lugar de asumirlo desde el código.\n\n### Entry points\n\n| Import                      | Contents                                              |\n| --------------------------- | ----------------------------------------------------- |\n| `@bacano/sdk`               | Core client, catalog, cart, checkout, orders, profile |\n| `@bacano/sdk/react`         | `BacanoProvider` and React hooks                      |\n| `@bacano/sdk/react/preview` | Optional live preview controller and toolbar          |\n| `@bacano/sdk/graphql`       | Raw GraphQL documents, for advanced use               |\n\n---\n\n## Live Content Preview\n\nStatic storefronts can show current published Bacano Content without rebuilding\ntheir public pages. Import the isolated preview entrypoint only from the\nstorefront preview route:\n\n```tsx\nimport { BacanoPreviewShell } from \"@bacano/sdk/react/preview\";\n```\n\nThe public storefront remains static. Preview V1 never exposes drafts and\nautomatically disables the SDK marketing runtime inside its tree. See\n[`STOREFRONT_PREVIEW.md`](./STOREFRONT_PREVIEW.md), the canonical contract for\nprovider hierarchy, responsibilities, security, agent checklist, and the\nvalidated reference implementation.\n\n---\n\n## Quick Start\n\n### 1. Create a Website in Bacano\n\nBefore using the SDK, an active website must exist in Bacano. Create it from\nthe **Websites** section of the Bacano platform, or ask your Bacano contact to\nset one up.\n\nRequired fields:\n\n- **Name**: display name.\n- **Slug**: SDK identifier, for example `my-store`.\n- **Branch / chain**: required for stock availability and cart creation.\n- **Domain**: optional custom domain, without `https://`.\n- **Advanced config**: optional JSON object consumed by the external web.\n\nThe branch matters: `checkAvailability()` and checkout/cart sync actions need a\n`chain_id`. A website without a branch can be resolved, but shopping actions\nwill fail with `NO_CHAIN`.\n\n### 2. Initialize the Client\n\n```typescript\nimport { createBacanoClient } from \"@bacano/sdk\";\n\nconst client = createBacanoClient({\n  apiUrl: \"https://api.bacanoerp.com\",\n  websiteSlug: \"my-store\",\n});\n\n// Must be called once — resolves the website context.\nawait client.init();\n```\n\nNext.js example:\n\n```env\nNEXT_PUBLIC_BACANO_API_URL=https://api.bacanoerp.com\nNEXT_PUBLIC_BACANO_WEBSITE_SLUG=my-store\n```\n\n```typescript\nconst client = createBacanoClient({\n  apiUrl: process.env.NEXT_PUBLIC_BACANO_API_URL!,\n  websiteSlug: process.env.NEXT_PUBLIC_BACANO_WEBSITE_SLUG!,\n  tokenStorage: \"memory\",\n});\n\nawait client.init();\n```\n\n### 3. Browse Products (No Auth Required)\n\n`catalog.getProducts()` only returns products that are active, enabled for the\nwebsite branch, have a valid `CLIENT` price and have available\ninventory in one of the inventory sources configured for the website. Websites\nwithout custom sources continue using the branch's default warehouse.\n\n```typescript\n// List products\nconst products = await client.catalog.getProducts({ limit: 10 });\n\n// Search across product names, descriptions, brands, and attributes\n// Results are ranked by relevance when no explicit sortBy is set\nconst results = await client.catalog.getProducts({ search: \"cotton\" });\n\n// Search suggestions (lightweight autocomplete)\nconst suggestions = await client.catalog.getSearchSuggestions({\n  query: \"shi\",\n  limit: 5,\n});\n// → [{ type: 'product', text: 'Shirt', id: '...' }, { type: 'brand', text: 'Shimano', id: '...' }]\n\n// Filter by category\nconst clothing = await client.catalog.getProducts({ categoryName: \"CLOTHES\" });\n\n// Filter by price range\nconst affordable = await client.catalog.getProducts({\n  minPrice: 10,\n  maxPrice: 50,\n});\n\n// In-stock only. This is already the website default, kept for UI clarity.\nconst available = await client.catalog.getProducts({ inStock: true });\n\n// Filter by color\nconst redItems = await client.catalog.getProducts({\n  colors: [\"Red\", \"Burgundy\"],\n});\n\n// Filter by reusable content/catalog tags\nconst babyGirl = await client.catalog.getProducts({\n  tags: [\"bebe-nina\"],\n});\n\n// Filter by dynamic attributes (category-specific)\nconst mediumCotton = await client.catalog.getProducts({\n  categoryName: \"CLOTHES\",\n  attributes: { Size: [\"M\"], Material: [\"Cotton\"] },\n});\n\n// Sort products\nconst newest = await client.catalog.getProducts({ sortBy: \"newest\" });\nconst cheapest = await client.catalog.getProducts({ sortBy: \"price_asc\" });\n\n// Combine multiple filters\nconst filtered = await client.catalog.getProducts({\n  categoryName: \"CLOTHES\",\n  colors: [\"Red\"],\n  minPrice: 20,\n  inStock: true,\n  sortBy: \"price_asc\",\n  limit: 20,\n});\n\n// Single product\nconst product = await client.catalog.getProduct(\"product-uuid\");\n\n// Static builds: fetch the complete sellable catalog and its first renderable\n// catalog page. This is the canonical source for initial HTML, routes,\n// metadata, sitemap and product page data.\nconst bootstrap = await client.catalog.getStaticCatalogBootstrap({\n  categoryListKey: \"categorias-web\",\n  attributeListKey: \"atributos\",\n  pageSize: 100,\n  initialPageSize: 24,\n  maxProducts: 10_000,\n  sortBy: \"name_asc\",\n});\n\nconst productByRoute = new Map(\n  bootstrap.products.map((item) => [item.slug || item.id, item]),\n);\n\n// Cards and filters use product.variants. Detail selectors use the official\n// helper so sold-out sizes remain visible and older snapshots stay compatible.\nconst detailVariants = getProductDetailVariants(product!);\n\n// Do not call getProductBySlug() once per route during the same build.\n// Reuse productByRoute from the snapshot instead.\n// Render bootstrap.initialPage in the initial catalog HTML instead of\n// publishing an empty skeleton that waits for a browser request.\n\n// After hydration, refresh only volatile state for visible variants.\nconst liveState = await client.catalog.getProductLiveState(\n  detailVariants.map((variant) => variant.id),\n);\n// Each item includes maxPurchasableQuantity for product and cart controls.\n\n// Responsive storage candidates are provided by the SDK.\nconst srcSet = formatMediaSrcSet(product.media[0]?.responsiveSources ?? []);\n\n// Editorial ContentMedia uses heroUrl plus intrinsic-width-aware\n// responsiveSources. See STOREFRONT_PERFORMANCE.md for the <picture> contract.\n\n// Automatic recommendations for the product detail. This is an independent,\n// lightweight request; Bacano resolves ranking, availability and public price.\nconst recommendations = await client.catalog.getProductRecommendations({\n  productId: product!.id,\n  limit: 16,\n});\n\n// Manually curated related products configured in Bacano.\n// Use these for recommendations, comparisons or complementary products.\n// Their public name always comes from the related product itself. Each item is\n// scoped to the current website branch and only includes active catalog items.\nfor (const related of product?.relatedProducts ?? []) {\n  console.log(related.productId);\n  console.log(related.slug);\n  console.log(related.name);\n  console.log(related.sku);\n  console.log(related.media[0]?.url);\n}\n\n// Customer-facing alternatives configured as one central option group.\n// The current product is included in members. Use displayLabel for the\n// selector and slug for navigation; keep relatedProducts for recommendations.\nif (product?.optionGroup) {\n  console.log(product.optionGroup.title);\n  for (const option of product.optionGroup.members) {\n    console.log(option.displayLabel ?? option.name, option.slug);\n  }\n}\n\n// Categories and brands\nconst categories = await client.catalog.getCategories();\nconst brands = await client.catalog.getBrands();\n\n// Product filters / facets (for building filter UIs)\nconst filters = await client.catalog.getProductFilters();\n// → { categories, brands, colors, priceRange: { min, max }, attributes: [] }\n\n// Category-aware facets (includes dynamic attributes for that category)\nconst clothingFilters = await client.catalog.getProductFilters({\n  categoryName: \"CLOTHES\",\n});\n// → { ..., attributes: [{ id, name: 'Size', values: [{ value: 'S', count: 5 }, ...] }] }\n\n// Public attribute list configured in Bacano.\n// Without filters it returns the full published list for the company.\nconst attributeList = await client.catalog.getAttributeList({\n  key: \"filtros-catalogo\",\n});\n\n// Without category/search filters, but still limited to real available products.\nconst applicableAttributeList = await client.catalog.getAttributeList({\n  key: \"filtros-catalogo\",\n  onlyApplicable: true,\n});\n\n// With filters, Bacano resolves only attributes and values that apply to\n// active, priced and in-stock products in the current website context.\nconst contextualAttributeList = await client.catalog.getAttributeList({\n  key: \"filtros-catalogo\",\n  onlyApplicable: true,\n  filters: {\n    categoryName: \"CLOTHES\",\n    tags: [\"bebe-nina\"],\n    minPrice: 10000,\n    maxPrice: 120000,\n  },\n});\n\n// Stock availability\nconst availability = await client.catalog.checkAvailability([\n  \"variant-uuid-1\",\n  \"variant-uuid-2\",\n]);\n// → [{ productVariantId, inStock: true, label: \"In Stock\",\n//      maxPurchasableQuantity: 8 }]\n```\n\n`maxPurchasableQuantity` is Bacano's current public purchase limit after active\nreservations, capped by the maximum accepted by public cart and checkout\nactions. When a website uses multiple warehouses, this is the maximum that one\nsource can fulfill; Bacano intentionally does not add stock from different\nwarehouses. It is not a raw warehouse inventory field. Use it to limit quantity\nselectors and the total units of that variant already present in the local\ncart. Refresh the variants in one batch when opening the cart or checkout; do\nnot request availability after every `+` click. This value can change after it\nis read, so Bacano still revalidates stock when checkout starts and finishes.\n\nAt checkout, each order line is reserved in the first configured warehouse,\nby priority, that can fulfill that complete line. Different lines may use\ndifferent warehouses, but Bacano does not split a single line between sources.\nThe storefront does not implement this allocation or send warehouse IDs.\n\n### 4. Local Cart And Checkout Start\n\nThe website checkout remains guest-first. Buyer credentials and email\nverification are owned by the website's Clerk application; passwords never\npass through this SDK or Bacano.\n\nWhile a visitor is only browsing and adding products, keep the cart in the web\napp local state. Do not create a Bacano order yet.\n\nWhen the visitor starts checkout and provides an identifier allowed by the\ncompany policy, send the local cart to Bacano in one operation:\n\n```typescript\nconst checkoutCart = await client.cart.startCheckout({\n  fulfillmentFamily: \"SHIPPING\", // use 'PICKUP' for store pickup\n  contact: {\n    name: \"Jane Doe\",\n    email: \"jane@example.com\",\n    phone: \"+573001112233\",\n    address: {\n      city: \"Bucaramanga\",\n      line1: \"Cra 1 # 2-3\",\n      notes: \"Porteria azul\",\n    },\n  },\n  items: [\n    { productVariantId: \"variant-uuid-1\", quantity: 2 },\n    { productVariantId: \"variant-uuid-2\", quantity: 1 },\n  ],\n});\n\nconsole.log(checkoutCart.id); // WEB + PENDING + UNPAID checkout order id\nconsole.log(checkoutCart.cartToken); // opaque cart token stored by the SDK\n```\n\nThis creates or recovers a `sales_channel=WEB`, `PENDING + UNPAID` order with\n`orders.website_contact_snapshot` and the received items. From this point on,\nthe checkout can be recovered in Bacano as an abandoned checkout if the customer\ndoes not pay or confirm. Bacano also stores `orders.sales_channel = WEB` for\nthese started web checkouts.\n\n`fulfillmentFamily` tells Bacano how the physical products will be fulfilled:\n`SHIPPING` creates/synchronizes the normal delivery flow and `PICKUP`\ncreates/synchronizes the pickup flow. Bacano stores this in\n`orders.fulfillment_family`.\n\nAfter checkout has started, cart edits go through Bacano and are guarded by\n`order_id + cart_token`:\n\n```typescript\n// Set variant quantity after startCheckout has created a Bacano cart session.\nawait client.cart.setItem(\"variant-uuid\", 2);\n\n// Compatibility alias for adding one variant quantity.\nawait client.cart.addItem(\"variant-uuid\", 2);\n\n// Update by line id. Internally resolves the variant and calls setItem.\nawait client.cart.updateItem(\"cart-item-uuid\", 5);\n\n// Remove by line id.\nawait client.cart.removeItem(\"cart-item-uuid\");\n\n// Discard the complete private cart and clear its SDK session.\nawait client.cart.clear();\n\n// View current cart from the stored guest session.\nconst currentCart = await client.cart.get();\nconsole.log(currentCart?.items); // CartItem[]\nconsole.log(currentCart?.totals); // { subtotal, tax, discount, total }\n```\n\nCart rules:\n\n- `cart.getOrCreate()` may create a private server cart without contact. This\n  is the supported path when the storefront needs authoritative stock, totals\n  or volume pricing before checkout.\n- Creating this browsing cart does not create delivery logistics. Delivery is\n  synchronized only by `cart.startCheckout()` after the customer selects the\n  fulfillment family.\n- Email, phone or a complete document pair can start a Bacano\n  `sales_channel=WEB`, `PENDING + UNPAID` checkout.\n- `sales_channel=WEB`, `PENDING + UNPAID` without `order_number` means checkout started or abandoned.\n- These started checkouts are tracked by `orders.website_cart_status` and should be managed from Bacano's abandoned-cart view, not mixed into the normal sales list.\n- `cart.clear()` marks the private cart as `discarded`, preserves its audit\n  history and removes only `@bacano/sdk:cart:{websiteSlug}`. It never deletes\n  storage owned by the storefront.\n- Removing the final line also discards the server cart and clears its private\n  SDK session automatically.\n- The web must collect `fulfillmentFamily` before starting checkout:\n  `SHIPPING` for delivery or `PICKUP` for store pickup.\n- The cart token is opaque. Bacano stores only its SHA-256 hash.\n- Cart edits go through Hasura Actions, not direct public table mutations.\n- Filling checkout does not create a formal `client` yet; it stores only\n  `website_contact_snapshot` on the order.\n- A pending unpaid web checkout does not reserve stock by itself, deduct\n  inventory, create payments or post accounting. Creating an external gateway\n  session reserves stock until the attempt finishes or expires.\n\n### 5. Guest Checkout Confirmation\n\nBefore confirming a shipping checkout, ask Bacano for location, shipping,\npayment and coupon options:\n\n```typescript\nconst deliveryOptions = await client.checkout.getDeliveryOptions();\nconst locations = await client.checkout.getLocationOptions();\nconst shippingPolicy = await client.checkout.getShippingPolicy();\nconst shippingProgress = await client.checkout.getFreeShippingProgress({\n  items: cartItems.map((item) => ({\n    productVariantId: item.productVariantId,\n    quantity: item.quantity,\n  })),\n});\nconst quotes = await client.checkout.getShippingQuotes({\n  address,\n  items: cartItems.map((item) => ({\n    productVariantId: item.productVariantId,\n    quantity: item.quantity,\n  })),\n});\nconst paymentOptions = await client.checkout.getPaymentOptions({\n  fulfillmentFamily: \"SHIPPING\",\n});\nawait client.checkout.applyCoupon({ code: \"BEBE10\" });\n```\n\n`getDeliveryOptions` can run before contact, cart or address exists. Use it to\nshow options such as `SHIPPING` and `PICKUP`. Call `getShippingQuotes` only when\nthe selected option is `SHIPPING` and the customer has provided an address.\n\nUse `getShippingPolicy()` for general storefront messages before a cart\nexists. Use `getFreeShippingProgress({ items })` to show cart progress before\ncollecting contact or address data. Bacano resolves current prices, stock,\nwebsite and shipping policy; the storefront must format the structured values\ninstead of hardcoding or recalculating them.\n\nFor the policy to be enabled, the website must have delivery enabled, a\npositive free-shipping threshold, and at least one active shipping service\nenabled for that website whose collection mode charges shipping with the sale\n(`with_sale`). Shipping collected directly by the carrier is intentionally not\noverridden by this promotion. These prerequisites are configured in Bacano;\nthe storefront must not infer or reproduce them.\n\n`getShippingPolicy()` is cached for five minutes per SDK client. This keeps\ncatalog navigation from repeatedly requesting the same configuration. After\nchanging the policy in Bacano, recreate the client or reload the storefront to\nvalidate it immediately. `getFreeShippingProgress()` always validates the\nsubmitted variants and quantities against Bacano's current prices and returns\n`enabled: false` with nullable amounts when the policy does not apply.\n\n`getShippingQuotes` returns the final shipping price for an address. Before a\nguest checkout exists, pass `items`. Once an active cart session exists, the\nSDK intentionally prefers the persisted cart and ignores loose items so\ncoupons and server-side totals remain authoritative.\n\nEach quote exposes `baseAmount` and the final `amount`. When Bacano's\nwebsite-level free-shipping policy applies, `amount` is zero and\n`freeShippingApplied` is `true`. Use `freeShippingRemaining` to show progress\nbefore the threshold is reached. Storefronts must not hardcode or recalculate\nthe threshold; Bacano revalidates it during `checkout.submit`.\n\nUse `getPaymentOptions({ fulfillmentFamily })` to render payment modes valid\nfor the selected delivery option. For example, `PICKUP` may return \"Pagar\nahora\" and \"Pagar al recoger\", while `SHIPPING` may return \"Pagar ahora\" and\n\"Pagar contraentrega\".\n\nOnly payment methods marked as **Disponible para web** in Bacano and enabled in\nthe website payment settings are returned. Gateway methods such as Wompi expose\n`gatewayCode`, `requiresPaymentSession` and public configuration only; secrets\nnever leave Bacano.\n\nEach payment option also exposes `initialPaymentPolicy` (`none`, `optional` or\n`required`), `requiresInitialPayment`, `minInitialAmount` and\n`suggestedInitialAmount`. When required, submit the selected option with:\n\n```typescript\ninitialPayment: {\n  amount: selectedAmount,\n  paymentMethodId: selectedInitialMethod.paymentMethodId,\n}\n```\n\nThe API enforces the policy, minimum and order total. Do not infer deposits from\nlabels or delivery mode.\n\n```typescript\nconst payNow = paymentOptions.find((option) => option.mode === \"pay_now\");\n\nconst result = await client.checkout.submit({\n  fulfillmentFamily: \"SHIPPING\",\n  contact: {\n    firstName: \"Jane\",\n    lastName: \"Doe\",\n    email: \"jane@example.com\",\n    cellphone: \"+573001112233\",\n    documentType: \"13\",\n    documentNumber: \"123456789\",\n  },\n  address,\n  shippingQuoteId: quotes[0].quoteId,\n  paymentMode: \"pay_now\",\n  paymentMethodId: payNow?.methods[0]?.paymentMethodId,\n  buyerAccountOptIn: true,\n});\n\nconst publicOrderUrl =\n  result.orderId && result.publicOrderToken\n    ? `/pedido/${result.orderId}?token=${result.publicOrderToken}`\n    : null;\n\nif (result.requiresPaymentSession && result.paymentMethodId) {\n  const session = await client.checkout.createPaymentSession({\n    orderId: result.orderId ?? undefined,\n    publicOrderToken: result.publicOrderToken ?? undefined,\n    paymentMethodId: result.paymentMethodId,\n    returnUrl:\n      `${window.location.origin}/pago/respuesta` +\n      `?orderId=${encodeURIComponent(result.orderId ?? \"\")}` +\n      `&token=${encodeURIComponent(result.publicOrderToken ?? \"\")}`,\n  });\n\n  if (\n    session.success &&\n    session.integrationMode === \"redirect\" &&\n    session.redirectUrl\n  ) {\n    window.location.assign(session.redirectUrl);\n  }\n}\n\nif (result.success) {\n  console.log(`Order ${result.orderNumber} placed!`);\n  console.log(publicOrderUrl);\n} else {\n  console.error(\"Checkout failed:\", result.errors);\n}\n```\n\n`buyerAccountOptIn` must reflect an explicit, unchecked-by-default buyer\nchoice. For guests, Bacano queues a Clerk activation invitation as soon as a\nvalid order is persisted, even when payment remains pending. Invalid attempts\nthat do not create an order send nothing, and checkout never waits for Clerk.\n`buyerAccountInvitationRequested` reports whether Bacano durably accepted the\nrequest. Authenticated buyers do not receive an invitation; their verified\nClerk token owns the order automatically. See [AUTHENTICATION.md](./AUTHENTICATION.md)\nfor the invitation landing-page and secure order-claim contract.\n\n`returnUrl` is the storefront response page. `session.redirectUrl` is the\nprovider-hosted checkout and is the only URL the storefront opens. The\nstorefront never renders gateway widgets or constructs Wompi/Addi/ePayco URLs.\nOn the response page, send the provider's public transaction ID back to Bacano\nwhen available and wait for the public order:\n\n```typescript\nawait client.checkout.reconcilePaymentSession({\n  orderId,\n  publicOrderToken,\n  paymentSessionId,\n  gatewayTransactionId,\n});\n\nconst order = await client.orders.waitForPayment({\n  orderId,\n  token: publicOrderToken,\n  intervalMs: 1_500,\n  timeoutMs: 45_000,\n});\n```\n\nLoad `getWebsitePublicConfig()` before rendering contact fields.\nPass the same required `websiteSlug` used to construct the client. Bacano\nselects that website explicitly and then verifies that the request Origin\nbelongs to it; Origin alone never chooses a storefront.\n`customerIdentification` exposes the company-level policy configured in\n`Settings > Sales > Checkout`: the primary identifier, additional required\nfields and valid document types. The storefront renders that contract; Bacano\nenforces it again and uses the configured primary identifier to recognize a\nreturning guest customer. `AUTO` preserves the legacy email-first, phone-second\nbehavior.\n\nThe storefront never approves a payment from query parameters. Bacano verifies\nthe transaction directly with the provider; the signed webhook remains the\nprimary confirmation path.\n\nAfter invitation acceptance, Bacano fills only missing commercial profile\nfields from its persisted order snapshots: name, mobile and primary shipping\naddress. Existing profile data is never overwritten, and the authenticated\nemail always comes from Clerk verification. `name` and `phone` remain\nsupported for older storefronts; prefer `firstName`, `lastName` and\n`cellphone` in new checkouts.\n\nCheckout submission is idempotent for the active SDK cart session. If Bacano\nreturns `ORDER_CONFIRMATION_RETRYABLE`, keep the current cart session and call\n`checkout.submit` again with the same data. Do not call `cart.startCheckout`\nagain: Bacano resumes the same `orderId + cartToken`, pending attempts do not\nconsume a sales number, and a replay after confirmation returns the existing\norder result. For gateway checkouts, the SDK retains the private cart session\nuntil `createPaymentSession` succeeds, then retires it. Payment response and\nretry pages must continue with the returned `orderId + publicOrderToken`; a\nsecond purchase starts a new cart instead of reusing the finalized order.\n\nThe private `orderId + cartToken` session belongs exclusively to the SDK. A\nstorefront must never read, remove or rewrite the\n`@bacano/sdk:cart:{websiteSlug}` key. When `cart.startCheckout()` discovers\nthat a persisted session is no longer usable, Bacano returns the stable\n`INVALID_CART_TOKEN` or `CART_NOT_FOUND` code. The SDK then removes only that\nprivate session and retries the same start operation exactly once without a\ntoken. Storefront-owned product state is not touched, `checkout.submit()` is\nnever repeated, and the failed token request creates no order. Other business\nerrors preserve the private session and are returned with their stable code.\n\nSigning in after starting as a guest does not rotate the cart token. Bacano\ncontinues an unowned guest cart and can continue a cart already linked to the\nsame authenticated buyer. Signing out, changing buyers, completing an order,\nor changing the website chain makes a non-matching private session\nnon-recoverable for that browser identity, so the next start creates one fresh\ncart through the bounded recovery above.\n\n### 6. Public Order Tracking\n\nConfirmation pages should not depend on browser-only snapshots. After a\nsuccessful checkout, `submit` returns `publicOrderToken`; use it with the order\nid to build a durable customer link:\n\n```typescript\nconst publicOrder = await client.orders.getPublicOrder({\n  orderId: result.orderId!,\n  token: result.publicOrderToken!,\n});\n\nconsole.log(publicOrder?.orderNumber);\nconsole.log(publicOrder?.status);\nconsole.log(publicOrder?.paymentStatus);\nconsole.log(publicOrder?.payment.requiresPaymentSession);\nconsole.log(publicOrder?.payment.nextAction);\nconsole.log(publicOrder?.items);\nconsole.log(publicOrder?.nextSteps);\n```\n\n`getPublicOrder` does not require login. Bacano validates the current website,\nthe order id and the opaque public token. The response is safe for customers:\norder state, payment state, delivery summary, payment summary, totals and item\nsummary. It does not expose private credentials, internal snapshots or editable\ncart permissions.\n\n`payment.nextAction` is the structured UI contract:\n`CREATE_PAYMENT_SESSION`, `WAIT_FOR_PAYMENT`, `RETRY_PAYMENT`,\n`PAY_ON_DELIVERY`, `PAY_AT_PICKUP`, `WAIT_FOR_ORDER_CONFIRMATION` or `NONE`.\n`nextSteps` is display copy only. A missing `payment.session` does not by itself\nmean that no gateway is required.\n\nFor payment gateways, the redirect page should be visual only. The gateway\nwebhook updates Bacano; `/pago/respuesta` can use `orderId + publicOrderToken`\nto redirect or link back to `/pedido/[id]`.\n\nThe checkout validates:\n\n- Cart ownership through `order_id + cart_token`\n- Order has `sales_channel=WEB`, `PENDING + UNPAID` and no `order_number`\n- Cart is not empty\n- Products are active and enabled for the website branch through `chain_products`\n- Products are enabled for the website branch\n- Sufficient stock for all items\n- All items have a valid positive `CLIENT` price\n\nIt also **recalculates totals** from current prices at checkout time to prevent\nstale-price exploits. Shipping and coupons are recalculated in Bacano as well;\nthe web only sends the selected IDs and address. On success the order keeps `sales_channel=WEB`, `PENDING + UNPAID`,\nreceives an order number, and Bacano creates or reuses the formal `client` by\nemail first, then phone. The selected fulfillment family is synchronized through\nthe existing delivery machinery so the ERP can continue pickup/shipping actions\nfrom the sale detail.\n\nCheckout intentionally does **not** create accounting entries, payments, stock\nreservations or inventory deductions in this iteration. Those effects happen in a\nfuture payment-confirmation flow.\n\n### 6. Optional Auth Module\n\nThe SDK still exposes `client.auth` for future logged-in customer flows, but it\nis not required for catalog, cart or guest checkout.\n\n### 7. Order History\n\n```typescript\nconst orders = await client.orders.list({ limit: 10 });\n\nconst order = await client.orders.get(\"order-uuid\");\nconsole.log(order?.orderNumber); // \"WEB-000001\"\nconsole.log(order?.status); // \"PENDING\", \"PAYED\", \"SENT\", \"COMPLETED\"\nconsole.log(order?.items); // OrderItem[]\n```\n\n### 8. Customer Profile\n\n```typescript\nconst profile = await client.profile.get();\nconsole.log(profile.name, profile.email);\n\nconst addresses = await client.profile.getAddresses();\nconst preferredShippingAddress = addresses.find((address) => address.isPrimary);\n\nawait client.profile.update({\n  name: \"Jane\",\n  lastname: \"Smith\",\n  cellphone: \"+573001234567\",\n  address: \"123 Main St\",\n  addressComplement: \"Apto 401\",\n  countryCode: \"CO\",\n  departmentId: \"68\",\n  municipalityId: \"68001\",\n});\n```\n\n`profile.email` is read-only and comes from the buyer's verified Clerk\nidentity. Use `cellphone` for the mobile/WhatsApp number in E.164 format;\n`phone` is an optional secondary telephone number. Never send passwords,\nverification codes or Clerk secrets through this module.\n\n`profile.getAddresses()` also requires an authenticated Clerk session. It\nreturns only checkout-ready addresses with canonical department and\nmunicipality data. A complete commercial profile address is `PRIMARY`; saved\ndelivery addresses are `SHIPPING`. `departmentId` and `municipalityId` are the\ncanonical geographic codes accepted by `checkout.getShippingQuotes()`. An\nincomplete legacy address is intentionally omitted so the storefront can show\nthe location form instead of guessing by display text. The storefront must not\nsend a `clientId`.\n\n---\n\n## Configuration Reference\n\n```typescript\ncreateBacanoClient({\n  // Required\n  apiUrl: string;        // Bacano public API URL\n  websiteSlug: string;   // URL-friendly identifier (e.g., \"my-store\")\n\n  // Optional\n  tokenStorage?: 'localStorage' | 'cookie' | 'memory'; // Guest cart session only\n  getAccessToken?: () => string | null | Promise<string | null>;\n});\n```\n\n### Cart Session Storage\n\n`tokenStorage` is retained for compatibility but stores only the guest cart\nidentifier/token. Buyer access tokens are never persisted by Bacano SDK; the\nconfigured identity provider owns their lifecycle.\n\n### Website favicon\n\nThe website's General settings can define one canonical favicon from Bacano's\nmedia library. It is returned by the existing public-config request, so a\nstorefront does not need another API call or direct Storage integration:\n\n```tsx\nconst publicConfig = await getWebsitePublicConfig({ apiUrl, websiteSlug });\nconst faviconUrl = publicConfig.branding.favicon?.originalUrl;\n```\n\nUse `faviconUrl` in the framework's metadata or document head. When it is\n`null`, keep the storefront's packaged fallback icon. The public contract\ncontains only browser-safe media metadata and a public Storage URL.\n\n---\n\n## React Integration\n\n### Storefront marketing and measurement\n\nGA4, Meta, and Microsoft Clarity are configured per website in Bacano and are\ndisabled by default.\nAn optional Google Tag Manager web container is also supported via\n`marketing.destinations.gtm.containerId`. It adds `bacano_*` browser events to\nthe data layer without replacing native destinations or server conversions.\nSee [GTM setup, limitations and duplication safeguards](./STOREFRONT_MARKETING.md#google-tag-manager-contenedor-web-opcional).\nThe existing public-config request returns only active public destination IDs;\nprovider secrets never reach the SDK. The runtime remains a no-op outside the\nwebsite's canonical production domain.\n\nMount one provider at the storefront root, using the same public config already\nloaded for buyer accounts:\n\n```tsx\nimport { getWebsitePublicConfig } from \"@bacano/sdk\";\nimport { BacanoMarketingProvider, useMarketing } from \"@bacano/sdk/react\";\n\nconst publicConfig = await getWebsitePublicConfig({ apiUrl, websiteSlug });\n\n<BacanoMarketingProvider publicConfig={publicConfig}>\n  <Storefront />\n</BacanoMarketingProvider>;\n\nfunction AddToCartButton({ variant }) {\n  const marketing = useMarketing();\n\n  async function add() {\n    await updateCartSuccessfully(variant.id);\n    marketing.track({\n      eventName: \"add_to_cart\",\n      value: variant.price,\n      items: [\n        {\n          itemId: variant.id, // always product_variant_id\n          itemName: variant.productName,\n          sku: variant.sku,\n          price: variant.price,\n          quantity: 1,\n        },\n      ],\n    });\n  }\n\n  return <button onClick={add}>Add to cart</button>;\n}\n```\n\nThe browser contract is versioned and accepts `page_view`, `search`,\n`view_item_list`, `select_item`, `view_item`, `add_to_cart`,\n`remove_from_cart`, `view_cart`, `begin_checkout`, `add_shipping_info`,\n`add_payment_info`, and `contact`. Emit events only after the related operation\nhas succeeded. Use one manual `page_view` source for SPA navigation because the\nGA4 adapter disables automatic page views.\n\nWhen Microsoft Clarity is active, this same provider loads it automatically and\nforwards canonical browser events as Clarity custom events. Do not install a\nsecond Clarity snippet or package in the storefront. Setup, privacy, and\nverification are documented in [`STOREFRONT_CLARITY.md`](./STOREFRONT_CLARITY.md).\n\nContact actions can identify their stable storefront location with the optional\n`contactPlacement` field. It accepts only `product_detail`, `floating`,\n`header`, `footer`, or `contact_page`; visible labels and arbitrary strings are\nnot part of the public contract. The runtime ignores the field on events other\nthan `contact`.\n\n```tsx\nmarketing.track({\n  eventName: \"contact\",\n  contactMethod: \"email\",\n  contactPlacement: \"footer\",\n});\n```\n\nA product contact keeps the same variant identity, value, and item payload used\nby the ecommerce events:\n\n```tsx\nmarketing.track({\n  eventName: \"contact\",\n  contactMethod: \"whatsapp\",\n  contactPlacement: \"product_detail\",\n  value: price * quantity,\n  items: [\n    {\n      itemId: variant.id,\n      itemName: product.name,\n      sku: variant.sku,\n      price,\n      quantity,\n      itemBrand: product.brand?.name,\n      itemCategory: product.category,\n      itemVariant: \"Talla: 12 meses / Color: Rosado\",\n    },\n  ],\n});\n```\n\nGA4 receives this field as `contact_placement`; Meta receives the same\n`contact_placement` key while preserving `contact_method`, `content_ids`, and\n`contents`.\n\nFor checkout selectors, an automatic default is not yet a customer choice.\nEmit `add_shipping_info` and `add_payment_info` immediately for an explicit,\nvalid selection, or once after a successful checkout submission when the\ncustomer kept an automatic default. Deduplicate both paths with the selected\ndelivery/payment identity. On product lists, `itemId` and `price` must come\nfrom the same public, price-bearing variant; the advertised variant is the\nlowest-price variant with stable `order` and ID tie-breakers.\n\nTransfer the runtime attribution snapshot when checkout starts and again when\nit is submitted. Bacano freezes the touchpoints on the order; the second\nsnapshot may only fill missing GA4 `client_id` and `session_id` values that the\nGoogle tag resolved asynchronously:\n\n```typescript\nawait client.cart.startCheckout({\n  contact,\n  items,\n  marketingAttribution: marketing.getAttribution() ?? undefined,\n});\n\nawait client.checkout.submit({\n  contact,\n  marketingAttribution: marketing.getAttribution() ?? undefined,\n  advertisingConsent: publicConfig.marketing.consentPolicy\n    ? {\n        policyId: publicConfig.marketing.consentPolicy.id,\n        policyVersion: publicConfig.marketing.consentPolicy.version,\n        statementHash: publicConfig.marketing.consentPolicy.statementHash,\n        granted: optionalAdvertisingCheckbox,\n      }\n    : undefined,\n});\n```\n\n`order_placed`, `purchase`, and `refund` are server-authoritative events. A\nstorefront must never emit them from a thank-you page or payment response route.\nURLs are centrally sanitized to retain only approved UTM and click identifiers.\nLinks and QR codes may additionally use `bacano_origin=<public-key>` to select a\ncompany-defined sales origin. The SDK preserves it with the attribution\nsnapshot; Bacano validates it server-side and otherwise falls back to the\nnormalized UTM/click-ID origin or `Web`.\nGoogle or Meta failures are isolated from catalog, cart, checkout, and payment.\nThis isolation also applies to Bacano's server-side outbox producers: losing a\nmarketing event must never roll back an order, payment, or refund transition.\nThe runtime captures GA4 browser identity and Meta browser context (`fbp`,\n`fbc`, and user agent) internally, so storefronts must not read cookies or\nconstruct provider identifiers themselves. Contact information remains governed\nby the website's explicit advertising-consent policy.\n\nAn active, validated integration can enable a temporary diagnostic window from\nBacano. GA4 events receive `debug_mode`; Meta server events receive its encrypted\nTest Events code. The mode is off by default, expires automatically, is cleared\nwhen an integration is paused or reconfigured, and never exposes the Meta code\nthrough public config or the SDK.\n\nThe canonical contract and acceptance checklist live in\n`docs/websites/MARKETING_MEASUREMENT_STOREFRONTS_CHECKLIST.md` in the Bacano ERP\nrepository.\n\nWebsite legal documents and the optional informational cookie notice are\navailable in `publicConfig.legal`. Their canonical contract lives in\n[`STOREFRONT_LEGAL.md`](./STOREFRONT_LEGAL.md), which ships inside this package.\nThe notice does not gate the marketing runtime; storefronts must not reinterpret\nit as a consent manager.\n\n### Setup\n\nWrap your app with `BacanoProvider`:\n\n```tsx\nimport { BacanoProvider } from \"@bacano/sdk/react\";\n\nfunction App() {\n  return (\n    <BacanoProvider\n      config={{\n        apiUrl: process.env.NEXT_PUBLIC_BACANO_API_URL!,\n        websiteSlug: \"my-store\",\n      }}\n    >\n      <Shop />\n    </BacanoProvider>\n  );\n}\n```\n\n### Initialization State\n\n```tsx\nimport { useBacanoState } from \"@bacano/sdk/react\";\n\nfunction Shop() {\n  const { loading, error } = useBacanoState();\n\n  if (loading) return <p>Loading website...</p>;\n  if (error) return <p>Error: {error.message}</p>;\n\n  return <ProductList />;\n}\n```\n\n### Available Hooks\n\n#### Buyer authentication with Clerk\n\n```tsx\nimport { ClerkProvider, useAuth } from \"@clerk/nextjs\";\nimport { BacanoProvider } from \"@bacano/sdk/react\";\n\nfunction StorefrontSdk({ children }: { children: React.ReactNode }) {\n  const { getToken } = useAuth();\n  return (\n    <BacanoProvider\n      config={{\n        apiUrl: process.env.NEXT_PUBLIC_BACANO_API_URL!,\n        websiteSlug: \"my-store\",\n        getAccessToken: () => getToken(),\n      }}\n    >\n      {children}\n    </BacanoProvider>\n  );\n}\n```\n\nMount `StorefrontSdk` inside the website-specific `ClerkProvider`. Use Clerk's\ncomponents or hooks for sign-in, sign-up, verification and password recovery.\nThe SDK obtains a fresh token for each protected request and never receives\nthe buyer password.\n\n#### `useProducts(opts?)`\n\n```tsx\nimport { getPrimaryProductImage, useProducts } from \"@bacano/sdk/react\";\n\nfunction ProductList() {\n  const {\n    data: products,\n    loading,\n    error,\n    refetch,\n  } = useProducts({\n    categoryName: \"Clothing\",\n    limit: 20,\n  });\n\n  if (loading) return <p>Loading...</p>;\n  if (error) return <p>Error: {error.message}</p>;\n\n  return (\n    <ul>\n      {products?.map((p) => {\n        const image = getPrimaryProductImage(p.media);\n\n        return (\n          <li key={p.id}>\n            {image && <img src={image.url} alt={image.alt ?? p.name} />}\n            <h3>{p.name}</h3>\n            <p>{p.brand?.name}</p>\n            {p.variants.map((v) => (\n              <span key={v.id}>\n                {v.sku}: ${v.prices[0]?.price}\n              </span>\n            ))}\n          </li>\n        );\n      })}\n    </ul>\n  );\n}\n```\n\n#### `useProduct(id)`\n\n```tsx\nimport { useProduct } from \"@bacano/sdk/react\";\n\nfunction ProductDetail({ productId }: { productId: string }) {\n  const { data: product, loading } = useProduct(productId);\n\n  if (loading || !product) return <p>Loading...</p>;\n\n  return (\n    <div>\n      <h1>{product.name}</h1>\n      <p>{product.description}</p>\n      {product.attributes.map((attr) => (\n        <span key={attr.id}>\n          {attr.name}: {attr.value}\n        </span>\n      ))}\n    </div>\n  );\n}\n```\n\n#### `useCategories()` and `useBrands()`\n\n```tsx\nimport { useCategories, useBrands } from \"@bacano/sdk/react\";\n\nfunction Sidebar() {\n  const { data: categories } = useCategories();\n  const { data: brands } = useBrands();\n\n  return (\n    <nav>\n      <h4>Categories</h4>\n      {categories?.map((cat) => (\n        <div key={cat.name}>\n          <strong>{cat.name}</strong>\n          <ul>\n            {cat.subcategories.map((sub) => (\n              <li key={sub.id}>{sub.name}</li>\n            ))}\n          </ul>\n        </div>\n      ))}\n\n      <h4>Brands</h4>\n      {brands?.map((b) => (\n        <span key={b.id}>{b.name}</span>\n      ))}\n    </nav>\n  );\n}\n```\n\n#### `useProductFilters(opts?)`\n\n```tsx\nimport { useProducts, useProductFilters } from \"@bacano/sdk/react\";\nimport { useState } from \"react\";\n\nfunction FilteredProductList() {\n  const [category, setCategory] = useState(\"CLOTHES\");\n  const [selectedColors, setSelectedColors] = useState<string[]>([]);\n  const [priceRange, setPriceRange] = useState<[number, number]>([0, 1000]);\n  const [selectedAttrs, setSelectedAttrs] = useState<Record<string, string[]>>(\n    {},\n  );\n\n  // Fetch available filter options for the selected category\n  const { data: facets } = useProductFilters({ categoryName: category });\n\n  // Fetch products with active filters applied\n  const { data: products, loading } = useProducts({\n    categoryName: category,\n    colors: selectedColors.length > 0 ? selectedColors : undefined,\n    minPrice: priceRange[0],\n    maxPrice: priceRange[1],\n    attributes:\n      Object.keys(selectedAttrs).length > 0 ? selectedAttrs : undefined,\n    inStock: true,\n    sortBy: \"price_asc\",\n  });\n\n  return (\n    <div style={{ display: \"flex\", gap: \"2rem\" }}>\n      {/* Filter sidebar built from facets */}\n      <aside>\n        <h4>\n          Price: ${facets?.priceRange.min} – ${facets?.priceRange.max}\n        </h4>\n\n        <h4>Colors</h4>\n        {facets?.colors.map((c) => (\n          <label key={c.value}>\n            <input\n              type=\"checkbox\"\n              onChange={() => {\n                /* toggle color */\n              }}\n            />\n            {c.value} ({c.count})\n          </label>\n        ))}\n\n        <h4>Dynamic Attributes</h4>\n        {facets?.attributes.map((attr) => (\n          <div key={attr.id}>\n            <strong>{attr.name}</strong>\n            {attr.values.map((v) => (\n              <label key={v.value}>\n                <input\n                  type=\"checkbox\"\n                  onChange={() => {\n                    /* toggle attr */\n                  }}\n                />\n                {v.value} ({v.count})\n              </label>\n            ))}\n          </div>\n        ))}\n      </aside>\n\n      {/* Product grid */}\n      <main>\n        {products?.map((p) => (\n          <div key={p.id}>{p.name}</div>\n        ))}\n      </main>\n    </div>\n  );\n}\n```\n\n#### `useSearchSuggestions(opts?)`\n\n```tsx\nimport { useSearchSuggestions } from \"@bacano/sdk/react\";\nimport { useState } from \"react\";\n\nfunction SearchBar() {\n  const [query, setQuery] = useState(\"\");\n  const { data: suggestions, loading } = useSearchSuggestions({\n    query,\n    limit: 8,\n  });\n\n  return (\n    <div>\n      <input\n        type=\"text\"\n        placeholder=\"Search products...\"\n        value={query}\n        onChange={(e) => setQuery(e.target.value)}\n      />\n      {query && suggestions && suggestions.length > 0 && (\n        <ul>\n          {suggestions.map((s, i) => (\n            <li key={i}>\n              <span>{s.type === \"brand\" ? \"🏷️\" : \"📦\"}</span>\n              {s.text}\n            </li>\n          ))}\n        </ul>\n      )}\n    </div>\n  );\n}\n```\n\n#### `useAvailability(variantIds)`\n\n```tsx\nimport { useAvailability } from \"@bacano/sdk/react\";\n\nfunction StockBadge({ variantIds }: { variantIds: string[] }) {\n  const { data: availability } = useAvailability(variantIds);\n\n  return (\n    <>\n      {availability?.map((a) => (\n        <span\n          key={a.productVariantId}\n          style={{ color: a.inStock ? \"green\" : \"red\" }}\n        >\n          {a.label}\n        </span>\n      ))}\n    </>\n  );\n}\n```\n\n#### `useCart()`\n\n```tsx\nimport { useCart } from \"@bacano/sdk/react\";\n\nfunction CartPage() {\n  const { cart, loading, startCheckout, updateItem, removeItem } = useCart();\n\n  async function handleStartCheckout() {\n    await startCheckout({\n      contact: { email: \"buyer@example.com\", phone: \"+573001112233\" },\n      items: [{ productVariantId: \"variant-uuid\", quantity: 1 }],\n    });\n  }\n\n  if (loading) return <p>Loading cart...</p>;\n  if (!cart || cart.items.length === 0) return <p>Cart is empty</p>;\n\n  return (\n    <div>\n      {cart.items.map((item) => (\n        <div key={item.id}>\n          <span>{item.productVariant.product.name}</span>\n          <span>SKU: {item.productVariant.sku}</span>\n          <span>Qty: {item.quantity}</span>\n          <button onClick={() => updateItem(item.id, item.quantity + 1)}>\n            +\n          </button>\n          <button onClick={() => updateItem(item.id, item.quantity - 1)}>\n            -\n          </button>\n          <button onClick={() => removeItem(item.id)}>Remove</button>\n        </div>\n      ))}\n      <p>Total: ${cart.totals.total}</p>\n      <button onClick={handleStartCheckout}>Start checkout</button>\n    </div>\n  );\n}\n```\n\n#### `useCheckout()`\n\n```tsx\nimport { useCheckout, useCart } from \"@bacano/sdk/react\";\n\nfunction CheckoutButton() {\n  const { cart } = useCart();\n  const { checkout, loading, error } = useCheckout();\n\n  async function handleCheckout() {\n    if (!cart) return;\n    try {\n      const result = await checkout({\n        contact: { email: \"buyer@example.com\", phone: \"+573001112233\" },\n      });\n      alert(`Order ${result.orderNumber} placed!`);\n    } catch (err) {\n      // error state is also updated automatically\n    }\n  }\n\n  return (\n    <div>\n      <button onClick={handleCheckout} disabled={loading || !cart}>\n        {loading ? \"Processing...\" : \"Place Order\"}\n      </button>\n      {error && <p style={{ color: \"red\" }}>{error.message}</p>}\n    </div>\n  );\n}\n```\n\n#### `useOrders(opts?)` and `useOrder(id)`\n\n```tsx\nimport { useOrders } from \"@bacano/sdk/react\";\n\nfunction OrderHistory() {\n  const { data: orders, loading } = useOrders({ limit: 10 });\n\n  if (loading) return <p>Loading...</p>;\n\n  return (\n    <ul>\n      {orders?.map((order) => (\n        <li key={order.id}>\n          {order.orderNumber} — {order.status} — ${order.total}\n        </li>\n      ))}\n    </ul>\n  );\n}\n```\n\n#### `useProfile()`\n\n```tsx\nimport { useProfile } from \"@bacano/sdk/react\";\n\nfunction ProfilePage() {\n  const { profile, loading, updateProfile } = useProfile();\n\n  if (loading || !profile) return <p>Loading...</p>;\n\n  return (\n    <form\n      onSubmit={async (e) => {\n        e.preventDefault();\n        const formData = new FormData(e.currentTarget);\n        await updateProfile({\n          name: formData.get(\"name\") as string,\n          address: formData.get(\"address\") as string,\n        });\n      }}\n    >\n      <input name=\"name\" defaultValue={profile.name ?? \"\"} />\n      <input name=\"address\" defaultValue={profile.address ?? \"\"} />\n      <button type=\"submit\">Save</button>\n    </form>\n  );\n}\n```\n\n### Hooks Summary\n\n| Hook                          | Returns                                                                                 | Auth Required |\n| ----------------------------- | --------------------------------------------------------------------------------------- | ------------- |\n| `useBacano()`                 | `BacanoClient`                                                                          | No            |\n| `useBacanoState()`            | `{ client, loading, error }`                                                            | No            |\n| `useProducts(opts?)`          | `{ data, loading, error, refetch }`                                                     | No            |\n| `useProduct(id)`              | `{ data, loading, error, refetch }`                                                     | No            |\n| `useCategories()`             | `{ data, loading, error, refetch }`                                                     | No            |\n| `useBrands()`                 | `{ data, loading, error, refetch }`                                                     | No            |\n| `useProductFilters(opts?)`    | `{ data, loading, error, refetch }`                                                     | No            |\n| `useSearchSuggestions(opts?)` | `{ data, loading, error, refetch }`                                                     | No            |\n| `useAvailability(ids)`        | `{ data, loading, error, refetch }`                                                     | No            |\n| `useCart()`                   | `{ cart, loading, error, startCheckout, getOrCreate, addItem, updateItem, removeItem, clear }` | No            |\n| `useCheckout()`               | `{ checkout, loading, error }`                                                          | No            |\n| `useOrders(opts?)`            | `{ data, loading, error, refetch }`                                                     | Yes           |\n| `useOrder(id)`                | `{ data, loading, error, refetch }`                                                     | Yes           |\n| `useProfile()`                | `{ profile, loading, error, updateProfile }`                                            | Yes           |\n\n---\n\n## Advanced: Bring Your Own GraphQL Client\n\nIf you use Apollo, urql, TanStack Query, or any other GraphQL client, you can import the raw typed documents instead:\n\n```typescript\nimport { documents, createAuthHeaders } from \"@bacano/sdk/graphql\";\nimport type { Product, Cart } from \"@bacano/sdk/graphql\";\n```\n\n### With Apollo Client\n\n```tsx\nimport { documents } from \"@bacano/sdk/graphql\";\nimport { useQuery, useMutation } from \"@apollo/client\";\n\nfunction ProductList({ companyId }: { companyId: string }) {\n  const { data, loading } = useQuery(documents.GET_PRODUCTS, {\n    variables: { companyId, limit: 20 },\n  });\n\n  // data.products is the raw Hasura response (snake_case)\n}\n\nfunction StartCheckoutButton({ variantId }: { variantId: string }) {\n  const [startCheckout] = useMutation(documents.START_GUEST_CHECKOUT);\n\n  return (\n    <button\n      onClick={() =>\n        startCheckout({\n          variables: {\n            websiteId: \"website-uuid\",\n            contact: { email: \"buyer@example.com\" },\n            items: [{ product_variant_id: variantId, quantity: 1 }],\n          },\n        })\n      }\n    >\n      Start checkout\n    </button>\n  );\n}\n```\n\n### With fetch (SSR / Server Components)\n\n```typescript\nimport { documents, createAuthHeaders } from \"@bacano/sdk/graphql\";\n\n// In a Next.js Server Component or API route:\nasync function getProducts(apiUrl: string, companyId: string) {\n  const res = await fetch(`${apiUrl}/api/v1/website/graphql`, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      // No auth headers = public role (anonymous catalog browsing)\n    },\n    body: JSON.stringify({\n      query: documents.GET_PRODUCTS,\n      variables: { companyId, limit: 20 },\n    }),\n  });\n\n  const { data } = await res.json();\n  return data.products;\n}\n\n// Authenticated request:\nasync function getOrders(\n  apiUrl: string,\n  getToken: () => Promise<string | null>,\n) {\n  const token = await getToken();\n  const res = await fetch(`${apiUrl}/api/v1/website/graphql`, {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      ...createAuthHeaders(token),\n    },\n    body: JSON.stringify({\n      query: documents.GET_ORDERS,\n      variables: { limit: 10 },\n    }),\n  });\n\n  const { data } = await res.json();\n  return data.orders;\n}\n```\n\n### Available Documents\n\n| Document                     | Type     | Description                                                            |\n| ---------------------------- | -------- | ---------------------------------------------------------------------- |\n| `RESOLVE_WEBSITE_BY_SLUG`    | Query    | Resolve website by slug                                                |\n| `GET_PRODUCTS`               | Query    | List products with variants, prices, media, attributes                 |\n| `GET_PRODUCT_BY_PK`          | Query    | Single product with full details                                       |\n| `GET_CATEGORIES`             | Query    | All categories with subcategories                                      |\n| `GET_BRANDS`                 | Query    | Company brands                                                         |\n| `CHECK_AVAILABILITY`         | Query    | Stock availability (boolean + label)                                   |\n| `GET_PRODUCT_FILTERS`        | Query    | Universal facets (price range, brands with counts, categories/colors)  |\n| `GET_ATTRIBUTE_FACETS`       | Query    | Category-specific attribute facets with value counts                   |\n| `GET_SEARCH_SUGGESTIONS`     | Query    | Lightweight product/brand name search for autocomplete                 |\n| `CREATE_CART`                | Mutation | Compatibility cart creation                                            |\n| `GET_CART`                   | Mutation | Current `WEB + PENDING + UNPAID` checkout with line items              |\n| `START_GUEST_CHECKOUT`       | Mutation | Create/update `WEB + PENDING + UNPAID` from contact + local cart items |\n| `SET_CART_ITEM`              | Mutation | Update item quantity after checkout has started                        |\n| `REMOVE_CART_ITEM`           | Mutation | Remove item after checkout has started                                 |\n| `GET_SHIPPING_POLICY`        | Mutation | Public website free-shipping policy without a cart                     |\n| `GET_FREE_SHIPPING_PROGRESS` | Mutation | Server-calculated progress from current cart items                     |\n| `GET_SHIPPING_QUOTES`        | Mutation | Final shipping quotes for an address                                   |\n| `CHECKOUT`                   | Mutation | Confirm checkout, assign client and order number                       |\n| `GET_ORDERS`                 | Query    | Order history                                                          |\n| `GET_ORDER_BY_PK`            | Query    | Single order with items                                                |\n| `GET_PROFILE`                | Query    | Customer profile                                                       |\n| `UPDATE_PROFILE`             | Mutation | Update customer profile                                                |\n\n---\n\n## SSR / Next.js Server-Side Usage\n\nFor server-side rendering or Server Components, use `memory` cart storage and\nprovide a server-side Clerk token provider when the request is authenticated:\n\n```typescript\nimport { createBacanoClient } from \"@bacano/sdk\";\n\n// In getServerSideProps or a Server Component:\nconst client = createBacanoClient({\n  apiUrl: process.env.BACANO_API_URL!,\n  websiteSlug: \"my-store\",\n  tokenStorage: \"memory\",\n  getAccessToken: async () => tokenFromClerkServerAuth ?? null,\n});\n\nawait client.init();\nconst orders = await client.orders.list();\n```\n\nProtected server-side requests must also reach Bacano with the storefront's\nexact configured `Origin`. Browser requests add it automatically; server\nproxies must preserve it.\n\n---\n\n## Error Handling\n\nThe SDK throws typed errors you can catch and handle:\n\n```typescript\nimport {\n  WebsiteError,\n  RateLimitError,\n  AuthError,\n  CheckoutError,\n  NotInitializedError,\n  GraphQLRequestError,\n} from \"@bacano/sdk\";\n\ntry {\n  await client.checkout.submit({\n    contact: { email: \"buyer@example.com\", phone: \"+573001112233\" },\n  });\n} catch (err) {\n  if (err instanceof CheckoutError) {\n    // Checkout validation failed\n    console.log(\"Validation errors:\", err.errors);\n    // e.g., [\"Insufficient stock for SKU-001\", \"Product XYZ is no longer available\"]\n    // ORDER_CONFIRMATION_RETRYABLE can be retried with checkout.submit;\n    // the SDK intentionally preserves the current cart session.\n  } else if (err instanceof AuthError) {\n    // Not logged in or session expired\n    console.log(\"Please log in again\");\n  } else if (err instanceof GraphQLRequestError) {\n    // Hasura returned GraphQL errors\n    console.log(\"GraphQL errors:\", err.graphqlErrors);\n  } else if (err instanceof NotInitializedError) {\n    // client.init() was not called\n  } else if (err instanceof RateLimitError) {\n    console.log(\"Retry after seconds:\", err.retryAfterSeconds);\n  } else if (err instanceof WebsiteError) {\n    // Other SDK error (network, rate limit, etc.)\n    console.log(\"Error code:\", err.code);\n    // Codes: NETWORK_ERROR, RATE_LIMITED, INVALID_RESPONSE,\n    // WEBSITE_NOT_FOUND, NO_CHAIN, etc.\n  }\n}\n```\n\n`RATE_LIMITED` errors expose `status = 429` and `retryAfterSeconds`. Normal SDK\noperations do not retry mutations automatically. The static catalog snapshot\nis a read-only build contract and safely retries up to four times, never before\nthe server's `Retry-After` window and with a three-minute cumulative wait cap.\n\nCommon setup errors:\n\n| Code / message      | Meaning                                        | Fix                                                            |\n| ------------------- | ---------------------------------------------- | -------------------------------------------------------------- |\n| `WEBSITE_NOT_FOUND` | No active website matches slug/domain.         | Check slug/domain and active status in Bacano.                 |\n| `NO_CHAIN`          | Website has no branch.  ","readmeFilename":"README.md"}