create-ailk 0.5.0 → 0.6.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.
Files changed (299) hide show
  1. package/README.md +55 -8
  2. package/component-catalog.json +336 -27
  3. package/component-catalog.md +25 -12
  4. package/dist/lib/api-boot-assertion.d.ts +46 -0
  5. package/dist/lib/api-boot-assertion.js +70 -0
  6. package/dist/lib/import-graph.d.ts +29 -0
  7. package/dist/lib/import-graph.js +140 -0
  8. package/dist/module-architecture.d.ts +1 -0
  9. package/dist/module-architecture.js +253 -127
  10. package/dist/surfaces.js +105 -7
  11. package/dist/template-manifest.d.ts +33 -0
  12. package/dist/template-manifest.js +99 -16
  13. package/dist/template-names.d.ts +1 -1
  14. package/dist/template-names.js +1 -0
  15. package/package.json +3 -2
  16. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +22 -2
  17. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +9 -2
  18. package/site-templates/marketing-site/ailk-template.json +1 -1
  19. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +2 -2
  20. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +1 -0
  21. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.json +10 -2
  22. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +47 -35
  23. package/site-templates/minimalism-site/ailk-template.json +2 -1
  24. package/site-templates/minimalism-site/assets/wordmark-placeholder.svg +28 -0
  25. package/site-templates/minimalism-site/content/en/HomePage/home.mdx +49 -19
  26. package/site-templates/simple-service/TEMPLATE-MANIFEST.json +240 -0
  27. package/site-templates/simple-service/TEMPLATE-MANIFEST.md +278 -0
  28. package/site-templates/simple-service/ailk-template.json +10 -0
  29. package/site-templates/simple-service/content/en/AboutPage/about.mdx +38 -0
  30. package/site-templates/simple-service/content/en/ContactPage/contact.mdx +67 -0
  31. package/site-templates/simple-service/content/en/FAQPage/faq.mdx +56 -0
  32. package/site-templates/simple-service/content/en/HomePage/home.mdx +85 -0
  33. package/site-templates/simple-service/content/en/Service/landscape-design.mdx +40 -0
  34. package/site-templates/simple-service/content/en/Service/lawn-maintenance.mdx +40 -0
  35. package/site-templates/simple-service/content/en/Service/seasonal-cleanup.mdx +40 -0
  36. package/site-templates/simple-service/content/en/ServicesList/services.mdx +72 -0
  37. package/site-templates/simple-service/provenance.json +4 -0
  38. package/templates/.env.example +72 -7
  39. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +8 -0
  40. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +12 -0
  41. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +12 -0
  42. package/templates/apps/api/.env.example +13 -0
  43. package/templates/apps/api/CLAUDE.md +26 -2
  44. package/templates/apps/api/jest.config.cjs +3 -0
  45. package/templates/apps/api/package.json +1 -0
  46. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +407 -0
  47. package/templates/apps/api/src/__tests__/module-exclusion.test.ts +83 -7
  48. package/templates/apps/api/src/__tests__/server.test.ts +471 -0
  49. package/templates/apps/api/src/__tests__/vercel-handler.test.ts +45 -0
  50. package/templates/apps/api/src/__tests__/workspace-module-registration.test.ts +2 -0
  51. package/templates/apps/api/src/config/index.ts +62 -0
  52. package/templates/apps/api/src/config/modules.ts +7 -3
  53. package/templates/apps/api/src/lib/__mocks__/prisma.ts +238 -2
  54. package/templates/apps/api/src/lib/__tests__/auth-email-budget.test.ts +143 -0
  55. package/templates/apps/api/src/lib/__tests__/content-adapter.test.ts +23 -0
  56. package/templates/apps/api/src/lib/__tests__/deliverable-asset-store.test.ts +125 -0
  57. package/templates/apps/api/src/lib/__tests__/error-serializer.test.ts +20 -0
  58. package/templates/apps/api/src/lib/__tests__/require-commerce-claim.test.ts +317 -0
  59. package/templates/apps/api/src/lib/__tests__/site.test.ts +238 -0
  60. package/templates/apps/api/src/lib/__tests__/stripe.test.ts +75 -0
  61. package/templates/apps/api/src/lib/auth-email-budget.ts +160 -0
  62. package/templates/apps/api/src/lib/content-adapter.ts +57 -31
  63. package/templates/apps/api/src/lib/deliverable-asset-store.ts +76 -0
  64. package/templates/apps/api/src/lib/error-serializer.ts +23 -3
  65. package/templates/apps/api/src/lib/outbound-http.ts +7 -2
  66. package/templates/apps/api/src/lib/require-commerce-claim.ts +250 -0
  67. package/templates/apps/api/src/lib/site.ts +208 -9
  68. package/templates/apps/api/src/lib/stripe.ts +66 -0
  69. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +182 -0
  70. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +42 -0
  71. package/templates/apps/api/src/middleware/rate-limit.ts +7 -1
  72. package/templates/apps/api/src/openapi/spec.ts +543 -2
  73. package/templates/apps/api/src/routes/auth/__tests__/auth-user.functional.test.ts +48 -0
  74. package/templates/apps/api/src/routes/auth/__tests__/transactional-email.test.ts +309 -0
  75. package/templates/apps/api/src/routes/auth/__tests__/user.test.ts +123 -0
  76. package/templates/apps/api/src/routes/auth/transactional-email.ts +273 -0
  77. package/templates/apps/api/src/routes/auth/user.ts +61 -0
  78. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +434 -0
  79. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +888 -0
  80. package/templates/apps/api/src/routes/checkout/index.ts +34 -0
  81. package/templates/apps/api/src/routes/checkout/session.ts +139 -0
  82. package/templates/apps/api/src/routes/checkout/sessions.ts +197 -0
  83. package/templates/apps/api/src/routes/content/__tests__/get-page.test.ts +554 -0
  84. package/templates/apps/api/src/routes/content/__tests__/list-pages.test.ts +108 -0
  85. package/templates/apps/api/src/routes/content/__tests__/search.test.ts +450 -0
  86. package/templates/apps/api/src/routes/content/get-page.ts +94 -12
  87. package/templates/apps/api/src/routes/content/index.ts +13 -73
  88. package/templates/apps/api/src/routes/content/list-pages.ts +15 -3
  89. package/templates/apps/api/src/routes/content/rate-limit.ts +15 -6
  90. package/templates/apps/api/src/routes/content/search.ts +129 -0
  91. package/templates/apps/api/src/routes/leads/__tests__/index.test.ts +447 -31
  92. package/templates/apps/api/src/routes/leads/index.ts +100 -13
  93. package/templates/apps/api/src/routes/project-listings/__tests__/configured-application.test.ts +51 -0
  94. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +351 -0
  95. package/templates/apps/api/src/routes/project-listings/__tests__/founder-identity.test.ts +51 -0
  96. package/templates/apps/api/src/routes/project-listings/__tests__/me.test.ts +5 -2
  97. package/templates/apps/api/src/routes/project-listings/__tests__/public.test.ts +4 -1
  98. package/templates/apps/api/src/routes/project-listings/__tests__/resume-email.test.ts +58 -0
  99. package/templates/apps/api/src/routes/project-listings/__tests__/site-answers.test.ts +107 -6
  100. package/templates/apps/api/src/routes/project-listings/__tests__/site-key.test.ts +87 -2
  101. package/templates/apps/api/src/routes/project-listings/__tests__/structured-address.test.ts +51 -0
  102. package/templates/apps/api/src/routes/project-listings/start.ts +5 -1
  103. package/templates/apps/api/src/routes/requests/__tests__/confirm.test.ts +686 -0
  104. package/templates/apps/api/src/routes/requests/confirm.ts +601 -0
  105. package/templates/apps/api/src/routes/requests/index.ts +54 -0
  106. package/templates/apps/api/src/routes/webhooks/README.md +265 -0
  107. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-dunning.test.ts +749 -0
  108. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +330 -0
  109. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-idempotency.test.ts +262 -0
  110. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +285 -0
  111. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-rate-limit.test.ts +213 -0
  112. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-request-paid.test.ts +301 -0
  113. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +648 -0
  114. package/templates/apps/api/src/routes/webhooks/index.ts +89 -0
  115. package/templates/apps/api/src/routes/webhooks/stripe.ts +1399 -0
  116. package/templates/apps/api/src/server.ts +439 -49
  117. package/templates/apps/api/src/services/__tests__/abandon-email.test.ts +39 -0
  118. package/templates/apps/api/src/services/__tests__/aeo-score.test.ts +217 -40
  119. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +620 -0
  120. package/templates/apps/api/src/services/__tests__/consent.test.ts +2 -0
  121. package/templates/apps/api/src/services/__tests__/deliverable-fulfillment.test.ts +300 -5
  122. package/templates/apps/api/src/services/__tests__/deliverable-resend.test.ts +20 -0
  123. package/templates/apps/api/src/services/__tests__/dunning-policy.test.ts +368 -0
  124. package/templates/apps/api/src/services/__tests__/lead-routing.test.ts +160 -0
  125. package/templates/apps/api/src/services/__tests__/listing-config.test.ts +166 -0
  126. package/templates/apps/api/src/services/__tests__/project-listings.fence.test.ts +154 -0
  127. package/templates/apps/api/src/services/__tests__/public-site-resolver.test.ts +137 -0
  128. package/templates/apps/api/src/services/__tests__/request-confirm.test.ts +444 -0
  129. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +238 -0
  130. package/templates/apps/api/src/services/__tests__/verified-email.test.ts +78 -0
  131. package/templates/apps/api/src/services/abandon-email.ts +8 -2
  132. package/templates/apps/api/src/services/aeo-score.ts +49 -12
  133. package/templates/apps/api/src/services/audit-log.ts +668 -0
  134. package/templates/apps/api/src/services/consent.ts +18 -0
  135. package/templates/apps/api/src/services/default-tenant.ts +70 -31
  136. package/templates/apps/api/src/services/deliverable-fulfillment.ts +141 -13
  137. package/templates/apps/api/src/services/dunning-policy.ts +294 -0
  138. package/templates/apps/api/src/services/entitlements.ts +80 -0
  139. package/templates/apps/api/src/services/lead-promotion.ts +13 -14
  140. package/templates/apps/api/src/services/lead-routing.ts +161 -2
  141. package/templates/apps/api/src/services/leads-inbox.ts +23 -2
  142. package/templates/apps/api/src/services/listing-config.ts +27 -9
  143. package/templates/apps/api/src/services/project-listings.ts +201 -6
  144. package/templates/apps/api/src/services/public-site-resolver.ts +106 -0
  145. package/templates/apps/api/src/services/request-confirm.ts +646 -0
  146. package/templates/apps/api/src/services/revalidation.ts +173 -0
  147. package/templates/apps/api/src/services/verified-email.ts +71 -0
  148. package/templates/apps/api/src/vercel-handler.ts +75 -35
  149. package/templates/apps/mcp/.env.example +17 -0
  150. package/templates/apps/mcp/CLAUDE.md +57 -24
  151. package/templates/apps/mcp/__tests__/aeo-cli-parity.test.ts +6 -0
  152. package/templates/apps/mcp/__tests__/audit.test.ts +137 -8
  153. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +79 -36
  154. package/templates/apps/mcp/__tests__/get_offerings.test.ts +111 -2
  155. package/templates/apps/mcp/__tests__/get_pricing.test.ts +82 -2
  156. package/templates/apps/mcp/__tests__/http-transport.test.ts +541 -2
  157. package/templates/apps/mcp/__tests__/index.test.ts +39 -0
  158. package/templates/apps/mcp/__tests__/lib/audit-single-page-readiness-scan.test.ts +143 -0
  159. package/templates/apps/mcp/__tests__/lib/commerce-claim.test.ts +111 -0
  160. package/templates/apps/mcp/__tests__/lib/content-adapter-parity.test.ts +65 -0
  161. package/templates/apps/mcp/__tests__/lib/content-adapter.test.ts +188 -0
  162. package/templates/apps/mcp/__tests__/lib/fail-closed-tools.test.ts +165 -0
  163. package/templates/apps/mcp/__tests__/lib/public-workspace.test.ts +124 -0
  164. package/templates/apps/mcp/__tests__/list_pages.test.ts +116 -0
  165. package/templates/apps/mcp/__tests__/module-exclusion.test.ts +7 -1
  166. package/templates/apps/mcp/__tests__/parity.test.ts +10 -7
  167. package/templates/apps/mcp/__tests__/purchase-disabled.test.ts +89 -22
  168. package/templates/apps/mcp/__tests__/read_content.test.ts +322 -1
  169. package/templates/apps/mcp/__tests__/search_content.test.ts +105 -2
  170. package/templates/apps/mcp/__tests__/server.test.ts +67 -14
  171. package/templates/apps/mcp/__tests__/start_purchase.test.ts +252 -0
  172. package/templates/apps/mcp/__tests__/tools/purchase.test.ts +300 -123
  173. package/templates/apps/mcp/jest.config.cjs +13 -0
  174. package/templates/apps/mcp/package.json +2 -0
  175. package/templates/apps/mcp/src/abuse/index.ts +159 -24
  176. package/templates/apps/mcp/src/config/modules.ts +10 -5
  177. package/templates/apps/mcp/src/http-transport.ts +102 -29
  178. package/templates/apps/mcp/src/index.ts +73 -11
  179. package/templates/apps/mcp/src/lib/audit-single-page.ts +90 -3
  180. package/templates/apps/mcp/src/lib/commerce-claim.ts +94 -0
  181. package/templates/apps/mcp/src/lib/content-adapter.ts +113 -0
  182. package/templates/apps/mcp/src/lib/empty-content-adapter.ts +139 -0
  183. package/templates/apps/mcp/src/lib/prisma.ts +39 -0
  184. package/templates/apps/mcp/src/lib/public-workspace.ts +133 -0
  185. package/templates/apps/mcp/src/lib/stripe-tax-signal.ts +59 -0
  186. package/templates/apps/mcp/src/server.ts +59 -35
  187. package/templates/apps/mcp/src/tools/audit.ts +26 -2
  188. package/templates/apps/mcp/src/tools/get_business_hours.ts +4 -3
  189. package/templates/apps/mcp/src/tools/get_faq.ts +4 -3
  190. package/templates/apps/mcp/src/tools/get_locations.ts +5 -3
  191. package/templates/apps/mcp/src/tools/get_offerings.ts +16 -4
  192. package/templates/apps/mcp/src/tools/get_pricing.ts +25 -6
  193. package/templates/apps/mcp/src/tools/get_site_info.ts +4 -3
  194. package/templates/apps/mcp/src/tools/index.ts +6 -4
  195. package/templates/apps/mcp/src/tools/list_pages.ts +4 -3
  196. package/templates/apps/mcp/src/tools/purchase.ts +128 -45
  197. package/templates/apps/mcp/src/tools/read_content.ts +20 -6
  198. package/templates/apps/mcp/src/tools/search_content.ts +11 -4
  199. package/templates/apps/web/.env.example +71 -5
  200. package/templates/apps/web/CLAUDE.md +44 -0
  201. package/templates/apps/web/app/.well-known/mcp.json/build-manifest.ts +18 -2
  202. package/templates/apps/web/app/.well-known/mcp.json/route.ts +11 -3
  203. package/templates/apps/web/app/[locale]/(auth)/__tests__/auth-pages.test.tsx +282 -0
  204. package/templates/apps/web/app/[locale]/(auth)/__tests__/password-reset.test.tsx +515 -0
  205. package/templates/apps/web/app/[locale]/(auth)/forgot-password/forgot-password-card.tsx +89 -0
  206. package/templates/apps/web/app/[locale]/(auth)/forgot-password/page.tsx +109 -0
  207. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +92 -0
  208. package/templates/apps/web/app/[locale]/(auth)/reset-password/page.tsx +135 -0
  209. package/templates/apps/web/app/[locale]/(auth)/reset-password/reset-password-card.tsx +109 -0
  210. package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/__tests__/page.test.tsx +48 -2
  211. package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/page.tsx +20 -6
  212. package/templates/apps/web/app/[locale]/(auth)/sign-in/sign-in-card.tsx +125 -0
  213. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +96 -0
  214. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +101 -0
  215. package/templates/apps/web/app/[locale]/(auth)/use-auth-card-flow.ts +102 -0
  216. package/templates/apps/web/app/[locale]/(auth)/verify-email/page.tsx +87 -0
  217. package/templates/apps/web/app/[locale]/(authed)/__tests__/gate.test.tsx +20 -10
  218. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/page.test.tsx +84 -0
  219. package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +58 -0
  220. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +63 -8
  221. package/templates/apps/web/app/[locale]/(authed)/layout.tsx +18 -1
  222. package/templates/apps/web/app/[locale]/cancellation/page.tsx +44 -0
  223. package/templates/apps/web/app/[locale]/layout.tsx +133 -87
  224. package/templates/apps/web/app/[locale]/purchase/__tests__/cancel.test.tsx +162 -0
  225. package/templates/apps/web/app/[locale]/purchase/__tests__/module-scope.test.ts +68 -0
  226. package/templates/apps/web/app/[locale]/purchase/__tests__/success.test.tsx +361 -0
  227. package/templates/apps/web/app/[locale]/purchase/cancel/page.tsx +115 -0
  228. package/templates/apps/web/app/[locale]/purchase/success/page.tsx +307 -0
  229. package/templates/apps/web/app/[locale]/returns/page.tsx +44 -0
  230. package/templates/apps/web/app/[locale]/shipping/page.tsx +44 -0
  231. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +670 -0
  232. package/templates/apps/web/app/api/revalidate/route.ts +194 -0
  233. package/templates/apps/web/auth.ts +407 -8
  234. package/templates/apps/web/jest.config.cjs +8 -4
  235. package/templates/apps/web/lib/__tests__/auth-email.test.ts +214 -0
  236. package/templates/apps/web/lib/__tests__/auth-routes.test.ts +74 -0
  237. package/templates/apps/web/lib/__tests__/meeting-slugs.test.ts +72 -0
  238. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +18 -1
  239. package/templates/apps/web/lib/auth-email.ts +318 -0
  240. package/templates/apps/web/lib/auth-env.ts +85 -0
  241. package/templates/apps/web/lib/auth-routes.ts +55 -0
  242. package/templates/apps/web/lib/meeting-slugs.ts +53 -0
  243. package/templates/apps/web/lib/telemetry-scrub.ts +5 -1
  244. package/templates/apps/web/messages/en.json +187 -0
  245. package/templates/apps/web/package.json +2 -1
  246. package/templates/apps/web/src/lib/commerce-claim.ts +33 -0
  247. package/templates/apps/web/src/lib/commerce-sections.ts +61 -0
  248. package/templates/content/en/CancellationPolicyPage/cancellation.mdx +108 -0
  249. package/templates/content/en/ReturnsPolicyPage/returns.mdx +108 -0
  250. package/templates/content/en/ShippingPolicyPage/shipping.mdx +108 -0
  251. package/templates/database/CHANGELOG.md +142 -0
  252. package/templates/database/README.md +10 -3
  253. package/templates/database/__tests__/appointment.db.test.ts +106 -0
  254. package/templates/database/__tests__/artifact-content-store.db.test.ts +316 -0
  255. package/templates/database/__tests__/composite-fence.db.test.ts +206 -0
  256. package/templates/database/__tests__/fence-fan-out.db.test.ts +711 -0
  257. package/templates/database/__tests__/fixtures/appointment-create-probe.ts +79 -0
  258. package/templates/database/__tests__/fixtures/project-listing-consent-probe.ts +100 -0
  259. package/templates/database/__tests__/flow-workspace-key.db.test.ts +263 -0
  260. package/templates/database/__tests__/prefixed-ids.db.test.ts +85 -9
  261. package/templates/database/__tests__/project-listing-consent-at.db.test.ts +111 -0
  262. package/templates/database/__tests__/tenancy.test.ts +141 -0
  263. package/templates/database/config/schema.prisma +79 -2
  264. package/templates/database/content/schema.prisma +87 -11
  265. package/templates/database/inbox/schema.prisma +452 -9
  266. package/templates/database/jest.config.cjs +5 -3
  267. package/templates/database/migrations/20260915120000_project_listing_solution/migration.sql +15 -0
  268. package/templates/database/migrations/20260916120000_artifact_content_store/migration.sql +158 -0
  269. package/templates/database/migrations/20260917120000_callback_request_confirm/migration.sql +40 -0
  270. package/templates/database/migrations/20260918120000_add_appointment/migration.sql +67 -0
  271. package/templates/database/migrations/20260918120000_asset_metadata_columns/migration.sql +70 -0
  272. package/templates/database/migrations/20260919120000_flow_workspace_key/migration.sql +181 -0
  273. package/templates/database/migrations/20260919130000_flow_definition_admin_columns/migration.sql +172 -0
  274. package/templates/database/migrations/20260919130000_workspace_meetings/migration.sql +41 -0
  275. package/templates/database/migrations/20260919140000_inbox_workspace_key/migration.sql +185 -0
  276. package/templates/database/migrations/20260920120000_lead_handled_at/migration.sql +70 -0
  277. package/templates/database/migrations/20260920130000_lead_workspace_source_index/migration.sql +57 -0
  278. package/templates/database/migrations/20260921120000_deliverable_grant_workspace_key/migration.sql +68 -0
  279. package/templates/database/migrations/20260922120000_tenancy_fence/migration.sql +1067 -0
  280. package/templates/database/migrations/20260923120000_listing_capturing_magnet/migration.sql +210 -0
  281. package/templates/database/package.json +1 -1
  282. package/templates/database/tenancy.ts +86 -1
  283. package/templates/database/tsconfig.json +1 -0
  284. package/versions.json +34 -34
  285. package/templates/apps/api/src/routes/content/__tests__/create.test.ts +0 -253
  286. package/templates/apps/api/src/routes/content/__tests__/delete.test.ts +0 -215
  287. package/templates/apps/api/src/routes/content/__tests__/update.test.ts +0 -266
  288. package/templates/apps/api/src/routes/content/create.ts +0 -115
  289. package/templates/apps/api/src/routes/content/delete.ts +0 -82
  290. package/templates/apps/api/src/routes/content/update.ts +0 -112
  291. package/templates/apps/mcp/__tests__/create_page.test.ts +0 -202
  292. package/templates/apps/mcp/__tests__/delete_page.test.ts +0 -177
  293. package/templates/apps/mcp/__tests__/update_page.test.ts +0 -196
  294. package/templates/apps/mcp/src/tools/create_page.ts +0 -96
  295. package/templates/apps/mcp/src/tools/delete_page.ts +0 -74
  296. package/templates/apps/mcp/src/tools/update_page.ts +0 -92
  297. package/templates/apps/web/app/[locale]/sign-in/sign-in-card.tsx +0 -123
  298. /package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/__tests__/next-path.test.ts +0 -0
  299. /package/templates/apps/web/app/[locale]/{sign-in → (auth)/sign-in}/next-path.ts +0 -0
