prism0x2a 0.6.1 → 0.7.2

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 (439) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +4 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +24 -0
  5. package/.next/standalone/.next/required-server-files.json +1 -1
  6. package/.next/standalone/.next/routes-manifest.json +24 -0
  7. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  17. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  20. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/amber/capabilities/[id]/page_client-reference-manifest.js +1 -1
  24. package/.next/standalone/.next/server/app/amber/capabilities/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/amber/capabilities.html +1 -1
  26. package/.next/standalone/.next/server/app/amber/capabilities.rsc +3 -3
  27. package/.next/standalone/.next/server/app/amber/capabilities.segments/_full.segment.rsc +3 -3
  28. package/.next/standalone/.next/server/app/amber/capabilities.segments/_head.segment.rsc +1 -1
  29. package/.next/standalone/.next/server/app/amber/capabilities.segments/_index.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/amber/capabilities.segments/_tree.segment.rsc +2 -2
  31. package/.next/standalone/.next/server/app/amber/capabilities.segments/amber/capabilities/__PAGE__.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/amber/capabilities.segments/amber/capabilities.segment.rsc +1 -1
  33. package/.next/standalone/.next/server/app/amber/capabilities.segments/amber.segment.rsc +1 -1
  34. package/.next/standalone/.next/server/app/amber/coverage/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/amber/coverage.html +1 -1
  36. package/.next/standalone/.next/server/app/amber/coverage.rsc +3 -3
  37. package/.next/standalone/.next/server/app/amber/coverage.segments/_full.segment.rsc +3 -3
  38. package/.next/standalone/.next/server/app/amber/coverage.segments/_head.segment.rsc +1 -1
  39. package/.next/standalone/.next/server/app/amber/coverage.segments/_index.segment.rsc +2 -2
  40. package/.next/standalone/.next/server/app/amber/coverage.segments/_tree.segment.rsc +2 -2
  41. package/.next/standalone/.next/server/app/amber/coverage.segments/amber/coverage/__PAGE__.segment.rsc +2 -2
  42. package/.next/standalone/.next/server/app/amber/coverage.segments/amber/coverage.segment.rsc +1 -1
  43. package/.next/standalone/.next/server/app/amber/coverage.segments/amber.segment.rsc +1 -1
  44. package/.next/standalone/.next/server/app/amber/files/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/amber/files.html +1 -1
  46. package/.next/standalone/.next/server/app/amber/files.rsc +3 -3
  47. package/.next/standalone/.next/server/app/amber/files.segments/_full.segment.rsc +3 -3
  48. package/.next/standalone/.next/server/app/amber/files.segments/_head.segment.rsc +1 -1
  49. package/.next/standalone/.next/server/app/amber/files.segments/_index.segment.rsc +2 -2
  50. package/.next/standalone/.next/server/app/amber/files.segments/_tree.segment.rsc +2 -2
  51. package/.next/standalone/.next/server/app/amber/files.segments/amber/files/__PAGE__.segment.rsc +2 -2
  52. package/.next/standalone/.next/server/app/amber/files.segments/amber/files.segment.rsc +1 -1
  53. package/.next/standalone/.next/server/app/amber/files.segments/amber.segment.rsc +1 -1
  54. package/.next/standalone/.next/server/app/amber/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/.next/server/app/amber.html +1 -1
  56. package/.next/standalone/.next/server/app/amber.rsc +3 -3
  57. package/.next/standalone/.next/server/app/amber.segments/_full.segment.rsc +3 -3
  58. package/.next/standalone/.next/server/app/amber.segments/_head.segment.rsc +1 -1
  59. package/.next/standalone/.next/server/app/amber.segments/_index.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/amber.segments/_tree.segment.rsc +2 -2
  61. package/.next/standalone/.next/server/app/amber.segments/amber/__PAGE__.segment.rsc +2 -2
  62. package/.next/standalone/.next/server/app/amber.segments/amber.segment.rsc +1 -1
  63. package/.next/standalone/.next/server/app/api/amber/capabilities/[id]/route.js +1 -1
  64. package/.next/standalone/.next/server/app/api/amber/capabilities/[id]/route.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/api/amber/capabilities/route.js +1 -1
  66. package/.next/standalone/.next/server/app/api/amber/capabilities/route.js.nft.json +1 -1
  67. package/.next/standalone/.next/server/app/api/amber/files/route.js +1 -1
  68. package/.next/standalone/.next/server/app/api/amber/files/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/api/amber/registry/route.js +1 -1
  70. package/.next/standalone/.next/server/app/api/amber/registry/route.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/api/amber/scan/route.js +1 -1
  72. package/.next/standalone/.next/server/app/api/amber/scan/route.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/api/blue/recommendations/route.js +1 -1
  74. package/.next/standalone/.next/server/app/api/blue/recommendations/route.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/api/blue/scan/route.js +4 -4
  76. package/.next/standalone/.next/server/app/api/blue/scan/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/blue/sessions/[id]/route.js +1 -1
  78. package/.next/standalone/.next/server/app/api/blue/sessions/[id]/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/config/test/route.js +1 -1
  80. package/.next/standalone/.next/server/app/api/config/test/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/green/cross-layer/route.js +1 -1
  82. package/.next/standalone/.next/server/app/api/green/cross-layer/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/green/insights/[id]/route.js +1 -1
  84. package/.next/standalone/.next/server/app/api/green/insights/[id]/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/green/insights/route.js +1 -1
  86. package/.next/standalone/.next/server/app/api/green/insights/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/green/queries/[id]/route.js +1 -1
  88. package/.next/standalone/.next/server/app/api/green/queries/[id]/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/green/queries/[id]/run/route.js +1 -1
  90. package/.next/standalone/.next/server/app/api/green/queries/[id]/run/route.js.nft.json +1 -1
  91. package/.next/standalone/.next/server/app/api/green/queries/route.js +1 -1
  92. package/.next/standalone/.next/server/app/api/green/queries/route.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/api/license/activate/route/app-paths-manifest.json +3 -0
  94. package/.next/standalone/.next/server/app/api/license/activate/route/build-manifest.json +9 -0
  95. package/.next/standalone/.next/server/app/api/license/activate/route/server-reference-manifest.json +4 -0
  96. package/.next/standalone/.next/server/app/api/license/activate/route.js +6 -0
  97. package/.next/standalone/.next/server/app/api/license/activate/route.js.map +5 -0
  98. package/.next/standalone/.next/server/app/api/license/activate/route.js.nft.json +1 -0
  99. package/.next/standalone/.next/server/app/api/license/activate/route_client-reference-manifest.js +3 -0
  100. package/.next/standalone/.next/server/app/api/license/deactivate/route/app-paths-manifest.json +3 -0
  101. package/.next/standalone/.next/server/app/api/license/deactivate/route/build-manifest.json +9 -0
  102. package/.next/standalone/.next/server/app/api/license/deactivate/route/server-reference-manifest.json +4 -0
  103. package/.next/standalone/.next/server/app/api/license/deactivate/route.js +6 -0
  104. package/.next/standalone/.next/server/app/api/license/deactivate/route.js.map +5 -0
  105. package/.next/standalone/.next/server/app/api/license/deactivate/route.js.nft.json +1 -0
  106. package/.next/standalone/.next/server/app/api/license/deactivate/route_client-reference-manifest.js +3 -0
  107. package/.next/standalone/.next/server/app/api/license/route.js +1 -1
  108. package/.next/standalone/.next/server/app/api/license/route.js.nft.json +1 -1
  109. package/.next/standalone/.next/server/app/api/license/validate/route/app-paths-manifest.json +3 -0
  110. package/.next/standalone/.next/server/app/api/license/validate/route/build-manifest.json +9 -0
  111. package/.next/standalone/.next/server/app/api/license/validate/route/server-reference-manifest.json +4 -0
  112. package/.next/standalone/.next/server/app/api/license/validate/route.js +6 -0
  113. package/.next/standalone/.next/server/app/api/license/validate/route.js.map +5 -0
  114. package/.next/standalone/.next/server/app/api/license/validate/route.js.nft.json +1 -0
  115. package/.next/standalone/.next/server/app/api/license/validate/route_client-reference-manifest.js +3 -0
  116. package/.next/standalone/.next/server/app/api/monorepo/route.js.nft.json +1 -1
  117. package/.next/standalone/.next/server/app/api/scan/route.js +1 -1
  118. package/.next/standalone/.next/server/app/api/scan/route.js.nft.json +1 -1
  119. package/.next/standalone/.next/server/app/blue/page_client-reference-manifest.js +1 -1
  120. package/.next/standalone/.next/server/app/blue/recommendations/[id]/page_client-reference-manifest.js +1 -1
  121. package/.next/standalone/.next/server/app/blue/recommendations/page_client-reference-manifest.js +1 -1
  122. package/.next/standalone/.next/server/app/blue/recommendations.html +1 -1
  123. package/.next/standalone/.next/server/app/blue/recommendations.rsc +3 -3
  124. package/.next/standalone/.next/server/app/blue/recommendations.segments/_full.segment.rsc +3 -3
  125. package/.next/standalone/.next/server/app/blue/recommendations.segments/_head.segment.rsc +1 -1
  126. package/.next/standalone/.next/server/app/blue/recommendations.segments/_index.segment.rsc +2 -2
  127. package/.next/standalone/.next/server/app/blue/recommendations.segments/_tree.segment.rsc +2 -2
  128. package/.next/standalone/.next/server/app/blue/recommendations.segments/blue/recommendations/__PAGE__.segment.rsc +2 -2
  129. package/.next/standalone/.next/server/app/blue/recommendations.segments/blue/recommendations.segment.rsc +1 -1
  130. package/.next/standalone/.next/server/app/blue/recommendations.segments/blue.segment.rsc +1 -1
  131. package/.next/standalone/.next/server/app/blue/sessions/[id]/page_client-reference-manifest.js +1 -1
  132. package/.next/standalone/.next/server/app/blue/sessions/page_client-reference-manifest.js +1 -1
  133. package/.next/standalone/.next/server/app/blue/sessions.html +1 -1
  134. package/.next/standalone/.next/server/app/blue/sessions.rsc +3 -3
  135. package/.next/standalone/.next/server/app/blue/sessions.segments/_full.segment.rsc +3 -3
  136. package/.next/standalone/.next/server/app/blue/sessions.segments/_head.segment.rsc +1 -1
  137. package/.next/standalone/.next/server/app/blue/sessions.segments/_index.segment.rsc +2 -2
  138. package/.next/standalone/.next/server/app/blue/sessions.segments/_tree.segment.rsc +2 -2
  139. package/.next/standalone/.next/server/app/blue/sessions.segments/blue/sessions/__PAGE__.segment.rsc +2 -2
  140. package/.next/standalone/.next/server/app/blue/sessions.segments/blue/sessions.segment.rsc +1 -1
  141. package/.next/standalone/.next/server/app/blue/sessions.segments/blue.segment.rsc +1 -1
  142. package/.next/standalone/.next/server/app/blue.html +1 -1
  143. package/.next/standalone/.next/server/app/blue.rsc +3 -3
  144. package/.next/standalone/.next/server/app/blue.segments/_full.segment.rsc +3 -3
  145. package/.next/standalone/.next/server/app/blue.segments/_head.segment.rsc +1 -1
  146. package/.next/standalone/.next/server/app/blue.segments/_index.segment.rsc +2 -2
  147. package/.next/standalone/.next/server/app/blue.segments/_tree.segment.rsc +2 -2
  148. package/.next/standalone/.next/server/app/blue.segments/blue/__PAGE__.segment.rsc +2 -2
  149. package/.next/standalone/.next/server/app/blue.segments/blue.segment.rsc +1 -1
  150. package/.next/standalone/.next/server/app/green/cross-layer/page_client-reference-manifest.js +1 -1
  151. package/.next/standalone/.next/server/app/green/cross-layer.html +1 -1
  152. package/.next/standalone/.next/server/app/green/cross-layer.rsc +3 -3
  153. package/.next/standalone/.next/server/app/green/cross-layer.segments/_full.segment.rsc +3 -3
  154. package/.next/standalone/.next/server/app/green/cross-layer.segments/_head.segment.rsc +1 -1
  155. package/.next/standalone/.next/server/app/green/cross-layer.segments/_index.segment.rsc +2 -2
  156. package/.next/standalone/.next/server/app/green/cross-layer.segments/_tree.segment.rsc +2 -2
  157. package/.next/standalone/.next/server/app/green/cross-layer.segments/green/cross-layer/__PAGE__.segment.rsc +2 -2
  158. package/.next/standalone/.next/server/app/green/cross-layer.segments/green/cross-layer.segment.rsc +1 -1
  159. package/.next/standalone/.next/server/app/green/cross-layer.segments/green.segment.rsc +1 -1
  160. package/.next/standalone/.next/server/app/green/insights/[id]/page_client-reference-manifest.js +1 -1
  161. package/.next/standalone/.next/server/app/green/insights/page_client-reference-manifest.js +1 -1
  162. package/.next/standalone/.next/server/app/green/insights.html +1 -1
  163. package/.next/standalone/.next/server/app/green/insights.rsc +3 -3
  164. package/.next/standalone/.next/server/app/green/insights.segments/_full.segment.rsc +3 -3
  165. package/.next/standalone/.next/server/app/green/insights.segments/_head.segment.rsc +1 -1
  166. package/.next/standalone/.next/server/app/green/insights.segments/_index.segment.rsc +2 -2
  167. package/.next/standalone/.next/server/app/green/insights.segments/_tree.segment.rsc +2 -2
  168. package/.next/standalone/.next/server/app/green/insights.segments/green/insights/__PAGE__.segment.rsc +2 -2
  169. package/.next/standalone/.next/server/app/green/insights.segments/green/insights.segment.rsc +1 -1
  170. package/.next/standalone/.next/server/app/green/insights.segments/green.segment.rsc +1 -1
  171. package/.next/standalone/.next/server/app/green/page_client-reference-manifest.js +1 -1
  172. package/.next/standalone/.next/server/app/green/queries/[id]/page_client-reference-manifest.js +1 -1
  173. package/.next/standalone/.next/server/app/green/queries/page_client-reference-manifest.js +1 -1
  174. package/.next/standalone/.next/server/app/green/queries.html +1 -1
  175. package/.next/standalone/.next/server/app/green/queries.rsc +3 -3
  176. package/.next/standalone/.next/server/app/green/queries.segments/_full.segment.rsc +3 -3
  177. package/.next/standalone/.next/server/app/green/queries.segments/_head.segment.rsc +1 -1
  178. package/.next/standalone/.next/server/app/green/queries.segments/_index.segment.rsc +2 -2
  179. package/.next/standalone/.next/server/app/green/queries.segments/_tree.segment.rsc +2 -2
  180. package/.next/standalone/.next/server/app/green/queries.segments/green/queries/__PAGE__.segment.rsc +2 -2
  181. package/.next/standalone/.next/server/app/green/queries.segments/green/queries.segment.rsc +1 -1
  182. package/.next/standalone/.next/server/app/green/queries.segments/green.segment.rsc +1 -1
  183. package/.next/standalone/.next/server/app/green.html +1 -1
  184. package/.next/standalone/.next/server/app/green.rsc +3 -3
  185. package/.next/standalone/.next/server/app/green.segments/_full.segment.rsc +3 -3
  186. package/.next/standalone/.next/server/app/green.segments/_head.segment.rsc +1 -1
  187. package/.next/standalone/.next/server/app/green.segments/_index.segment.rsc +2 -2
  188. package/.next/standalone/.next/server/app/green.segments/_tree.segment.rsc +2 -2
  189. package/.next/standalone/.next/server/app/green.segments/green/__PAGE__.segment.rsc +2 -2
  190. package/.next/standalone/.next/server/app/green.segments/green.segment.rsc +1 -1
  191. package/.next/standalone/.next/server/app/index.html +1 -1
  192. package/.next/standalone/.next/server/app/index.rsc +3 -3
  193. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  194. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  195. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  196. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  197. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  198. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  199. package/.next/standalone/.next/server/app/pricing/page/app-paths-manifest.json +3 -0
  200. package/.next/standalone/.next/server/app/pricing/page/build-manifest.json +16 -0
  201. package/.next/standalone/.next/server/app/pricing/page/next-font-manifest.json +10 -0
  202. package/.next/standalone/.next/server/app/pricing/page/react-loadable-manifest.json +1 -0
  203. package/.next/standalone/.next/server/app/pricing/page/server-reference-manifest.json +4 -0
  204. package/.next/standalone/.next/server/app/pricing/page.js +14 -0
  205. package/.next/standalone/.next/server/app/pricing/page.js.map +5 -0
  206. package/.next/standalone/.next/server/app/pricing/page.js.nft.json +1 -0
  207. package/.next/standalone/.next/server/app/pricing/page_client-reference-manifest.js +3 -0
  208. package/.next/standalone/.next/server/app/pricing.html +1 -0
  209. package/.next/standalone/.next/server/app/pricing.meta +15 -0
  210. package/.next/standalone/.next/server/app/pricing.rsc +21 -0
  211. package/.next/standalone/.next/server/app/pricing.segments/_full.segment.rsc +21 -0
  212. package/.next/standalone/.next/server/app/pricing.segments/_head.segment.rsc +6 -0
  213. package/.next/standalone/.next/server/app/pricing.segments/_index.segment.rsc +5 -0
  214. package/.next/standalone/.next/server/app/pricing.segments/_tree.segment.rsc +3 -0
  215. package/.next/standalone/.next/server/app/pricing.segments/pricing/__PAGE__.segment.rsc +9 -0
  216. package/.next/standalone/.next/server/app/pricing.segments/pricing.segment.rsc +5 -0
  217. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  218. package/.next/standalone/.next/server/app/settings.html +2 -2
  219. package/.next/standalone/.next/server/app/settings.rsc +3 -3
  220. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  221. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  222. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  223. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  224. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
  225. package/.next/standalone/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  226. package/.next/standalone/.next/server/app-paths-manifest.json +4 -0
  227. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0xv4rrt._.js → [root-of-the-server]__04187lj._.js} +2 -2
  228. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0o~b3pl._.js → [root-of-the-server]__057dm7o._.js} +2 -2
  229. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08rxe0c._.js +1 -1
  230. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09l4tge._.js +3 -0
  231. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-m3qqb._.js → [root-of-the-server]__09snvkf._.js} +2 -2
  232. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0m54e40._.js → [root-of-the-server]__0ae2a50._.js} +2 -2
  233. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_1-q9._.js +3 -0
  234. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0sqgu0x._.js → [root-of-the-server]__0e-cuw5._.js} +2 -2
  235. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0z3su._._.js → [root-of-the-server]__0ei452y._.js} +2 -2
  236. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0j4r.sn._.js → [root-of-the-server]__0fxxbt1._.js} +2 -2
  237. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0~pq-2q._.js → [root-of-the-server]__0jwdt56._.js} +2 -2
  238. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0idrx7n._.js → [root-of-the-server]__0kgqm5d._.js} +2 -2
  239. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0lut4-l._.js → [root-of-the-server]__0m_11-d._.js} +2 -2
  240. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__13u~wki._.js → [root-of-the-server]__0mh73gz._.js} +2 -2
  241. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0p0b_67._.js +3 -0
  242. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0i7owf4._.js → [root-of-the-server]__0s130_c._.js} +2 -2
  243. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0skt4tx._.js +3 -0
  244. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0xbagnl._.js → [root-of-the-server]__0v3_gr6._.js} +2 -2
  245. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0~f~0tr._.js → [root-of-the-server]__119q6r9._.js} +2 -2
  246. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-61.35._.js → [root-of-the-server]__12glosw._.js} +2 -2
  247. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13.5op0._.js +3 -0
  248. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_license_activate_route_actions_0jh6t~s.js +3 -0
  249. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_license_deactivate_route_actions_0tmpd4n.js +3 -0
  250. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_license_validate_route_actions_0lhsct4.js +3 -0
  251. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0es1n-0._.js +3 -0
  252. package/.next/standalone/.next/server/chunks/ssr/_0a2egyj._.js +1 -1
  253. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_pricing_page_actions_0gvv0qw.js +3 -0
  254. package/.next/standalone/.next/server/chunks/ssr/app_amber_capabilities_[id]_page_tsx_12~.miw._.js +1 -1
  255. package/.next/standalone/.next/server/chunks/ssr/app_amber_capabilities_page_tsx_0.t9mpr._.js +1 -1
  256. package/.next/standalone/.next/server/chunks/ssr/app_amber_coverage_page_tsx_01yia_n._.js +1 -1
  257. package/.next/standalone/.next/server/chunks/ssr/app_amber_files_page_tsx_00pdkc~._.js +1 -1
  258. package/.next/standalone/.next/server/chunks/ssr/app_amber_page_tsx_0ihx6zl._.js +1 -1
  259. package/.next/standalone/.next/server/chunks/ssr/app_blue_page_tsx_0zg5eg-._.js +1 -1
  260. package/.next/standalone/.next/server/chunks/ssr/app_blue_recommendations_[id]_page_tsx_10zzlnx._.js +1 -1
  261. package/.next/standalone/.next/server/chunks/ssr/app_blue_recommendations_page_tsx_08w-50l._.js +1 -1
  262. package/.next/standalone/.next/server/chunks/ssr/app_blue_sessions_[id]_page_tsx_0_~w1xj._.js +1 -1
  263. package/.next/standalone/.next/server/chunks/ssr/app_blue_sessions_page_tsx_0kbuf.c._.js +1 -1
  264. package/.next/standalone/.next/server/chunks/ssr/app_green_cross-layer_page_tsx_0a80o-~._.js +1 -1
  265. package/.next/standalone/.next/server/chunks/ssr/app_green_insights_[id]_page_tsx_0se6uk1._.js +1 -1
  266. package/.next/standalone/.next/server/chunks/ssr/app_green_insights_page_tsx_04g8_lf._.js +1 -1
  267. package/.next/standalone/.next/server/chunks/ssr/app_green_page_tsx_10g2g6w._.js +1 -1
  268. package/.next/standalone/.next/server/chunks/ssr/app_green_queries_[id]_page_tsx_0hg.qma._.js +1 -1
  269. package/.next/standalone/.next/server/chunks/ssr/app_green_queries_page_tsx_0.p0r7z._.js +1 -1
  270. package/.next/standalone/.next/server/chunks/ssr/app_page_tsx_0es_sk2._.js +1 -1
  271. package/.next/standalone/.next/server/chunks/ssr/app_pricing_page_tsx_0uxncj9._.js +3 -0
  272. package/.next/standalone/.next/server/chunks/ssr/app_settings_page_tsx_0~q~t-v._.js +1 -1
  273. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_09d0h78.js +4 -0
  274. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  275. package/.next/standalone/.next/server/next-font-manifest.js +1 -1
  276. package/.next/standalone/.next/server/next-font-manifest.json +3 -0
  277. package/.next/standalone/.next/server/pages/404.html +1 -1
  278. package/.next/standalone/.next/server/pages/500.html +1 -1
  279. package/.next/standalone/.next/static/chunks/0-nogwaahf00r.js +1 -0
  280. package/.next/standalone/.next/static/chunks/0-ozct-0~_~y0.js +1 -0
  281. package/.next/standalone/.next/static/chunks/0043va.q9c120.js +1 -0
  282. package/.next/standalone/.next/static/chunks/0062k_6y6ie8k.js +1 -0
  283. package/.next/standalone/.next/static/chunks/01x6uo5zvt23j.js +1 -0
  284. package/.next/standalone/.next/static/chunks/03f4g06bhu.q-.js +1 -0
  285. package/.next/standalone/.next/static/chunks/06ciexs8mfsoh.js +1 -0
  286. package/.next/standalone/.next/static/chunks/06lbhw~p794rn.js +1 -0
  287. package/.next/standalone/.next/static/chunks/0921_~z_rxr9h.js +1 -0
  288. package/.next/standalone/.next/static/chunks/0_uy4bqezjrpu.js +1 -0
  289. package/.next/standalone/.next/static/chunks/0aqr1e8db8tr2.js +1 -0
  290. package/.next/standalone/.next/static/chunks/0gtjarbzj_b0s.js +1 -0
  291. package/.next/standalone/.next/static/chunks/0i826dpus7xfj.js +1 -0
  292. package/.next/standalone/.next/static/chunks/0l.f7bl92nc~2.css +2 -0
  293. package/.next/standalone/.next/static/chunks/0mtsra7dpsxy_.js +1 -0
  294. package/.next/standalone/.next/static/chunks/0nc15zt~yfrj3.js +1 -0
  295. package/.next/standalone/.next/static/chunks/0ptkiyk6p_hgq.js +1 -0
  296. package/.next/standalone/.next/static/chunks/0vsoyv8nkj.rx.js +1 -0
  297. package/.next/standalone/.next/static/chunks/0zpu7b02c6huw.js +1 -0
  298. package/.next/standalone/.next/static/chunks/10ibvf69namr1.js +1 -0
  299. package/.next/standalone/.next/static/chunks/1655x4_8fq5li.js +1 -0
  300. package/.next/standalone/.next/static/static/chunks/0-nogwaahf00r.js +1 -0
  301. package/.next/standalone/.next/static/static/chunks/0-ozct-0~_~y0.js +1 -0
  302. package/.next/standalone/.next/static/static/chunks/0043va.q9c120.js +1 -0
  303. package/.next/standalone/.next/static/static/chunks/0062k_6y6ie8k.js +1 -0
  304. package/.next/standalone/.next/static/static/chunks/01x6uo5zvt23j.js +1 -0
  305. package/.next/standalone/.next/static/static/chunks/03f4g06bhu.q-.js +1 -0
  306. package/.next/standalone/.next/static/static/chunks/06ciexs8mfsoh.js +1 -0
  307. package/.next/standalone/.next/static/static/chunks/06lbhw~p794rn.js +1 -0
  308. package/.next/standalone/.next/static/static/chunks/0921_~z_rxr9h.js +1 -0
  309. package/.next/standalone/.next/static/static/chunks/0_uy4bqezjrpu.js +1 -0
  310. package/.next/standalone/.next/static/static/chunks/0aqr1e8db8tr2.js +1 -0
  311. package/.next/standalone/.next/static/static/chunks/0gtjarbzj_b0s.js +1 -0
  312. package/.next/standalone/.next/static/static/chunks/0i826dpus7xfj.js +1 -0
  313. package/.next/standalone/.next/static/static/chunks/0l.f7bl92nc~2.css +2 -0
  314. package/.next/standalone/.next/static/static/chunks/0mtsra7dpsxy_.js +1 -0
  315. package/.next/standalone/.next/static/static/chunks/0nc15zt~yfrj3.js +1 -0
  316. package/.next/standalone/.next/static/static/chunks/0ptkiyk6p_hgq.js +1 -0
  317. package/.next/standalone/.next/static/static/chunks/0vsoyv8nkj.rx.js +1 -0
  318. package/.next/standalone/.next/static/static/chunks/0zpu7b02c6huw.js +1 -0
  319. package/.next/standalone/.next/static/static/chunks/10ibvf69namr1.js +1 -0
  320. package/.next/standalone/.next/static/static/chunks/1655x4_8fq5li.js +1 -0
  321. package/.next/standalone/CHANGELOG.md +78 -0
  322. package/.next/standalone/app/api/blue/scan/route.ts +12 -0
  323. package/.next/standalone/app/api/license/activate/route.ts +41 -0
  324. package/.next/standalone/app/api/license/deactivate/route.ts +22 -0
  325. package/.next/standalone/app/api/license/route.ts +23 -3
  326. package/.next/standalone/app/api/license/validate/route.ts +23 -0
  327. package/.next/standalone/app/pricing/page.tsx +289 -0
  328. package/.next/standalone/app/settings/page.tsx +180 -59
  329. package/.next/standalone/components/PrismDock.tsx +1 -0
  330. package/.next/standalone/components/pricing/BillingToggle.tsx +53 -0
  331. package/.next/standalone/components/pricing/FeatureList.tsx +19 -0
  332. package/.next/standalone/components/pricing/PricingCard.tsx +120 -0
  333. package/.next/standalone/docs/strategy/monetization-thinking.md +164 -0
  334. package/.next/standalone/lib/prism/features.shared.ts +15 -5
  335. package/.next/standalone/lib/prism/features.ts +9 -5
  336. package/.next/standalone/lib/prism/hooks/useLicense.ts +26 -2
  337. package/.next/standalone/lib/prism/lemonsqueezy/client.ts +162 -0
  338. package/.next/standalone/lib/prism/lemonsqueezy/tierMapping.ts +26 -0
  339. package/.next/standalone/lib/prism/license/lemonsqueezy.ts +142 -0
  340. package/.next/standalone/lib/prism/license/store.ts +17 -8
  341. package/.next/standalone/lib/prism/license/types.ts +35 -11
  342. package/.next/standalone/lib/prism/license/validate.ts +40 -11
  343. package/.next/standalone/package.json +2 -2
  344. package/.next/standalone/server.js +1 -1
  345. package/.next/standalone/tsconfig.tsbuildinfo +1 -1
  346. package/.next/static/chunks/0-nogwaahf00r.js +1 -0
  347. package/.next/static/chunks/0-ozct-0~_~y0.js +1 -0
  348. package/.next/static/chunks/0043va.q9c120.js +1 -0
  349. package/.next/static/chunks/0062k_6y6ie8k.js +1 -0
  350. package/.next/static/chunks/01x6uo5zvt23j.js +1 -0
  351. package/.next/static/chunks/03f4g06bhu.q-.js +1 -0
  352. package/.next/static/chunks/06ciexs8mfsoh.js +1 -0
  353. package/.next/static/chunks/06lbhw~p794rn.js +1 -0
  354. package/.next/static/chunks/0921_~z_rxr9h.js +1 -0
  355. package/.next/static/chunks/0_uy4bqezjrpu.js +1 -0
  356. package/.next/static/chunks/0aqr1e8db8tr2.js +1 -0
  357. package/.next/static/chunks/0gtjarbzj_b0s.js +1 -0
  358. package/.next/static/chunks/0i826dpus7xfj.js +1 -0
  359. package/.next/static/chunks/0l.f7bl92nc~2.css +2 -0
  360. package/.next/static/chunks/0mtsra7dpsxy_.js +1 -0
  361. package/.next/static/chunks/0nc15zt~yfrj3.js +1 -0
  362. package/.next/static/chunks/0ptkiyk6p_hgq.js +1 -0
  363. package/.next/static/chunks/0vsoyv8nkj.rx.js +1 -0
  364. package/.next/static/chunks/0zpu7b02c6huw.js +1 -0
  365. package/.next/static/chunks/10ibvf69namr1.js +1 -0
  366. package/.next/static/chunks/1655x4_8fq5li.js +1 -0
  367. package/CHANGELOG.md +78 -0
  368. package/package.json +2 -2
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c4z._.._.js +0 -3
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0tsv3gt._.js +0 -3
  371. package/.next/standalone/.next/static/chunks/06w_r5ib1et20.css +0 -2
  372. package/.next/standalone/.next/static/chunks/07c3wweseos.8.js +0 -1
  373. package/.next/standalone/.next/static/chunks/0_mxo3sdn-obc.js +0 -1
  374. package/.next/standalone/.next/static/chunks/0_r6ls5m8p~ft.js +0 -1
  375. package/.next/standalone/.next/static/chunks/0amsn1mknilcs.js +0 -1
  376. package/.next/standalone/.next/static/chunks/0ca9m7vrn2t7n.js +0 -1
  377. package/.next/standalone/.next/static/chunks/0c~l5bjb.rw_-.js +0 -1
  378. package/.next/standalone/.next/static/chunks/0dpf4si7n7imd.js +0 -1
  379. package/.next/standalone/.next/static/chunks/0du4cx1~k7d83.js +0 -1
  380. package/.next/standalone/.next/static/chunks/0g6lo0qyyyd8q.js +0 -1
  381. package/.next/standalone/.next/static/chunks/0lmcd5yqytd7q.js +0 -1
  382. package/.next/standalone/.next/static/chunks/0mlj0bhfz2s6h.js +0 -1
  383. package/.next/standalone/.next/static/chunks/0nu3srr5njzka.js +0 -1
  384. package/.next/standalone/.next/static/chunks/0qsy_4~44nzw1.js +0 -1
  385. package/.next/standalone/.next/static/chunks/1006uokkrcoe4.js +0 -1
  386. package/.next/standalone/.next/static/chunks/105mo4ttns4ro.js +0 -1
  387. package/.next/standalone/.next/static/chunks/10q-0rneqwysg.js +0 -1
  388. package/.next/standalone/.next/static/chunks/12kh0-iq.4m3c.js +0 -1
  389. package/.next/standalone/.next/static/chunks/13_6yxs82pu_4.js +0 -1
  390. package/.next/standalone/.next/static/chunks/16btub.0e2sr1.js +0 -1
  391. package/.next/standalone/.next/static/static/chunks/06w_r5ib1et20.css +0 -2
  392. package/.next/standalone/.next/static/static/chunks/07c3wweseos.8.js +0 -1
  393. package/.next/standalone/.next/static/static/chunks/0_mxo3sdn-obc.js +0 -1
  394. package/.next/standalone/.next/static/static/chunks/0_r6ls5m8p~ft.js +0 -1
  395. package/.next/standalone/.next/static/static/chunks/0amsn1mknilcs.js +0 -1
  396. package/.next/standalone/.next/static/static/chunks/0ca9m7vrn2t7n.js +0 -1
  397. package/.next/standalone/.next/static/static/chunks/0c~l5bjb.rw_-.js +0 -1
  398. package/.next/standalone/.next/static/static/chunks/0dpf4si7n7imd.js +0 -1
  399. package/.next/standalone/.next/static/static/chunks/0du4cx1~k7d83.js +0 -1
  400. package/.next/standalone/.next/static/static/chunks/0g6lo0qyyyd8q.js +0 -1
  401. package/.next/standalone/.next/static/static/chunks/0lmcd5yqytd7q.js +0 -1
  402. package/.next/standalone/.next/static/static/chunks/0mlj0bhfz2s6h.js +0 -1
  403. package/.next/standalone/.next/static/static/chunks/0nu3srr5njzka.js +0 -1
  404. package/.next/standalone/.next/static/static/chunks/0qsy_4~44nzw1.js +0 -1
  405. package/.next/standalone/.next/static/static/chunks/1006uokkrcoe4.js +0 -1
  406. package/.next/standalone/.next/static/static/chunks/105mo4ttns4ro.js +0 -1
  407. package/.next/standalone/.next/static/static/chunks/10q-0rneqwysg.js +0 -1
  408. package/.next/standalone/.next/static/static/chunks/12kh0-iq.4m3c.js +0 -1
  409. package/.next/standalone/.next/static/static/chunks/13_6yxs82pu_4.js +0 -1
  410. package/.next/standalone/.next/static/static/chunks/16btub.0e2sr1.js +0 -1
  411. package/.next/static/chunks/06w_r5ib1et20.css +0 -2
  412. package/.next/static/chunks/07c3wweseos.8.js +0 -1
  413. package/.next/static/chunks/0_mxo3sdn-obc.js +0 -1
  414. package/.next/static/chunks/0_r6ls5m8p~ft.js +0 -1
  415. package/.next/static/chunks/0amsn1mknilcs.js +0 -1
  416. package/.next/static/chunks/0ca9m7vrn2t7n.js +0 -1
  417. package/.next/static/chunks/0c~l5bjb.rw_-.js +0 -1
  418. package/.next/static/chunks/0dpf4si7n7imd.js +0 -1
  419. package/.next/static/chunks/0du4cx1~k7d83.js +0 -1
  420. package/.next/static/chunks/0g6lo0qyyyd8q.js +0 -1
  421. package/.next/static/chunks/0lmcd5yqytd7q.js +0 -1
  422. package/.next/static/chunks/0mlj0bhfz2s6h.js +0 -1
  423. package/.next/static/chunks/0nu3srr5njzka.js +0 -1
  424. package/.next/static/chunks/0qsy_4~44nzw1.js +0 -1
  425. package/.next/static/chunks/1006uokkrcoe4.js +0 -1
  426. package/.next/static/chunks/105mo4ttns4ro.js +0 -1
  427. package/.next/static/chunks/10q-0rneqwysg.js +0 -1
  428. package/.next/static/chunks/12kh0-iq.4m3c.js +0 -1
  429. package/.next/static/chunks/13_6yxs82pu_4.js +0 -1
  430. package/.next/static/chunks/16btub.0e2sr1.js +0 -1
  431. /package/.next/standalone/.next/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_buildManifest.js +0 -0
  432. /package/.next/standalone/.next/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_clientMiddlewareManifest.js +0 -0
  433. /package/.next/standalone/.next/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_ssgManifest.js +0 -0
  434. /package/.next/standalone/.next/static/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_buildManifest.js +0 -0
  435. /package/.next/standalone/.next/static/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_clientMiddlewareManifest.js +0 -0
  436. /package/.next/standalone/.next/static/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_ssgManifest.js +0 -0
  437. /package/.next/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_buildManifest.js +0 -0
  438. /package/.next/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_clientMiddlewareManifest.js +0 -0
  439. /package/.next/static/{pxEf_JFJYiGcbQWz1fBY7 → W2AhxwlOVhsTt-b4T3Mjc}/_ssgManifest.js +0 -0
