@cimplify/sdk 0.40.1 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/deploy.mjs +561 -0
- package/dist/cli/commands/dev.mjs +434 -0
- package/dist/cli/commands/domains.mjs +479 -0
- package/dist/cli/commands/env.mjs +610 -0
- package/dist/cli/commands/link.mjs +325 -0
- package/dist/cli/commands/login.mjs +515 -0
- package/dist/cli/commands/logout.mjs +54 -0
- package/dist/cli/commands/logs.mjs +358 -0
- package/dist/cli/commands/projects.mjs +327 -0
- package/dist/cli/commands/rollback.mjs +477 -0
- package/dist/cli/commands/status.mjs +380 -0
- package/dist/cli/commands/unlink.mjs +58 -0
- package/dist/cli/commands/whoami.mjs +234 -0
- package/dist/dispatcher.mjs +94 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/templates/storefront-bakery/.env.example +5 -0
- package/templates/storefront-bakery/AGENTS.md +57 -0
- package/templates/storefront-bakery/app/about/page.tsx +21 -44
- package/templates/storefront-bakery/app/accessibility/page.tsx +11 -0
- package/templates/storefront-bakery/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-bakery/app/account/orders/page.tsx +21 -0
- package/templates/storefront-bakery/app/account/page.tsx +22 -0
- package/templates/storefront-bakery/app/account/settings/page.tsx +21 -0
- package/templates/storefront-bakery/app/categories/[slug]/page.tsx +2 -1
- package/templates/storefront-bakery/app/collections/[slug]/page.tsx +2 -1
- package/templates/storefront-bakery/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-bakery/app/contact/page.tsx +54 -0
- package/templates/storefront-bakery/app/error.tsx +60 -0
- package/templates/storefront-bakery/app/faq/page.tsx +13 -89
- package/templates/storefront-bakery/app/layout.tsx +37 -2
- package/templates/storefront-bakery/app/llms.txt/route.ts +94 -0
- package/templates/storefront-bakery/app/login/page.tsx +17 -0
- package/templates/storefront-bakery/app/not-found.tsx +39 -0
- package/templates/storefront-bakery/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-bakery/app/page.tsx +6 -6
- package/templates/storefront-bakery/app/privacy/page.tsx +24 -68
- package/templates/storefront-bakery/app/returns/page.tsx +11 -0
- package/templates/storefront-bakery/app/robots.ts +18 -0
- package/templates/storefront-bakery/app/search/page.tsx +38 -0
- package/templates/storefront-bakery/app/search/search-client.tsx +7 -0
- package/templates/storefront-bakery/app/shipping/page.tsx +16 -0
- package/templates/storefront-bakery/app/shop/page.tsx +3 -2
- package/templates/storefront-bakery/app/signup/page.tsx +17 -0
- package/templates/storefront-bakery/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-bakery/app/sitemap.ts +62 -0
- package/templates/storefront-bakery/app/terms/page.tsx +24 -82
- package/templates/storefront-bakery/app/track-order/page.tsx +24 -0
- package/templates/storefront-bakery/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-bakery/components/account-iframe.tsx +13 -0
- package/templates/storefront-bakery/components/footer.tsx +88 -130
- package/templates/storefront-bakery/components/header.tsx +8 -16
- package/templates/storefront-bakery/components/policy-page.tsx +49 -0
- package/templates/storefront-bakery/lib/brand.ts +568 -0
- package/templates/storefront-fashion/.env.example +16 -0
- package/templates/storefront-fashion/AGENTS.md +52 -0
- package/templates/storefront-fashion/README.md +77 -0
- package/templates/storefront-fashion/app/about/page.tsx +41 -0
- package/templates/storefront-fashion/app/accessibility/page.tsx +11 -0
- package/templates/storefront-fashion/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-fashion/app/account/orders/page.tsx +21 -0
- package/templates/storefront-fashion/app/account/page.tsx +22 -0
- package/templates/storefront-fashion/app/account/settings/page.tsx +21 -0
- package/templates/storefront-fashion/app/cart/page.tsx +9 -0
- package/templates/storefront-fashion/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-fashion/app/categories/[slug]/page.tsx +130 -0
- package/templates/storefront-fashion/app/checkout/page.tsx +17 -0
- package/templates/storefront-fashion/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-fashion/app/collections/[slug]/page.tsx +130 -0
- package/templates/storefront-fashion/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-fashion/app/contact/page.tsx +54 -0
- package/templates/storefront-fashion/app/error.tsx +61 -0
- package/templates/storefront-fashion/app/faq/page.tsx +46 -0
- package/templates/storefront-fashion/app/globals.css +46 -0
- package/templates/storefront-fashion/app/layout.tsx +76 -0
- package/templates/storefront-fashion/app/llms.txt/route.ts +94 -0
- package/templates/storefront-fashion/app/login/page.tsx +17 -0
- package/templates/storefront-fashion/app/lookbook/page.tsx +132 -0
- package/templates/storefront-fashion/app/not-found.tsx +39 -0
- package/templates/storefront-fashion/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-fashion/app/orders/[id]/page.tsx +24 -0
- package/templates/storefront-fashion/app/page.tsx +183 -0
- package/templates/storefront-fashion/app/privacy/page.tsx +44 -0
- package/templates/storefront-fashion/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-fashion/app/products/[slug]/product-detail.tsx +71 -0
- package/templates/storefront-fashion/app/returns/page.tsx +11 -0
- package/templates/storefront-fashion/app/robots.ts +18 -0
- package/templates/storefront-fashion/app/search/page.tsx +38 -0
- package/templates/storefront-fashion/app/search/search-client.tsx +7 -0
- package/templates/storefront-fashion/app/shipping/page.tsx +16 -0
- package/templates/storefront-fashion/app/shop/page.tsx +63 -0
- package/templates/storefront-fashion/app/shop/shop-client.tsx +32 -0
- package/templates/storefront-fashion/app/signup/page.tsx +17 -0
- package/templates/storefront-fashion/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-fashion/app/sitemap.ts +59 -0
- package/templates/storefront-fashion/app/size-guide/page.tsx +155 -0
- package/templates/storefront-fashion/app/terms/page.tsx +44 -0
- package/templates/storefront-fashion/app/track-order/page.tsx +24 -0
- package/templates/storefront-fashion/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-fashion/components/account-iframe.tsx +13 -0
- package/templates/storefront-fashion/components/brand-marquee.tsx +27 -0
- package/templates/storefront-fashion/components/cart-pill.tsx +32 -0
- package/templates/storefront-fashion/components/category-grid.tsx +28 -0
- package/templates/storefront-fashion/components/category-tiles.tsx +104 -0
- package/templates/storefront-fashion/components/collection-strip.tsx +45 -0
- package/templates/storefront-fashion/components/feature-hero.tsx +82 -0
- package/templates/storefront-fashion/components/footer.tsx +153 -0
- package/templates/storefront-fashion/components/header.tsx +43 -0
- package/templates/storefront-fashion/components/hero.tsx +28 -0
- package/templates/storefront-fashion/components/nav-link.tsx +20 -0
- package/templates/storefront-fashion/components/newsletter.tsx +50 -0
- package/templates/storefront-fashion/components/policy-page.tsx +49 -0
- package/templates/storefront-fashion/components/promo-banner.tsx +41 -0
- package/templates/storefront-fashion/components/providers.tsx +31 -0
- package/templates/storefront-fashion/components/section-heading.tsx +37 -0
- package/templates/storefront-fashion/components/store-product-card.tsx +83 -0
- package/templates/storefront-fashion/components/trade-in-cta.tsx +54 -0
- package/templates/storefront-fashion/components/trust-bar.tsx +66 -0
- package/templates/storefront-fashion/lib/brand.ts +516 -0
- package/templates/storefront-fashion/lib/cart.ts +27 -0
- package/templates/storefront-fashion/next.config.ts +40 -0
- package/templates/storefront-fashion/package.json +28 -0
- package/templates/storefront-fashion/postcss.config.mjs +7 -0
- package/templates/storefront-fashion/tsconfig.json +23 -0
- package/templates/storefront-grocery/.env.example +16 -0
- package/templates/storefront-grocery/AGENTS.md +39 -0
- package/templates/storefront-grocery/README.md +73 -0
- package/templates/storefront-grocery/app/about/page.tsx +38 -0
- package/templates/storefront-grocery/app/accessibility/page.tsx +11 -0
- package/templates/storefront-grocery/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-grocery/app/account/orders/page.tsx +21 -0
- package/templates/storefront-grocery/app/account/page.tsx +22 -0
- package/templates/storefront-grocery/app/account/settings/page.tsx +21 -0
- package/templates/storefront-grocery/app/cart/page.tsx +9 -0
- package/templates/storefront-grocery/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-grocery/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-grocery/app/checkout/page.tsx +17 -0
- package/templates/storefront-grocery/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-grocery/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-grocery/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-grocery/app/contact/page.tsx +54 -0
- package/templates/storefront-grocery/app/error.tsx +60 -0
- package/templates/storefront-grocery/app/faq/page.tsx +46 -0
- package/templates/storefront-grocery/app/globals.css +45 -0
- package/templates/storefront-grocery/app/layout.tsx +75 -0
- package/templates/storefront-grocery/app/llms.txt/route.ts +94 -0
- package/templates/storefront-grocery/app/login/page.tsx +17 -0
- package/templates/storefront-grocery/app/not-found.tsx +39 -0
- package/templates/storefront-grocery/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-grocery/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-grocery/app/page.tsx +97 -0
- package/templates/storefront-grocery/app/privacy/page.tsx +44 -0
- package/templates/storefront-grocery/app/returns/page.tsx +11 -0
- package/templates/storefront-grocery/app/robots.ts +18 -0
- package/templates/storefront-grocery/app/search/page.tsx +38 -0
- package/templates/storefront-grocery/app/search/search-client.tsx +7 -0
- package/templates/storefront-grocery/app/shipping/page.tsx +16 -0
- package/templates/storefront-grocery/app/shop/page.tsx +31 -0
- package/templates/storefront-grocery/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-grocery/app/signup/page.tsx +17 -0
- package/templates/storefront-grocery/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-grocery/app/sitemap.ts +62 -0
- package/templates/storefront-grocery/app/terms/page.tsx +44 -0
- package/templates/storefront-grocery/app/track-order/page.tsx +24 -0
- package/templates/storefront-grocery/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-grocery/components/account-iframe.tsx +13 -0
- package/templates/storefront-grocery/components/cart-pill.tsx +32 -0
- package/templates/storefront-grocery/components/category-grid.tsx +28 -0
- package/templates/storefront-grocery/components/collection-strip.tsx +45 -0
- package/templates/storefront-grocery/components/footer.tsx +148 -0
- package/templates/storefront-grocery/components/header.tsx +43 -0
- package/templates/storefront-grocery/components/hero.tsx +25 -0
- package/templates/storefront-grocery/components/nav-link.tsx +20 -0
- package/templates/storefront-grocery/components/policy-page.tsx +49 -0
- package/templates/storefront-grocery/components/providers.tsx +31 -0
- package/templates/storefront-grocery/components/store-product-card.tsx +83 -0
- package/templates/storefront-grocery/lib/brand.ts +373 -0
- package/templates/storefront-grocery/lib/cart.ts +27 -0
- package/templates/storefront-grocery/next.config.ts +40 -0
- package/templates/storefront-grocery/package.json +28 -0
- package/templates/storefront-grocery/postcss.config.mjs +7 -0
- package/templates/storefront-grocery/tsconfig.json +23 -0
- package/templates/storefront-restaurant/.env.example +16 -0
- package/templates/storefront-restaurant/AGENTS.md +39 -0
- package/templates/storefront-restaurant/README.md +73 -0
- package/templates/storefront-restaurant/app/about/page.tsx +38 -0
- package/templates/storefront-restaurant/app/accessibility/page.tsx +11 -0
- package/templates/storefront-restaurant/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-restaurant/app/account/orders/page.tsx +21 -0
- package/templates/storefront-restaurant/app/account/page.tsx +22 -0
- package/templates/storefront-restaurant/app/account/settings/page.tsx +21 -0
- package/templates/storefront-restaurant/app/cart/page.tsx +9 -0
- package/templates/storefront-restaurant/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-restaurant/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-restaurant/app/checkout/page.tsx +17 -0
- package/templates/storefront-restaurant/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-restaurant/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-restaurant/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-restaurant/app/contact/page.tsx +54 -0
- package/templates/storefront-restaurant/app/error.tsx +60 -0
- package/templates/storefront-restaurant/app/faq/page.tsx +46 -0
- package/templates/storefront-restaurant/app/globals.css +44 -0
- package/templates/storefront-restaurant/app/layout.tsx +80 -0
- package/templates/storefront-restaurant/app/llms.txt/route.ts +94 -0
- package/templates/storefront-restaurant/app/login/page.tsx +17 -0
- package/templates/storefront-restaurant/app/not-found.tsx +39 -0
- package/templates/storefront-restaurant/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-restaurant/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-restaurant/app/page.tsx +97 -0
- package/templates/storefront-restaurant/app/privacy/page.tsx +44 -0
- package/templates/storefront-restaurant/app/reservations/page.tsx +66 -0
- package/templates/storefront-restaurant/app/reservations/reservations-client.tsx +234 -0
- package/templates/storefront-restaurant/app/returns/page.tsx +11 -0
- package/templates/storefront-restaurant/app/robots.ts +18 -0
- package/templates/storefront-restaurant/app/search/page.tsx +38 -0
- package/templates/storefront-restaurant/app/search/search-client.tsx +7 -0
- package/templates/storefront-restaurant/app/shipping/page.tsx +16 -0
- package/templates/storefront-restaurant/app/shop/page.tsx +31 -0
- package/templates/storefront-restaurant/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-restaurant/app/signup/page.tsx +17 -0
- package/templates/storefront-restaurant/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-restaurant/app/sitemap.ts +62 -0
- package/templates/storefront-restaurant/app/terms/page.tsx +44 -0
- package/templates/storefront-restaurant/app/track-order/page.tsx +24 -0
- package/templates/storefront-restaurant/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-restaurant/components/account-iframe.tsx +13 -0
- package/templates/storefront-restaurant/components/cart-pill.tsx +32 -0
- package/templates/storefront-restaurant/components/category-grid.tsx +28 -0
- package/templates/storefront-restaurant/components/collection-strip.tsx +45 -0
- package/templates/storefront-restaurant/components/footer.tsx +148 -0
- package/templates/storefront-restaurant/components/header.tsx +43 -0
- package/templates/storefront-restaurant/components/hero.tsx +25 -0
- package/templates/storefront-restaurant/components/nav-link.tsx +20 -0
- package/templates/storefront-restaurant/components/policy-page.tsx +49 -0
- package/templates/storefront-restaurant/components/product-modal.tsx +105 -0
- package/templates/storefront-restaurant/components/providers.tsx +31 -0
- package/templates/storefront-restaurant/components/store-product-card.tsx +83 -0
- package/templates/storefront-restaurant/lib/brand.ts +375 -0
- package/templates/storefront-restaurant/lib/cart.ts +27 -0
- package/templates/storefront-restaurant/next.config.ts +40 -0
- package/templates/storefront-restaurant/package.json +28 -0
- package/templates/storefront-restaurant/postcss.config.mjs +7 -0
- package/templates/storefront-restaurant/tsconfig.json +23 -0
- package/templates/storefront-retail/.env.example +5 -0
- package/templates/storefront-retail/AGENTS.md +64 -0
- package/templates/storefront-retail/app/about/page.tsx +24 -54
- package/templates/storefront-retail/app/accessibility/page.tsx +11 -0
- package/templates/storefront-retail/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-retail/app/account/orders/page.tsx +21 -0
- package/templates/storefront-retail/app/account/page.tsx +22 -0
- package/templates/storefront-retail/app/account/settings/page.tsx +21 -0
- package/templates/storefront-retail/app/categories/[slug]/page.tsx +2 -1
- package/templates/storefront-retail/app/collections/[slug]/page.tsx +2 -1
- package/templates/storefront-retail/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-retail/app/contact/page.tsx +54 -0
- package/templates/storefront-retail/app/error.tsx +61 -0
- package/templates/storefront-retail/app/faq/page.tsx +11 -92
- package/templates/storefront-retail/app/layout.tsx +37 -8
- package/templates/storefront-retail/app/llms.txt/route.ts +94 -0
- package/templates/storefront-retail/app/login/page.tsx +17 -0
- package/templates/storefront-retail/app/not-found.tsx +39 -0
- package/templates/storefront-retail/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-retail/app/page.tsx +16 -73
- package/templates/storefront-retail/app/privacy/page.tsx +24 -81
- package/templates/storefront-retail/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-retail/app/products/[slug]/product-detail.tsx +71 -0
- package/templates/storefront-retail/app/returns/page.tsx +11 -0
- package/templates/storefront-retail/app/robots.ts +18 -0
- package/templates/storefront-retail/app/search/page.tsx +38 -0
- package/templates/storefront-retail/app/search/search-client.tsx +7 -0
- package/templates/storefront-retail/app/shipping/page.tsx +16 -0
- package/templates/storefront-retail/app/shop/page.tsx +3 -3
- package/templates/storefront-retail/app/signup/page.tsx +17 -0
- package/templates/storefront-retail/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-retail/app/sitemap.ts +59 -0
- package/templates/storefront-retail/app/terms/page.tsx +24 -97
- package/templates/storefront-retail/app/track-order/page.tsx +24 -0
- package/templates/storefront-retail/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-retail/components/account-iframe.tsx +13 -0
- package/templates/storefront-retail/components/brand-marquee.tsx +6 -15
- package/templates/storefront-retail/components/feature-hero.tsx +2 -1
- package/templates/storefront-retail/components/footer.tsx +85 -120
- package/templates/storefront-retail/components/header.tsx +10 -12
- package/templates/storefront-retail/components/newsletter.tsx +7 -9
- package/templates/storefront-retail/components/policy-page.tsx +49 -0
- package/templates/storefront-retail/components/promo-banner.tsx +12 -15
- package/templates/storefront-retail/components/store-product-card.tsx +7 -7
- package/templates/storefront-retail/components/trade-in-cta.tsx +11 -17
- package/templates/storefront-retail/components/trust-bar.tsx +45 -5
- package/templates/storefront-retail/lib/brand.ts +663 -0
- package/templates/storefront-services/.env.example +16 -0
- package/templates/storefront-services/AGENTS.md +41 -0
- package/templates/storefront-services/README.md +73 -0
- package/templates/storefront-services/app/about/page.tsx +38 -0
- package/templates/storefront-services/app/accessibility/page.tsx +11 -0
- package/templates/storefront-services/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-services/app/account/orders/page.tsx +21 -0
- package/templates/storefront-services/app/account/page.tsx +22 -0
- package/templates/storefront-services/app/account/settings/page.tsx +21 -0
- package/templates/storefront-services/app/book/book-client.tsx +195 -0
- package/templates/storefront-services/app/book/page.tsx +65 -0
- package/templates/storefront-services/app/cart/page.tsx +9 -0
- package/templates/storefront-services/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-services/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-services/app/checkout/page.tsx +17 -0
- package/templates/storefront-services/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-services/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-services/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-services/app/contact/page.tsx +54 -0
- package/templates/storefront-services/app/error.tsx +60 -0
- package/templates/storefront-services/app/faq/page.tsx +46 -0
- package/templates/storefront-services/app/globals.css +45 -0
- package/templates/storefront-services/app/layout.tsx +80 -0
- package/templates/storefront-services/app/llms.txt/route.ts +94 -0
- package/templates/storefront-services/app/login/page.tsx +17 -0
- package/templates/storefront-services/app/not-found.tsx +39 -0
- package/templates/storefront-services/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-services/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-services/app/page.tsx +97 -0
- package/templates/storefront-services/app/privacy/page.tsx +44 -0
- package/templates/storefront-services/app/returns/page.tsx +11 -0
- package/templates/storefront-services/app/robots.ts +18 -0
- package/templates/storefront-services/app/search/page.tsx +38 -0
- package/templates/storefront-services/app/search/search-client.tsx +7 -0
- package/templates/storefront-services/app/shipping/page.tsx +16 -0
- package/templates/storefront-services/app/shop/page.tsx +31 -0
- package/templates/storefront-services/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-services/app/signup/page.tsx +17 -0
- package/templates/storefront-services/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-services/app/sitemap.ts +62 -0
- package/templates/storefront-services/app/terms/page.tsx +44 -0
- package/templates/storefront-services/app/track-order/page.tsx +24 -0
- package/templates/storefront-services/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-services/components/account-iframe.tsx +13 -0
- package/templates/storefront-services/components/cart-pill.tsx +32 -0
- package/templates/storefront-services/components/category-grid.tsx +28 -0
- package/templates/storefront-services/components/collection-strip.tsx +45 -0
- package/templates/storefront-services/components/footer.tsx +148 -0
- package/templates/storefront-services/components/header.tsx +43 -0
- package/templates/storefront-services/components/hero.tsx +25 -0
- package/templates/storefront-services/components/nav-link.tsx +20 -0
- package/templates/storefront-services/components/policy-page.tsx +49 -0
- package/templates/storefront-services/components/product-modal.tsx +105 -0
- package/templates/storefront-services/components/providers.tsx +31 -0
- package/templates/storefront-services/components/store-product-card.tsx +83 -0
- package/templates/storefront-services/lib/brand.ts +394 -0
- package/templates/storefront-services/lib/cart.ts +27 -0
- package/templates/storefront-services/next.config.ts +40 -0
- package/templates/storefront-services/package.json +28 -0
- package/templates/storefront-services/postcss.config.mjs +7 -0
- package/templates/storefront-services/tsconfig.json +23 -0
- /package/templates/{storefront-retail → storefront-grocery}/components/product-modal.tsx +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { promises } from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
// src/cli/errors.ts
|
|
6
|
+
var CLI_ERROR_CODE = {
|
|
7
|
+
NOT_LOGGED_IN: "NOT_LOGGED_IN",
|
|
8
|
+
NOT_LINKED: "NOT_LINKED",
|
|
9
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
10
|
+
AUTH_FAILED: "AUTH_FAILED",
|
|
11
|
+
PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
|
|
12
|
+
INVALID_INPUT: "INVALID_INPUT",
|
|
13
|
+
ALREADY_LINKED: "ALREADY_LINKED",
|
|
14
|
+
SERVER_ERROR: "SERVER_ERROR"};
|
|
15
|
+
var EXIT_CODE = {
|
|
16
|
+
ERROR: 1};
|
|
17
|
+
var CliError = class extends Error {
|
|
18
|
+
constructor(code, message, exitCode = EXIT_CODE.ERROR) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = "CliError";
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.exitCode = exitCode;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/cli/api-client.ts
|
|
27
|
+
var DEFAULT_API_BASE_URL = "https://api.cimplify.io";
|
|
28
|
+
var ENV_API_BASE_URL = "CIMPLIFY_API_URL";
|
|
29
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
30
|
+
var HEADER_AUTHORIZATION = "Authorization";
|
|
31
|
+
var HEADER_CONTENT_TYPE = "Content-Type";
|
|
32
|
+
var HEADER_ACCEPT = "Accept";
|
|
33
|
+
var HEADER_USER_AGENT = "User-Agent";
|
|
34
|
+
var BEARER_PREFIX = "Bearer ";
|
|
35
|
+
var CONTENT_TYPE_JSON = "application/json";
|
|
36
|
+
var USER_AGENT = "cimplify-cli";
|
|
37
|
+
var METHOD_GET = "GET";
|
|
38
|
+
var METHOD_POST = "POST";
|
|
39
|
+
var METHOD_PUT = "PUT";
|
|
40
|
+
var METHOD_DELETE = "DELETE";
|
|
41
|
+
var STATUS_UNAUTHORIZED = 401;
|
|
42
|
+
var STATUS_FORBIDDEN = 403;
|
|
43
|
+
var STATUS_NOT_FOUND = 404;
|
|
44
|
+
var STATUS_CONFLICT = 409;
|
|
45
|
+
var STATUS_BAD_REQUEST_MIN = 400;
|
|
46
|
+
var STATUS_SERVER_ERROR_MIN = 500;
|
|
47
|
+
var ApiClient = class _ApiClient {
|
|
48
|
+
constructor(baseUrl, apiKey) {
|
|
49
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
50
|
+
this.apiKey = apiKey;
|
|
51
|
+
}
|
|
52
|
+
static fromAuth(auth) {
|
|
53
|
+
return new _ApiClient(auth.apiBaseUrl, auth.apiKey);
|
|
54
|
+
}
|
|
55
|
+
static unauthenticated(baseUrl = resolveBaseUrl()) {
|
|
56
|
+
return new _ApiClient(baseUrl, "");
|
|
57
|
+
}
|
|
58
|
+
static withKey(apiKey, baseUrl = resolveBaseUrl()) {
|
|
59
|
+
return new _ApiClient(baseUrl, apiKey);
|
|
60
|
+
}
|
|
61
|
+
get(pathname, options) {
|
|
62
|
+
return this.request(METHOD_GET, pathname, void 0, options);
|
|
63
|
+
}
|
|
64
|
+
post(pathname, body, options) {
|
|
65
|
+
return this.request(METHOD_POST, pathname, body, options);
|
|
66
|
+
}
|
|
67
|
+
put(pathname, body, options) {
|
|
68
|
+
return this.request(METHOD_PUT, pathname, body, options);
|
|
69
|
+
}
|
|
70
|
+
delete(pathname, options) {
|
|
71
|
+
return this.request(METHOD_DELETE, pathname, void 0, options);
|
|
72
|
+
}
|
|
73
|
+
async request(method, pathname, body, options) {
|
|
74
|
+
const url = this.buildUrl(pathname, options?.query);
|
|
75
|
+
const headers = {
|
|
76
|
+
[HEADER_ACCEPT]: CONTENT_TYPE_JSON,
|
|
77
|
+
[HEADER_USER_AGENT]: USER_AGENT
|
|
78
|
+
};
|
|
79
|
+
if (this.apiKey) {
|
|
80
|
+
headers[HEADER_AUTHORIZATION] = `${BEARER_PREFIX}${this.apiKey}`;
|
|
81
|
+
}
|
|
82
|
+
let payload;
|
|
83
|
+
if (body !== void 0) {
|
|
84
|
+
headers[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON;
|
|
85
|
+
payload = JSON.stringify(body);
|
|
86
|
+
}
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
89
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
90
|
+
let response;
|
|
91
|
+
try {
|
|
92
|
+
response = await fetch(url, {
|
|
93
|
+
method,
|
|
94
|
+
headers,
|
|
95
|
+
body: payload,
|
|
96
|
+
signal: controller.signal
|
|
97
|
+
});
|
|
98
|
+
} catch (err) {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
throw toNetworkError(err);
|
|
101
|
+
}
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
return parseResponse(response);
|
|
104
|
+
}
|
|
105
|
+
buildUrl(pathname, query) {
|
|
106
|
+
const base = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
107
|
+
const url = new URL(`${this.baseUrl}${base}`);
|
|
108
|
+
if (query) {
|
|
109
|
+
for (const [k, v] of Object.entries(query)) {
|
|
110
|
+
if (v === void 0 || v === null) continue;
|
|
111
|
+
url.searchParams.set(k, String(v));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return url.toString();
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
function resolveBaseUrl(override) {
|
|
118
|
+
const fromEnv = process.env[ENV_API_BASE_URL];
|
|
119
|
+
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_API_BASE_URL;
|
|
120
|
+
}
|
|
121
|
+
async function parseResponse(response) {
|
|
122
|
+
const text = await response.text();
|
|
123
|
+
let body = void 0;
|
|
124
|
+
if (text.length > 0) {
|
|
125
|
+
try {
|
|
126
|
+
body = JSON.parse(text);
|
|
127
|
+
} catch {
|
|
128
|
+
throw new CliError(
|
|
129
|
+
CLI_ERROR_CODE.SERVER_ERROR,
|
|
130
|
+
`Server returned non-JSON response (status ${response.status}): ${truncate(text)}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (response.ok) {
|
|
135
|
+
if (body && typeof body === "object" && "data" in body) {
|
|
136
|
+
return body.data;
|
|
137
|
+
}
|
|
138
|
+
return body;
|
|
139
|
+
}
|
|
140
|
+
const code = mapStatusToCode(response.status);
|
|
141
|
+
const message = extractErrorMessage(body, response.status);
|
|
142
|
+
throw new CliError(code, message);
|
|
143
|
+
}
|
|
144
|
+
function mapStatusToCode(status) {
|
|
145
|
+
if (status === STATUS_UNAUTHORIZED) return CLI_ERROR_CODE.AUTH_FAILED;
|
|
146
|
+
if (status === STATUS_FORBIDDEN) return CLI_ERROR_CODE.AUTH_FAILED;
|
|
147
|
+
if (status === STATUS_NOT_FOUND) return CLI_ERROR_CODE.PROJECT_NOT_FOUND;
|
|
148
|
+
if (status === STATUS_CONFLICT) return CLI_ERROR_CODE.ALREADY_LINKED;
|
|
149
|
+
if (status >= STATUS_SERVER_ERROR_MIN) return CLI_ERROR_CODE.SERVER_ERROR;
|
|
150
|
+
if (status >= STATUS_BAD_REQUEST_MIN) return CLI_ERROR_CODE.INVALID_INPUT;
|
|
151
|
+
return CLI_ERROR_CODE.SERVER_ERROR;
|
|
152
|
+
}
|
|
153
|
+
function extractErrorMessage(body, status) {
|
|
154
|
+
if (body && typeof body === "object") {
|
|
155
|
+
const envelope = body;
|
|
156
|
+
if (envelope.error && typeof envelope.error.error_message === "string") {
|
|
157
|
+
return envelope.error.error_code ? `${envelope.error.error_code}: ${envelope.error.error_message}` : envelope.error.error_message;
|
|
158
|
+
}
|
|
159
|
+
if (typeof envelope.message === "string") return envelope.message;
|
|
160
|
+
}
|
|
161
|
+
return `HTTP ${status}`;
|
|
162
|
+
}
|
|
163
|
+
function toNetworkError(err) {
|
|
164
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
165
|
+
return new CliError(CLI_ERROR_CODE.NETWORK_ERROR, "Request timed out.");
|
|
166
|
+
}
|
|
167
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
168
|
+
return new CliError(CLI_ERROR_CODE.NETWORK_ERROR, `Network error: ${message}`);
|
|
169
|
+
}
|
|
170
|
+
function truncate(value, max = 200) {
|
|
171
|
+
return value.length > max ? `${value.slice(0, max)}\u2026` : value;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/cli/args.ts
|
|
175
|
+
function parseArgs(argv) {
|
|
176
|
+
const positional = [];
|
|
177
|
+
const flags = /* @__PURE__ */ new Map();
|
|
178
|
+
for (let i = 0; i < argv.length; i++) {
|
|
179
|
+
const arg = argv[i];
|
|
180
|
+
if (!arg.startsWith("--")) {
|
|
181
|
+
positional.push(arg);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const eq = arg.indexOf("=");
|
|
185
|
+
if (eq !== -1) {
|
|
186
|
+
flags.set(arg.slice(2, eq), arg.slice(eq + 1));
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const name = arg.slice(2);
|
|
190
|
+
const next = argv[i + 1];
|
|
191
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
192
|
+
flags.set(name, next);
|
|
193
|
+
i++;
|
|
194
|
+
} else {
|
|
195
|
+
flags.set(name, true);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return { positional, flags };
|
|
199
|
+
}
|
|
200
|
+
var AUTH_FILE_NAME = "auth.json";
|
|
201
|
+
var PROJECT_FILE_NAME = "project.json";
|
|
202
|
+
var STATE_FILE_NAME = "state.json";
|
|
203
|
+
var PROJECT_DIR_NAME = ".cimplify";
|
|
204
|
+
var ENV_XDG_CONFIG_HOME = "XDG_CONFIG_HOME";
|
|
205
|
+
var APP_CONFIG_DIR_NAME = "cimplify";
|
|
206
|
+
var HOME_CONFIG_DIR_NAME = ".config";
|
|
207
|
+
var ENCODING_UTF8 = "utf8";
|
|
208
|
+
function authConfigDir() {
|
|
209
|
+
const xdg = process.env[ENV_XDG_CONFIG_HOME];
|
|
210
|
+
return xdg ? path.join(xdg, APP_CONFIG_DIR_NAME) : path.join(os.homedir(), HOME_CONFIG_DIR_NAME, APP_CONFIG_DIR_NAME);
|
|
211
|
+
}
|
|
212
|
+
function authConfigPath() {
|
|
213
|
+
return path.join(authConfigDir(), AUTH_FILE_NAME);
|
|
214
|
+
}
|
|
215
|
+
function projectConfigDir(cwd = process.cwd()) {
|
|
216
|
+
return path.join(cwd, PROJECT_DIR_NAME);
|
|
217
|
+
}
|
|
218
|
+
function projectConfigPath(cwd = process.cwd()) {
|
|
219
|
+
return path.join(projectConfigDir(cwd), PROJECT_FILE_NAME);
|
|
220
|
+
}
|
|
221
|
+
function projectStatePath(cwd = process.cwd()) {
|
|
222
|
+
return path.join(projectConfigDir(cwd), STATE_FILE_NAME);
|
|
223
|
+
}
|
|
224
|
+
async function readJsonFile(filePath) {
|
|
225
|
+
try {
|
|
226
|
+
const raw = await promises.readFile(filePath, ENCODING_UTF8);
|
|
227
|
+
return JSON.parse(raw);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
if (err.code === "ENOENT") return null;
|
|
230
|
+
throw err;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function readAuth() {
|
|
234
|
+
const data = await readJsonFile(authConfigPath());
|
|
235
|
+
if (!data) {
|
|
236
|
+
throw new CliError(
|
|
237
|
+
CLI_ERROR_CODE.NOT_LOGGED_IN,
|
|
238
|
+
"Not logged in. Run `cimplify login` first."
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
return data;
|
|
242
|
+
}
|
|
243
|
+
async function readProjectLink(cwd = process.cwd()) {
|
|
244
|
+
const data = await readJsonFile(projectConfigPath(cwd));
|
|
245
|
+
if (!data) {
|
|
246
|
+
throw new CliError(
|
|
247
|
+
CLI_ERROR_CODE.NOT_LINKED,
|
|
248
|
+
"No project linked. Run `cimplify link <project-id>` first."
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return data;
|
|
252
|
+
}
|
|
253
|
+
async function readProjectState(cwd = process.cwd()) {
|
|
254
|
+
return readJsonFile(projectStatePath(cwd));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/cli/output.ts
|
|
258
|
+
var RESET = "\x1B[0m";
|
|
259
|
+
var BOLD_OPEN = "\x1B[1m";
|
|
260
|
+
var DIM_OPEN = "\x1B[2m";
|
|
261
|
+
function wrap(open, value) {
|
|
262
|
+
return `${open}${value}${RESET}`;
|
|
263
|
+
}
|
|
264
|
+
function bold(value) {
|
|
265
|
+
return wrap(BOLD_OPEN, value);
|
|
266
|
+
}
|
|
267
|
+
function dim(value) {
|
|
268
|
+
return wrap(DIM_OPEN, value);
|
|
269
|
+
}
|
|
270
|
+
function info(message) {
|
|
271
|
+
console.log(message);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/cli/types.ts
|
|
275
|
+
var DEPLOYMENT_STATUS = {
|
|
276
|
+
QUEUED: "queued"};
|
|
277
|
+
|
|
278
|
+
// src/cli/commands/status.ts
|
|
279
|
+
var QUERY_LIMIT = "limit";
|
|
280
|
+
var LATEST_DEPLOYMENT_LIMIT = 1;
|
|
281
|
+
var SECONDS_PER_MINUTE = 60;
|
|
282
|
+
var SECONDS_PER_HOUR = 3600;
|
|
283
|
+
var SECONDS_PER_DAY = 86400;
|
|
284
|
+
var SHA_DISPLAY_LEN = 7;
|
|
285
|
+
function deploymentsEndpoint(businessId, projectId) {
|
|
286
|
+
return `/v1/businesses/${encodeURIComponent(businessId)}/projects/${encodeURIComponent(projectId)}/deployments`;
|
|
287
|
+
}
|
|
288
|
+
function deploymentProgressEndpoint(businessId, projectId, deploymentId) {
|
|
289
|
+
return `/v1/businesses/${encodeURIComponent(businessId)}/projects/${encodeURIComponent(projectId)}/deployments/${encodeURIComponent(deploymentId)}/progress`;
|
|
290
|
+
}
|
|
291
|
+
function relativeTime(fromIso, now = /* @__PURE__ */ new Date()) {
|
|
292
|
+
if (!fromIso) return "unknown";
|
|
293
|
+
const then = new Date(fromIso);
|
|
294
|
+
if (Number.isNaN(then.getTime())) return fromIso;
|
|
295
|
+
const diffSec = Math.floor((now.getTime() - then.getTime()) / 1e3);
|
|
296
|
+
if (diffSec < SECONDS_PER_MINUTE) return `${diffSec} second${diffSec === 1 ? "" : "s"} ago`;
|
|
297
|
+
if (diffSec < SECONDS_PER_HOUR) {
|
|
298
|
+
const m = Math.floor(diffSec / SECONDS_PER_MINUTE);
|
|
299
|
+
return `${m} minute${m === 1 ? "" : "s"} ago`;
|
|
300
|
+
}
|
|
301
|
+
if (diffSec < SECONDS_PER_DAY) {
|
|
302
|
+
const h = Math.floor(diffSec / SECONDS_PER_HOUR);
|
|
303
|
+
return `${h} hour${h === 1 ? "" : "s"} ago`;
|
|
304
|
+
}
|
|
305
|
+
const d = Math.floor(diffSec / SECONDS_PER_DAY);
|
|
306
|
+
return `${d} day${d === 1 ? "" : "s"} ago`;
|
|
307
|
+
}
|
|
308
|
+
function renderStatus(link, row, now = /* @__PURE__ */ new Date()) {
|
|
309
|
+
const out = [];
|
|
310
|
+
out.push(`${bold("Project:")} ${link.projectId}${link.framework ? dim(` (${link.framework})`) : ""}`);
|
|
311
|
+
if (link.remoteUrl) {
|
|
312
|
+
const branch = link.defaultBranch ? ` @ ${link.defaultBranch}` : "";
|
|
313
|
+
out.push(`${bold("Linked:")} ${link.remoteUrl}${branch}`);
|
|
314
|
+
}
|
|
315
|
+
out.push("");
|
|
316
|
+
if (!row) {
|
|
317
|
+
out.push(dim("No deployments yet. Run `cimplify deploy`."));
|
|
318
|
+
return out;
|
|
319
|
+
}
|
|
320
|
+
out.push(bold("Latest deployment:"));
|
|
321
|
+
out.push(` ID: ${row.id}`);
|
|
322
|
+
out.push(` Status: ${row.status}`);
|
|
323
|
+
if (row.environment) out.push(` Env: ${row.environment}`);
|
|
324
|
+
if (row.trigger) out.push(` Trigger: ${row.trigger}`);
|
|
325
|
+
if (row.sha) out.push(` SHA: ${row.sha.slice(0, SHA_DISPLAY_LEN)}`);
|
|
326
|
+
if (row.url) out.push(` URL: ${row.url}`);
|
|
327
|
+
if (row.startedAt) out.push(` Started: ${relativeTime(row.startedAt, now)}`);
|
|
328
|
+
return out;
|
|
329
|
+
}
|
|
330
|
+
async function run(argv) {
|
|
331
|
+
parseArgs(argv);
|
|
332
|
+
const auth = await readAuth();
|
|
333
|
+
const link = await readProjectLink();
|
|
334
|
+
const client = ApiClient.fromAuth(auth);
|
|
335
|
+
const state = await readProjectState();
|
|
336
|
+
let row = null;
|
|
337
|
+
if (state?.lastDeploymentId) {
|
|
338
|
+
const progress = await client.get(
|
|
339
|
+
deploymentProgressEndpoint(link.businessId, link.projectId, state.lastDeploymentId)
|
|
340
|
+
);
|
|
341
|
+
row = {
|
|
342
|
+
id: state.lastDeploymentId,
|
|
343
|
+
status: progress.status ?? DEPLOYMENT_STATUS.QUEUED,
|
|
344
|
+
sha: state.lastDeploymentSha,
|
|
345
|
+
url: progress.url ?? void 0,
|
|
346
|
+
startedAt: state.lastDeploymentAt,
|
|
347
|
+
environment: state.lastDeploymentEnv
|
|
348
|
+
};
|
|
349
|
+
} else {
|
|
350
|
+
const recent = await client.get(
|
|
351
|
+
deploymentsEndpoint(link.businessId, link.projectId),
|
|
352
|
+
{ query: { [QUERY_LIMIT]: LATEST_DEPLOYMENT_LIMIT } }
|
|
353
|
+
);
|
|
354
|
+
const latest = recent[0];
|
|
355
|
+
if (latest) {
|
|
356
|
+
row = {
|
|
357
|
+
id: latest.id,
|
|
358
|
+
status: latest.status,
|
|
359
|
+
trigger: latest.trigger,
|
|
360
|
+
sha: latest.git_sha ?? void 0,
|
|
361
|
+
url: latest.url ?? void 0,
|
|
362
|
+
startedAt: latest.created_at,
|
|
363
|
+
environment: latest.environment
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
for (const line of renderStatus(
|
|
368
|
+
{
|
|
369
|
+
projectId: link.projectId,
|
|
370
|
+
remoteUrl: link.remoteUrl,
|
|
371
|
+
defaultBranch: link.defaultBranch,
|
|
372
|
+
framework: link.framework
|
|
373
|
+
},
|
|
374
|
+
row
|
|
375
|
+
)) {
|
|
376
|
+
info(line);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export { run as default, relativeTime, renderStatus };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { promises } from 'fs';
|
|
2
|
+
import 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
// src/cli/config.ts
|
|
6
|
+
var PROJECT_FILE_NAME = "project.json";
|
|
7
|
+
var STATE_FILE_NAME = "state.json";
|
|
8
|
+
var PROJECT_DIR_NAME = ".cimplify";
|
|
9
|
+
function projectConfigDir(cwd = process.cwd()) {
|
|
10
|
+
return path.join(cwd, PROJECT_DIR_NAME);
|
|
11
|
+
}
|
|
12
|
+
function projectConfigPath(cwd = process.cwd()) {
|
|
13
|
+
return path.join(projectConfigDir(cwd), PROJECT_FILE_NAME);
|
|
14
|
+
}
|
|
15
|
+
function projectStatePath(cwd = process.cwd()) {
|
|
16
|
+
return path.join(projectConfigDir(cwd), STATE_FILE_NAME);
|
|
17
|
+
}
|
|
18
|
+
async function clearProjectLink(cwd = process.cwd()) {
|
|
19
|
+
let removed = false;
|
|
20
|
+
for (const target of [projectConfigPath(cwd), projectStatePath(cwd)]) {
|
|
21
|
+
try {
|
|
22
|
+
await promises.unlink(target);
|
|
23
|
+
removed = true;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
if (err.code !== "ENOENT") throw err;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return removed;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/cli/output.ts
|
|
32
|
+
var RESET = "\x1B[0m";
|
|
33
|
+
var GREEN_OPEN = "\x1B[32m";
|
|
34
|
+
var PREFIX_SUCCESS = "\u2713";
|
|
35
|
+
function wrap(open, value) {
|
|
36
|
+
return `${open}${value}${RESET}`;
|
|
37
|
+
}
|
|
38
|
+
function green(value) {
|
|
39
|
+
return wrap(GREEN_OPEN, value);
|
|
40
|
+
}
|
|
41
|
+
function success(message) {
|
|
42
|
+
console.log(`${green(PREFIX_SUCCESS)} ${message}`);
|
|
43
|
+
}
|
|
44
|
+
function info(message) {
|
|
45
|
+
console.log(message);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/cli/commands/unlink.ts
|
|
49
|
+
async function run(_argv) {
|
|
50
|
+
const removed = await clearProjectLink();
|
|
51
|
+
if (removed) {
|
|
52
|
+
success("Unlinked project.");
|
|
53
|
+
} else {
|
|
54
|
+
info("No project link to remove.");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { run as default };
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { promises } from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
// src/cli/errors.ts
|
|
6
|
+
var CLI_ERROR_CODE = {
|
|
7
|
+
NOT_LOGGED_IN: "NOT_LOGGED_IN",
|
|
8
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
9
|
+
AUTH_FAILED: "AUTH_FAILED",
|
|
10
|
+
PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
|
|
11
|
+
INVALID_INPUT: "INVALID_INPUT",
|
|
12
|
+
ALREADY_LINKED: "ALREADY_LINKED",
|
|
13
|
+
SERVER_ERROR: "SERVER_ERROR"};
|
|
14
|
+
var EXIT_CODE = {
|
|
15
|
+
ERROR: 1};
|
|
16
|
+
var CliError = class extends Error {
|
|
17
|
+
constructor(code, message, exitCode = EXIT_CODE.ERROR) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "CliError";
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.exitCode = exitCode;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/cli/api-client.ts
|
|
26
|
+
var DEFAULT_API_BASE_URL = "https://api.cimplify.io";
|
|
27
|
+
var ENV_API_BASE_URL = "CIMPLIFY_API_URL";
|
|
28
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
29
|
+
var HEADER_AUTHORIZATION = "Authorization";
|
|
30
|
+
var HEADER_CONTENT_TYPE = "Content-Type";
|
|
31
|
+
var HEADER_ACCEPT = "Accept";
|
|
32
|
+
var HEADER_USER_AGENT = "User-Agent";
|
|
33
|
+
var BEARER_PREFIX = "Bearer ";
|
|
34
|
+
var CONTENT_TYPE_JSON = "application/json";
|
|
35
|
+
var USER_AGENT = "cimplify-cli";
|
|
36
|
+
var METHOD_GET = "GET";
|
|
37
|
+
var METHOD_POST = "POST";
|
|
38
|
+
var METHOD_PUT = "PUT";
|
|
39
|
+
var METHOD_DELETE = "DELETE";
|
|
40
|
+
var STATUS_UNAUTHORIZED = 401;
|
|
41
|
+
var STATUS_FORBIDDEN = 403;
|
|
42
|
+
var STATUS_NOT_FOUND = 404;
|
|
43
|
+
var STATUS_CONFLICT = 409;
|
|
44
|
+
var STATUS_BAD_REQUEST_MIN = 400;
|
|
45
|
+
var STATUS_SERVER_ERROR_MIN = 500;
|
|
46
|
+
var ApiClient = class _ApiClient {
|
|
47
|
+
constructor(baseUrl, apiKey) {
|
|
48
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
49
|
+
this.apiKey = apiKey;
|
|
50
|
+
}
|
|
51
|
+
static fromAuth(auth) {
|
|
52
|
+
return new _ApiClient(auth.apiBaseUrl, auth.apiKey);
|
|
53
|
+
}
|
|
54
|
+
static unauthenticated(baseUrl = resolveBaseUrl()) {
|
|
55
|
+
return new _ApiClient(baseUrl, "");
|
|
56
|
+
}
|
|
57
|
+
static withKey(apiKey, baseUrl = resolveBaseUrl()) {
|
|
58
|
+
return new _ApiClient(baseUrl, apiKey);
|
|
59
|
+
}
|
|
60
|
+
get(pathname, options) {
|
|
61
|
+
return this.request(METHOD_GET, pathname, void 0, options);
|
|
62
|
+
}
|
|
63
|
+
post(pathname, body, options) {
|
|
64
|
+
return this.request(METHOD_POST, pathname, body, options);
|
|
65
|
+
}
|
|
66
|
+
put(pathname, body, options) {
|
|
67
|
+
return this.request(METHOD_PUT, pathname, body, options);
|
|
68
|
+
}
|
|
69
|
+
delete(pathname, options) {
|
|
70
|
+
return this.request(METHOD_DELETE, pathname, void 0, options);
|
|
71
|
+
}
|
|
72
|
+
async request(method, pathname, body, options) {
|
|
73
|
+
const url = this.buildUrl(pathname, options?.query);
|
|
74
|
+
const headers = {
|
|
75
|
+
[HEADER_ACCEPT]: CONTENT_TYPE_JSON,
|
|
76
|
+
[HEADER_USER_AGENT]: USER_AGENT
|
|
77
|
+
};
|
|
78
|
+
if (this.apiKey) {
|
|
79
|
+
headers[HEADER_AUTHORIZATION] = `${BEARER_PREFIX}${this.apiKey}`;
|
|
80
|
+
}
|
|
81
|
+
let payload;
|
|
82
|
+
if (body !== void 0) {
|
|
83
|
+
headers[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON;
|
|
84
|
+
payload = JSON.stringify(body);
|
|
85
|
+
}
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
88
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
89
|
+
let response;
|
|
90
|
+
try {
|
|
91
|
+
response = await fetch(url, {
|
|
92
|
+
method,
|
|
93
|
+
headers,
|
|
94
|
+
body: payload,
|
|
95
|
+
signal: controller.signal
|
|
96
|
+
});
|
|
97
|
+
} catch (err) {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
throw toNetworkError(err);
|
|
100
|
+
}
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
return parseResponse(response);
|
|
103
|
+
}
|
|
104
|
+
buildUrl(pathname, query) {
|
|
105
|
+
const base = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
106
|
+
const url = new URL(`${this.baseUrl}${base}`);
|
|
107
|
+
if (query) {
|
|
108
|
+
for (const [k, v] of Object.entries(query)) {
|
|
109
|
+
if (v === void 0 || v === null) continue;
|
|
110
|
+
url.searchParams.set(k, String(v));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return url.toString();
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
function resolveBaseUrl(override) {
|
|
117
|
+
const fromEnv = process.env[ENV_API_BASE_URL];
|
|
118
|
+
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_API_BASE_URL;
|
|
119
|
+
}
|
|
120
|
+
async function parseResponse(response) {
|
|
121
|
+
const text = await response.text();
|
|
122
|
+
let body = void 0;
|
|
123
|
+
if (text.length > 0) {
|
|
124
|
+
try {
|
|
125
|
+
body = JSON.parse(text);
|
|
126
|
+
} catch {
|
|
127
|
+
throw new CliError(
|
|
128
|
+
CLI_ERROR_CODE.SERVER_ERROR,
|
|
129
|
+
`Server returned non-JSON response (status ${response.status}): ${truncate(text)}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (response.ok) {
|
|
134
|
+
if (body && typeof body === "object" && "data" in body) {
|
|
135
|
+
return body.data;
|
|
136
|
+
}
|
|
137
|
+
return body;
|
|
138
|
+
}
|
|
139
|
+
const code = mapStatusToCode(response.status);
|
|
140
|
+
const message = extractErrorMessage(body, response.status);
|
|
141
|
+
throw new CliError(code, message);
|
|
142
|
+
}
|
|
143
|
+
function mapStatusToCode(status) {
|
|
144
|
+
if (status === STATUS_UNAUTHORIZED) return CLI_ERROR_CODE.AUTH_FAILED;
|
|
145
|
+
if (status === STATUS_FORBIDDEN) return CLI_ERROR_CODE.AUTH_FAILED;
|
|
146
|
+
if (status === STATUS_NOT_FOUND) return CLI_ERROR_CODE.PROJECT_NOT_FOUND;
|
|
147
|
+
if (status === STATUS_CONFLICT) return CLI_ERROR_CODE.ALREADY_LINKED;
|
|
148
|
+
if (status >= STATUS_SERVER_ERROR_MIN) return CLI_ERROR_CODE.SERVER_ERROR;
|
|
149
|
+
if (status >= STATUS_BAD_REQUEST_MIN) return CLI_ERROR_CODE.INVALID_INPUT;
|
|
150
|
+
return CLI_ERROR_CODE.SERVER_ERROR;
|
|
151
|
+
}
|
|
152
|
+
function extractErrorMessage(body, status) {
|
|
153
|
+
if (body && typeof body === "object") {
|
|
154
|
+
const envelope = body;
|
|
155
|
+
if (envelope.error && typeof envelope.error.error_message === "string") {
|
|
156
|
+
return envelope.error.error_code ? `${envelope.error.error_code}: ${envelope.error.error_message}` : envelope.error.error_message;
|
|
157
|
+
}
|
|
158
|
+
if (typeof envelope.message === "string") return envelope.message;
|
|
159
|
+
}
|
|
160
|
+
return `HTTP ${status}`;
|
|
161
|
+
}
|
|
162
|
+
function toNetworkError(err) {
|
|
163
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
164
|
+
return new CliError(CLI_ERROR_CODE.NETWORK_ERROR, "Request timed out.");
|
|
165
|
+
}
|
|
166
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
167
|
+
return new CliError(CLI_ERROR_CODE.NETWORK_ERROR, `Network error: ${message}`);
|
|
168
|
+
}
|
|
169
|
+
function truncate(value, max = 200) {
|
|
170
|
+
return value.length > max ? `${value.slice(0, max)}\u2026` : value;
|
|
171
|
+
}
|
|
172
|
+
var AUTH_FILE_NAME = "auth.json";
|
|
173
|
+
var ENV_XDG_CONFIG_HOME = "XDG_CONFIG_HOME";
|
|
174
|
+
var APP_CONFIG_DIR_NAME = "cimplify";
|
|
175
|
+
var HOME_CONFIG_DIR_NAME = ".config";
|
|
176
|
+
var ENCODING_UTF8 = "utf8";
|
|
177
|
+
function authConfigDir() {
|
|
178
|
+
const xdg = process.env[ENV_XDG_CONFIG_HOME];
|
|
179
|
+
return xdg ? path.join(xdg, APP_CONFIG_DIR_NAME) : path.join(os.homedir(), HOME_CONFIG_DIR_NAME, APP_CONFIG_DIR_NAME);
|
|
180
|
+
}
|
|
181
|
+
function authConfigPath() {
|
|
182
|
+
return path.join(authConfigDir(), AUTH_FILE_NAME);
|
|
183
|
+
}
|
|
184
|
+
async function readJsonFile(filePath) {
|
|
185
|
+
try {
|
|
186
|
+
const raw = await promises.readFile(filePath, ENCODING_UTF8);
|
|
187
|
+
return JSON.parse(raw);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
if (err.code === "ENOENT") return null;
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function readAuth() {
|
|
194
|
+
const data = await readJsonFile(authConfigPath());
|
|
195
|
+
if (!data) {
|
|
196
|
+
throw new CliError(
|
|
197
|
+
CLI_ERROR_CODE.NOT_LOGGED_IN,
|
|
198
|
+
"Not logged in. Run `cimplify login` first."
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return data;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/cli/output.ts
|
|
205
|
+
var RESET = "\x1B[0m";
|
|
206
|
+
var BOLD_OPEN = "\x1B[1m";
|
|
207
|
+
var DIM_OPEN = "\x1B[2m";
|
|
208
|
+
function wrap(open, value) {
|
|
209
|
+
return `${open}${value}${RESET}`;
|
|
210
|
+
}
|
|
211
|
+
function bold(value) {
|
|
212
|
+
return wrap(BOLD_OPEN, value);
|
|
213
|
+
}
|
|
214
|
+
function dim(value) {
|
|
215
|
+
return wrap(DIM_OPEN, value);
|
|
216
|
+
}
|
|
217
|
+
function info(message) {
|
|
218
|
+
console.log(message);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/cli/commands/whoami.ts
|
|
222
|
+
var ENDPOINT_AUTH_ME = "/v1/auth/me";
|
|
223
|
+
async function run(_argv) {
|
|
224
|
+
const auth = await readAuth();
|
|
225
|
+
const client = ApiClient.fromAuth(auth);
|
|
226
|
+
const me = await client.get(ENDPOINT_AUTH_ME);
|
|
227
|
+
info(`${bold("Account")} ${me.id}`);
|
|
228
|
+
if (me.email) info(`${bold("Email")} ${me.email}`);
|
|
229
|
+
if (me.name) info(`${bold("Name")} ${me.name}`);
|
|
230
|
+
info(`${bold("Business")} ${me.business_id}`);
|
|
231
|
+
info(`${bold("API")} ${dim(auth.apiBaseUrl)}`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export { run as default };
|