@@ -49,6 +49,10 @@
49
49
  "emptyState": "No documentation yet. Add MDX files to",
50
50
  "emptyStateTrailing": "to populate this list."
51
51
  },
52
+ "cancellation": {
53
+ "heading": "Cancellation Policy",
54
+ "emptyState": "Cancellation policy content coming soon."
55
+ },
52
56
  "careers": {
53
57
  "heading": "Careers",
54
58
  "emptyState": "Career listings coming soon."
@@ -214,10 +218,39 @@
214
218
  "heading": "Projects",
215
219
  "emptyState": "Projects listing coming soon."
216
220
  },
221
+ "purchase": {
222
+ "success": {
223
+ "title": "Payment successful",
224
+ "message": "Thanks for your order — here's what you bought.",
225
+ "statusLabel": "Paid",
226
+ "sessionIdLabel": "Order",
227
+ "lineItem": "Qty {quantity} · {amount}",
228
+ "continueLabel": "Back to services",
229
+ "pendingHeadline": "We have your order",
230
+ "pendingBody": "Payment is still settling. This page will not update on its own — check your email for the receipt, or come back in a few minutes.",
231
+ "unknownHeadline": "We can't look up this order from here",
232
+ "unknownBody": "Check your email for the receipt from checkout — it has everything about your order.",
233
+ "ctaHeadline": "Keep going",
234
+ "ctaDescription": "Have a look at what else we offer.",
235
+ "ctaLabel": "Browse services"
236
+ },
237
+ "cancel": {
238
+ "title": "Checkout canceled",
239
+ "message": "Nothing was charged. Your card was not billed.",
240
+ "statusLabel": "Canceled",
241
+ "ctaHeadline": "Still interested?",
242
+ "ctaDescription": "Head back to the service menu whenever you're ready.",
243
+ "ctaLabel": "Back to services"
244
+ }
245
+ },
217
246
  "resources": {
218
247
  "heading": "Resources",
219
248
  "emptyState": "Resources listing coming soon."
220
249
  },