@@ -0,0 +1,53 @@
1
+ "use client";
2
+
3
+ interface BillingToggleProps {
4
+ yearly: boolean;
5
+ onChange: (yearly: boolean) => void;
6
+ }
7
+
8
+ export function BillingToggle({ yearly, onChange }: BillingToggleProps) {
9
+ return (
10
+ <div className="flex items-center gap-3">
11
+ <button
12
+ onClick={() => onChange(false)}
13
+ className="text-sm font-medium transition-colors"
14
+ style={{ color: yearly ? "rgba(148,163,184,0.6)" : "rgb(226,232,240)" }}
15
+ >
16
+ Monthly
17
+ </button>
18
+
19
+ <button
20
+ onClick={() => onChange(!yearly)}
21
+ className="relative w-11 h-6 rounded-full transition-colors"
22
+ style={{
23
+ background: yearly ? "rgb(99,102,241)" : "rgba(51,65,85,0.6)",
24
+ border: "1px solid rgba(71,85,105,0.5)",
25
+ }}
26
+ aria-label="Toggle billing period"
27
+ >
28
+ <span
29
+ className="absolute top-0.5 w-5 h-5 rounded-full transition-transform"
30
+ style={{
31
+ left: "2px",
32
+ background: "rgb(226,232,240)",
33
+ transform: yearly ? "translateX(20px)" : "translateX(0)",
34
+ }}
35
+ />
36
+ </button>
37
+
38
+ <button
39
+ onClick={() => onChange(true)}
40
+ className="text-sm font-medium transition-colors flex items-center gap-1.5"
41
+ style={{ color: yearly ? "rgb(226,232,240)" : "rgba(148,163,184,0.6)" }}
42
+ >
43
+ Yearly
44
+ <span
45
+ className="text-xs px-1.5 py-0.5 rounded-full font-semibold"
46
+ style={{ background: "rgba(52,211,153,0.15)", color: "rgb(52,211,153)" }}
47
+ >
48
+ −17%
49
+ </span>
50
+ </button>
51
+ </div>
52
+ );
53
+ }
@@ -0,0 +1,19 @@
1
+ interface FeatureListProps {
2
+ features: string[];
3
+ dimmed?: boolean;
4
+ }
5
+
6
+ export function FeatureList({ features, dimmed }: FeatureListProps) {
7
+ return (
8
+ <ul className="flex flex-col gap-2">
9
+ {features.map((f) => (
10
+ <li key={f} className="flex items-start gap-2 text-sm" style={{ color: dimmed ? "rgba(148,163,184,0.5)" : "rgb(148,163,184)" }}>
11
+ <span className="mt-0.5 flex-shrink-0" style={{ color: dimmed ? "rgba(71,85,105,0.5)" : "rgb(71,85,105)" }}>
12
+
13
+ </span>
14
+ {f}
15
+ </li>
16
+ ))}
17
+ </ul>
18
+ );
19
+ }
@@ -0,0 +1,120 @@
1
+ import Link from "next/link";
2
+ import { FeatureList } from "./FeatureList";
3
+ import type { LicenseTier } from "@/lib/prism/license/types";
4
+
5
+ export interface PricingCardProps {
6
+ tier: LicenseTier;
7
+ name: string;
8
+ tagline: string;
9
+ monthlyPrice: number;
10
+ yearlyMonthlyPrice: number;
11
+ yearly: boolean;
12
+ unit?: string;
13
+ checkoutUrl: string | null;
14
+ features: string[];
15
+ highlighted?: boolean;
16
+ isCurrent?: boolean;
17
+ accentColor: string;
18
+ accentBg: string;
19
+ accentBorder: string;
20
+ }
21
+
22
+ export function PricingCard({
23
+ name,
24
+ tagline,
25
+ monthlyPrice,
26
+ yearlyMonthlyPrice,
27
+ yearly,
28
+ unit,
29
+ checkoutUrl,
30
+ features,
31
+ highlighted,
32
+ isCurrent,
33
+ accentColor,
34
+ accentBg,
35
+ accentBorder,
36
+ }: PricingCardProps) {
37
+ const displayPrice = yearly ? yearlyMonthlyPrice : monthlyPrice;
38
+ const isFree = monthlyPrice === 0;
39
+
40
+ return (
41
+ <div
42
+ className="relative flex flex-col rounded-2xl p-6 gap-5"
43
+ style={{
44
+ background: highlighted ? "var(--surface-elevated)" : "var(--surface-panel)",
45
+ border: highlighted ? `1px solid ${accentBorder}` : "1px solid var(--border-default)",
46
+ boxShadow: highlighted
47
+ ? `0 0 0 1px ${accentBorder}, 0 4px 24px rgba(15,23,42,.2), inset 0 1px 0 rgba(255,255,255,.06)`
48
+ : "0 1px 2px rgba(15,23,42,.05), 0 4px 16px rgba(15,23,42,.08), inset 0 1px 0 rgba(255,255,255,.04)",
49
+ }}
50
+ >
51
+ {highlighted && (
52
+ <div
53
+ className="absolute -top-px left-6 right-6 h-px rounded-full"
54
+ style={{ background: `linear-gradient(90deg, transparent, ${accentColor}, transparent)` }}
55
+ />
56
+ )}
57
+
58
+ {isCurrent && (
59
+ <span
60
+ className="absolute top-4 right-4 text-xs px-2 py-0.5 rounded-full font-semibold"
61
+ style={{ background: accentBg, color: accentColor, border: `1px solid ${accentBorder}` }}
62
+ >
63
+ Current plan
64
+ </span>
65
+ )}
66
+
67
+ {/* Header */}
68
+ <div className="flex flex-col gap-1">
69
+ <h3 className="text-base font-semibold" style={{ color: accentColor }}>{name}</h3>
70
+ <p className="text-xs text-slate-500">{tagline}</p>
71
+ </div>
72
+
73
+ {/* Price */}
74
+ <div className="flex items-end gap-1.5">
75
+ {isFree ? (
76
+ <span className="text-3xl font-bold text-slate-100">Free</span>
77
+ ) : (
78
+ <>
79
+ <span className="text-3xl font-bold text-slate-100">€{displayPrice}</span>
80
+ <span className="text-sm text-slate-500 mb-1">/mo{unit ? ` /${unit}` : ""}</span>
81
+ </>
82
+ )}
83
+ </div>
84
+ {!isFree && yearly && (
85
+ <p className="text-xs text-slate-500 -mt-3">
86
+ billed €{displayPrice * 12}/yr — save €{(monthlyPrice - yearlyMonthlyPrice) * 12}/yr
87
+ </p>
88
+ )}
89
+
90
+ {/* CTA */}
91
+ {isFree ? (
92
+ <div
93
+ className="text-center py-2 rounded-lg text-sm font-semibold text-slate-500"
94
+ style={{ background: "rgba(51,65,85,0.2)", border: "1px solid rgba(51,65,85,0.3)" }}
95
+ >
96
+ {isCurrent ? "Your current plan" : "No payment needed"}
97
+ </div>
98
+ ) : checkoutUrl ? (
99
+ <Link
100
+ href={checkoutUrl}
101
+ target="_blank"
102
+ rel="noopener noreferrer"
103
+ className="text-center py-2.5 rounded-lg text-sm font-semibold transition-all"
104
+ style={{
105
+ background: isCurrent ? "transparent" : accentBg,
106
+ color: isCurrent ? accentColor : accentColor,
107
+ border: `1px solid ${accentBorder}`,
108
+ }}
109
+ >
110
+ {isCurrent ? "Manage subscription →" : "Get started →"}
111
+ </Link>
112
+ ) : null}
113
+
114
+ {/* Features */}
115
+ <div className="pt-1 border-t" style={{ borderColor: "var(--border-default)" }}>
116
+ <FeatureList features={features} />
117
+ </div>
118
+ </div>
119
+ );
120
+ }
@@ -593,3 +593,167 @@ Free-trial-limit is per-installation but easily reset by uninstalling. Mitigatio
593
593
  - Pro tier removes watermark
