@cosmicdrift/kumiko-samples 0.374.0 → 0.378.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 (247) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +6 -4
  3. package/packages/bundled-features/src/account-security/changes.json +6 -0
  4. package/packages/bundled-features/src/account-security/constants.ts +1 -0
  5. package/packages/bundled-features/src/account-security/index.ts +1 -0
  6. package/packages/bundled-features/src/admin-shell/web/client-plugin.tsx +1 -1
  7. package/packages/bundled-features/src/audit/web/client-plugin.tsx +1 -1
  8. package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +1 -1
  9. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +1 -1
  10. package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +1 -1
  11. package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +3 -3
  12. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +1 -1
  13. package/packages/bundled-features/src/auth-email-password/web/index.ts +1 -1
  14. package/packages/bundled-features/src/auth-email-password/web/session.tsx +1 -1
  15. package/packages/bundled-features/src/auth-email-password/web/tenant-menu-items.tsx +1 -1
  16. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +1 -1
  17. package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +1 -1
  18. package/packages/bundled-features/src/auth-foundation/changes.json +6 -0
  19. package/packages/bundled-features/src/auth-foundation/env.ts +27 -0
  20. package/packages/bundled-features/src/auth-foundation/index.ts +1 -0
  21. package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
  22. package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +1 -1
  23. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-pages.ts +1 -1
  24. package/packages/bundled-features/src/billing-foundation/contact-card.ts +14 -0
  25. package/packages/bundled-features/src/billing-foundation/handlers/billing-plans.query.ts +1 -1
  26. package/packages/bundled-features/src/billing-foundation/index.ts +1 -0
  27. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +1 -0
  28. package/packages/bundled-features/src/billing-foundation/types.ts +12 -0
  29. package/packages/bundled-features/src/billing-foundation/validate-options.ts +16 -0
  30. package/packages/bundled-features/src/billing-foundation/web/billing-contact-plan.tsx +32 -0
  31. package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +5 -15
  32. package/packages/bundled-features/src/billing-foundation/web/cancel-contract-dialog.tsx +2 -2
  33. package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +1 -1
  34. package/packages/bundled-features/src/billing-foundation/web/client-plugin.tsx +1 -1
  35. package/packages/bundled-features/src/billing-foundation/web/localized-params.ts +14 -0
  36. package/packages/bundled-features/src/cap-counter/changes.json +12 -0
  37. package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -0
  38. package/packages/bundled-features/src/cap-overview/web/cap-cards-panel.tsx +3 -3
  39. package/packages/bundled-features/src/cap-overview/web/client-plugin.tsx +1 -1
  40. package/packages/bundled-features/src/channel-email/changes.json +6 -0
  41. package/packages/bundled-features/src/channel-email/email-channel.ts +2 -1
  42. package/packages/bundled-features/src/compliance-profiles/web/client-plugin.tsx +1 -1
  43. package/packages/bundled-features/src/config/feature.ts +2 -2
  44. package/packages/bundled-features/src/config/web/i18n.ts +1 -0
  45. package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
  46. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +1 -1
  47. package/packages/bundled-features/src/delivery/unsubscribe-page.ts +1 -1
  48. package/packages/bundled-features/src/delivery/web/client-plugin.tsx +1 -1
  49. package/packages/bundled-features/src/delivery/web/delivery-status-cell.tsx +1 -1
  50. package/packages/bundled-features/src/feature-toggles/web/client-plugin.tsx +1 -1
  51. package/packages/bundled-features/src/file-provider-s3/changes.json +6 -0
  52. package/packages/bundled-features/src/file-provider-s3/env-named-feature.ts +45 -0
  53. package/packages/bundled-features/src/file-provider-s3/env-schema.ts +20 -13
  54. package/packages/bundled-features/src/file-provider-s3/index.ts +4 -0
  55. package/packages/bundled-features/src/folders/web/client-plugin.tsx +1 -1
  56. package/packages/bundled-features/src/folders/web/folder-section.tsx +3 -4
  57. package/packages/bundled-features/src/host-routing/README.md +7 -0
  58. package/packages/bundled-features/src/host-routing/changes.json +6 -0
  59. package/packages/bundled-features/src/host-routing/constants.ts +4 -0
  60. package/packages/bundled-features/src/host-routing/dispatch.ts +34 -26
  61. package/packages/bundled-features/src/host-routing/feature.ts +122 -41
  62. package/packages/bundled-features/src/host-routing/host.ts +28 -1
  63. package/packages/bundled-features/src/host-routing/index.ts +3 -0
  64. package/packages/bundled-features/src/host-routing/options.ts +45 -2
  65. package/packages/bundled-features/src/host-routing/redirects.ts +33 -0
  66. package/packages/bundled-features/src/host-routing/tenant-lookup.ts +65 -0
  67. package/packages/bundled-features/src/host-routing/validate-options.ts +48 -1
  68. package/packages/bundled-features/src/inbound-mail-foundation/changes.json +13 -0
  69. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +8 -0
  70. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +11 -4
  71. package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +42 -0
  72. package/packages/bundled-features/src/inbound-mail-foundation/index.ts +4 -0
  73. package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +100 -0
  74. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +2 -2
  75. package/packages/bundled-features/src/jobs/web/client-plugin.tsx +1 -1
  76. package/packages/bundled-features/src/legal-pages/changes.json +6 -0
  77. package/packages/bundled-features/src/legal-pages/feature.ts +14 -1
  78. package/packages/bundled-features/src/legal-pages/layout.ts +6 -6
  79. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +1 -1
  80. package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
  81. package/packages/bundled-features/src/mail-foundation/feature.ts +21 -22
  82. package/packages/bundled-features/src/mail-foundation/i18n.ts +3 -2
  83. package/packages/bundled-features/src/mail-transport-smtp/i18n.ts +1 -1
  84. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +1 -1
  85. package/packages/bundled-features/src/notes-history/web/client-plugin.tsx +1 -1
  86. package/packages/bundled-features/src/page-render/branding.ts +1 -1
  87. package/packages/bundled-features/src/page-render/layout.ts +2 -2
  88. package/packages/bundled-features/src/page-render/markdown.ts +1 -1
  89. package/packages/bundled-features/src/personal-access-tokens/i18n.ts +1 -1
  90. package/packages/bundled-features/src/personal-access-tokens/screens.ts +1 -1
  91. package/packages/bundled-features/src/secrets/feature.ts +4 -4
  92. package/packages/bundled-features/src/seo/sitemap.ts +1 -1
  93. package/packages/bundled-features/src/shared/mail-template-body.ts +1 -1
  94. package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +127 -2
  95. package/packages/bundled-features/src/tags/web/client-plugin.tsx +1 -1
  96. package/packages/bundled-features/src/template-resolver/changes.json +38 -0
  97. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +61 -3
  98. package/packages/bundled-features/src/template-resolver/constants.ts +3 -0
  99. package/packages/bundled-features/src/template-resolver/document-blocks.ts +36 -0
  100. package/packages/bundled-features/src/template-resolver/document-images.ts +29 -0
  101. package/packages/bundled-features/src/template-resolver/document-ops.ts +515 -0
  102. package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +44 -0
  103. package/packages/bundled-features/src/template-resolver/document-schema.ts +5 -0
  104. package/packages/bundled-features/src/template-resolver/feature.ts +79 -34
  105. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +1 -0
  106. package/packages/bundled-features/src/template-resolver/handlers/collection-item.query.ts +1 -1
  107. package/packages/bundled-features/src/template-resolver/handlers/collection-list.query.ts +1 -1
  108. package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +2 -6
  109. package/packages/bundled-features/src/template-resolver/handlers/collection-shared.ts +0 -6
  110. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +67 -58
  111. package/packages/bundled-features/src/template-resolver/handlers/discard-draft.write.ts +36 -13
  112. package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +86 -0
  113. package/packages/bundled-features/src/template-resolver/handlers/document-blocks.query.ts +48 -0
  114. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +11 -3
  115. package/packages/bundled-features/src/template-resolver/handlers/import-bundle.write.ts +37 -28
  116. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +66 -62
  117. package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +134 -0
  118. package/packages/bundled-features/src/template-resolver/handlers/preview.query.ts +2 -1
  119. package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +62 -49
  120. package/packages/bundled-features/src/template-resolver/handlers/resource-link-pdf.write.ts +44 -29
  121. package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +52 -36
  122. package/packages/bundled-features/src/template-resolver/handlers/resource-upload.write.ts +126 -106
  123. package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +38 -0
  124. package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +31 -0
  125. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +105 -110
  126. package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +110 -103
  127. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +22 -1
  128. package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +56 -28
  129. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +38 -29
  130. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +24 -9
  131. package/packages/bundled-features/src/template-resolver/index.ts +8 -1
  132. package/packages/bundled-features/src/template-resolver/{web/placeholder-text.ts → placeholder-text.ts} +1 -1
  133. package/packages/bundled-features/src/template-resolver/qualified-names.ts +4 -0
  134. package/packages/bundled-features/src/template-resolver/seeding.ts +3 -1
  135. package/packages/bundled-features/src/template-resolver/template-bundle.ts +6 -1
  136. package/packages/bundled-features/src/template-resolver/template-edit-policy.ts +91 -0
  137. package/packages/bundled-features/src/template-resolver/template-preview.ts +32 -10
  138. package/packages/bundled-features/src/template-resolver/template-validation.ts +32 -11
  139. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +3 -3
  140. package/packages/bundled-features/src/template-resolver/web/document-editor-extensions.ts +29 -0
  141. package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +43 -5
  142. package/packages/bundled-features/src/template-resolver/web/document-toolbar-blocks.ts +9 -33
  143. package/packages/bundled-features/src/template-resolver/web/i18n.ts +30 -0
  144. package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +2 -2
  145. package/packages/bundled-features/src/tenant/web/client-plugin.tsx +1 -1
  146. package/packages/bundled-features/src/tenant/web/member-status-cell.tsx +1 -1
  147. package/packages/bundled-features/src/tier-engine/web/client-plugin.tsx +1 -1
  148. package/packages/bundled-features/src/user-data-rights/changes.json +6 -0
  149. package/packages/bundled-features/src/user-data-rights/env.ts +15 -0
  150. package/packages/bundled-features/src/user-data-rights/feature.ts +4 -2
  151. package/packages/bundled-features/src/user-data-rights/index.ts +1 -0
  152. package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
  153. package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
  154. package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +1 -1
  155. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +1 -1
  156. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +2 -2
  157. package/packages/bundled-features/src/waitlist/changes.json +6 -0
  158. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +51 -2
  159. package/samples/apps/admin-console/package.json +0 -3
  160. package/samples/apps/admin-console/src/app/client.tsx +1 -1
  161. package/samples/apps/admin-console/src/app/shell.tsx +1 -1
  162. package/samples/apps/config-demo/package.json +1 -3
  163. package/samples/apps/config-demo/src/app/client.tsx +1 -1
  164. package/samples/apps/config-demo/src/app/shell.tsx +2 -2
  165. package/samples/apps/config-demo/src/features/demo/web/index.ts +1 -1
  166. package/samples/apps/config-demo/tsconfig.json +0 -12
  167. package/samples/apps/marketing-demo/package.json +1 -3
  168. package/samples/apps/marketing-demo/src/app/client.tsx +1 -1
  169. package/samples/apps/marketing-demo/src/app/shell.tsx +1 -1
  170. package/samples/apps/marketing-demo/src/features/assets/web/index.ts +1 -1
  171. package/samples/apps/marketing-demo/src/features/helpdesk/web/index.ts +1 -1
  172. package/samples/apps/showcase/package.json +1 -3
  173. package/samples/apps/showcase/src/app/client.tsx +1 -1
  174. package/samples/apps/showcase/src/app/shell.tsx +1 -1
  175. package/samples/apps/showcase/src/features/demos/web/index.ts +1 -1
  176. package/samples/apps/showcase/src/features/demos/web/pages/sidebar-panel.tsx +1 -1
  177. package/samples/apps/showcase/src/features/demos/web/pages/toast.tsx +1 -1
  178. package/samples/apps/showcase/src/features/items/web/index.ts +1 -1
  179. package/samples/apps/styleguide/package.json +1 -3
  180. package/samples/apps/styleguide/src/app/client.tsx +1 -1
  181. package/samples/apps/styleguide/src/app/shell.tsx +2 -2
  182. package/samples/apps/styleguide/src/features/ai-settings/web.ts +1 -1
  183. package/samples/apps/styleguide/src/features/content/web.tsx +2 -2
  184. package/samples/apps/styleguide/src/features/demo/web.ts +1 -1
  185. package/samples/apps/styleguide/src/features/examples/web.ts +1 -1
  186. package/samples/apps/styleguide/src/features/gallery/web/Gallery.tsx +1 -1
  187. package/samples/apps/styleguide/src/features/gallery/web/index.ts +1 -1
  188. package/samples/apps/styleguide/src/features/widgets/demo-locale.ts +1 -1
  189. package/samples/apps/styleguide/src/features/widgets/lib/format.ts +1 -1
  190. package/samples/apps/styleguide/src/features/widgets/web/DashboardFilterEcho.tsx +1 -1
  191. package/samples/apps/styleguide/src/features/widgets/web/FormExamples.tsx +1 -1
  192. package/samples/apps/styleguide/src/features/widgets/web/Widgets.tsx +1 -1
  193. package/samples/apps/styleguide/src/features/widgets/web/index.ts +1 -1
  194. package/samples/apps/styleguide/tsconfig.json +0 -12
  195. package/samples/apps/ui-walkthrough/package.json +1 -3
  196. package/samples/apps/ui-walkthrough/src/app/client.tsx +1 -1
  197. package/samples/apps/ui-walkthrough/src/app/help-action.tsx +37 -0
  198. package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +2 -0
  199. package/samples/apps/ui-walkthrough/src/app/shell.tsx +7 -1
  200. package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +20 -0
  201. package/samples/apps/ui-walkthrough/src/features/billing/web/index.ts +1 -1
  202. package/samples/apps/ui-walkthrough/src/features/rental/feature.ts +65 -1
  203. package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +70 -0
  204. package/samples/apps/ui-walkthrough/src/features/rental/invoice-receive.ts +20 -0
  205. package/samples/apps/ui-walkthrough/src/features/rental/lease-support.ts +15 -0
  206. package/samples/apps/ui-walkthrough/src/features/rental/qualified-names.ts +2 -0
  207. package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +79 -0
  208. package/samples/apps/ui-walkthrough/src/features/rental/web/index.ts +3 -1
  209. package/samples/apps/ui-walkthrough/src/features/rental/web/upload-standard-layout.tsx +61 -0
  210. package/samples/apps/ui-walkthrough/src/features/tasks/i18n.ts +8 -0
  211. package/samples/apps/ui-walkthrough/src/features/tasks/web/index.ts +1 -1
  212. package/samples/apps/ui-walkthrough/src/features/vehicles/web/index.ts +1 -1
  213. package/samples/apps/ui-walkthrough/src/run-config.ts +32 -3
  214. package/samples/apps/use-all-bundled/bin/main.ts +3 -2
  215. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +12 -0
  216. package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +1 -1
  217. package/samples/apps/use-all-bundled/feature-manifest.json +3 -2
  218. package/samples/apps/use-all-bundled/package.json +1 -3
  219. package/samples/apps/use-all-bundled/src/app/client.tsx +1 -1
  220. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +5 -4
  221. package/samples/apps/use-all-bundled/src/app/shell.tsx +1 -1
  222. package/samples/apps/use-all-bundled/src/run-config.ts +10 -1
  223. package/samples/apps/workspaces/package.json +1 -3
  224. package/samples/apps/workspaces/src/app/client.tsx +1 -1
  225. package/samples/apps/workspaces/src/app/shell.tsx +1 -1
  226. package/samples/apps/workspaces/src/features/demo/web/index.ts +1 -1
  227. package/samples/apps/workspaces/src/features/demo-driver/web/index.ts +1 -1
  228. package/samples/recipes/apex-landing/package.json +1 -1
  229. package/samples/recipes/apex-landing/src/feature.ts +1 -1
  230. package/samples/recipes/apex-surface-auth/README.md +1 -1
  231. package/samples/recipes/apex-surface-auth/src/feature.ts +2 -2
  232. package/samples/recipes/compose-stacks/README.md +7 -4
  233. package/samples/recipes/delivery-notifications/README.md +1 -1
  234. package/samples/recipes/embedded/README.md +8 -0
  235. package/samples/recipes/embedded/src/feature.ts +8 -0
  236. package/samples/recipes/embedded/src/handlers/invoice-receive.write.ts +38 -0
  237. package/samples/recipes/embedded/src/screens/invoice-receive.screen.ts +59 -0
  238. package/samples/recipes/embedded-entity-form/package.json +0 -1
  239. package/samples/recipes/embedded-entity-form/src/web/accept-suggestion-drawer.tsx +1 -1
  240. package/samples/recipes/notes-history-basic/README.md +1 -1
  241. package/samples/recipes/record-detail-layout/package.json +0 -1
  242. package/samples/recipes/tags-basic/README.md +1 -1
  243. package/samples/recipes/user-profile/README.md +1 -1
  244. package/samples/recipes/wizard-form/package.json +0 -1
  245. package/samples/recipes/wizard-form/src/web/index.ts +2 -2
  246. package/samples/recipes/wizard-form/src/web/listing-review-section.tsx +2 -2
  247. package/samples/recipes/writeform-section/package.json +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-samples",