250
+ "returns": {
251
+ "heading": "Returns & Refunds",
252
+ "emptyState": "Returns and refunds content coming soon."
253
+ },
221
254
  "schedule": {
222
255
  "title": "Book a call",
223
256
  "description": "Pick a time that works for you.",
@@ -240,6 +273,10 @@
240
273
  "heading": "Services",
241
274
  "emptyState": "Services listing coming soon."
242
275
  },
276
+ "shipping": {
277
+ "heading": "Shipping Policy",
278
+ "emptyState": "Shipping policy content coming soon."
279
+ },
243
280
  "software": {
244
281
  "heading": "Software",
245
282
  "description": "The @working-theory/* packages \u2014 typed tools for building AX-first products.",
@@ -396,6 +433,64 @@
396
433
  "signInFailed": "We couldn't sign you in. Check your details and try again.",
397
434
  "providerFailed": "We couldn't start sign-in with that provider. Try again."
398
435
  },
436
+ "auth": {
437
+ "signUpTitle": "Create an account",
438
+ "signUpDescription": "Create an account on this site.",
439
+ "forgotTitle": "Reset your password",
440
+ "forgotDescription": "Request a password reset link.",
441
+ "resetTitle": "Choose a new password",
442
+ "resetDescription": "Set a new password for your account.",
443
+ "verifyEmailTitle": "Check your email",
444
+ "verifyEmailDescription": "Follow the link we sent to continue.",
445
+ "email": "Email address",
446
+ "password": "Password",
447
+ "confirmPassword": "Confirm password",
448
+ "newPassword": "New password",
449
+ "orContinue": "Or continue with",
450
+ "ssoPrefix": "Continue with",
451
+ "google": "Google",
452
+ "github": "GitHub",
453
+ "backToSignIn": "Back to sign in",
454
+ "signUpHeading": "Create your account",
455
+ "signUpSubhead": "Enter your details to get started.",
456
+ "signUpSubmit": "Create account",
457
+ "signUpFooterPrompt": "Already have an account?",
458
+ "signUpFooterLink": "Sign in",
459
+ "signUpNotConfiguredSubhead": "Sign-up is not configured for this site yet. Set a provider's environment variables to enable it.",
460
+ "signUpFailed": "We couldn't create your account. Check your details and try again.",
461
+ "providerFailed": "We couldn't start sign-up with that provider. Try again.",
462
+ "invitationHeading": "Accounts are by invitation",
463
+ "invitationSubhead": "This site does not offer public sign-up.",
464
+ "invitationBody": "If you were invited, open the link in your invitation email to create your account.",
465
+ "forgotHeading": "Reset your password",
466
+ "forgotSubhead": "Enter your email and we will send a reset link.",
467
+ "forgotSubmit": "Send reset link",
468
+ "resetHeading": "Choose a new password",
469
+ "resetSubhead": "Choose a new password for your account.",
470
+ "resetSubmit": "Set new password",
471
+ "forgotUnavailableHeading": "Password reset isn't available",
472
+ "forgotUnavailableSubhead": "This site does not offer password reset.",
473
+ "forgotUnavailableBody": "Sign in with one of the providers on the sign-in page, or ask the site owner for help getting back in.",
474
+ "resetUnavailableHeading": "Password reset isn't available",
475
+ "resetUnavailableSubhead": "This reset link cannot be used on this site.",
476
+ "resetUnavailableBody": "Password reset is not enabled here. Sign in with one of the providers on the sign-in page instead.",
477
+ "sentToPrefix": "We sent it to",
478
+ "resetRequestFailed": "We couldn't send a reset link just now. Try again in a few minutes.",
479
+ "resetFailed": "We couldn't set that password. The link may have expired \u2014 request a new one.",
480
+ "passwordMismatch": "Both passwords must match.",
481
+ "resetExpiredHeading": "This reset link has expired",
482
+ "resetExpiredSubhead": "Reset links are single-use and last one hour.",
483
+ "resetExpiredBody": "Request a new link from the sign-in page and follow the most recent email.",
484
+ "verifyExpiredHeading": "This confirmation link has expired",
485
+ "verifyExpiredSubhead": "Confirmation links last 24 hours.",
486
+ "verifyExpiredBody": "Sign in again and we'll send you a fresh confirmation email.",
487
+ "sentHeading": "Check your email",
488
+ "sentSubhead": "Follow the link we just sent to continue.",
489
+ "sentBody": "Check your inbox and follow the link to continue. You can close this tab once you're done.",
490
+ "footerPrivacy": "Privacy",
491
+ "footerTerms": "Terms",
492
+ "footerHelp": "Help"
493
+ },
399
494
  "account": {
400
495
  "title": "Your account",
401
496
  "description": "Your profile, results, and purchases.",
@@ -433,6 +528,12 @@
433
528
  "date": "Date",
434
529
  "emptyHeadline": "No purchases yet",
435
530
  "emptyDescription": "Purchases you complete will appear here."
531
+ },
532
+ "subscription": {
533
+ "headline": "Your payment didn't go through",
534
+ "descriptionPastDue": "Update your card to keep your subscription active.",
535
+ "descriptionCanceled": "Your subscription was canceled. Update your card by {date} to keep your access.",
536
+ "action": "Update payment method"
436
537
  }
