@cimplify/cli 0.6.12 → 0.6.15

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.
Files changed (41) hide show
  1. package/dist/{add-UZRM3FSU.mjs → add-6KEKFXOW.mjs} +1 -1
  2. package/dist/{assets-EBEMMENZ.mjs → assets-74SK63TR.mjs} +73 -24
  3. package/dist/chunk-DEWCHGWU.mjs +5707 -0
  4. package/dist/{chunk-A2L5IV57.mjs → chunk-JLSDFVML.mjs} +1 -1
  5. package/dist/{chunk-E7P6GL73.mjs → chunk-OSS47KZP.mjs} +2 -2
  6. package/dist/dispatcher.mjs +10 -10
  7. package/dist/{doctor-Q6DWYG4D.mjs → doctor-WL25JRS3.mjs} +2 -2
  8. package/dist/{explain-RA3PQCUF.mjs → explain-NY5A533M.mjs} +8 -1
  9. package/dist/{introspect-HKNLBZ73.mjs → introspect-J7GVKQK7.mjs} +2 -2
  10. package/dist/{list-U67HVMX5.mjs → list-FXOFYX4H.mjs} +1 -1
  11. package/dist/{update-UT46Z6X4.mjs → update-WNZKECFJ.mjs} +1 -1
  12. package/package.json +2 -2
  13. package/templates/storefront-auto/app/api/revalidate/route.ts +5 -0
  14. package/templates/storefront-auto/app/products/[slug]/page.tsx +8 -3
  15. package/templates/storefront-auto/bun.lock +10 -681
  16. package/templates/storefront-auto/package.json +1 -1
  17. package/templates/storefront-bakery/app/api/revalidate/route.ts +5 -0
  18. package/templates/storefront-bakery/bun.lock +10 -681
  19. package/templates/storefront-bakery/package.json +1 -1
  20. package/templates/storefront-fashion/app/api/revalidate/route.ts +5 -0
  21. package/templates/storefront-fashion/app/products/[slug]/page.tsx +8 -3
  22. package/templates/storefront-fashion/bun.lock +12 -683
  23. package/templates/storefront-fashion/package.json +1 -1
  24. package/templates/storefront-grocery/app/api/revalidate/route.ts +5 -0
  25. package/templates/storefront-grocery/bun.lock +10 -681
  26. package/templates/storefront-grocery/package.json +1 -1
  27. package/templates/storefront-pharmacy/app/api/revalidate/route.ts +5 -0
  28. package/templates/storefront-pharmacy/app/products/[slug]/page.tsx +8 -3
  29. package/templates/storefront-pharmacy/bun.lock +10 -681
  30. package/templates/storefront-pharmacy/package.json +1 -1
  31. package/templates/storefront-restaurant/app/api/revalidate/route.ts +5 -0
  32. package/templates/storefront-restaurant/bun.lock +10 -681
  33. package/templates/storefront-restaurant/package.json +1 -1
  34. package/templates/storefront-retail/app/api/revalidate/route.ts +5 -0
  35. package/templates/storefront-retail/app/products/[slug]/page.tsx +8 -3
  36. package/templates/storefront-retail/bun.lock +10 -681
  37. package/templates/storefront-retail/package.json +1 -1
  38. package/templates/storefront-services/app/api/revalidate/route.ts +5 -0
  39. package/templates/storefront-services/bun.lock +10 -681
  40. package/templates/storefront-services/package.json +1 -1
  41. package/dist/chunk-VOQJ7GYE.mjs +0 -5707
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { gitDetectRoot, gitCurrentBranch, gitCurrentSha, gitStatusPorcelain } from './chunk-K5464A3L.mjs';
3
3
  import { parseEnvFile } from './chunk-DBZ3UOQ2.mjs';
4
- import { package_default } from './chunk-E7P6GL73.mjs';
4
+ import { package_default } from './chunk-OSS47KZP.mjs';
5
5
  import { parseArgs } from './chunk-C4M3DXKC.mjs';