594
594
 
595
595
  Watermark approach is friction-light, doesn't disable feature, drives conversion via embarrassment-factor.
596
+
597
+ ---
598
+
599
+ ## FINAL LOCK 2026-05-18
600
+
601
+ After multiple iterations, the monetization decisions are locked for v0.7.0 implementation.
602
+
603
+ ### Pricing — LOCKED
604
+
605
+ | Tier | Price | Annual | Includes |
606
+ |---|---|---|---|
607
+ | **Free** | $0 | $0 | Up to 50k LOC/project, static analysis only, no LLM, watermark, 60-day update delay |
608
+ | **Pro (prism0x2A)** | $39/month | $390/year (save 17%) | Unlimited LOC, monorepo, LLM, no watermark, immediate updates |
609
+ | **Team (prism0x2A)** | $99/dev/month | $990/dev/year (save 17%) | Pro + shared state, CI, team dashboard |
610
+ | **Pro (forge0x2B)** | $29/month | $290/year (save 17%) | Unlimited generations, all asset types |
611
+ | **Spectrum 0x55 Bundle** | $49/month | $490/year (save 17%) | prism0x2A Pro + forge0x2B Pro (save $19/m vs separate) |
612
+ | **Enterprise** | Custom | — | Self-hosted, SLA, revenue-share for $10M+ ARR |
613
+
614
+ **Free trial for forge0x2B:** 3 free generations per installation.
615
+
616
+ ### Value Justification
617
+
618
+ - Pro tier: 1:25 to 1:50 value-to-price ratio (saves 10-19h/m at $100/h dev rate)
619
+ - Team tier: 1:6 to 1:12 ratio
620
+ - forge0x2B: 1:22 ratio
621
+ - Bundle: $228/year savings, anchors as "Save 28%"
622
+
623
+ ### Bundle Brand — Spectrum 0x55
624
+
625
+ **Brand Name:** Spectrum
626
+ **Hex Identifier:** 0x55 (`0x2A + 0x2B = 0x55`)
627
+ **Tagline:** "0x55 — for U." (0x55 = ASCII 'U')
628
+ **Sub-Tagline:** "The full spectrum: prism0x2A + forge0x2B."
629
+
630
+ **Easter Egg Layer:**
631
+ - 0x55 binary: 01010101 — alternating bit pattern (yin-yang aesthetic)
632
+ - 0x55 ASCII: 'U' — "for you, the developer"
633
+ - Math: prism0x2A (42) + forge0x2B (43) = 85 = 0x55
634
+
635
+ **Logo Direction (when designed):**
636
+ - Could feature 'U' or '0x55' subtly
637
+ - Binary 01010101 pattern as design element
638
+ - Docs/marketing: "0x2A + 0x2B = 0x55"
639
+
640
+ ### Payment Provider — LOCKED: Lemonsqueezy
641
+
642
+ **Reasoning:**
643
+ - Merchant-of-Record handles all EU VAT + US Sales Tax compliance
644
+ - Built-in License Keys feature (no DIY server needed)
645
+ - 5% + €0.50 fee vs 2.9% + €0.30 for raw Stripe
646
+ - 2.1% premium = trivial cost for full tax-compliance peace-of-mind
647
+ - Built-in customer portal, subscriptions UI, webhook system
648
+
649
+ **Lemonsqueezy products to configure:**
650
+
651
+ 1. `prism0x2A Pro` (subscription, variants: monthly $39, yearly $390)
652
+ 2. `prism0x2A Team` (subscription, per-seat, variants: monthly $99/seat, yearly $990/seat)
653
+ 3. `forge0x2B Pro` (subscription, variants: monthly $29, yearly $290)
654
+ 4. `Spectrum 0x55 Bundle` (subscription, variants: monthly $49, yearly $490)
655
+
656
+ All products have License-Keys enabled. License-Key API validates on activation.
657
+
658
+ ### Implementation Sequence
659
+
660
+ ```
661
+ v0.7.0 — Lemonsqueezy Integration (BIG wave)
662
+ - Lemonsqueezy account setup (user)
663
+ - Products configured (user)
664
+ - License-Key validation in prism0x2A Settings
665
+ - Online-validation + offline-cache (30 days)
666
+ - Customer portal integration
667
+ - Webhook handling for subscription events
668
+
669
+ v0.7.1 — Pricing-Page (small wave)
670
+ - /pricing route
671
+ - Tier comparison table
672
+ - "Subscribe" buttons → Lemonsqueezy checkout
673
+ - Free-trial flow for forge0x2B
674
+
675
+ v0.7.2 — Guided Tour (Phase 2.5 backlog)
676
+
677
+ v0.8.0 — Marketing Landing
678
+ - Hero animation (prism-spectrum metaphor)
679
+ - prism0x2a.dev setup
680
+ - References pricing-page
681
+
682
+ 🚀 HN-Launch (with paid tier active)
683
+
684
+ Post-launch:
685
+ - forgesmith engine v0.1.0
686
+ - forge0x2B dashboard v0.1.0
687
+ - Spectrum 0x55 Bundle marketing push
688
+ ```
689
+
690
+ ### Closed Open-Questions (final)
691
+
692
+ | # | Question | Decision |
693
+ |---|---|---|
694
+ | 1 | Payment provider | Lemonsqueezy (MoR) |
695
+ | 2 | Pricing | $39/$99/$29/$49 confirmed |
696
+ | 3 | Bundle name | Spectrum 0x55 |
697
+ | 4 | Annual discount | 17% (2 months free) |
698
+ | 5 | Free tier limit | 50k LOC/project |
699
+ | 6 | Free trial (forge0x2B) | 3 generations |
700
+ | 7 | License validation | Lemonsqueezy License Keys API + offline cache |
701
+ | 8 | Customer portal | Lemonsqueezy built-in |
702
+ | 9 | Revenue share | Enterprise-only, $10M+ ARR negotiation |
703
+
704
+ ### Anti-Patterns Avoided (final)
705
+
706
+ - ❌ Free for revenue < $X (charity model) → REJECTED
707
+ - ❌ Pure FOSS (no revenue capture) → REJECTED
708
+ - ❌ Phone-home telemetry → REJECTED
709
+ - ❌ Hard-disable at limits → REJECTED (degraded mode + CTA instead)
710
+ - ❌ Raw Stripe (tax compliance nightmare) → REJECTED in favor of Lemonsqueezy
711
+
712
+ ### Status: LOCKED — Ready for v0.7.0 Implementation
713
+
714
+ ---
715
+
716
+ ## EUR Pricing Adjustment 2026-05-18
717
+
718
+ ### Context
719
+
720
+ Lemonsqueezy store was configured with EUR as default currency (German legal entity). All pricing now expressed in EUR with same numeric values as original USD spec.
721
+
722
+ ### Rationale: Same numbers, different currency
723
+
724
+ - Clean numbers (€39 / €99 / €29 / €49)
725
+ - Slight premium for EU market vs USD ($39 ≈ €36 at current FX)
726
+ - Lemonsqueezy auto-converts for non-EU customers
727
+ - US customers see ~$42 (FX-converted by Lemonsqueezy) — fair premium for buying from EU vendor
728
+
729
+ ### Final EUR Pricing (LOCKED)
730
+
731
+ | Tier | Monthly | Yearly (17% off) |
732
+ |---|---|---|
733
+ | **Free** | €0 | — |
734
+ | **Pro (prism0x2A)** | €39 | €390 |
735
+ | **Team (prism0x2A)** | €99/dev | €990/dev |
736
+ | **Pro (forge0x2B)** | €29 | €290 |
737
+ | **Spectrum 0x55 Bundle** | €49 | €490 |
738
+
739
+ ### Lemonsqueezy Product IDs (Reference)
740
+
741
+ ```
742
+ prism0x2A Pro: 1066633
743
+ prism0x2A Team: 1066653
744
+ forge0x2B Pro: 1066668
745
+ Spectrum 0x55 Bundle: 1066695
746
+ ```
747
+
748
+ Checkout-Variant-UUIDs:
749
+ ```
750
+ prism0x2A Pro: a9097951-5d54-438c-89ef-3e093d88f6c6
751
+ prism0x2A Team: ddcff26c-303a-4993-a7a7-73129b150a97
752
+ forge0x2B Pro: 21c1146e-9fea-4c32-a4fc-c5a5e64215e7
753
+ Spectrum 0x55 Bundle: 64d25b45-7c4a-410d-b4aa-7504f98ab5f7
754
+ ```
755
+
756
+ Marketing-copy adapts:
757
+ - "Save €19/month with Spectrum 0x55 Bundle" (was: "$19")
758
+ - "starts at €39/month" (was: "$39")
759
+ - Spectrum description: "0x55 = 0x2A + 0x2B (and ASCII U)" unchanged
@@ -8,17 +8,27 @@ export interface FeatureDef {
8
8
  }