437
538
  },
438
539
  "admin": {
@@ -480,5 +581,91 @@
480
581
  "emptyHeadline": "No members yet",
481
582
  "emptyDescription": "People with access to this workspace will appear here."
482
583
  }
584
+ },
585
+ "edit": {
586
+ "title": "Pages",
587
+ "description": "Edit your site's pages and publish changes without a deploy.",
588
+ "listHeading": "Pages",
589
+ "listDescription": "Every page on this site. Choose one to edit its content and publish your changes.",
590
+ "listEmptyHeadline": "No pages yet",
591
+ "listEmptyDescription": "Pages you create appear here, ready to edit and publish.",
592
+ "statusDraft": "Draft",
593
+ "statusPublished": "Published",
594
+ "statusPublishedWithDraft": "Published, with unpublished changes",
595
+ "licenceRequiredHeadline": "Content editing is a Pro feature",
596
+ "licenceRequiredDescription": "Editing pages without a deploy is part of Pro. Add a Pro licence to this site to turn it on.",
597
+ "notFoundHeadline": "Page not found",
598
+ "notFoundDescription": "There is no page at this address. It may have been renamed or removed.",
599
+ "editor": {
600
+ "tabForm": "Details",
601
+ "tabBody": "Body",
602
+ "tabPreview": "Preview",
603
+ "tabCode": "Code",
604
+ "statusDraft": "Draft",
605
+ "statusNotYetLive": "Not yet live",
606
+ "statusPublished": "Published",
607
+ "frontmatterHeading": "Page details",
608
+ "frontmatterTitle": "Title",
609
+ "frontmatterSlug": "Slug",
610
+ "frontmatterDescription": "Description",
611
+ "issuesHeading": "Fix these before publishing",
612
+ "saveButton": "Save draft",
613
+ "saving": "Saving\u2026",
614
+ "saved": "Saved",
615
+ "saveError": "Could not save. Try again.",
616
+ "publishButton": "Publish",
617
+ "publishing": "Publishing\u2026",
618
+ "published": "Published",
619
+ "publishError": "Could not publish. Try again.",
620
+ "unpublishButton": "Unpublish",
621
+ "unpublishing": "Unpublishing\u2026",
622
+ "unpublished": "Unpublished",
623
+ "unpublishError": "Could not unpublish. Try again.",
624
+ "conflictHeading": "Someone else saved this page",
625
+ "conflictMessage": "This page changed since you opened it. Reload to take their version, or overwrite it with yours.",
626
+ "conflictReload": "Reload their version",
627
+ "conflictOverwrite": "Overwrite with mine",
628
+ "imageInsertLabel": "Insert an image",
629
+ "imageInsertHint": "The image is uploaded and its markdown inserted at the cursor.",
630
+ "imageAlt": "Image",
631
+ "imageInsertError": "Could not upload that image. Try again.",
632
+ "codeHeading": "Composed MDX",
633
+ "diffLegendAdded": "Added",
634
+ "diffLegendRemoved": "Removed",
635
+ "diffLegendUnchanged": "Unchanged"
636
+ },
637
+ "sections": {
638
+ "heading": "Sections",
639
+ "arrayAdd": "Add",
640
+ "arrayRemove": "Remove",
641
+ "unsupportedField": "This field is edited as raw JSON",
642
+ "sectionLevelErrors": "Other problems with this section"
643
+ },
644
+ "body": {
645
+ "label": "Body",
646
+ "hint": "Markdown. Headings, links, lists and images all work.",
647
+ "machinePreambleNotice": "This page starts with imports or components. They are preserved and are not editable here."
648
+ }
649
+ },
650
+ "appointments": {
651
+ "title": "Appointments",
652
+ "description": "Your site's upcoming bookings, soonest first.",
653
+ "forbiddenHeadline": "You don't have access",
654
+ "forbiddenDescription": "Sign in with the account that owns this site to see its bookings.",
655
+ "table": {
656
+ "caption": "Upcoming bookings for your site",
657
+ "columnWhen": "When",
658
+ "columnWho": "Who",
659
+ "columnStatus": "Status",
660
+ "columnPaid": "Paid",
661
+ "statusPending": "Pending",
662
+ "statusConfirmed": "Confirmed",
663
+ "statusCancelled": "Cancelled",
664
+ "paidYes": "Paid",
665
+ "paidNo": "Unpaid",
666
+ "next": "Next page",
667
+ "emptyHeadline": "No upcoming bookings",
668
+ "emptyDescription": "When someone books a time with you, the appointment appears here automatically."
669
+ }
483
670
  }