3
- "version": "0.374.0",
3
+ "version": "0.378.0",
4
4
  "description": "Source trees of the Kumiko sample recipes, sample apps and bundled features in repo layout, for tooling such as few-shot corpus builds.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-bundled-features",
3
- "version": "0.374.0",
3
+ "version": "0.378.0",
4
4
  "description": "Built-in features — tenant, user, auth, delivery. The stuff you'd rewrite anyway, already typed.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -137,6 +137,7 @@
137
137
  "./template-resolver/web": "./src/template-resolver/web/index.ts",
138
138
  "./renderer-foundation": "./src/renderer-foundation/index.ts",
139
139
  "./account-security": "./src/account-security/index.ts",
140
+ "./account-security/constants": "./src/account-security/constants.ts",
140
141
  "./host-routing": "./src/host-routing/index.ts",
141
142
  "./legal-pages": "./src/legal-pages/index.ts",
142
143
  "./legal-pages/constants": "./src/legal-pages/constants.ts",
@@ -152,11 +153,8 @@
152
153
  "./workflow-runner": "./src/workflow-runner/index.ts"
153
154
  },
154
155
  "dependencies": {
155
- "@cosmicdrift/kumiko-dispatcher-live": "workspace:*",
156
156
  "@cosmicdrift/kumiko-framework": "workspace:*",
157
- "@cosmicdrift/kumiko-headless": "workspace:*",
158
157
  "@cosmicdrift/kumiko-renderer": "workspace:*",
159
- "@cosmicdrift/kumiko-renderer-web": "workspace:*",
160
158
  "@cosmicdrift/kumiko-types": "workspace:*",
161
159
  "@mollie/api-client": "^4.5.0",
162
160
  "@node-rs/argon2": "^2.0.2",
@@ -656,6 +654,10 @@
656
654
  "types": "./dist/account-security/index.d.ts",
657
655
  "default": "./dist/account-security/index.js"
658
656
  },