9
9
 
10
10
  export const FEATURES = {
11
- monorepo: { tier: "pro" as LicenseTier, label: "Monorepo support" },
12
- aggregate_scan: { tier: "pro" as LicenseTier, label: "Aggregate workspace scan" },
13
- cross_workspace_insights: { tier: "pro" as LicenseTier, label: "Cross-workspace insights" },
14
- llm_insights: { tier: "pro" as LicenseTier, label: "AI-powered insights" },
11
+ // Pro-tier features
12
+ monorepo: { tier: "pro" as LicenseTier, label: "Monorepo support" },
13
+ aggregate_scan: { tier: "pro" as LicenseTier, label: "Aggregate workspace scan" },
14
+ cross_workspace_insights: { tier: "pro" as LicenseTier, label: "Cross-workspace insights" },
15
+ llm_insights: { tier: "pro" as LicenseTier, label: "AI-powered insights" },
16
+ custom_queries: { tier: "pro" as LicenseTier, label: "Custom GREEN queries" },
17
+ cross_layer_context: { tier: "pro" as LicenseTier, label: "Cross-layer context" },
18
+ auto_insights: { tier: "pro" as LicenseTier, label: "Auto-generated insights" },
19
+ // Team-tier features
20
+ team_sync: { tier: "team" as LicenseTier, label: "Team sync" },
21
+ ci_integration: { tier: "team" as LicenseTier, label: "CI integration" },
22
+ // forge-pro / Spectrum features
23
+ forge_unlimited: { tier: "forge-pro" as LicenseTier, label: "forge0x2B unlimited" },
24
+ forge_unlimited_generation: { tier: "forge-pro" as LicenseTier, label: "forge0x2B unlimited generation" },
15
25
  } satisfies Record<string, FeatureDef>;