484
671
  }
@@ -21,7 +21,9 @@
21
21
  "@working-theory/api-client": "workspace:*",
22
22
  "@working-theory/content-adapters": "workspace:*",
23
23
  "@working-theory/database": "workspace:*",
24
+ "@working-theory/ids": "workspace:*",
24
25
  "@working-theory/jsonld": "workspace:*",
26
+ "@working-theory/license": "workspace:*",
25
27
  "@working-theory/metadata": "workspace:*",
26
28
  "@working-theory/page-renderer": "workspace:*",
27
29
  "@working-theory/schema": "workspace:*",
@@ -64,7 +66,6 @@
64
66
  "@eslint/js": "^10.0.1",
65
67
  "globals": "^17.7.0",
66
68
  "typescript-eslint": "^8.62.1",
67
- "@working-theory/license": "workspace:*",
68
69
  "@working-theory/sections-registry": "workspace:*"
69
70
  }
70
71
  }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The deployment's `commerce` add-on claim, resolved PER REQUEST (#6084 D12).
3
+ *
4
+ * Extracted from `app/.well-known/mcp.json/route.ts`'s own inline
5
+ * `resolveCommerceClaim()` (#5971) — that route's behaviour is unchanged;
6
+ * only its import line moves. `/purchase/success` and `/purchase/cancel`
7
+ * need the identical check (D12's shape-2 gate: the pages ship BASE TREE
8
+ * and gate at REQUEST time on this claim, exactly as the checkout
9
+ * primitives do — `apps/api/src/lib/require-commerce-claim.ts`), so this is
10
+ * extracted ONCE and imported three times rather than copied a third time.
11
+ *
12
+ * Fail-closed (NFR-3 mirror): anything short of a positively-held,
13
+ * unrevoked claim reads as absent, and a licence read that throws never
14
+ * takes the caller down with it. Called PER REQUEST rather than memoised —
15
+ * unlike `apps/mcp/src/lib/commerce-claim.ts`'s boot-time memoisation — so a
16
+ * site that buys commerce after its last deploy starts serving immediately
17
+ * rather than waiting on a redeploy.
18
+ */
19
+ import { checkLicense } from "@working-theory/license";
20
+
21
+ /** The licence `features[]` claim that turns the commerce add-on on. */
22
+ const COMMERCE_FEATURE = "commerce";
23
+
24
+ export async function resolveCommerceClaim(): Promise<boolean> {
25
+ try {
26
+ const result = await checkLicense();
27
+ return (
28
+ result.revoked !== true && result.features.includes(COMMERCE_FEATURE)
29
+ );
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Lazily registers the paid `@working-theory/ui-commerce` slice's sections
3
+ * (`payment-receipt`) — never a static top-level import (#6084, code-review
4
+ * finding on this issue's PR).
5
+ *
6
+ * `/purchase/success` and `/purchase/cancel` ship in the BASE TREE
7
+ * (`surfaces.ts` `CORE_ROUTE_DIRS`, D12) so a site that buys the `commerce`
8
+ * add-on after its last deploy gets working return pages without a
9
+ * redeploy. But a KEYLESS scaffold carries NO `ui-commerce` dependency by
10
+ * design — `packages/create-ailk/scripts/build-templates.mjs`'s
11
+ * `transformPaidUiPackages()` strips it from a keyless `apps/web/package.json`,
12
+ * and `__tests__/paid-module-honest-states.test.ts`'s "#5581 U6" suite
13
+ * asserts a keyless scaffold declares NONE of the four paid `ui-*` packages
14
+ * as a dependency. A plain top-level, STATIC named-import of that package's
15
+ * `registerCommerceSections` export would leave every keyless customer's
16
+ * build failing with `ERR_MODULE_NOT_FOUND` — webpack resolves a static
17
+ * import at BUILD time regardless of whether the code path importing it
18
+ * ever executes at runtime, so gating the CALL at request time (as
19
+ * `resolveCommerceClaim()` already does) is not enough on its own.
20
+ *
21
+ * The `webpackIgnore` magic comment tells webpack to leave this `import()`
22
+ * unresolved at build time; Node's own ESM loader then attempts it at
23
+ * RUNTIME, where a keyless deployment's absent package throws a genuine
24
+ * (caught) resolution error instead of a build failure. This repo's `dev`
25
+ * and `build` scripts both force `--webpack` (never Turbopack, which does
26
+ * not honor this comment), so the magic comment is reliably honored here.
27
+ *
28
+ * On success, the real `payment-receipt` renderer is registered and the
29
+ * caller may build a `payment-receipt` section as usual. On failure (the
30
+ * package genuinely is not installed), the caller MUST NOT construct a bare
31
+ * `payment-receipt` section anyway — `SectionRenderer`'s dispatch table
32
+ * falls back to `ModuleAbsent`, which renders `null` in production
33
+ * (`packages/ui/src/sections/ModuleAbsent.tsx`) — silently dropping the
34
+ * title/message/status that is this page's entire point. The caller must
35
+ * build an OSS `content-block` fallback carrying the same copy instead.
36
+ *
37
+ * Registered (or found absent) once per process — memoised, so a concurrent
38
+ * request never double-registers or double-attempts a failed resolution.
39
+ * This is a build-presence fact, not the license claim itself (which
40
+ * `resolveCommerceClaim()` deliberately re-checks every request); a
41
+ * process only changes which packages are on disk via a fresh deploy, which
42
+ * is a fresh process.
43
+ */
44
+ let registration: Promise<boolean> | undefined;
45
+
46
+ export function ensureCommerceSectionsRegistered(): Promise<boolean> {
47
+ if (!registration) {
48
+ registration = (async () => {
49
+ try {
50
+ const mod = await import(
51
+ /* webpackIgnore: true */ "@working-theory/ui-commerce"
52
+ );
53
+ mod.registerCommerceSections();
54
+ return true;
55
+ } catch {
56
+ return false;
57
+ }
58
+ })();
59
+ }
60
+ return registration;
61
+ }
@@ -0,0 +1,108 @@
1
+ ---
2
+ type: "CancellationPolicyPage"
3
+ slug: "cancellation"
4
+ title: "Cancellation Policy"
5
+ description: "How to cancel or reschedule a booking on this site, the notice required, and what a late cancellation or no-show costs."
6
+ updatedAt: "2026-09-17"
7
+ sections:
8
+ [
9
+ {
10
+ "id": "cancellation-document",
11
+ "type": "document-chassis",
12
+ "data":
13
+ {
14
+ "headline": "Cancellation Policy",
15
+ "backHref": "/",
16
+ "backLabel": "Back home",
17
+ "navGroupLabel": "Contents",
18
+ "stats":
19
+ [
20
+ { "label": "Last updated", "sublabel": "17 September 2026" },
21
+ { "label": "Applies to", "sublabel": "Bookings made on this site" },
22
+ ],
23
+ "sections":
24
+ [
25
+ {
26
+ "id": "intro",
27
+ "heading": "Cancellation Policy",
28
+ "blocks":
29
+ [
30
+ {
31
+ "kind": "paragraph",
32
+ "text": "This page explains how cancellations and reschedules work for bookings made on this site. Replace the starter copy below with the policy you actually operate — the headings are the ones a customer and an agent both look for, so keep them and fill in your own terms.",
33
+ },
34
+ ],
35
+ },
36
+ {
37
+ "id": "notice",
38
+ "heading": "How much notice is required",
39
+ "blocks":
40
+ [
41
+ {
42
+ "kind": "paragraph",
43
+ "text": "State the notice period in hours before the appointment, and say how it is measured. A customer reading at midnight should be able to work out, without arithmetic you have not shown them, whether they are still inside it.",
44
+ },
45
+ ],
46
+ },
47
+ {
48
+ "id": "how-to-cancel",
49
+ "heading": "How to cancel or reschedule",
50
+ "blocks":
51
+ [
52
+ {
53
+ "kind": "paragraph",
54
+ "text": "Give one route to cancel and one to reschedule, and say whether a reschedule inside the notice period counts as a cancellation. If a booking confirmation carries a self-service link, name it here.",
55
+ },
56
+ ],
57
+ },
58
+ {
59
+ "id": "fees",
60
+ "heading": "Late cancellations and no-shows",
61
+ "blocks":
62
+ [
63
+ {
64
+ "kind": "paragraph",
65
+ "text": "Say what a late cancellation costs and what a no-show costs, as a figure or a share of the booking, and when each is charged. If you hold a deposit, say what happens to it in each case.",
66
+ },
67
+ ],
68
+ },
69
+ {
70
+ "id": "our-cancellations",
71
+ "heading": "If we cancel",
72
+ "blocks":
73
+ [
74
+ {
75
+ "kind": "paragraph",
76
+ "text": "Set out what a customer gets if you cancel or move an appointment — a full refund, a rebooking, or both — and how quickly you tell them. A policy that only binds one side reads as one.",
77
+ },
78
+ ],
79
+ },
80
+ {
81
+ "id": "exceptions",
82
+ "heading": "Exceptions",
83
+ "blocks":
84
+ [
85
+ {
86
+ "kind": "paragraph",
87
+ "text": "Name the circumstances in which you waive a fee — illness, bereavement, severe weather — and say what you need from the customer to apply the waiver. Vague discretion is worse for you than a short written list.",
88
+ },
89
+ ],
90
+ },
91
+ {
92
+ "id": "contact",
93
+ "heading": "Questions about a booking",
94
+ "blocks":
95
+ [
96
+ {
97
+ "kind": "paragraph",
98
+ "text": "Point to the one place a customer should write, and say roughly how quickly you answer.",
99
+ },
100
+ ],
101
+ },
102
+ ],
103
+ },
104
+ },
105
+ ]
106
+ ---
107
+
108
+ {/* Rendered from frontmatter `sections[]`; the MDX body is not read by the section-catalog renderer. schema.org has no cancellation-policy type, so this page emits a plain WebPage (#5947, D2) — a real policy field reaches the JSON-LD through the `schema:` escape hatch, never a coined @type. */}
@@ -0,0 +1,108 @@
1
+ ---
2
+ type: "ReturnsPolicyPage"
3
+ slug: "returns"
4
+ title: "Returns & Refunds"
5
+ description: "How to return an order from this site, how long you have, and how refunds are issued."
6
+ updatedAt: "2026-09-17"
7
+ sections:
8
+ [
9
+ {
10
+ "id": "returns-document",
11
+ "type": "document-chassis",
12
+ "data":
13
+ {
14
+ "headline": "Returns & Refunds",
15
+ "backHref": "/",
16
+ "backLabel": "Back home",
17
+ "navGroupLabel": "Contents",
18
+ "stats":
19
+ [
20
+ { "label": "Last updated", "sublabel": "17 September 2026" },
21
+ { "label": "Applies to", "sublabel": "Orders placed on this site" },
22
+ ],
23
+ "sections":
24
+ [
25
+ {
26
+ "id": "intro",
27
+ "heading": "Returns & Refunds",
28
+ "blocks":
29
+ [
30
+ {
31
+ "kind": "paragraph",
32
+ "text": "This page explains how returns and refunds work on this site. Replace the starter copy below with the policy you actually operate — the headings are the ones a customer and an agent both look for, so keep them and fill in your own terms.",
33
+ },
34
+ ],
35
+ },
36
+ {
37
+ "id": "return-window",
38
+ "heading": "How long you have",
39
+ "blocks":
40
+ [
41
+ {
42
+ "kind": "paragraph",
43
+ "text": "State the return window in days, counted from a date a customer can verify — delivery, not dispatch. If different products carry different windows, say which, and say plainly which items cannot be returned at all.",
44
+ },
45
+ ],
46
+ },
47
+ {
48
+ "id": "condition",
49
+ "heading": "What condition an item must be in",
50
+ "blocks":
51
+ [
52
+ {
53
+ "kind": "paragraph",
54
+ "text": "Describe the condition an item must come back in — unused, original packaging, tags attached, or whatever your standard is. Name anything that voids a return, such as a removed seal on a digital product or a personalised item.",
55
+ },
56
+ ],
57
+ },
58
+ {
59
+ "id": "how-to-return",
60
+ "heading": "How to start a return",
61
+ "blocks":
62
+ [
63
+ {
64
+ "kind": "paragraph",
65
+ "text": "Give the customer one route to start a return and the information they need to hand: an order number, the item, and the reason. If you issue a return label, say who pays for it; if you do not, say that too.",
66
+ },
67
+ ],
68
+ },
69
+ {
70
+ "id": "refunds",
71
+ "heading": "How refunds are issued",
72
+ "blocks":
73
+ [
74
+ {
75
+ "kind": "paragraph",
76
+ "text": "Say what a customer gets back — the item price, the original shipping, or both — and how long the refund takes to reach the payment method it came from. If you offer store credit or an exchange instead, describe when each applies.",
77
+ },
78
+ ],
79
+ },
80
+ {
81
+ "id": "exchanges",
82
+ "heading": "Exchanges and faulty items",
83
+ "blocks":
84
+ [
85
+ {
86
+ "kind": "paragraph",
87
+ "text": "A faulty or incorrectly shipped item is usually not an ordinary return. Set out how those are handled, and say whether the return window above applies to them.",
88
+ },
89
+ ],
90
+ },
91
+ {
92
+ "id": "contact",
93
+ "heading": "Questions about a return",
94
+ "blocks":
95
+ [
96
+ {
97
+ "kind": "paragraph",
98
+ "text": "Point to the one place a customer should write, and say roughly how quickly you answer. A returns policy nobody can ask a question about is a policy that generates disputes.",
99
+ },
100
+ ],
101
+ },
102
+ ],
103
+ },
104
+ },
105
+ ]
106
+ ---
107
+
108
+ {/* Rendered from frontmatter `sections[]`; the MDX body is not read by the section-catalog renderer. The JSON-LD for this page — a WebPage wrapping a MerchantReturnPolicy — is emitted by `buildReturnsPolicyPage` (#5947), not hand-rolled here. */}
@@ -0,0 +1,108 @@
1
+ ---
2
+ type: "ShippingPolicyPage"
3
+ slug: "shipping"
4
+ title: "Shipping Policy"
5
+ description: "Where orders from this site ship, how long delivery takes, what it costs, and what happens when a parcel goes missing."
6
+ updatedAt: "2026-09-17"
7
+ sections:
8
+ [
9
+ {
10
+ "id": "shipping-document",
11
+ "type": "document-chassis",
12
+ "data":
13
+ {
14
+ "headline": "Shipping Policy",
15
+ "backHref": "/",
16
+ "backLabel": "Back home",
17
+ "navGroupLabel": "Contents",
18
+ "stats":
19
+ [
20
+ { "label": "Last updated", "sublabel": "17 September 2026" },
21
+ { "label": "Applies to", "sublabel": "Orders shipped from this site" },
22
+ ],
23
+ "sections":
24
+ [
25
+ {
26
+ "id": "intro",
27
+ "heading": "Shipping Policy",
28
+ "blocks":
29
+ [
30
+ {
31
+ "kind": "paragraph",
32
+ "text": "This page explains how orders from this site are shipped. Replace the starter copy below with the policy you actually operate — the headings are the ones a customer and an agent both look for, so keep them and fill in your own terms.",
33
+ },
34
+ ],
35
+ },
36
+ {
37
+ "id": "destinations",
38
+ "heading": "Where we ship",
39
+ "blocks":
40
+ [
41
+ {
42
+ "kind": "paragraph",
43
+ "text": "List the countries or regions you ship to, and say plainly where you do not. If some products are restricted to a subset of those destinations, say which.",
44
+ },
45
+ ],
46
+ },
47
+ {
48
+ "id": "processing-and-transit",
49
+ "heading": "How long it takes",
50
+ "blocks":
51
+ [
52
+ {
53
+ "kind": "paragraph",
54
+ "text": "Give processing time and transit time as two separate figures, in business days, per shipping option. A single blended estimate is the one thing customers most often read as a promise you did not make.",
55
+ },
56
+ ],
57
+ },
58
+ {
59
+ "id": "costs",
60
+ "heading": "What shipping costs",
61
+ "blocks":
62
+ [
63
+ {
64
+ "kind": "paragraph",
65
+ "text": "Set out the cost of each shipping option and any threshold above which it is free. Say whether the figure shown at checkout is final, and whether duties and import taxes are included or collected on delivery.",
66
+ },
67
+ ],
68
+ },
69
+ {
70
+ "id": "tracking",
71
+ "heading": "Tracking your order",
72
+ "blocks":
73
+ [
74
+ {
75
+ "kind": "paragraph",
76
+ "text": "Say when tracking information is sent, where it comes from, and what a customer should do if it has not updated for a while.",
77
+ },
78
+ ],
79
+ },
80
+ {
81
+ "id": "lost-or-damaged",
82
+ "heading": "Lost or damaged parcels",
83
+ "blocks":
84
+ [
85
+ {
86
+ "kind": "paragraph",
87
+ "text": "Describe how long a parcel must be missing before you treat it as lost, what you do then, and what you need from the customer — photographs for damage, a written report for a loss. Returns of damaged goods are the returns policy's business; link to it rather than restating it here.",
88
+ },
89
+ ],
90
+ },
91
+ {
92
+ "id": "contact",
93
+ "heading": "Questions about a delivery",
94
+ "blocks":
95
+ [
96
+ {
97
+ "kind": "paragraph",
98
+ "text": "Point to the one place a customer should write, and say roughly how quickly you answer.",
99
+ },
100
+ ],
101
+ },
102
+ ],
103
+ },
104
+ },
105
+ ]
106
+ ---
107
+
108
+ {/* Rendered from frontmatter `sections[]`; the MDX body is not read by the section-catalog renderer. `OfferShippingDetails` is offer-scoped, not page-scoped, so this page emits a plain WebPage (#5947, D3) — real rates belong on an Offer, or reach this page's JSON-LD through the `schema:` escape hatch. */}