6
6
  import { readAuthOrNull, readProjectLinkOrNull, readProjectState } from './chunk-UBAI443T.mjs';
7
7
  import { bold, dim, yellow, green, info, result, red } from './chunk-E2T2SBP5.mjs';
@@ -2,7 +2,7 @@
2
2
  // package.json
3
3
  var package_default = {
4
4
  name: "@cimplify/cli",
5
- version: "0.6.12",
5
+ version: "0.6.15",
6
6
  description: "Cimplify CLI \u2014 deploy, manage env vars, link projects, and scaffold storefronts",
7
7
  keywords: [
8
8
  "cimplify",
@@ -47,7 +47,7 @@ var package_default = {
47
47
  vitest: "^4.1.5"
48
48
  },
49
49
  dependencies: {
50
- "@cimplify/sdk": "^0.48.2"
50
+ "@cimplify/sdk": "^0.49.1"
51
51
  }
52
52
  };
53
53
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { TEMPLATES } from './chunk-VOQJ7GYE.mjs';
3
- import { package_default } from './chunk-E7P6GL73.mjs';
2
+ import { TEMPLATES } from './chunk-DEWCHGWU.mjs';
3
+ import { package_default } from './chunk-OSS47KZP.mjs';
4
4
 
5
5
  // src/dispatcher.ts
6
6
  var VERSION = package_default.version ?? "unknown";
@@ -138,16 +138,16 @@ var COMMANDS = {
138
138
  logs: () => import('./logs-YNN2PQ24.mjs'),
139
139
  status: () => import('./status-JSYXM5RT.mjs'),
140
140
  dev: () => import('./dev-ONW2S77K.mjs'),
141
- introspect: () => import('./introspect-HKNLBZ73.mjs'),
141
+ introspect: () => import('./introspect-J7GVKQK7.mjs'),
142
142
  inspect: () => import('./inspect-CGYX4DDF.mjs'),
143
- doctor: () => import('./doctor-Q6DWYG4D.mjs'),
144
- explain: () => import('./explain-RA3PQCUF.mjs'),
145
- assets: () => import('./assets-EBEMMENZ.mjs'),
143
+ doctor: () => import('./doctor-WL25JRS3.mjs'),
144
+ explain: () => import('./explain-NY5A533M.mjs'),
145
+ assets: () => import('./assets-74SK63TR.mjs'),
146
146
  repo: () => import('./repo-KNQMSPVV.mjs'),
147
- list: () => import('./list-U67HVMX5.mjs'),
148
- add: () => import('./add-UZRM3FSU.mjs'),
149
- update: () => import('./update-UT46Z6X4.mjs'),
150
- upgrade: () => import('./update-UT46Z6X4.mjs'),
147
+ list: () => import('./list-FXOFYX4H.mjs'),
148
+ add: () => import('./add-6KEKFXOW.mjs'),
149
+ update: () => import('./update-WNZKECFJ.mjs'),
150
+ upgrade: () => import('./update-WNZKECFJ.mjs'),
151
151
  "auth-step-up": () => import('./auth-step-up-BIUYQJP6.mjs')
152
152
  };
153
153
  var COMMAND_PREFIXES = {
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { gatherIntrospection } from './chunk-A2L5IV57.mjs';
2
+ import { gatherIntrospection } from './chunk-JLSDFVML.mjs';
3
3
  import './chunk-K5464A3L.mjs';
4
4
  import './chunk-DBZ3UOQ2.mjs';
5
- import './chunk-E7P6GL73.mjs';
5
+ import './chunk-OSS47KZP.mjs';
6
6
  import { parseArgs, flagBool } from './chunk-C4M3DXKC.mjs';
7
7
  import { ApiClient } from './chunk-MAOO6ZZ5.mjs';
8
8
  import { readAuthOrNull } from './chunk-UBAI443T.mjs';
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { package_default } from './chunk-E7P6GL73.mjs';
2
+ import { package_default } from './chunk-OSS47KZP.mjs';
3
3
  import { parseArgs } from './chunk-C4M3DXKC.mjs';
4
4
  import { bold, dim, info, result, CliError, CLI_ERROR_CODE } from './chunk-E2T2SBP5.mjs';
5
5
 
@@ -152,6 +152,13 @@ var TOPICS = [
152
152
  "source_url": "https://cimplify.dev/docs/cli/inspect#shape_hints-vocabulary",
153
153
  "body": "## `shape_hints` vocabulary\nFlat string tokens for agents to branch on. Adding tokens is non-breaking; removing/renaming bumps `schema_version`.\n\n### Catalogue size\n\n| Token | Meaning |\n| --- | --- |\n| `empty_catalogue` | 0 products. Whole storefront needs an empty-state. |\n| `tiny_catalogue` | 1\u20139 products. Skip search, deep filters. |\n| `small_catalogue` | 10\u201399 products. Default UX. |\n| `medium_catalogue` | 100\u2013999 products. Search nice-to-have. |\n| `large_catalogue` | 1000+ products. Search + facets required. |\n\n### Feature presence\n\n| Token | Meaning |\n| --- | --- |\n| `has_variants` | At least one product has variants \u2192 variant picker UI. |\n| `has_addons` | At least one product has add-on options \u2192 modifier UI. |\n| `has_subscriptions` | Billing plans exist \u2192 recurring pricing toggle. |\n| `has_composites` | Bundle / composite products exist. |\n| `has_recipes` | Products linked to `ProductComponent` (restaurant / manufacturing). |\n| `has_time_profiles` | Products have time-of-day windows \u2192 hours-aware UI. |\n| `has_input_fields` | Buyer-supplied inputs (engraving, message). |\n| `has_custom_attributes` | Custom attribute schemas defined. |\n| `per_location_pricing` | Prices vary by location. |\n| `multi_currency` | >1 currency configured. |\n| `multi_location` | >1 location configured. |\n\n### Merchandising state\n\n| Token | Meaning |\n| --- | --- |\n| `uses_collections` | \u22651 non-empty collection exists. |\n| `uses_categories` | \u22651 non-empty category. |\n| `has_empty_collection` | \u22651 collection has 0 products. |\n| `has_empty_category` | \u22651 category has 0 products. |\n| `untagged_majority` | >50% of products are untagged. |\n| `unmerchandised_majority` | >50% of products aren't in any collection. |\n\n### Data quality\n\n| Token | Meaning |\n| --- | --- |\n| `has_image_gaps` | \u22651 product missing image. |\n| `has_description_gaps` | \u22651 product missing description. |\n| `has_price_gaps` | \u22651 product missing price. |\n\n### Environment\n\n| Token | Meaning |\n| --- | --- |\n| `mock_data` | Reading from `cimplify-mock` (key isn't `cpk_live_*` / `cpk_test_*`). |\n"
154
154
  },
155
+ {
156
+ "name": "revalidation-tags",
157
+ "title": "Revalidation",
158
+ "description": "Canonical cimplify:* cache-tag vocabulary + revalidate helpers",
159
+ "source_url": "https://cimplify.dev/docs/sdk/revalidation",
160
+ "body": 'Cimplify storefronts cache catalogue reads with Next 16\'s `\'use cache\'` + `cacheTag`. When the merchant edits a product, collection, or brand asset, Cimplify POSTs to your storefront\'s `/api/revalidate` with the canonical tag set, and your handler calls `revalidateTag(tag)` for each.\n\nThis page is the canonical contract between Cimplify and your storefront. Use the typed helpers \u2014 never hand-write tag strings \u2014 so the scheme stays in one place.\n\n## Tags\n\nAll tags are namespaced under `cimplify:` so they can\'t collide with consumer tags. Build them via `tags` from `@cimplify/sdk/server`:\n\n```ts\n\n// In a cached server function:\nasync function getProducts() {\n "use cache";\n cacheTag(tags.products());\n cacheLife("hours");\n // \u2026\n}\n```\n\n### Catalogue\n\n| Helper | Tag |\n| --- | --- |\n| `tags.products()` | `cimplify:products` |\n| `tags.product(id)` | `cimplify:product:{id}` |\n| `tags.categories()` | `cimplify:categories` |\n| `tags.category(id)` | `cimplify:category:{id}` |\n| `tags.categoryProducts(id)` | `cimplify:category:{id}:products` |\n| `tags.collections()` | `cimplify:collections` |\n| `tags.collection(id)` | `cimplify:collection:{id}` |\n| `tags.collectionProducts(id)` | `cimplify:collection:{id}:products` |\n| `tags.tag(name)` | `cimplify:tag:{name}` (product tag, e.g. "vegan") |\n| `tags.addons()` | `cimplify:addons` |\n| `tags.addon(id)` | `cimplify:addon:{id}` |\n| `tags.stock()` | `cimplify:stock` |\n| `tags.stockFor(productId)` | `cimplify:stock:{productId}` |\n\n### Brand / business\n\n| Helper | Tag |\n| --- | --- |\n| `tags.business()` | `cimplify:business` |\n| `tags.brand()` | `cimplify:brand` |\n| `tags.locations()` | `cimplify:locations` |\n| `tags.location(id)` | `cimplify:location:{id}` |\n| `tags.locale()` | `cimplify:locale` |\n\n### Pricing / subscriptions\n\n| Helper | Tag |\n| --- | --- |\n| `tags.pricing()` | `cimplify:pricing` |\n| `tags.subscriptions()` | `cimplify:subscriptions` |\n| `tags.subscription(id)` | `cimplify:subscription:{id}` |\n\n### Customer-scoped (Server Actions only)\n\n| Helper | Tag |\n| --- | --- |\n| `tags.orders(customerId)` | `cimplify:orders:{customerId}` |\n| `tags.order(id)` | `cimplify:order:{id}` |\n\n## Granularity\n\nTag with **both** a broad and a precise tag on every read so either-flavour invalidation works:\n\n```ts\ncacheTag(tags.products(), tags.product(id));\n```\n\nThe broad tag (`products`) catches "I changed something product-related, invalidate everything." The precise tag (`product:{id}`) catches "I changed exactly this one product, invalidate only its entries."\n\n## Revalidating from a Server Action\n\n```ts\n\nexport async function saveProduct(id: string, data: ProductInput) {\n await client.catalogue.updateProduct(id, data);\n await revalidateProduct(id);\n}\n```\n\nHelpers:\n\n| Helper | Invalidates |\n| --- | --- |\n| `revalidateProducts()` | `products` |\n| `revalidateProduct(id)` | `product:{id}` + `products` |\n| `revalidateCategories()` | `categories` |\n| `revalidateCategory(id)` | `category:{id}` + `category:{id}:products` + `categories` |\n| `revalidateCollections()` | `collections` |\n| `revalidateCollection(id)` | `collection:{id}` + `collection:{id}:products` + `collections` |\n| `revalidateBusiness()` | `business` |\n| `revalidateBrand()` | `brand` |\n| `revalidateLocations()` | `locations` |\n| `revalidateLocation(id)` | `location:{id}` + `locations` |\n| `revalidatePricing()` | `pricing` + `products` |\n| `revalidateAddOns()` | `addons` |\n| `revalidateAddOn(id)` | `addon:{id}` + `addons` |\n| `revalidateSubscriptions()` | `subscriptions` |\n| `revalidateSubscription(id)` | `subscription:{id}` + `subscriptions` |\n| `revalidateStock(productId?)` | `stock:{productId}` + `stock` (or just `stock` if no id) |\n| `revalidateByTag(tag)` | escape hatch for a raw tag |\n\n## The Cimplify \u2192 storefront contract\n\nWhen a merchant edits something in the dashboard, Cimplify POSTs to your storefront\'s `/api/revalidate` with the matching tag set:\n\n```http\nPOST /api/revalidate\nx-cimplify-timestamp: 1716480000000\nx-cimplify-signature: sha256=<hex>\ncontent-type: application/json\n\n{ "tags": ["cimplify:products", "cimplify:product:p_abc123"] }\n```\n\nYour handler verifies the HMAC (shared secret in `CIMPLIFY_REVALIDATE_SECRET`), iterates `revalidateTag(tag)` for each, and returns 200. The route handler ships in every Cimplify storefront template \u2014 you don\'t write it.\n\nThe tags Cimplify sends use the **exact strings** from this table. If you\'ve tagged your caches with the helpers above, your storefront stays in sync automatically.\n\n## Dynamic routes \u2014 tag by **ID**, never by slug\n\nCimplify dispatches revalidation tags **keyed by database ID**, not by URL slug. A `/products/[slug]` page that caches itself under `tags.product(slug)` will never be invalidated by an edit \u2014 the tag the storefront wrote doesn\'t match the tag Cimplify fires.\n\nAlways resolve the slug to a record first, then tag with `record.id`. Next 16 lets you call `cacheTag` **after** an `await`, so this is one function, not two:\n\n```ts title="app/products/[slug]/page.tsx \u2014 correct"\n\nasync function getProduct(slug: string) {\n "use cache";\n cacheLife("max");\n\n const r = await getServerClient().catalogue.getProductBySlug(slug);\n if (!r.ok) {\n // 404s tagged at the collection level so deleting + re-creating works.\n cacheTag(tags.products());\n return null;\n }\n\n // Tag with the resolved ID so revalidateProduct(id) from Cimplify hits.\n cacheTag(tags.product(r.value.id), tags.products());\n return r.value;\n}\n```\n\nThe same pattern applies to `[slug]` routes for categories, collections, addons, locations, and so on \u2014 always tag with the resolved `record.id`, never with the URL slug.\n\n### Why this matters\n\n- **Renames don\'t orphan.** The cache key is keyed on the slug (the function argument), so a renamed product gets a fresh cache entry under the new slug. The old slug-keyed entry is invalidated via the `tags.products()` collection tag and will 404 naturally.\n- **IDs are stable.** Cimplify\'s bus emits `ProductUpdated { id }` events; the slug isn\'t on the event payload, and adding it would create races with concurrent rename. Keeping the tag scheme ID-only keeps the contract simple.\n- **You get instant freshness.** With Cimplify\'s tag-cache + CDN-purge in place, a `cacheLife("max")` entry can sit cached for days and still flip fresh within ~1s of an edit \u2014 but only if the tag actually matches.\n\n## `cacheLife` \u2014 go long\n\nPair the ID-keyed tagging above with a long `cacheLife`. Cimplify invalidates both the CDN and the underlying R2 cache layer the moment a tag fires, so there\'s no benefit to short timer-based expirations. Defaults that work:\n\n| Page shape | Recommended `cacheLife` |\n| --- | --- |\n| Detail page tagged with `tags.product(id)` | `"max"` |\n| Listing tagged with `tags.products()` | `"max"` (or `"days"` if you prefer a backstop) |\n| Slug-keyed wrapper tagged only with collection (e.g. slug\u2192id lookup) | `"days"` |\n| Pages that mix cached chrome with uncached personalisation | the cached parts: `"max"`; personalised parts: no `\'use cache\'` |\n\nShort profiles (`"minutes"`, `"hours"`) are only needed when you\'re caching data **not** owned by Cimplify (a weather API, an external CMS) \u2014 anything Cimplify owns is covered by on-demand invalidation.\n\n## Tag taxonomy is locked\n\nThe vocabulary above is the v1 contract. Adding new tag helpers is non-breaking; removing or renaming any of them bumps the SDK major version. Agents that bake these strings into prompts can pin to v0.x of `@cimplify/sdk`.\n'
161
+ },
155
162
  {
156
163
  "name": "inspect-suggestions",
157
164
  "title": "Inspect \u2014 `suggestions[].kind` vocabulary",
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- export { run as default, extractMockSeed, gatherIntrospection, renderIntrospection } from './chunk-A2L5IV57.mjs';
2
+ export { run as default, extractMockSeed, gatherIntrospection, renderIntrospection } from './chunk-JLSDFVML.mjs';
3
3
  import './chunk-K5464A3L.mjs';
4
4
  import './chunk-DBZ3UOQ2.mjs';
5
- import './chunk-E7P6GL73.mjs';
5
+ import './chunk-OSS47KZP.mjs';
6
6
  import './chunk-C4M3DXKC.mjs';
7
7
  import './chunk-UBAI443T.mjs';
8
8
  import './chunk-E2T2SBP5.mjs';
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { REGISTRY_INDEX } from './chunk-VOQJ7GYE.mjs';
2
+ import { REGISTRY_INDEX } from './chunk-DEWCHGWU.mjs';
3
3
  import { parseArgs, flagBool } from './chunk-C4M3DXKC.mjs';
4
4
  import { CliError, CLI_ERROR_CODE, info, bold, dim, green, result } from './chunk-E2T2SBP5.mjs';
5
5
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { package_default } from './chunk-E7P6GL73.mjs';
2
+ import { package_default } from './chunk-OSS47KZP.mjs';
3
3
  import { promptYesNo } from './chunk-ITAFAORS.mjs';
4
4
  import { parseArgs, flagBool, flagString } from './chunk-C4M3DXKC.mjs';
5
5
  import { success, bold, info, dim, result, failure, CliError, CLI_ERROR_CODE, step, isJsonMode } from './chunk-E2T2SBP5.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cimplify/cli",
3
- "version": "0.6.12",
3
+ "version": "0.6.15",
4
4
  "description": "Cimplify CLI — deploy, manage env vars, link projects, and scaffold storefronts",
5
5
  "keywords": [
6
6
  "cimplify",
@@ -45,6 +45,6 @@
45
45
  "vitest": "^4.1.5"
46
46
  },
47
47
  "dependencies": {
48
- "@cimplify/sdk": "^0.48.2"
48
+ "@cimplify/sdk": "^0.49.1"
49
49
  }
50
50
  }
@@ -0,0 +1,5 @@
1
+ import { revalidateRouteHandler } from "@cimplify/sdk/server";
2
+
3
+ export async function POST(req: Request): Promise<Response> {
4
+ return revalidateRouteHandler(req);
5
+ }
@@ -43,12 +43,17 @@ interface ProductData {
43
43
 
44
44
  async function getProduct(slug: string): Promise<ProductData | null> {
45
45
  "use cache";
46
- cacheTag(tags.product(slug), tags.products());
47
- cacheLife("hours");
46
+ cacheLife("max");
48
47
 
49
48
  const client = getServerClient();
50
49
  const r = await client.catalogue.getProductBySlug(slug);
51
- if (!r.ok) return null;
50
+ if (!r.ok) {
51
+ cacheTag(tags.products());
52
+ return null;
53
+ }
54
+ // Tag with the resolved ID — Cimplify dispatches tags.product(id), not slug.
55
+ // See https://cimplify.dev/docs/sdk/revalidation#dynamic-routes--tag-by-id-never-by-slug
56
+ cacheTag(tags.product(r.value.id), tags.products());
52
57
 
53
58
  const related = r.value.category_id
54
59
  ? await client.catalogue