16
26
 
17
27
  export type FeatureName = keyof typeof FEATURES;
18
28
 
19
29
  export const FREE_TIER_LOC_LIMIT = 50_000;
20
30
 
21
- /** Returns true if the feature should show a Pro badge in the UI (static, no license check). */
31
+ /** Returns true if the feature should show a Pro/upgrade badge in the UI (static, no license check). */
22
32
  export function showProBadge(name: FeatureName): boolean {
23
33
  return FEATURES[name].tier !== "free";
24
34
  }
@@ -1,10 +1,9 @@
1
1
  import { loadLicense } from "./license/store";
2
- import { effectiveTier, hasFeatureTier } from "./license/validate";
3
- import { FEATURES } from "./features.shared";
4
- import type { LicenseTier, FeatureName } from "./features.shared";
5
-
2
+ import { effectiveTier, hasFeatureTier, hasForge } from "./license/validate";
6
3
  export { FEATURES, FREE_TIER_LOC_LIMIT, showProBadge } from "./features.shared";
7
4
  export type { LicenseTier, FeatureDef, FeatureName } from "./features.shared";
5
+ import { FEATURES } from "./features.shared";
6
+ import type { LicenseTier, FeatureName } from "./features.shared";
8
7
 
9
8
  /** Returns the effective tier for the given target project. */