657
+ "./account-security/constants": {
658
+ "types": "./dist/account-security/constants.d.ts",
659
+ "default": "./dist/account-security/constants.js"
660
+ },
659
661
  "./host-routing": {
660
662
  "types": "./dist/host-routing/index.d.ts",
661
663
  "default": "./dist/host-routing/index.js"
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.376.0",
4
+ "type": "improvement",
5
+ "title": "Client-safe account-security/constants subpath",
6
+ "detail": "\"@cosmicdrift/kumiko-bundled-features/account-security/constants\" exports ACCOUNT_SECURITY_FEATURE, the screen id and QN, the nav label and the new ACCOUNT_SECURITY_SCREEN_TITLE_KEY without importing server code."
7
+ },
2
8
  {
3
9
  "version": "0.370.0",
4
10
  "type": "improvement",
@@ -3,4 +3,5 @@
3
3
  export const ACCOUNT_SECURITY_FEATURE = "account-security";
4
4
  export const ACCOUNT_SECURITY_SCREEN_ID = "account-security";
5
5
  export const ACCOUNT_SECURITY_SCREEN_QN = `${ACCOUNT_SECURITY_FEATURE}:screen:${ACCOUNT_SECURITY_SCREEN_ID}`;
6
+ export const ACCOUNT_SECURITY_SCREEN_TITLE_KEY = `screen:${ACCOUNT_SECURITY_SCREEN_ID}.title`;
6
7
  export const ACCOUNT_SECURITY_NAV_LABEL = `${ACCOUNT_SECURITY_FEATURE}:nav.accountSecurity`;
@@ -3,6 +3,7 @@ export {
3
3
  ACCOUNT_SECURITY_NAV_LABEL,
4
4
  ACCOUNT_SECURITY_SCREEN_ID,
5
5
  ACCOUNT_SECURITY_SCREEN_QN,
6
+ ACCOUNT_SECURITY_SCREEN_TITLE_KEY,
6
7
  } from "./constants.ts";
7
8
  export {
8
9
  type AccountSecurityFeatureOptions,
@@ -1,6 +1,6 @@
1
1
  // @runtime client
2
2
  import { mergeTranslations, type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
3
- import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer-web";
3
+ import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
4
4
  import { ADMIN_SHELL_FEATURE } from "../constants.ts";
5
5
  import { defaultTranslations } from "./i18n.ts";
6
6
 
@@ -1,6 +1,6 @@
1
1
  // @runtime client
2
2
  import { mergeTranslations, type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
3
- import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer-web";
3
+ import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
4
4
  import { AUDIT_FEATURE } from "../constants.ts";
5
5
  import { defaultTranslations } from "./i18n.ts";
6
6
 
@@ -11,7 +11,7 @@ import {
11
11
  mailT,
12
12
  resolveMailLocale,
13
13
  } from "@cosmicdrift/kumiko-framework/i18n";
14
- import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-headless";
14
+ import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-renderer/headless";
15
15
  import { AUTH_EMAIL_PASSWORD_FEATURE } from "./constants.ts";
16
16
 
17
17
  export const AUTH_MAIL_KINDS = {
@@ -9,8 +9,8 @@
9
9
  // reuse'n ihn hier, damit die Konstanten (Cookie-Name, Header-Name)
10
10
  // nicht divergieren.
11
11
 
12
- import { CSRF_HEADER_NAME, readCsrfToken } from "@cosmicdrift/kumiko-dispatcher-live";
13
12
  import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
13
+ import { CSRF_HEADER_NAME, readCsrfToken } from "@cosmicdrift/kumiko-renderer/live";
14
14
 
15
15
  export type TenantSummary = {
16
16
  readonly tenantId: string;
@@ -15,7 +15,7 @@
15
15
  // die früheren authButtonClass/authMutedLinkClass sind dorthin gewandert.
16
16
 
17
17
  import { usePrimitives } from "@cosmicdrift/kumiko-renderer";
18
- import { BareFormProvider, cn } from "@cosmicdrift/kumiko-renderer-web";
18
+ import { BareFormProvider, cn } from "@cosmicdrift/kumiko-renderer/web";
19
19
  import { createContext, type ReactNode, useContext, useEffect, useState } from "react";
20
20
 
21
21
  // Wrappt die zentrierte Auth-Card in ihre Umgebung. Default = Fullscreen-
@@ -48,9 +48,9 @@ export type EmailPasswordClientOptions = {
48
48
  readonly translations?: TranslationsByLocale;
49
49
  };
50
50
 
51
- // Struktural identisch zur renderer-web ClientFeatureDefinition, aber
52
- // ohne harte Dep auf @cosmicdrift/kumiko-renderer-web — so bleibt das Feature auch
53
- // für React-Native-Renderer (wenn sie kommen) nutzbar.
51
+ // Structurally identical to the renderer/web ClientFeatureDefinition, but
52
+ // without a hard dependency on @cosmicdrift/kumiko-renderer/web, so the feature
53
+ // stays usable by other renderers.
54
54
  export type EmailPasswordClientFeature = {
55
55
  readonly name: "auth-email-password";
56
56
  readonly providers: readonly ComponentType<{ children: ReactNode }>[];
@@ -6,7 +6,7 @@
6
6
  // importieren weiter die Einzelkomponenten direkt — DefaultTopbarActions
7
7
  // ist Convenience, kein Muss.
8
8
 
9
- import { ThemeToggle } from "@cosmicdrift/kumiko-renderer-web";
9
+ import { ThemeToggle } from "@cosmicdrift/kumiko-renderer/web";
10
10
  import type { ReactNode } from "react";
11
11
  import { TenantSwitcher } from "./tenant-switcher.tsx";
12
12
  import { UserMenu } from "./user-menu.tsx";
@@ -3,7 +3,7 @@
3
3
  // Wird über den Sub-Path-Export `@cosmicdrift/kumiko-bundled-features/auth-email-
4
4
  // password/web` konsumiert — die Server-Seite (defineFeature) lebt in
5
5
  // `@cosmicdrift/kumiko-bundled-features/auth-email-password` und hat keine
6
- // React-/DOM-Deps. Trennung bleibt sauber so wie renderer vs renderer-web.
6
+ // React-/DOM-Deps. Trennung bleibt sauber so wie renderer vs renderer/web.
7
7
 
8
8
  export { defaultTranslations, mergeTranslations } from "../i18n.ts";
9
9
  export type {
@@ -9,12 +9,12 @@
9
9
  // unter `<SessionProvider>`; der `useSession()`-Hook liefert den State
10
10
  // und die Transitions.
11
11
 
12
- import { readCsrfToken } from "@cosmicdrift/kumiko-dispatcher-live";
13
12
  import {
14
13
  type CurrentUser,
15
14
  CurrentUserProvider,
16
15
  useSessionEndedSignal,
17
16
  } from "@cosmicdrift/kumiko-renderer";
17
+ import { readCsrfToken } from "@cosmicdrift/kumiko-renderer/live";
18
18
  import {
19
19
  createContext,
20
20
  type ReactNode,
@@ -7,7 +7,7 @@ import {
7
7
  DropdownMenuCheckboxItem,
8
8
  DropdownMenuLabel,
9
9
  DropdownMenuSeparator,
10
- } from "@cosmicdrift/kumiko-renderer-web";
10
+ } from "@cosmicdrift/kumiko-renderer/web";
11
11
  import type { ReactNode } from "react";
12
12
  import { useSession } from "./session.tsx";
13
13
 
@@ -22,7 +22,7 @@ import {
22
22
  DropdownMenuContent,
23
23
  DropdownMenuLabel,
24
24
  DropdownMenuTrigger,
25
- } from "@cosmicdrift/kumiko-renderer-web";
25
+ } from "@cosmicdrift/kumiko-renderer/web";
26
26
  import { Building2, ChevronDown } from "lucide-react";
27
27
  import { type ReactNode, useCallback, useState } from "react";
28
28
  import { useSession } from "./session.tsx";
@@ -21,7 +21,7 @@ import {
21
21
  SidebarMenu,
22
22
  SidebarMenuButton,
23
23
  SidebarMenuItem,
24
- } from "@cosmicdrift/kumiko-renderer-web";
24
+ } from "@cosmicdrift/kumiko-renderer/web";
25
25
  import { ChevronDown, ChevronsUpDown, LogOut } from "lucide-react";
26
26
  import type { ReactNode } from "react";
27
27
  import { useSession } from "./session.tsx";
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.376.0",
4
+ "type": "improvement",
5
+ "title": "authEnvSchema for auth.admin and auth.mail",
6
+ "detail": "authEnvSchema declares APP_BASE_URL, AUTH_ADMIN_EMAIL and AUTH_ADMIN_PASSWORD with descriptions and the pulumi secret marker; an app spreads its shape into its env schema."
7
+ },
2
8
  {
3
9
  "version": "0.371.0",
4
10
  "type": "improvement",
@@ -0,0 +1,27 @@
1
+ import * as z from "zod";
2
+
3
+ const ADMIN_PASSWORD_MIN_LENGTH = 16;
4
+
5
+ /** Env block behind `auth.admin` and `auth.mail`: the first admin login and the public app URL
6
+ * the mail links and the Origin guard derive from. Unset keys leave the matching option to
7
+ * explicit values; an app spreads `.shape` into its env schema and passes the parsed values on. */
8
+ export const authEnvSchema = z.object({
9
+ APP_BASE_URL: z
10
+ .url()
11
+ .optional()
12
+ .describe(
13
+ "Public https URL of the app; auth mail links, the Origin guard and unsubscribe links use it.",
14
+ ),
15
+ AUTH_ADMIN_EMAIL: z
16
+ .email()
17
+ .optional()
18
+ .describe("Login of the admin seeded through `auth.admin`."),
19
+ AUTH_ADMIN_PASSWORD: z
20
+ .string()
21
+ .min(ADMIN_PASSWORD_MIN_LENGTH)
22
+ .optional()
23
+ .describe(
24
+ "Password of the admin seeded through `auth.admin`. Generate with: openssl rand -hex 24",
25
+ )
26
+ .meta({ kumiko: { pulumi: { generator: "openssl rand -hex 24", secret: true } } }),
27
+ });
@@ -1,5 +1,6 @@
1
1
  // Public API of the auth-foundation bundled-feature.
2
2
 
3
+ export { authEnvSchema } from "./env.ts";
3
4
  export {
4
5
  createAuthFoundationFeature,
5
6
  type ResolvedTenantResolver,
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.377.0",
4
+ "type": "improvement",
5
+ "title": "Optional contact card in the billing plan catalog",
6
+ "detail": "catalog.contact takes labelKey, benefits, actionLabelKey and an absolute https: or mailto: href. The billing-plans query returns it as contact, the billing-plans panel renders it as the last card without a price for every viewRole, also when the caller cannot purchase or billing is off. Boot validation rejects empty keys and any other href."
7
+ },
2
8
  {
3
9
  "version": "0.371.0",
4
10
  "type": "improvement",
@@ -1,4 +1,4 @@
1
- import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-headless";
1
+ import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-renderer/headless";
2
2
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
3
3
  import { Marked } from "marked";
4
4
  import {
@@ -2,7 +2,7 @@
2
2
  // no JavaScript. Every echoed value goes through escapeHtml/escapeHtmlAttr.
3
3
 
4
4
  import { type AnonymousExtraRoute, getSessionCookies } from "@cosmicdrift/kumiko-framework/api";
5
- import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-headless";
5
+ import { escapeHtml, escapeHtmlAttr } from "@cosmicdrift/kumiko-renderer/headless";
6
6
  import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
7
7
  import type { Context } from "hono";
8
8
  import { getCookie } from "hono/cookie";
@@ -0,0 +1,14 @@
1
+ // @runtime client
2
+
3
+ /** Shared by boot validation and the panel (defense in depth); keep free of server imports. */
4
+ export function isContactCardHref(href: string): boolean {
5
+ if (href !== href.trim()) return false;
6
+ let url: URL;
7
+ try {
8
+ url = new URL(href);
9
+ } catch {
10
+ return false;
11
+ }
12
+ if (url.protocol === "https:") return true;
13
+ return url.protocol === "mailto:" && url.pathname !== "";
14
+ }
@@ -29,7 +29,7 @@ export function createBillingPlansQuery(
29
29
  return {
30
30
  name: "billing-plans",
31
31
  description:
32
- "Lists the purchasable plans with live price, benefits, the caller's current tier and which action (checkout | switch | current | unavailable | paymentPending) each plan offers.",
32
+ "Lists the purchasable plans with live price, benefits, the caller's current tier and which action (checkout | switch | current | unavailable | paymentPending) each plan offers, plus the optional price-less contact card.",
33
33
  schema: billingPlansSchema,
34
34
  access: { roles: catalog.viewRoles },
35
35
  handler: async (_query, ctx): Promise<BillingPlansResult> => {
@@ -85,6 +85,7 @@ export {
85
85
  type BillingFoundationOptions,
86
86
  type BillingPlanBenefit,
87
87
  type BillingPlanCatalog,
88
+ type BillingPlanContactCard,
88
89
  type BillingPlanPrice,
89
90
  type BillingPlansResult,
90
91
  type BillingPlanView,
@@ -231,5 +231,6 @@ export async function buildBillingPlans(
231
231
  subscription,
232
232
  canPurchase,
233
233
  plans,
234
+ ...(catalog.contact !== undefined && { contact: catalog.contact }),
234
235
  };
235
236
  }
@@ -355,6 +355,14 @@ export type BillingPlanBenefit = {
355
355
  readonly params?: Readonly<Record<string, string | number>>;
356
356
  };
357
357
 
358
+ /** Price-less card (e.g. "Enterprise · Contact us"); `href` must be an absolute https: or mailto: URL. */
359
+ export type BillingPlanContactCard = {
360
+ readonly labelKey: string;
361
+ readonly benefits: readonly BillingPlanBenefit[];
362
+ readonly actionLabelKey: string;
363
+ readonly href: string;
364
+ };
365
+
358
366
  export type BillingPlanCatalog<TTier extends string = string> = {
359
367
  /** Purchasable tiers, in display order. */
360
368
  readonly plans: readonly TTier[];
@@ -380,6 +388,8 @@ export type BillingPlanCatalog<TTier extends string = string> = {
380
388
  readonly returnPath?: string;
381
389
  /** Defaults to the only registered provider exposing `priceToTier`. */
382
390
  readonly providerName?: string;
391
+ /** Rendered as the last card, no price, visible to `viewRoles` regardless of `purchaseRoles`. */
392
+ readonly contact?: BillingPlanContactCard;
383
393
  };
384
394
 
385
395
  export type LegalLinkSet = {
@@ -483,6 +493,8 @@ export type BillingPlansResult = {
483
493
  } | null;
484
494
  readonly canPurchase: boolean;
485
495
  readonly plans: readonly BillingPlanView[];
496
+ /** Present only when `catalog.contact` is configured. */
497
+ readonly contact?: BillingPlanContactCard;
486
498
  /** Present only when `consumerProtection` is configured. */
487
499
  readonly consumerProtection?: {
488
500
  readonly consentTexts: Readonly<
@@ -6,8 +6,10 @@
6
6
  import * as z from "zod";
7
7
  import { isTerminationScope, TERMINATION_SCOPES } from "./constants.ts";
8
8
  import { CONSENT_LOCALES, type ConsentLocale } from "./consumer-protection/consent-locale.ts";
9
+ import { isContactCardHref } from "./contact-card.ts";
9
10
  import {
10
11
  type BillingFoundationOptions,
12
+ type BillingPlanContactCard,
11
13
  type ConsumerProtectionOptions,
12
14
  isLegalLinkSet,
13
15
  type LegalLinkSet,
@@ -83,6 +85,19 @@ function validateLegalLinkSet(set: LegalLinkSet, path: string): void {
83
85
  }
84
86
  }
85
87
 
88
+ function validateContactCard(contact: BillingPlanContactCard): void {
89
+ for (const key of ["labelKey", "actionLabelKey"] as const) {
90
+ if (contact[key].trim() === "") {
91
+ throw new Error(`createBillingFoundationFeature: catalog.contact.${key} must not be empty.`);
92
+ }
93
+ }
94
+ if (!isContactCardHref(contact.href)) {
95
+ throw new Error(
96
+ `createBillingFoundationFeature: catalog.contact.href "${contact.href}" must be an absolute https: or mailto: URL.`,
97
+ );
98
+ }
99
+ }
100
+
86
101
  function validateBaseUrl(baseUrl: string): void {
87
102
  let parsed: URL;
88
103
  try {
@@ -147,4 +162,5 @@ export function validateOptions(options: BillingFoundationOptions): void {
147
162
  if (catalog.viewRoles.length === 0) {
148
163
  throw new Error("createBillingFoundationFeature: catalog.viewRoles must not be empty.");
149
164
  }
165
+ if (catalog.contact !== undefined) validateContactCard(catalog.contact);
150
166
  }
@@ -0,0 +1,32 @@
1
+ // @runtime client
2
+
3
+ import { useLocale, useTranslation } from "@cosmicdrift/kumiko-renderer";
4
+ import { PlanCard } from "@cosmicdrift/kumiko-renderer/web";
5
+ import type { ReactNode } from "react";
6
+ import { isContactCardHref } from "../contact-card.ts";
7
+ import type { BillingPlanContactCard } from "../types.ts";
8
+ import { localizedParams } from "./localized-params.ts";
9
+
10
+ export function BillingContactPlan({
11
+ contact,
12
+ }: {
13
+ readonly contact: BillingPlanContactCard;
14
+ }): ReactNode {
15
+ const t = useTranslation();
16
+ const locale = useLocale().locale();
17
+ if (!isContactCardHref(contact.href)) return null;
18
+ return (
19
+ <PlanCard
20
+ title={t(contact.labelKey)}
21
+ features={contact.benefits.map((benefit) =>
22
+ t(benefit.labelKey, localizedParams(benefit.params, locale)),
23
+ )}
24
+ ctaLink={{
25
+ label: t(contact.actionLabelKey),
26
+ href: contact.href,
27
+ target: new URL(contact.href).protocol === "https:" ? "_blank" : undefined,
28
+ }}
29
+ testId="billing-plan-card-contact"
30
+ />
31
+ );
32
+ }
@@ -1,6 +1,5 @@
1
1
  // @runtime client
2
2
 
3
- import { toInstant, type WriteResult } from "@cosmicdrift/kumiko-headless";
4
3
  import {
5
4
  type ExtensionSectionProps,
6
5
  useLocale,
@@ -9,12 +8,13 @@ import {
9
8
  useQuery,
10
9
  useTranslation,
11
10
  } from "@cosmicdrift/kumiko-renderer";
11
+ import { toInstant, type WriteResult } from "@cosmicdrift/kumiko-renderer/headless";
12
12
  import {
13
13
  formatMoney,
14
14
  PlanCard,
15
15
  type PlanCardActionSlot,
16
16
  PlanGrid,
17
- } from "@cosmicdrift/kumiko-renderer-web";
17
+ } from "@cosmicdrift/kumiko-renderer/web";
18
18
  import { type ReactNode, useState } from "react";
19
19
  import {
20
20
  BillingPlanActions,
@@ -23,8 +23,10 @@ import {
23
23
  SubscriptionStatuses,
24
24
  } from "../constants.ts";
25
25
  import type { BillingPlansResult, BillingPlanView } from "../types.ts";
26
+ import { BillingContactPlan } from "./billing-contact-plan.tsx";
26
27
  import { CancelContractDialog } from "./cancel-contract-dialog.tsx";
27
28
  import { CheckoutConsentDialog, type CheckoutConsentPayload } from "./checkout-consent-dialog.tsx";
29
+ import { localizedParams } from "./localized-params.ts";
28
30
 
29
31
  type UseTranslation = ReturnType<typeof useTranslation>;
30
32
 
@@ -42,19 +44,6 @@ function renewalKey(price: BillingPlanView["price"]): string | undefined {
42
44
  : `billing-foundation.consent.renews.${price.interval}`;
43
45
  }
44
46
 
45
- function localizedParams(
46
- params: Readonly<Record<string, string | number>> | undefined,
47
- locale: string,
48
- ): Readonly<Record<string, string>> | undefined {
49
- if (params === undefined) return undefined;
50
- const localized: Record<string, string> = {};
51
- for (const [key, value] of Object.entries(params)) {
52
- localized[key] =
53
- typeof value === "number" ? new Intl.NumberFormat(locale).format(value) : value;
54
- }
55
- return localized;
56
- }
57
-
58
47
  /** Which action the plan "would" offer if it weren't blocked — mirrors
59
48
  * plan-catalog.ts's own decision tree, since `unavailable` collapses both
60
49
  * "would checkout" and "would switch" into one action and the disabled CTA
@@ -329,6 +318,7 @@ export function BillingPlansPanel(_props: ExtensionSectionProps): ReactNode {
329
318
  {...toCardProps(plan)}
330
319
  />
331
320
  ))}
321
+ {result.contact !== undefined && <BillingContactPlan contact={result.contact} />}
332
322
  </PlanGrid>
333
323
  {consumerProtection !== undefined &&
334
324
  consentPlan !== undefined &&
@@ -1,13 +1,13 @@
1
1
  // @runtime client
2
2
 
3
- import { toInstant } from "@cosmicdrift/kumiko-headless";
4
3
  import {
5
4
  useLocale,
6
5
  useMutation,
7
6
  usePrimitives,
8
7
  useTranslation,
9
8
  } from "@cosmicdrift/kumiko-renderer";
10
- import { ModeSwitch } from "@cosmicdrift/kumiko-renderer-web";
9
+ import { toInstant } from "@cosmicdrift/kumiko-renderer/headless";
10
+ import { ModeSwitch } from "@cosmicdrift/kumiko-renderer/web";
11
11
  import { type ReactNode, useState } from "react";
12
12
  import { SubscriptionFoundationHandlers } from "../constants.ts";
13
13
  import type { ContractTerminationDeclarationType, ContractTerminationKind } from "../events.ts";
@@ -1,7 +1,7 @@
1
1
  // @runtime client
2
2
 
3
- import type { WriteResult } from "@cosmicdrift/kumiko-headless";
4
3
  import { useLocale, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
4
+ import type { WriteResult } from "@cosmicdrift/kumiko-renderer/headless";
5
5
  import { type ReactNode, useState } from "react";
6
6
  import { resolveConsentLocale } from "../consumer-protection/consent-locale.ts";
7
7
  import type { BillingPlansResult } from "../types.ts";
@@ -1,6 +1,6 @@
1
1
  // @runtime client
2
2
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
3
- import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer-web";
3
+ import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
4
4
  import { BILLING_FOUNDATION_FEATURE, BILLING_PLANS_PANEL_COMPONENT } from "../constants.ts";
5
5
  import { BillingPlansPanel } from "./billing-plans-panel.tsx";
6
6
 
@@ -0,0 +1,14 @@
1
+ // @runtime client
2
+
3
+ export function localizedParams(
4
+ params: Readonly<Record<string, string | number>> | undefined,
5
+ locale: string,
6
+ ): Readonly<Record<string, string>> | undefined {
7
+ if (params === undefined) return undefined;
8
+ const localized: Record<string, string> = {};
9
+ for (const [key, value] of Object.entries(params)) {
10
+ localized[key] =
11
+ typeof value === "number" ? new Intl.NumberFormat(locale).format(value) : value;
12
+ }
13
+ return localized;
14
+ }
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "version": "0.378.0",
4
+ "type": "fix",
5
+ "title": "Stock caps are atomic under parallel writes",
6
+ "detail": "withStockCap now takes a transaction-scoped advisory lock per tenant and cap, so concurrent creates cannot both pass the check and exceed the cap."
7
+ },
8
+ {
9
+ "version": "0.378.0",
10
+ "type": "improvement",
11
+ "title": "withStockCap no longer widens the handler's grants",
12
+ "detail": "withStockCap serialises through TenantDb.advisoryXactLock instead of ctx.db.unsafeRaw(), so wrapped handlers no longer receive an implicit unsafeRaw grant."
13
+ },
2
14
  {
3
15
  "version": "0.370.0",
4
16
  "type": "breaking",
@@ -24,6 +24,10 @@ export type CapLimitContext = {
24
24
  readonly config?: ConfigAccessor;
25
25
  };
26
26
 
27
+ // pg_advisory_xact_lock namespace (int4): 'scap' as ASCII, disjoint from the
28
+ // framework's other fixed advisory-lock keys.
29
+ const STOCK_CAP_LOCK_NAMESPACE = 0x73636170;
30
+
27
31
  // What the cap guards need from a write handler's ctx.
28
32
  export type CapGuardContext = CapLimitContext & { readonly db: TenantDb };
29
33
 
@@ -53,6 +57,7 @@ export function createStockCapGuard<TCaps>(
53
57
  spec: StockCapSpec<TCaps>,
54
58
  context: CapLimitContext = {},
55
59
  ): Promise<WriteFailure | null> {
60
+ // Lock-free on its own: a direct call outside withStockCap is not atomic.
56
61
  const caps = await resolveTierCaps(db, context);
57
62
  const current = await db.count(spec.table, { ...spec.where, tenantId: db.tenantId });
58
63
  const { state, limit } = enforceStockCap({
@@ -73,6 +78,10 @@ export function createStockCapGuard<TCaps>(
73
78
  return {
74
79
  ...handler,
75
80
  handler: async (event, ctx) => {
81
+ // ctx.db is the handler's transaction, so the xact lock releases with its commit or
82
+ // rollback. A handler wrapped in several caps must list them in the same order
83
+ // everywhere; Postgres aborts one side of an inverse order with a deadlock error.
84
+ await ctx.db.advisoryXactLock(STOCK_CAP_LOCK_NAMESPACE, spec.code);
76
85
  const failure = await checkStockCap(ctx.db, spec, { config: ctx.config });
77
86
  return failure ?? handler.handler(event, ctx);
78
87
  },
@@ -1,13 +1,13 @@
1
- import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-headless";
2
1
  // @runtime client
3
2
  import type { ExtensionSectionProps } from "@cosmicdrift/kumiko-renderer";
4
3
  import { usePrimitives, useQuery, useTranslation } from "@cosmicdrift/kumiko-renderer";
4
+ import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-renderer/headless";
5
5
  import {
6
6
  EmptyState,
7
7
  StatCard,
8
8
  StatusBadge,
9
9
  type StatusTone,
10
- } from "@cosmicdrift/kumiko-renderer-web";
10
+ } from "@cosmicdrift/kumiko-renderer/web";
11
11
  import { Database, FileText, Gauge, Hash, Mail, Users } from "lucide-react";
12
12
  import type { ComponentType, ReactNode } from "react";
13
13
  import { CapOverviewQueries } from "../constants.ts";
@@ -68,7 +68,7 @@ export function CapCardsPanel({ filterParams }: ExtensionSectionProps): ReactNod
68
68
  return (
69
69
  <div
70
70
  // Arbitrary bracket values (grid-cols-[repeat(...)]) never compiled:
71
- // styles.css's Tailwind v4 @source scan only covers renderer-web/src,
71
+ // styles.css's Tailwind v4 @source scan only covers renderer/web/src,
72
72
  // renderer/src and samples/**/src (see its comment) — bundled-features
73
73
  // isn't scanned, so a class unique to this file has no generated rule
74
74
  // and silently no-ops (the grid fell back to one implicit column,
@@ -1,6 +1,6 @@
1
1
  // @runtime client
2
2
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
3
- import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer-web";
3
+ import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
4
4
  import {
5
5
  CAP_CARDS_PANEL_COMPONENT,
6
6
  CAP_OVERVIEW_FEATURE,
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.376.0",
4
+ "type": "improvement",
5
+ "title": "resolveEmail receives a typed tenant database",
6
+ "detail": "The context of EmailChannelOptions resolveEmail types db as TenantDb, so resolvers read tables without a cast."
7
+ },
2
8
  {
3
9
  "version": "0.370.0",
4
10
  "type": "improvement",