10
9
  export function getCurrentTier(targetPath: string): LicenseTier {
@@ -12,9 +11,14 @@ export function getCurrentTier(targetPath: string): LicenseTier {
12
11
  return effectiveTier(license);
13
12
  }
14
13
 
15
- /** Returns true if the license at targetPath grants access to the named feature. */
14
+ /** Returns true if the license grants access to the named feature. */
16
15
  export function isFeatureAvailable(targetPath: string, name: FeatureName): boolean {
17
16
  const license = loadLicense(targetPath);
18
17
  const required = FEATURES[name].tier;
19
18
  return hasFeatureTier(license, required);
20
19
  }
20
+
21
+ /** Returns true if forge0x2B features are enabled for this target. */
22
+ export function isForgeAvailable(targetPath: string): boolean {
23
+ return hasForge(loadLicense(targetPath));
24
+ }
@@ -11,13 +11,25 @@ export interface LicenseInfo {
11
11
  features: string[];
12
12
  isValid: boolean;
13
13
  isExpired: boolean;
14
+ // Lemonsqueezy fields
15
+ licenseKey: string | null; // masked (e.g. "LS-A****-B")
16
+ instanceId: string | null;
17
+ productName: string | null;
18
+ subscriptionStatus: "active" | "cancelled" | "expired" | "paused" | null;
19
+ validatedAt: number | null;
20
+ revalidationDue: number | null;
21
+ gracePeriodEnd: number | null;
22
+ activationLimit: number | null;
23
+ activationUsage: number | null;
24
+ cacheStatus: "valid" | "grace" | "expired" | "no-cache";
25
+ daysSinceValidation: number | null;
14
26
  }
15
27
 
16
28
  export interface UseLicenseResult {
17
29
  license: LicenseInfo | null;
18
30
  ready: boolean;
19
31
  refresh: () => void;
20
- /** True when tier is pro/team/enterprise and license is valid. */
32
+ /** True when tier is pro/spectrum/team/enterprise and license is valid. */
21
33
  isPro: boolean;
22
34
  }
23
35
 
@@ -29,6 +41,17 @@ const FREE_INFO: LicenseInfo = {
29
41
  features: [],
30
42
  isValid: false,
31
43
  isExpired: false,
44
+ licenseKey: null,
45
+ instanceId: null,
46
+ productName: null,
47
+ subscriptionStatus: null,
48
+ validatedAt: null,
49
+ revalidationDue: null,
50
+ gracePeriodEnd: null,
51
+ activationLimit: null,
52
+ activationUsage: null,
53
+ cacheStatus: "no-cache",
54
+ daysSinceValidation: null,
32
55
  };
33
56
 
34
57
  export function useLicense(tq: string): UseLicenseResult {
@@ -46,7 +69,8 @@ export function useLicense(tq: string): UseLicenseResult {
46
69
 
47
70
  const refresh = useCallback(() => setTick((t) => t + 1), []);
48
71
 
49
- const isPro = !!license && license.tier !== "free" && license.isValid && !license.isExpired;
72
+ const isPro = !!license && license.tier !== "free" && license.tier !== "forge-pro"
73
+ && license.isValid && !license.isExpired && license.cacheStatus !== "expired";
50
74
 
51
75
  return { license, ready, refresh, isPro };
52
76
  }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Lemonsqueezy License Keys API — raw fetch client.
3
+ *
4
+ * License key endpoints are unauthenticated (they use the key itself, not bearer auth).
5
+ * The public API key (LEMONSQUEEZY_API_KEY) is for store-management endpoints only,
6
+ * not needed here. We keep it available for future store-level calls.
7
+ *
8
+ * Docs: https://docs.lemonsqueezy.com/api/license-keys
9
+ */
10
+
11
+ const LS_BASE = "https://api.lemonsqueezy.com/v1/licenses";
12
+
13
+ // ─── Typed errors ────────────────────────────────────────────────────────────
14
+
15
+ export type LsErrorCode =
16
+ | "invalid_key" // key not found in LS (404)
17
+ | "activation_limit" // max instances reached (409)
18
+ | "not_activated" // instance not found for validate/deactivate (404)
19
+ | "api_error" // LS returned unexpected error (502)
20
+ | "network_error"; // fetch failed entirely
21
+
22
+ export class LsApiError extends Error {
23
+ constructor(
24
+ message: string,
25
+ public readonly code: LsErrorCode,
26
+ public readonly httpStatus?: number,
27
+ ) {
28
+ super(message);
29
+ this.name = "LsApiError";
30
+ }
31
+ }
32
+
33
+ /** Map LS error strings to typed error codes. */
34
+ function classifyLsError(message: string, httpStatus: number): LsErrorCode {
35
+ const m = message.toLowerCase();
36
+ if (m.includes("does not exist") || m.includes("not found") || httpStatus === 404) return "invalid_key";
37
+ if (m.includes("activation limit") || m.includes("reached its activation") || httpStatus === 422) return "activation_limit";
38
+ if (m.includes("instance") && (m.includes("not found") || m.includes("does not exist"))) return "not_activated";
39
+ return "api_error";
40
+ }
41
+
42
+ // ─── Response shapes ──────────────────────────────────────────────────────────
43
+
44
+ export interface LsLicenseKey {
45
+ id: number;
46
+ status: "active" | "inactive" | "expired" | "disabled";
47
+ key: string;
48
+ activation_limit: number | null;
49
+ activation_usage: number;
50
+ created_at: string;
51
+ expires_at: string | null;
52
+ }
53
+
54
+ export interface LsInstance {
55
+ id: string;
56
+ name: string;
57
+ created_at: string;
58
+ }
59
+
60
+ export interface LsMeta {
61
+ store_id: number;
62
+ order_id: number;
63
+ order_item_id: number;
64
+ product_id: number;
65
+ product_name: string;
66
+ variant_id: number;
67
+ variant_name: string;
68
+ customer_id: number;
69
+ customer_name: string;
70
+ customer_email: string;
71
+ }
72
+
73
+ export interface LsActivateResponse {
74
+ activated: boolean;
75
+ error: string | null;
76
+ license_key: LsLicenseKey;
77
+ instance: LsInstance;
78
+ meta: LsMeta;
79
+ }
80
+
81
+ export interface LsValidateResponse {
82
+ valid: boolean;
83
+ error: string | null;
84
+ license_key: LsLicenseKey;
85
+ instance: LsInstance | null;
86
+ meta: LsMeta;
87
+ }
88
+
89
+ export interface LsDeactivateResponse {
90
+ deactivated: boolean;
91
+ error: string | null;
92
+ license_key: LsLicenseKey;
93
+ meta: LsMeta;
94
+ }
95
+
96
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
97
+
98
+ async function lsPost<T>(endpoint: string, params: Record<string, string>): Promise<T> {
99
+ const body = new URLSearchParams(params);
100
+ let res: Response;
101
+ try {
102
+ res = await fetch(`${LS_BASE}/${endpoint}`, {
103
+ method: "POST",
104
+ headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
105
+ body: body.toString(),
106
+ });
107
+ } catch (cause) {
108
+ throw new LsApiError(
109
+ `Network error reaching Lemonsqueezy API: ${cause instanceof Error ? cause.message : String(cause)}`,
110
+ "network_error",
111
+ );
112
+ }
113
+ const json = await res.json() as T & { error?: string | null };
114
+ return { _status: res.status, ...json } as T;
115
+ }
116
+
117
+ // ─── API calls ───────────────────────────────────────────────────────────────
118
+
119
+ export async function lsActivate(
120
+ licenseKey: string,
121
+ instanceName: string,
122
+ ): Promise<LsActivateResponse> {
123
+ const json = await lsPost<LsActivateResponse & { _status: number }>("activate", {
124
+ license_key: licenseKey,
125
+ instance_name: instanceName,
126
+ });
127
+ if (!json.activated) {
128
+ const msg = json.error ?? "Lemonsqueezy activation failed";
129
+ throw new LsApiError(msg, classifyLsError(msg, json._status), json._status);
130
+ }
131
+ return json;
132
+ }
133
+
134
+ export async function lsValidate(
135
+ licenseKey: string,
136
+ instanceId: string,
137
+ ): Promise<LsValidateResponse> {
138
+ const json = await lsPost<LsValidateResponse & { _status: number }>("validate", {
139
+ license_key: licenseKey,
140
+ instance_id: instanceId,
141
+ });
142
+ if (!json.valid) {
143
+ const msg = json.error ?? "Lemonsqueezy validation failed";
144
+ throw new LsApiError(msg, classifyLsError(msg, json._status), json._status);
145
+ }
146
+ return json;
147
+ }
148
+
149
+ export async function lsDeactivate(
150
+ licenseKey: string,
151
+ instanceId: string,
152
+ ): Promise<LsDeactivateResponse> {
153
+ const json = await lsPost<LsDeactivateResponse & { _status: number }>("deactivate", {
154
+ license_key: licenseKey,
155
+ instance_id: instanceId,
156
+ });
157
+ if (!json.deactivated) {
158
+ const msg = json.error ?? "Lemonsqueezy deactivation failed";
159
+ throw new LsApiError(msg, classifyLsError(msg, json._status), json._status);
160
+ }
161
+ return json;
162
+ }
@@ -0,0 +1,26 @@
1
+ import type { LicenseTier } from "../license/types";
2
+
3
+ export class ProductNotRecognizedError extends Error {
4
+ constructor(productName: string) {
5
+ super(`Unrecognized Lemonsqueezy product: "${productName}". Add it to PRODUCT_TIER_MAP.`);
6
+ this.name = "ProductNotRecognizedError";
7
+ }
8
+ }
9
+
10
+ const PRODUCT_TIER_MAP: Record<string, LicenseTier> = {
11
+ "prism0x2A Pro": "pro",
12
+ "prism0x2A Team": "team",
13
+ "forge0x2B Pro": "forge-pro",
14
+ "Spectrum 0x55": "spectrum",
15
+ "Spectrum 0x55 Bundle": "spectrum",
16
+ };
17
+
18
+ /** Maps Lemonsqueezy product_name to internal LicenseTier. Throws if unrecognized. */
19
+ export function mapProductNameToTier(productName: string): LicenseTier {
20
+ const tier = PRODUCT_TIER_MAP[productName];
21
+ if (!tier) throw new ProductNotRecognizedError(productName);
22
+ return tier;
23
+ }
24
+
25
+ /** All recognized product names (for validation). */
26
+ export const RECOGNIZED_PRODUCTS = Object.keys(PRODUCT_TIER_MAP);