thanh-kit 2.5.0 → 2.5.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 (886) hide show
  1. package/dist/index.js +20 -61
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/templates/.ck.json +60 -0
  5. package/templates/.ckignore +27 -0
  6. package/templates/.mcp.json.example +23 -0
  7. package/templates/agents/brainstormer.md +18 -2
  8. package/templates/agents/code-reviewer.md +122 -142
  9. package/templates/agents/code-simplifier.md +50 -100
  10. package/templates/agents/debugger.md +27 -11
  11. package/templates/agents/docs-manager.md +100 -38
  12. package/templates/agents/fullstack-developer.md +15 -3
  13. package/templates/agents/git-manager.md +11 -386
  14. package/templates/agents/journal-writer.md +13 -8
  15. package/templates/agents/mcp-manager.md +21 -6
  16. package/templates/agents/planner.md +24 -8
  17. package/templates/agents/project-manager.md +17 -121
  18. package/templates/agents/researcher.md +22 -7
  19. package/templates/agents/tester.md +23 -7
  20. package/templates/agents/ui-ux-designer.md +23 -14
  21. package/templates/{commands → command-archive}/ask.md +5 -5
  22. package/templates/{commands → command-archive}/ck-help.md +18 -2
  23. package/templates/command-archive/docs/init.md +38 -0
  24. package/templates/command-archive/docs/summarize.md +22 -0
  25. package/templates/command-archive/docs/update.md +76 -0
  26. package/templates/command-archive/journal.md +18 -0
  27. package/templates/{commands → command-archive}/kanban.md +5 -7
  28. package/templates/{commands → command-archive}/plan/archive.md +2 -2
  29. package/templates/command-archive/plan/red-team.md +200 -0
  30. package/templates/command-archive/plan/validate.md +188 -0
  31. package/templates/command-archive/preview.md +283 -0
  32. package/templates/command-archive/review/codebase/parallel.md +122 -0
  33. package/templates/{commands → command-archive}/test/ui.md +3 -3
  34. package/templates/{commands → command-archive}/use-mcp.md +6 -2
  35. package/templates/command-archive/worktree.md +109 -0
  36. package/templates/hooks/__tests__/ck-config-utils.test.cjs +557 -0
  37. package/templates/hooks/__tests__/descriptive-name.test.cjs +292 -0
  38. package/templates/hooks/__tests__/dev-rules-reminder.test.cjs +336 -0
  39. package/templates/hooks/__tests__/integration/path-resolution.test.cjs +319 -0
  40. package/templates/hooks/__tests__/privacy-block.test.cjs +273 -0
  41. package/templates/hooks/__tests__/session-init.test.cjs +308 -0
  42. package/templates/hooks/__tests__/skill-dedup.test.cjs +527 -0
  43. package/templates/hooks/__tests__/subagent-init.test.cjs +622 -0
  44. package/templates/hooks/__tests__/task-completed-handler.test.cjs +246 -0
  45. package/templates/hooks/__tests__/team-context-inject.test.cjs +804 -0
  46. package/templates/hooks/__tests__/teammate-idle-handler.test.cjs +254 -0
  47. package/templates/hooks/cook-after-plan-reminder.cjs +72 -0
  48. package/templates/hooks/descriptive-name.cjs +47 -0
  49. package/templates/hooks/dev-rules-reminder.cjs +37 -214
  50. package/templates/hooks/lib/__tests__/README.md +240 -0
  51. package/templates/hooks/lib/__tests__/ck-config-utils.test.cjs +613 -1
  52. package/templates/hooks/lib/__tests__/context-builder.test.cjs +468 -0
  53. package/templates/hooks/lib/__tests__/project-detector.test.cjs +754 -0
  54. package/templates/hooks/lib/__tests__/statusline-integration.test.cjs +678 -0
  55. package/templates/hooks/lib/__tests__/statusline.test.cjs +689 -0
  56. package/templates/hooks/lib/ck-config-utils.cjs +146 -21
  57. package/templates/hooks/lib/colors.cjs +95 -0
  58. package/templates/hooks/lib/config-counter.cjs +103 -0
  59. package/templates/hooks/lib/context-builder.cjs +616 -0
  60. package/templates/hooks/lib/git-info-cache.cjs +143 -0
  61. package/templates/hooks/lib/hook-logger.cjs +92 -0
  62. package/templates/hooks/lib/privacy-checker.cjs +297 -0
  63. package/templates/hooks/lib/project-detector.cjs +474 -0
  64. package/templates/hooks/lib/scout-checker.cjs +263 -0
  65. package/templates/hooks/lib/transcript-parser.cjs +181 -0
  66. package/templates/hooks/notifications/discord_notify.sh +17 -4
  67. package/templates/hooks/notifications/docs/discord-hook-setup.md +26 -10
  68. package/templates/hooks/notifications/docs/telegram-hook-setup.md +24 -6
  69. package/templates/hooks/notifications/notify.cjs +0 -0
  70. package/templates/hooks/notifications/send-discord.sh +0 -0
  71. package/templates/hooks/notifications/telegram_notify.sh +17 -4
  72. package/templates/hooks/post-edit-simplify-reminder.cjs +156 -0
  73. package/templates/hooks/privacy-block.cjs +97 -188
  74. package/templates/hooks/scout-block/broad-pattern-detector.cjs +4 -6
  75. package/templates/hooks/scout-block/error-formatter.cjs +0 -0
  76. package/templates/hooks/scout-block/path-extractor.cjs +102 -13
  77. package/templates/hooks/scout-block/pattern-matcher.cjs +16 -1
  78. package/templates/hooks/scout-block/tests/{test-broad-pattern-detector.js → test-broad-pattern-detector.cjs} +1 -61
  79. package/templates/hooks/scout-block/tests/{test-build-command-allowlist.js → test-build-command-allowlist.cjs} +1 -1
  80. package/templates/hooks/scout-block/tests/{test-error-formatter.js → test-error-formatter.cjs} +1 -1
  81. package/templates/hooks/scout-block/tests/{test-full-flow-edge-cases.js → test-full-flow-edge-cases.cjs} +1 -1
  82. package/templates/hooks/scout-block/tests/{test-monorepo-scenarios.js → test-monorepo-scenarios.cjs} +1 -1
  83. package/templates/hooks/scout-block/tests/{test-path-extractor.js → test-path-extractor.cjs} +1 -1
  84. package/templates/hooks/scout-block/tests/{test-pattern-matcher.js → test-pattern-matcher.cjs} +1 -1
  85. package/templates/hooks/scout-block.cjs +100 -87
  86. package/templates/hooks/session-init.cjs +197 -330
  87. package/templates/hooks/skill-dedup.cjs +268 -0
  88. package/templates/hooks/subagent-init.cjs +75 -22
  89. package/templates/hooks/task-completed-handler.cjs +118 -0
  90. package/templates/hooks/team-context-inject.cjs +176 -0
  91. package/templates/hooks/teammate-idle-handler.cjs +121 -0
  92. package/templates/hooks/tests/scout-block/broad-pattern-detector.test.cjs +231 -0
  93. package/templates/hooks/tests/scout-block/fixtures/ckignore-custom.txt +6 -0
  94. package/templates/hooks/tests/scout-block/fixtures/ckignore-default.txt +13 -0
  95. package/templates/hooks/tests/scout-block/fixtures/ckignore-negation.txt +8 -0
  96. package/templates/hooks/tests/scout-block/path-extractor.test.cjs +527 -0
  97. package/templates/hooks/tests/scout-block/pattern-matcher.test.cjs +293 -0
  98. package/templates/hooks/tests/scout-block/scout-checker.test.cjs +741 -0
  99. package/templates/hooks/tests/{test-ckignore.js → test-ckignore.cjs} +0 -0
  100. package/templates/hooks/tests/{test-modularization-hook.js → test-modularization-hook.cjs} +0 -0
  101. package/templates/hooks/tests/{test-privacy-block.js → test-privacy-block.cjs} +1 -1
  102. package/templates/hooks/tests/test-scout-block.cjs +315 -0
  103. package/templates/hooks/usage-context-awareness.cjs +179 -0
  104. package/templates/metadata.json +104 -0
  105. package/templates/{workflows → rules}/development-rules.md +12 -53
  106. package/templates/rules/orchestration-protocol.md +43 -0
  107. package/templates/{workflows → rules}/primary-workflow.md +16 -4
  108. package/templates/rules/team-coordination-rules.md +90 -0
  109. package/templates/schemas/ck-config.schema.json +381 -0
  110. package/templates/scripts/README.md +94 -198
  111. package/templates/scripts/ck-help.py +19 -855
  112. package/templates/scripts/commands_data.yaml +3 -621
  113. package/templates/scripts/fix-shebang-permissions.sh +50 -0
  114. package/templates/scripts/generate_catalogs.py +37 -8
  115. package/templates/scripts/resolve_env.py +0 -0
  116. package/templates/scripts/scan_commands.py +14 -96
  117. package/templates/scripts/scan_skills.py +59 -19
  118. package/templates/scripts/set-active-plan.cjs +8 -3
  119. package/templates/scripts/skills_data.yaml +2 -596
  120. package/templates/scripts/test-ck-help.py +15 -0
  121. package/templates/scripts/test_ck_help.py +139 -0
  122. package/templates/scripts/test_ck_help_integration.py +72 -0
  123. package/templates/scripts/validate-docs.cjs +342 -0
  124. package/templates/scripts/win_compat.py +0 -0
  125. package/templates/scripts/worktree.cjs +4 -652
  126. package/templates/scripts/worktree.test.cjs +5 -330
  127. package/templates/settings.json +104 -239
  128. package/templates/skills/README.md +95 -255
  129. package/templates/skills/THIRD_PARTY_NOTICES.md +405 -0
  130. package/templates/skills/agent-browser/SKILL.md +294 -0
  131. package/templates/skills/agent-browser/references/.gitkeep +0 -0
  132. package/templates/skills/agent-browser/references/agent-browser-vs-chrome-devtools.md +112 -0
  133. package/templates/skills/agent-browser/references/browserbase-cloud-setup.md +161 -0
  134. package/templates/skills/ai-artist/SKILL.md +103 -56
  135. package/templates/skills/ai-artist/data/awesome-prompts.csv +3592 -0
  136. package/templates/skills/ai-artist/data/lighting.csv +19 -0
  137. package/templates/skills/ai-artist/data/nano-banana-templates.csv +17 -0
  138. package/templates/skills/ai-artist/data/platforms.csv +11 -0
  139. package/templates/skills/ai-artist/data/styles.csv +26 -0
  140. package/templates/skills/ai-artist/data/techniques.csv +19 -0
  141. package/templates/skills/ai-artist/data/use-cases.csv +16 -0
  142. package/templates/skills/ai-artist/references/awesome-nano-banana-pro-prompts.md +8575 -0
  143. package/templates/skills/ai-artist/references/nano-banana.md +78 -1
  144. package/templates/skills/ai-artist/references/validation-workflow.md +117 -0
  145. package/templates/skills/ai-artist/scripts/core.py +197 -0
  146. package/templates/skills/ai-artist/scripts/extract_prompts.py +102 -0
  147. package/templates/skills/ai-artist/scripts/generate.py +370 -0
  148. package/templates/skills/ai-artist/scripts/search.py +147 -0
  149. package/templates/skills/ai-multimodal/SKILL.md +4 -3
  150. package/templates/skills/ai-multimodal/scripts/check_setup.py +12 -2
  151. package/templates/skills/ai-multimodal/scripts/document_converter.py +0 -0
  152. package/templates/skills/ai-multimodal/scripts/gemini_batch_process.py +3 -2
  153. package/templates/skills/ai-multimodal/scripts/media_optimizer.py +0 -0
  154. package/templates/skills/ask/SKILL.md +58 -0
  155. package/templates/skills/backend-development/SKILL.md +3 -2
  156. package/templates/skills/better-auth/SKILL.md +3 -2
  157. package/templates/skills/better-auth/scripts/better_auth_init.py +3 -3
  158. package/templates/skills/bootstrap/SKILL.md +101 -0
  159. package/templates/skills/bootstrap/references/shared-phases.md +59 -0
  160. package/templates/skills/bootstrap/references/workflow-auto.md +52 -0
  161. package/templates/skills/bootstrap/references/workflow-fast.md +50 -0
  162. package/templates/skills/bootstrap/references/workflow-full.md +60 -0
  163. package/templates/skills/bootstrap/references/workflow-parallel.md +59 -0
  164. package/templates/{commands/brainstorm.md → skills/brainstorm/SKILL.md} +21 -18
  165. package/templates/skills/chrome-devtools/SKILL.md +221 -68
  166. package/templates/skills/chrome-devtools/scripts/README.md +18 -0
  167. package/templates/skills/chrome-devtools/scripts/__tests__/error-handling.test.js +102 -0
  168. package/templates/skills/chrome-devtools/scripts/aria-snapshot.js +2 -1
  169. package/templates/skills/chrome-devtools/scripts/click.js +2 -1
  170. package/templates/skills/chrome-devtools/scripts/connect-chrome.js +146 -0
  171. package/templates/skills/chrome-devtools/scripts/console.js +3 -1
  172. package/templates/skills/chrome-devtools/scripts/evaluate.js +6 -3
  173. package/templates/skills/chrome-devtools/scripts/fill.js +2 -1
  174. package/templates/skills/chrome-devtools/scripts/import-cookies.js +205 -0
  175. package/templates/skills/chrome-devtools/scripts/inject-auth.js +2 -1
  176. package/templates/skills/chrome-devtools/scripts/install-deps.sh +0 -0
  177. package/templates/skills/chrome-devtools/scripts/install.sh +0 -0
  178. package/templates/skills/chrome-devtools/scripts/lib/browser.js +60 -4
  179. package/templates/skills/chrome-devtools/scripts/navigate.js +86 -2
  180. package/templates/skills/chrome-devtools/scripts/network.js +3 -1
  181. package/templates/skills/chrome-devtools/scripts/performance.js +3 -1
  182. package/templates/skills/chrome-devtools/scripts/screenshot.js +2 -1
  183. package/templates/skills/chrome-devtools/scripts/select-ref.js +2 -1
  184. package/templates/skills/chrome-devtools/scripts/snapshot.js +2 -1
  185. package/templates/skills/chrome-devtools/scripts/ws-debug.js +44 -0
  186. package/templates/skills/chrome-devtools/scripts/ws-full-debug.js +107 -0
  187. package/templates/skills/ck-help/SKILL.md +102 -0
  188. package/templates/skills/ck-help/scripts/ck-help.py +1321 -0
  189. package/templates/skills/ck-help/scripts/commands_data.yaml +3 -0
  190. package/templates/skills/ck-help/scripts/skills_data.yaml +593 -0
  191. package/templates/skills/code-review/SKILL.md +97 -93
  192. package/templates/skills/code-review/references/code-review-reception.md +113 -209
  193. package/templates/skills/code-review/references/codebase-scan-workflow.md +29 -0
  194. package/templates/skills/code-review/references/edge-case-scouting.md +119 -0
  195. package/templates/skills/code-review/references/parallel-review-workflow.md +69 -0
  196. package/templates/skills/code-review/references/requesting-code-review.md +115 -104
  197. package/templates/skills/code-review/references/task-management-reviews.md +140 -0
  198. package/templates/skills/code-review/references/verification-before-completion.md +138 -138
  199. package/templates/skills/coding-level/SKILL.md +56 -0
  200. package/templates/skills/common/README.md +120 -0
  201. package/templates/skills/common/api_key_helper.py +411 -0
  202. package/templates/skills/common/api_key_rotator.py +248 -0
  203. package/templates/skills/context-engineering/SKILL.md +108 -0
  204. package/templates/skills/context-engineering/references/context-compression.md +84 -0
  205. package/templates/skills/context-engineering/references/context-degradation.md +93 -0
  206. package/templates/skills/context-engineering/references/context-fundamentals.md +75 -0
  207. package/templates/skills/context-engineering/references/context-optimization.md +82 -0
  208. package/templates/skills/context-engineering/references/evaluation.md +89 -0
  209. package/templates/skills/context-engineering/references/memory-systems.md +88 -0
  210. package/templates/skills/context-engineering/references/multi-agent-patterns.md +90 -0
  211. package/templates/skills/context-engineering/references/project-development.md +97 -0
  212. package/templates/skills/context-engineering/references/runtime-awareness.md +202 -0
  213. package/templates/skills/context-engineering/references/tool-design.md +86 -0
  214. package/templates/skills/context-engineering/scripts/compression_evaluator.py +349 -0
  215. package/templates/skills/context-engineering/scripts/context_analyzer.py +317 -0
  216. package/templates/skills/context-engineering/scripts/tests/test_edge_cases.py +246 -0
  217. package/templates/skills/cook/README.md +86 -0
  218. package/templates/skills/cook/SKILL.md +113 -0
  219. package/templates/skills/cook/references/intent-detection.md +101 -0
  220. package/templates/skills/cook/references/review-cycle.md +75 -0
  221. package/templates/skills/cook/references/subagent-patterns.md +75 -0
  222. package/templates/skills/cook/references/workflow-steps.md +172 -0
  223. package/templates/skills/copywriting/SKILL.md +94 -0
  224. package/templates/skills/copywriting/references/copy-formulas.md +150 -0
  225. package/templates/skills/copywriting/references/cta-patterns.md +168 -0
  226. package/templates/skills/copywriting/references/email-copy.md +193 -0
  227. package/templates/skills/copywriting/references/headline-templates.md +140 -0
  228. package/templates/skills/copywriting/references/landing-page-copy.md +175 -0
  229. package/templates/skills/copywriting/references/power-words.md +189 -0
  230. package/templates/skills/copywriting/references/social-media-copy.md +222 -0
  231. package/templates/skills/copywriting/references/workflow-cro.md +83 -0
  232. package/templates/skills/copywriting/references/workflow-enhance.md +32 -0
  233. package/templates/skills/copywriting/references/workflow-fast.md +29 -0
  234. package/templates/skills/copywriting/references/workflow-good.md +39 -0
  235. package/templates/skills/copywriting/references/writing-styles.md +247 -0
  236. package/templates/skills/copywriting/scripts/extract-writing-styles.py +308 -0
  237. package/templates/skills/copywriting/templates/copy-brief.md +49 -0
  238. package/templates/skills/databases/SKILL.md +7 -155
  239. package/templates/skills/databases/analytics.md +198 -0
  240. package/templates/skills/databases/db-design.md +188 -0
  241. package/templates/skills/databases/incremental-etl.md +213 -0
  242. package/templates/skills/databases/scripts/db_backup.py +0 -0
  243. package/templates/skills/databases/scripts/db_migrate.py +3 -2
  244. package/templates/skills/databases/scripts/db_performance_check.py +3 -2
  245. package/templates/skills/databases/stacks/bigquery.md +231 -0
  246. package/templates/skills/databases/stacks/d1_cloudflare.md +137 -0
  247. package/templates/skills/databases/stacks/mysql.md +216 -0
  248. package/templates/skills/databases/stacks/postgres.md +235 -0
  249. package/templates/skills/databases/stacks/sqlite.md +244 -0
  250. package/templates/skills/databases/transactional.md +176 -0
  251. package/templates/skills/debug/SKILL.md +121 -0
  252. package/templates/skills/debug/references/frontend-verification.md +103 -0
  253. package/templates/skills/debug/references/investigation-methodology.md +101 -0
  254. package/templates/skills/debug/references/log-and-ci-analysis.md +97 -0
  255. package/templates/skills/debug/references/performance-diagnostics.md +113 -0
  256. package/templates/skills/debug/references/reporting-standards.md +122 -0
  257. package/templates/skills/debug/references/task-management-debugging.md +155 -0
  258. package/templates/skills/devops/SKILL.md +65 -253
  259. package/templates/skills/devops/references/kubernetes-basics.md +99 -0
  260. package/templates/skills/devops/references/kubernetes-helm-advanced.md +75 -0
  261. package/templates/skills/devops/references/kubernetes-helm.md +81 -0
  262. package/templates/skills/devops/references/kubernetes-kubectl.md +74 -0
  263. package/templates/skills/devops/references/kubernetes-security-advanced.md +98 -0
  264. package/templates/skills/devops/references/kubernetes-security.md +95 -0
  265. package/templates/skills/devops/references/kubernetes-troubleshooting-advanced.md +74 -0
  266. package/templates/skills/devops/references/kubernetes-troubleshooting.md +49 -0
  267. package/templates/skills/devops/references/kubernetes-workflows-advanced.md +75 -0
  268. package/templates/skills/devops/references/kubernetes-workflows.md +78 -0
  269. package/templates/skills/devops/scripts/cloudflare_deploy.py +0 -0
  270. package/templates/skills/devops/scripts/docker_optimize.py +3 -2
  271. package/templates/skills/docs/SKILL.md +55 -0
  272. package/templates/skills/docs/references/init-workflow.md +32 -0
  273. package/templates/skills/docs/references/summarize-workflow.md +18 -0
  274. package/templates/skills/docs/references/update-workflow.md +59 -0
  275. package/templates/skills/docs-seeker/SKILL.md +3 -2
  276. package/templates/skills/docs-seeker/scripts/analyze-llms-txt.js +0 -0
  277. package/templates/skills/docs-seeker/scripts/detect-topic.js +0 -0
  278. package/templates/skills/docs-seeker/scripts/fetch-docs.js +0 -0
  279. package/templates/skills/docs-seeker/scripts/tests/run-tests.js +0 -0
  280. package/templates/skills/docs-seeker/scripts/tests/test-analyze-llms.js +0 -0
  281. package/templates/skills/docs-seeker/scripts/tests/test-detect-topic.js +0 -0
  282. package/templates/skills/docs-seeker/scripts/tests/test-fetch-docs.js +0 -0
  283. package/templates/skills/docs-seeker/scripts/utils/env-loader.js +0 -0
  284. package/templates/skills/document-skills/docx/SKILL.md +2 -2
  285. package/templates/skills/document-skills/docx/ooxml/scripts/pack.py +0 -0
  286. package/templates/skills/document-skills/docx/ooxml/scripts/unpack.py +0 -0
  287. package/templates/skills/document-skills/docx/ooxml/scripts/validate.py +0 -0
  288. package/templates/skills/document-skills/docx/scripts/document.py +0 -0
  289. package/templates/skills/document-skills/docx/scripts/utilities.py +0 -0
  290. package/templates/skills/document-skills/pdf/SKILL.md +2 -2
  291. package/templates/skills/document-skills/pptx/SKILL.md +2 -2
  292. package/templates/skills/document-skills/pptx/ooxml/scripts/pack.py +0 -0
  293. package/templates/skills/document-skills/pptx/ooxml/scripts/unpack.py +0 -0
  294. package/templates/skills/document-skills/pptx/ooxml/scripts/validate.py +0 -0
  295. package/templates/skills/document-skills/pptx/scripts/inventory.py +0 -0
  296. package/templates/skills/document-skills/pptx/scripts/rearrange.py +0 -0
  297. package/templates/skills/document-skills/pptx/scripts/replace.py +0 -0
  298. package/templates/skills/document-skills/pptx/scripts/thumbnail.py +0 -0
  299. package/templates/skills/document-skills/xlsx/SKILL.md +2 -2
  300. package/templates/skills/document-skills/xlsx/recalc.py +3 -2
  301. package/templates/skills/find-skills/SKILL.md +134 -0
  302. package/templates/skills/fix/SKILL.md +111 -0
  303. package/templates/skills/fix/references/complexity-assessment.md +72 -0
  304. package/templates/skills/fix/references/mode-selection.md +46 -0
  305. package/templates/skills/fix/references/parallel-exploration.md +100 -0
  306. package/templates/skills/fix/references/review-cycle.md +77 -0
  307. package/templates/skills/fix/references/skill-activation-matrix.md +78 -0
  308. package/templates/skills/fix/references/task-orchestration.md +103 -0
  309. package/templates/skills/fix/references/workflow-ci.md +28 -0
  310. package/templates/skills/fix/references/workflow-deep.md +122 -0
  311. package/templates/skills/fix/references/workflow-logs.md +72 -0
  312. package/templates/skills/fix/references/workflow-quick.md +59 -0
  313. package/templates/skills/fix/references/workflow-standard.md +111 -0
  314. package/templates/skills/fix/references/workflow-test.md +75 -0
  315. package/templates/skills/fix/references/workflow-types.md +33 -0
  316. package/templates/skills/fix/references/workflow-ui.md +75 -0
  317. package/templates/skills/frontend-design/SKILL.md +78 -91
  318. package/templates/skills/frontend-design/references/ai-multimodal-overview.md +6 -6
  319. package/templates/skills/frontend-design/references/animejs.md +395 -395
  320. package/templates/skills/frontend-design/references/asset-generation.md +4 -4
  321. package/templates/skills/frontend-design/references/visual-analysis-overview.md +1 -1
  322. package/templates/skills/frontend-design/references/workflow-3d.md +102 -0
  323. package/templates/skills/frontend-design/references/workflow-describe.md +87 -0
  324. package/templates/skills/frontend-design/references/workflow-immersive.md +87 -0
  325. package/templates/skills/frontend-design/references/workflow-quick.md +57 -0
  326. package/templates/skills/frontend-design/references/workflow-screenshot.md +63 -0
  327. package/templates/skills/frontend-design/references/workflow-video.md +74 -0
  328. package/templates/skills/frontend-development/SKILL.md +4 -3
  329. package/templates/skills/git/SKILL.md +114 -0
  330. package/templates/skills/git/references/branch-management.md +88 -0
  331. package/templates/skills/git/references/commit-standards.md +46 -0
  332. package/templates/skills/git/references/gh-cli-guide.md +109 -0
  333. package/templates/skills/git/references/safety-protocols.md +69 -0
  334. package/templates/skills/git/references/workflow-commit.md +58 -0
  335. package/templates/skills/git/references/workflow-merge.md +48 -0
  336. package/templates/skills/git/references/workflow-pr.md +58 -0
  337. package/templates/skills/git/references/workflow-push.md +52 -0
  338. package/templates/skills/gkg/SKILL.md +91 -0
  339. package/templates/skills/gkg/references/cli-commands.md +106 -0
  340. package/templates/skills/gkg/references/http-api.md +102 -0
  341. package/templates/skills/gkg/references/language-support.md +57 -0
  342. package/templates/skills/gkg/references/mcp-tools.md +99 -0
  343. package/templates/skills/google-adk-python/SKILL.md +91 -195
  344. package/templates/skills/google-adk-python/references/agent-types-and-architecture.md +128 -0
  345. package/templates/skills/google-adk-python/references/callbacks-plugins-observability.md +117 -0
  346. package/templates/skills/google-adk-python/references/deployment-cloud-run-vertex-gke.md +138 -0
  347. package/templates/skills/google-adk-python/references/evaluation-testing-cli.md +112 -0
  348. package/templates/skills/google-adk-python/references/multi-agent-and-a2a-protocol.md +145 -0
  349. package/templates/skills/google-adk-python/references/sessions-state-memory-artifacts.md +131 -0
  350. package/templates/skills/google-adk-python/references/tools-and-mcp-integration.md +146 -0
  351. package/templates/skills/install.ps1 +130 -26
  352. package/templates/skills/install.sh +383 -63
  353. package/templates/{commands/journal.md → skills/journal/SKILL.md} +5 -1
  354. package/templates/skills/kanban/SKILL.md +99 -0
  355. package/templates/skills/markdown-novel-viewer/SKILL.md +314 -0
  356. package/templates/skills/markdown-novel-viewer/assets/directory-browser.css +215 -0
  357. package/templates/skills/markdown-novel-viewer/assets/favicon.png +0 -0
  358. package/templates/skills/markdown-novel-viewer/assets/novel-theme.css +16 -0
  359. package/templates/skills/markdown-novel-viewer/assets/reader.js +838 -0
  360. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-base.css +54 -0
  361. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-components.css +180 -0
  362. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-content.css +176 -0
  363. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-header.css +217 -0
  364. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-mermaid.css +153 -0
  365. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-overlays.css +202 -0
  366. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-responsive.css +285 -0
  367. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-sidebar.css +359 -0
  368. package/templates/skills/markdown-novel-viewer/assets/styles/novel-theme-variables.css +56 -0
  369. package/templates/skills/markdown-novel-viewer/assets/template.html +149 -0
  370. package/templates/skills/markdown-novel-viewer/bun.lock +38 -0
  371. package/templates/skills/markdown-novel-viewer/package.json +15 -0
  372. package/templates/skills/markdown-novel-viewer/scripts/lib/http-server.cjs +434 -0
  373. package/templates/skills/markdown-novel-viewer/scripts/lib/markdown-renderer.cjs +335 -0
  374. package/templates/skills/markdown-novel-viewer/scripts/lib/plan-navigator.cjs +571 -0
  375. package/templates/skills/markdown-novel-viewer/scripts/lib/port-finder.cjs +48 -0
  376. package/templates/skills/markdown-novel-viewer/scripts/lib/process-mgr.cjs +150 -0
  377. package/templates/skills/markdown-novel-viewer/scripts/server.cjs +411 -0
  378. package/templates/skills/markdown-novel-viewer/scripts/tests/server.test.cjs +283 -0
  379. package/templates/skills/markdown-novel-viewer/tests/dashboard-assets.test.cjs +340 -0
  380. package/templates/skills/markdown-novel-viewer/tests/dashboard-renderer.test.cjs +404 -0
  381. package/templates/skills/markdown-novel-viewer/tests/http-server.test.cjs +271 -0
  382. package/templates/skills/markdown-novel-viewer/tests/run-tests.cjs +51 -0
  383. package/templates/skills/markdown-novel-viewer/tests/test-framework.cjs +154 -0
  384. package/templates/skills/markdown-novel-viewer/tests/verify-xss.cjs +90 -0
  385. package/templates/skills/mcp-builder/SKILL.md +3 -2
  386. package/templates/skills/mcp-builder/scripts/evaluation.py +9 -1
  387. package/templates/skills/mcp-management/SKILL.md +8 -7
  388. package/templates/skills/mcp-management/references/gemini-cli-integration.md +16 -10
  389. package/templates/skills/mcp-management/scripts/cli.ts +0 -0
  390. package/templates/skills/mcp-management/scripts/dist/analyze-tools.js +0 -0
  391. package/templates/skills/mcp-management/scripts/dist/cli.js +0 -0
  392. package/templates/skills/mcp-management/scripts/dist/mcp-client.js +0 -0
  393. package/templates/skills/mcp-management/scripts/mcp-client.ts +0 -0
  394. package/templates/skills/media-processing/SKILL.md +3 -2
  395. package/templates/skills/media-processing/scripts/batch-remove-background.sh +0 -0
  396. package/templates/skills/media-processing/scripts/batch_resize.py +0 -0
  397. package/templates/skills/media-processing/scripts/media_convert.py +0 -0
  398. package/templates/skills/media-processing/scripts/remove-background.sh +0 -0
  399. package/templates/skills/media-processing/scripts/remove-bg-node.js +0 -0
  400. package/templates/skills/media-processing/scripts/tests/test_batch_resize.py +0 -0
  401. package/templates/skills/media-processing/scripts/tests/test_media_convert.py +0 -0
  402. package/templates/skills/media-processing/scripts/tests/test_video_optimize.py +0 -0
  403. package/templates/skills/media-processing/scripts/video_optimize.py +0 -0
  404. package/templates/skills/mermaidjs-v11/SKILL.md +116 -0
  405. package/templates/skills/mermaidjs-v11/references/cli-usage.md +228 -0
  406. package/templates/skills/mermaidjs-v11/references/configuration.md +232 -0
  407. package/templates/skills/mermaidjs-v11/references/diagram-types.md +315 -0
  408. package/templates/skills/mermaidjs-v11/references/examples.md +344 -0
  409. package/templates/skills/mermaidjs-v11/references/integration.md +310 -0
  410. package/templates/skills/mintlify/SKILL.md +121 -0
  411. package/templates/skills/mintlify/references/ai-features-and-integrations-reference.md +756 -0
  412. package/templates/skills/mintlify/references/api-documentation-components-reference.md +873 -0
  413. package/templates/skills/mintlify/references/deployment-and-continuous-integration-reference.md +674 -0
  414. package/templates/skills/mintlify/references/docs-json-configuration-reference.md +724 -0
  415. package/templates/skills/mintlify/references/mdx-components-reference.md +551 -0
  416. package/templates/skills/mintlify/references/navigation-structure-and-organization-reference.md +775 -0
  417. package/templates/skills/mobile-development/SKILL.md +3 -2
  418. package/templates/skills/payment-integration/README.md +44 -12
  419. package/templates/skills/payment-integration/SKILL.md +82 -97
  420. package/templates/skills/payment-integration/references/creem/api.md +139 -0
  421. package/templates/skills/payment-integration/references/creem/checkouts.md +99 -0
  422. package/templates/skills/payment-integration/references/creem/licensing.md +136 -0
  423. package/templates/skills/payment-integration/references/creem/overview.md +65 -0
  424. package/templates/skills/payment-integration/references/creem/sdk.md +161 -0
  425. package/templates/skills/payment-integration/references/creem/subscriptions.md +129 -0
  426. package/templates/skills/payment-integration/references/creem/webhooks.md +120 -0
  427. package/templates/skills/payment-integration/references/implementation-workflows.md +43 -0
  428. package/templates/skills/payment-integration/references/multi-provider-order-management-patterns.md +821 -0
  429. package/templates/skills/payment-integration/references/paddle/api.md +116 -0
  430. package/templates/skills/payment-integration/references/paddle/best-practices.md +130 -0
  431. package/templates/skills/payment-integration/references/paddle/overview.md +57 -0
  432. package/templates/skills/payment-integration/references/paddle/paddle-js.md +106 -0
  433. package/templates/skills/payment-integration/references/paddle/sdk.md +131 -0
  434. package/templates/skills/payment-integration/references/paddle/subscriptions.md +118 -0
  435. package/templates/skills/payment-integration/references/paddle/webhooks.md +112 -0
  436. package/templates/skills/payment-integration/references/polar/best-practices.md +781 -361
  437. package/templates/skills/payment-integration/references/sepay/best-practices.md +870 -268
  438. package/templates/skills/payment-integration/references/stripe/stripe-best-practices.md +32 -0
  439. package/templates/skills/payment-integration/references/stripe/stripe-cli.md +148 -0
  440. package/templates/skills/payment-integration/references/stripe/stripe-js.md +116 -0
  441. package/templates/skills/payment-integration/references/stripe/stripe-sdks.md +84 -0
  442. package/templates/skills/payment-integration/references/stripe/stripe-upgrade.md +175 -0
  443. package/templates/skills/payment-integration/scripts/checkout-helper.js +0 -0
  444. package/templates/skills/payment-integration/scripts/polar-webhook-verify.js +0 -0
  445. package/templates/skills/payment-integration/scripts/sepay-webhook-verify.js +0 -0
  446. package/templates/skills/payment-integration/scripts/test-scripts.js +0 -0
  447. package/templates/skills/plan/SKILL.md +137 -0
  448. package/templates/skills/plan/references/archive-workflow.md +53 -0
  449. package/templates/skills/{planning → plan}/references/codebase-understanding.md +1 -1
  450. package/templates/skills/{planning → plan}/references/output-standards.md +15 -1
  451. package/templates/skills/{planning → plan}/references/plan-organization.md +12 -19
  452. package/templates/skills/plan/references/red-team-personas.md +69 -0
  453. package/templates/skills/plan/references/red-team-workflow.md +77 -0
  454. package/templates/skills/{planning → plan}/references/research-phase.md +2 -2
  455. package/templates/skills/plan/references/task-management.md +132 -0
  456. package/templates/skills/plan/references/validate-question-framework.md +80 -0
  457. package/templates/skills/plan/references/validate-workflow.md +65 -0
  458. package/templates/skills/plan/references/workflow-modes.md +145 -0
  459. package/templates/skills/plans-kanban/SKILL.md +167 -0
  460. package/templates/skills/plans-kanban/assets/dashboard-template.html +119 -0
  461. package/templates/skills/plans-kanban/assets/dashboard.css +1594 -0
  462. package/templates/skills/plans-kanban/assets/dashboard.js +596 -0
  463. package/templates/skills/plans-kanban/assets/favicon.png +0 -0
  464. package/templates/skills/plans-kanban/package.json +13 -0
  465. package/templates/skills/plans-kanban/scripts/lib/dashboard-renderer.cjs +884 -0
  466. package/templates/skills/plans-kanban/scripts/lib/http-server.cjs +310 -0
  467. package/templates/skills/plans-kanban/scripts/lib/plan-metadata-extractor.cjs +489 -0
  468. package/templates/skills/plans-kanban/scripts/lib/plan-parser.cjs +175 -0
  469. package/templates/skills/plans-kanban/scripts/lib/plan-scanner.cjs +272 -0
  470. package/templates/skills/plans-kanban/scripts/lib/port-finder.cjs +48 -0
  471. package/templates/skills/plans-kanban/scripts/lib/process-mgr.cjs +128 -0
  472. package/templates/skills/plans-kanban/scripts/server.cjs +260 -0
  473. package/templates/skills/preview/SKILL.md +75 -0
  474. package/templates/skills/preview/references/generation-modes.md +95 -0
  475. package/templates/skills/preview/references/view-mode.md +42 -0
  476. package/templates/skills/problem-solving/SKILL.md +3 -2
  477. package/templates/skills/project-management/SKILL.md +122 -0
  478. package/templates/skills/project-management/references/documentation-triggers.md +60 -0
  479. package/templates/skills/project-management/references/hydration-workflow.md +85 -0
  480. package/templates/skills/project-management/references/progress-tracking.md +96 -0
  481. package/templates/skills/project-management/references/reporting-patterns.md +94 -0
  482. package/templates/skills/project-management/references/task-operations.md +85 -0
  483. package/templates/skills/react-best-practices/AGENTS.md +2249 -0
  484. package/templates/skills/react-best-practices/README.md +123 -0
  485. package/templates/skills/react-best-practices/SKILL.md +122 -0
  486. package/templates/skills/react-best-practices/metadata.json +15 -0
  487. package/templates/skills/react-best-practices/rules/_sections.md +46 -0
  488. package/templates/skills/react-best-practices/rules/_template.md +28 -0
  489. package/templates/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  490. package/templates/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  491. package/templates/skills/react-best-practices/rules/async-api-routes.md +38 -0
  492. package/templates/skills/react-best-practices/rules/async-defer-await.md +80 -0
  493. package/templates/skills/react-best-practices/rules/async-dependencies.md +36 -0
  494. package/templates/skills/react-best-practices/rules/async-parallel.md +28 -0
  495. package/templates/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  496. package/templates/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  497. package/templates/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  498. package/templates/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  499. package/templates/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  500. package/templates/skills/react-best-practices/rules/bundle-preload.md +50 -0
  501. package/templates/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  502. package/templates/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  503. package/templates/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  504. package/templates/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  505. package/templates/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  506. package/templates/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  507. package/templates/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  508. package/templates/skills/react-best-practices/rules/js-early-exit.md +50 -0
  509. package/templates/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  510. package/templates/skills/react-best-practices/rules/js-index-maps.md +37 -0
  511. package/templates/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  512. package/templates/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  513. package/templates/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  514. package/templates/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  515. package/templates/skills/react-best-practices/rules/rendering-activity.md +26 -0
  516. package/templates/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  517. package/templates/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  518. package/templates/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  519. package/templates/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  520. package/templates/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  521. package/templates/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  522. package/templates/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  523. package/templates/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  524. package/templates/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  525. package/templates/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  526. package/templates/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  527. package/templates/skills/react-best-practices/rules/rerender-memo.md +44 -0
  528. package/templates/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  529. package/templates/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  530. package/templates/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  531. package/templates/skills/react-best-practices/rules/server-cache-react.md +26 -0
  532. package/templates/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
  533. package/templates/skills/react-best-practices/rules/server-serialization.md +38 -0
  534. package/templates/skills/remotion/SKILL.md +44 -0
  535. package/templates/skills/remotion/rules/3d.md +86 -0
  536. package/templates/skills/remotion/rules/animations.md +29 -0
  537. package/templates/skills/remotion/rules/assets/charts-bar-chart.tsx +173 -0
  538. package/templates/skills/remotion/rules/assets/text-animations-typewriter.tsx +100 -0
  539. package/templates/skills/remotion/rules/assets/text-animations-word-highlight.tsx +108 -0
  540. package/templates/skills/remotion/rules/assets.md +78 -0
  541. package/templates/skills/remotion/rules/audio.md +172 -0
  542. package/templates/skills/remotion/rules/calculate-metadata.md +104 -0
  543. package/templates/skills/remotion/rules/can-decode.md +75 -0
  544. package/templates/skills/remotion/rules/charts.md +58 -0
  545. package/templates/skills/remotion/rules/compositions.md +146 -0
  546. package/templates/skills/remotion/rules/display-captions.md +126 -0
  547. package/templates/skills/remotion/rules/extract-frames.md +229 -0
  548. package/templates/skills/remotion/rules/fonts.md +152 -0
  549. package/templates/skills/remotion/rules/get-audio-duration.md +58 -0
  550. package/templates/skills/remotion/rules/get-video-dimensions.md +68 -0
  551. package/templates/skills/remotion/rules/get-video-duration.md +58 -0
  552. package/templates/skills/remotion/rules/gifs.md +138 -0
  553. package/templates/skills/remotion/rules/images.md +130 -0
  554. package/templates/skills/remotion/rules/import-srt-captions.md +67 -0
  555. package/templates/skills/remotion/rules/lottie.md +68 -0
  556. package/templates/skills/remotion/rules/measuring-dom-nodes.md +35 -0
  557. package/templates/skills/remotion/rules/measuring-text.md +143 -0
  558. package/templates/skills/remotion/rules/sequencing.md +106 -0
  559. package/templates/skills/remotion/rules/tailwind.md +11 -0
  560. package/templates/skills/remotion/rules/text-animations.md +20 -0
  561. package/templates/skills/remotion/rules/timing.md +179 -0
  562. package/templates/skills/remotion/rules/transcribe-captions.md +19 -0
  563. package/templates/skills/remotion/rules/transitions.md +122 -0
  564. package/templates/skills/remotion/rules/trimming.md +53 -0
  565. package/templates/skills/remotion/rules/videos.md +171 -0
  566. package/templates/skills/repomix/SKILL.md +3 -2
  567. package/templates/skills/repomix/scripts/repomix_batch.py +0 -0
  568. package/templates/skills/research/SKILL.md +9 -6
  569. package/templates/skills/scout/SKILL.md +89 -0
  570. package/templates/skills/scout/references/external-scouting.md +140 -0
  571. package/templates/skills/scout/references/internal-scouting.md +119 -0
  572. package/templates/skills/scout/references/task-management-scouting.md +125 -0
  573. package/templates/skills/sequential-thinking/SKILL.md +3 -2
  574. package/templates/skills/sequential-thinking/scripts/format-thought.js +0 -0
  575. package/templates/skills/sequential-thinking/scripts/process-thought.js +0 -0
  576. package/templates/skills/shader/SKILL.md +113 -0
  577. package/templates/skills/shader/references/glsl-cellular-voronoi-worley-noise-patterns.md +142 -0
  578. package/templates/skills/shader/references/glsl-colors-rgb-hsb-gradients-mixing-color-spaces.md +143 -0
  579. package/templates/skills/shader/references/glsl-fbm-fractional-brownian-motion-turbulence-octaves.md +146 -0
  580. package/templates/skills/shader/references/glsl-fundamentals-data-types-vectors-precision-coordinates.md +104 -0
  581. package/templates/skills/shader/references/glsl-noise-random-perlin-simplex-cellular-voronoi.md +115 -0
  582. package/templates/skills/shader/references/glsl-pattern-symmetry-truchet-domain-warping.md +134 -0
  583. package/templates/skills/shader/references/glsl-patterns-tiling-fract-matrices-transformations.md +133 -0
  584. package/templates/skills/shader/references/glsl-procedural-textures-clouds-marble-wood-terrain.md +144 -0
  585. package/templates/skills/shader/references/glsl-shader-builtin-functions-complete-api-reference.md +112 -0
  586. package/templates/skills/shader/references/glsl-shapes-polygon-star-polar-sdf-combinations.md +124 -0
  587. package/templates/skills/shader/references/glsl-shapes-sdf-circles-rectangles-polar-distance-fields.md +106 -0
  588. package/templates/skills/shader/references/glsl-shaping-functions-step-smoothstep-curves-interpolation.md +141 -0
  589. package/templates/skills/shopify/SKILL.md +3 -2
  590. package/templates/skills/shopify/scripts/shopify_init.py +5 -5
  591. package/templates/skills/skill-creator/SKILL.md +91 -238
  592. package/templates/skills/skill-creator/references/benchmark-optimization-guide.md +86 -0
  593. package/templates/skills/skill-creator/references/distribution-guide.md +79 -0
  594. package/templates/skills/skill-creator/references/mcp-skills-integration.md +71 -0
  595. package/templates/skills/skill-creator/references/metadata-quality-criteria.md +76 -0
  596. package/templates/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -0
  597. package/templates/skills/skill-creator/references/plugin-marketplace-overview.md +89 -0
  598. package/templates/skills/skill-creator/references/plugin-marketplace-schema.md +93 -0
  599. package/templates/skills/skill-creator/references/plugin-marketplace-sources.md +103 -0
  600. package/templates/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -0
  601. package/templates/skills/skill-creator/references/script-quality-criteria.md +106 -0
  602. package/templates/skills/skill-creator/references/skill-anatomy-and-requirements.md +76 -0
  603. package/templates/skills/skill-creator/references/skill-creation-workflow.md +95 -0
  604. package/templates/skills/skill-creator/references/skill-design-patterns.md +75 -0
  605. package/templates/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -0
  606. package/templates/skills/skill-creator/references/structure-organization-criteria.md +114 -0
  607. package/templates/skills/skill-creator/references/testing-and-iteration.md +78 -0
  608. package/templates/skills/skill-creator/references/token-efficiency-criteria.md +74 -0
  609. package/templates/skills/skill-creator/references/troubleshooting-guide.md +80 -0
  610. package/templates/skills/skill-creator/references/validation-checklist.md +83 -0
  611. package/templates/skills/skill-creator/references/writing-effective-instructions.md +88 -0
  612. package/templates/skills/skill-creator/references/yaml-frontmatter-reference.md +91 -0
  613. package/templates/skills/skill-creator/scripts/debug.zip +0 -0
  614. package/templates/skills/skill-creator/scripts/encoding_utils.py +36 -0
  615. package/templates/skills/skill-creator/scripts/init_skill.py +9 -4
  616. package/templates/skills/skill-creator/scripts/package_skill.py +5 -0
  617. package/templates/skills/skill-creator/scripts/quick_validate.py +6 -2
  618. package/templates/skills/tanstack/SKILL.md +141 -0
  619. package/templates/skills/tanstack/references/tanstack-ai.md +97 -0
  620. package/templates/skills/tanstack/references/tanstack-form.md +125 -0
  621. package/templates/skills/tanstack/references/tanstack-start.md +100 -0
  622. package/templates/skills/team/SKILL.md +285 -0
  623. package/templates/skills/team/references/agent-teams-controls-and-modes.md +107 -0
  624. package/templates/skills/team/references/agent-teams-examples-and-best-practices.md +182 -0
  625. package/templates/skills/team/references/agent-teams-official-docs.md +175 -0
  626. package/templates/skills/template-skill/SKILL.md +1 -1
  627. package/templates/skills/test/SKILL.md +109 -0
  628. package/templates/skills/test/references/report-format.md +58 -0
  629. package/templates/skills/test/references/test-execution-workflow.md +103 -0
  630. package/templates/skills/test/references/ui-testing-workflow.md +65 -0
  631. package/templates/skills/threejs/SKILL.md +106 -53
  632. package/templates/skills/threejs/data/api-reference.csv +61 -0
  633. package/templates/skills/threejs/data/categories.csv +14 -0
  634. package/templates/skills/threejs/data/examples-all.csv +557 -0
  635. package/templates/skills/threejs/data/use-cases.csv +21 -0
  636. package/templates/skills/threejs/references/00-fundamentals.md +487 -0
  637. package/templates/skills/threejs/references/11-materials-advanced.md +1 -1
  638. package/templates/skills/threejs/references/11-materials.md +519 -0
  639. package/templates/skills/threejs/references/17-shader.md +641 -0
  640. package/templates/skills/threejs/references/18-geometry.md +547 -0
  641. package/templates/skills/threejs/scripts/core.py +236 -0
  642. package/templates/skills/threejs/scripts/extract_examples.py +688 -0
  643. package/templates/skills/threejs/scripts/generate_csv_from_json.py +135 -0
  644. package/templates/skills/threejs/scripts/search.py +77 -0
  645. package/templates/skills/ui-styling/SKILL.md +3 -2
  646. package/templates/skills/ui-styling/scripts/shadcn_add.py +0 -0
  647. package/templates/skills/ui-styling/scripts/tailwind_config_gen.py +1 -1
  648. package/templates/skills/ui-ux-pro-max/SKILL.md +69 -32
  649. package/templates/skills/ui-ux-pro-max/data/charts.csv +25 -25
  650. package/templates/skills/ui-ux-pro-max/data/colors.csv +96 -96
  651. package/templates/skills/ui-ux-pro-max/data/landing.csv +30 -30
  652. package/templates/skills/ui-ux-pro-max/data/products.csv +96 -96
  653. package/templates/skills/ui-ux-pro-max/data/prompts.csv +20 -20
  654. package/templates/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
  655. package/templates/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
  656. package/templates/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
  657. package/templates/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
  658. package/templates/skills/ui-ux-pro-max/data/stacks/react.csv +54 -54
  659. package/templates/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
  660. package/templates/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
  661. package/templates/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -50
  662. package/templates/skills/ui-ux-pro-max/data/styles.csv +58 -58
  663. package/templates/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  664. package/templates/skills/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
  665. package/templates/skills/ui-ux-pro-max/scripts/design_system.py +494 -0
  666. package/templates/skills/ui-ux-pro-max/scripts/search.py +84 -61
  667. package/templates/skills/use-mcp/SKILL.md +42 -0
  668. package/templates/skills/watzup/SKILL.md +12 -0
  669. package/templates/skills/web-design-guidelines/SKILL.md +36 -0
  670. package/templates/skills/web-frameworks/SKILL.md +4 -3
  671. package/templates/skills/web-frameworks/scripts/nextjs_init.py +13 -13
  672. package/templates/skills/web-frameworks/scripts/turborepo_migrate.py +0 -0
  673. package/templates/skills/web-testing/SKILL.md +97 -0
  674. package/templates/skills/web-testing/references/accessibility-testing.md +84 -0
  675. package/templates/skills/web-testing/references/api-testing.md +78 -0
  676. package/templates/skills/web-testing/references/ci-cd-testing-workflows.md +121 -0
  677. package/templates/skills/web-testing/references/component-testing.md +94 -0
  678. package/templates/skills/web-testing/references/contract-testing.md +146 -0
  679. package/templates/skills/web-testing/references/cross-browser-checklist.md +72 -0
  680. package/templates/skills/web-testing/references/database-testing.md +139 -0
  681. package/templates/skills/web-testing/references/e2e-testing-playwright.md +119 -0
  682. package/templates/skills/web-testing/references/functional-testing-checklist.md +88 -0
  683. package/templates/skills/web-testing/references/interactive-testing-patterns.md +89 -0
  684. package/templates/skills/web-testing/references/load-testing-k6.md +93 -0
  685. package/templates/skills/web-testing/references/mobile-gesture-testing.md +85 -0
  686. package/templates/skills/web-testing/references/performance-core-web-vitals.md +124 -0
  687. package/templates/skills/web-testing/references/playwright-component-testing.md +115 -0
  688. package/templates/skills/web-testing/references/pre-release-checklist.md +75 -0
  689. package/templates/skills/web-testing/references/security-checklists.md +81 -0
  690. package/templates/skills/web-testing/references/security-testing-overview.md +92 -0
  691. package/templates/skills/web-testing/references/shadow-dom-testing.md +70 -0
  692. package/templates/skills/web-testing/references/test-data-management.md +131 -0
  693. package/templates/skills/web-testing/references/test-flakiness-mitigation.md +86 -0
  694. package/templates/skills/web-testing/references/testing-pyramid-strategy.md +76 -0
  695. package/templates/skills/web-testing/references/unit-integration-testing.md +138 -0
  696. package/templates/skills/web-testing/references/visual-regression.md +92 -0
  697. package/templates/skills/web-testing/references/vulnerability-payloads.md +93 -0
  698. package/templates/skills/web-testing/scripts/analyze-test-results.js +280 -0
  699. package/templates/skills/web-testing/scripts/init-playwright.js +233 -0
  700. package/templates/skills/worktree/SKILL.md +96 -0
  701. package/templates/skills/worktree/scripts/worktree.cjs +916 -0
  702. package/templates/skills/worktree/scripts/worktree.test.cjs +792 -0
  703. package/templates/statusline.cjs +477 -244
  704. package/templates/statusline.ps1 +0 -1
  705. package/templates/statusline.sh +0 -1
  706. package/templates/agents/README.md +0 -172
  707. package/templates/agents/copywriter.md +0 -113
  708. package/templates/agents/database-admin.md +0 -97
  709. package/templates/agents/scout-external.md +0 -146
  710. package/templates/agents/scout.md +0 -260
  711. package/templates/commands/README.md +0 -251
  712. package/templates/commands/bootstrap/auto/fast.md +0 -111
  713. package/templates/commands/bootstrap/auto/parallel.md +0 -66
  714. package/templates/commands/bootstrap/auto.md +0 -115
  715. package/templates/commands/bootstrap.md +0 -137
  716. package/templates/commands/build.md +0 -39
  717. package/templates/commands/checkpoint.md +0 -156
  718. package/templates/commands/code/auto.md +0 -170
  719. package/templates/commands/code/no-test.md +0 -158
  720. package/templates/commands/code/parallel.md +0 -55
  721. package/templates/commands/code-simplifier.md +0 -71
  722. package/templates/commands/code.md +0 -176
  723. package/templates/commands/compact.md +0 -57
  724. package/templates/commands/content/cro.md +0 -43
  725. package/templates/commands/content/enhance.md +0 -14
  726. package/templates/commands/content/fast.md +0 -13
  727. package/templates/commands/content/good.md +0 -16
  728. package/templates/commands/context.md +0 -48
  729. package/templates/commands/cook/auto/fast.md +0 -26
  730. package/templates/commands/cook/auto/parallel.md +0 -49
  731. package/templates/commands/cook/auto.md +0 -15
  732. package/templates/commands/cook/fast.md +0 -47
  733. package/templates/commands/cook/hard.md +0 -80
  734. package/templates/commands/cook/parallel.md +0 -90
  735. package/templates/commands/cook.md +0 -105
  736. package/templates/commands/create-feature.md +0 -48
  737. package/templates/commands/db-migrate.md +0 -52
  738. package/templates/commands/debug.md +0 -13
  739. package/templates/commands/design/3d.md +0 -83
  740. package/templates/commands/design/describe.md +0 -23
  741. package/templates/commands/design/fast.md +0 -31
  742. package/templates/commands/design/good.md +0 -35
  743. package/templates/commands/design/screenshot.md +0 -34
  744. package/templates/commands/design/video.md +0 -34
  745. package/templates/commands/docs/init.md +0 -39
  746. package/templates/commands/docs/summarize.md +0 -31
  747. package/templates/commands/docs/update.md +0 -57
  748. package/templates/commands/feature.md +0 -62
  749. package/templates/commands/fix/ci.md +0 -17
  750. package/templates/commands/fix/fast.md +0 -19
  751. package/templates/commands/fix/hard.md +0 -39
  752. package/templates/commands/fix/logs.md +0 -26
  753. package/templates/commands/fix/parallel.md +0 -54
  754. package/templates/commands/fix/test.md +0 -20
  755. package/templates/commands/fix/types.md +0 -9
  756. package/templates/commands/fix/ui.md +0 -48
  757. package/templates/commands/fix-issue.md +0 -177
  758. package/templates/commands/fix.md +0 -43
  759. package/templates/commands/generate-dto.md +0 -67
  760. package/templates/commands/git/cm.md +0 -5
  761. package/templates/commands/git/cp.md +0 -4
  762. package/templates/commands/git/merge.md +0 -40
  763. package/templates/commands/git/pr.md +0 -48
  764. package/templates/commands/integrate/polar.md +0 -28
  765. package/templates/commands/integrate/sepay.md +0 -28
  766. package/templates/commands/investigate.md +0 -324
  767. package/templates/commands/lint.md +0 -47
  768. package/templates/commands/migration.md +0 -111
  769. package/templates/commands/performance.md +0 -110
  770. package/templates/commands/plan/ci.md +0 -33
  771. package/templates/commands/plan/cro.md +0 -69
  772. package/templates/commands/plan/fast.md +0 -86
  773. package/templates/commands/plan/hard.md +0 -103
  774. package/templates/commands/plan/parallel.md +0 -152
  775. package/templates/commands/plan/preview.md +0 -40
  776. package/templates/commands/plan/two.md +0 -52
  777. package/templates/commands/plan/validate.md +0 -132
  778. package/templates/commands/plan.md +0 -36
  779. package/templates/commands/pr.md +0 -49
  780. package/templates/commands/preview.md +0 -87
  781. package/templates/commands/release-notes.md +0 -144
  782. package/templates/commands/review/post-task.md +0 -157
  783. package/templates/commands/review-changes.md +0 -46
  784. package/templates/commands/review.md +0 -56
  785. package/templates/commands/scout/ext.md +0 -35
  786. package/templates/commands/scout.md +0 -283
  787. package/templates/commands/security.md +0 -119
  788. package/templates/commands/skill/add.md +0 -36
  789. package/templates/commands/skill/create.md +0 -29
  790. package/templates/commands/skill/fix-logs.md +0 -22
  791. package/templates/commands/skill/optimize/auto.md +0 -25
  792. package/templates/commands/skill/optimize.md +0 -34
  793. package/templates/commands/skill/plan.md +0 -45
  794. package/templates/commands/worktree.md +0 -126
  795. package/templates/hooks/.python-cache.json +0 -1
  796. package/templates/hooks/README.md +0 -246
  797. package/templates/hooks/backend-csharp-context.cjs +0 -223
  798. package/templates/hooks/design-system-context.cjs +0 -185
  799. package/templates/hooks/frontend-typescript-context.cjs +0 -233
  800. package/templates/hooks/lib/ck-paths.cjs +0 -110
  801. package/templates/hooks/lib/context-tracker.cjs +0 -335
  802. package/templates/hooks/notify-waiting.js +0 -117
  803. package/templates/hooks/post-edit-prettier.cjs +0 -189
  804. package/templates/hooks/post-task-review.cjs +0 -142
  805. package/templates/hooks/scss-styling-context.cjs +0 -213
  806. package/templates/hooks/session-end.cjs +0 -35
  807. package/templates/hooks/tests/test-context-tracker.cjs +0 -454
  808. package/templates/hooks/tests/test-scout-block.js +0 -163
  809. package/templates/hooks/workflow-router.cjs +0 -326
  810. package/templates/hooks/write-compact-marker.cjs +0 -159
  811. package/templates/memory/session-log.md +0 -186
  812. package/templates/router/README.md +0 -294
  813. package/templates/router/agents-guide.md +0 -38
  814. package/templates/router/commands-guide.md +0 -122
  815. package/templates/router/decision-flow.md +0 -92
  816. package/templates/router/skills-guide.md +0 -127
  817. package/templates/router/workflows-guide.md +0 -68
  818. package/templates/scripts/__pycache__/win_compat.cpython-312.pyc +0 -0
  819. package/templates/scripts/plan-preview.cjs +0 -921
  820. package/templates/skills/arch-cross-service-integration/SKILL.md +0 -48
  821. package/templates/skills/arch-performance-optimization/SKILL.md +0 -306
  822. package/templates/skills/arch-security-review/SKILL.md +0 -344
  823. package/templates/skills/branch-comparison/SKILL.md +0 -150
  824. package/templates/skills/bug-diagnosis/SKILL.md +0 -309
  825. package/templates/skills/claude-code/references/advanced-features.md +0 -399
  826. package/templates/skills/claude-code/references/agent-skills.md +0 -399
  827. package/templates/skills/claude-code/references/api-reference.md +0 -498
  828. package/templates/skills/claude-code/references/best-practices.md +0 -447
  829. package/templates/skills/claude-code/references/cicd-integration.md +0 -428
  830. package/templates/skills/claude-code/references/common-workflows.md +0 -119
  831. package/templates/skills/claude-code/references/configuration.md +0 -480
  832. package/templates/skills/claude-code/references/enterprise-features.md +0 -472
  833. package/templates/skills/claude-code/references/getting-started.md +0 -252
  834. package/templates/skills/claude-code/references/hooks-and-plugins.md +0 -444
  835. package/templates/skills/claude-code/references/hooks-comprehensive.md +0 -622
  836. package/templates/skills/claude-code/references/ide-integration.md +0 -316
  837. package/templates/skills/claude-code/references/mcp-integration.md +0 -386
  838. package/templates/skills/claude-code/references/slash-commands.md +0 -489
  839. package/templates/skills/claude-code/references/troubleshooting.md +0 -456
  840. package/templates/skills/claude-code/skill.md +0 -60
  841. package/templates/skills/debugging/SKILL.md +0 -84
  842. package/templates/skills/developer-growth-analysis/SKILL.md +0 -322
  843. package/templates/skills/documentation/SKILL.md +0 -134
  844. package/templates/skills/domain-name-brainstormer/SKILL.md +0 -212
  845. package/templates/skills/dual-pass-review/SKILL.md +0 -249
  846. package/templates/skills/feature-docs/SKILL.md +0 -294
  847. package/templates/skills/feature-implementation/SKILL.md +0 -262
  848. package/templates/skills/feature-investigation/SKILL.md +0 -346
  849. package/templates/skills/frontend-design-pro/SKILL.md +0 -58
  850. package/templates/skills/package-upgrade/SKILL.md +0 -189
  851. package/templates/skills/plan-analysis/SKILL.md +0 -191
  852. package/templates/skills/planning/SKILL.md +0 -115
  853. package/templates/skills/planning-with-files/SKILL.md +0 -160
  854. package/templates/skills/planning-with-files/examples.md +0 -202
  855. package/templates/skills/planning-with-files/reference.md +0 -110
  856. package/templates/skills/project-index/SKILL.md +0 -97
  857. package/templates/skills/project-index/scripts/scan-structure.js +0 -417
  858. package/templates/skills/project-index/scripts/scan_structure.py +0 -450
  859. package/templates/skills/readme-improvement/SKILL.md +0 -177
  860. package/templates/skills/skill-share/SKILL.md +0 -80
  861. package/templates/skills/tasks-code-review/SKILL.md +0 -298
  862. package/templates/skills/tasks-documentation/SKILL.md +0 -328
  863. package/templates/skills/tasks-spec-update/SKILL.md +0 -318
  864. package/templates/skills/tasks-test-generation/SKILL.md +0 -433
  865. package/templates/skills/test-generation/SKILL.md +0 -203
  866. package/templates/skills/webapp-testing/LICENSE.txt +0 -202
  867. package/templates/skills/webapp-testing/SKILL.md +0 -96
  868. package/templates/skills/webapp-testing/examples/console_logging.py +0 -35
  869. package/templates/skills/webapp-testing/examples/element_discovery.py +0 -40
  870. package/templates/skills/webapp-testing/examples/static_html_automation.py +0 -33
  871. package/templates/skills/webapp-testing/scripts/with_server.py +0 -106
  872. package/templates/workflows/README.md +0 -241
  873. package/templates/workflows/orchestration-protocol.md +0 -16
  874. /package/templates/{commands → command-archive}/coding-level.md +0 -0
  875. /package/templates/{commands → command-archive}/review/codebase.md +0 -0
  876. /package/templates/{commands → command-archive}/test.md +0 -0
  877. /package/templates/{commands → command-archive}/watzup.md +0 -0
  878. /package/templates/hooks/scout-block/vendor/{ignore.js → ignore.cjs} +0 -0
  879. /package/templates/{workflows → rules}/documentation-management.md +0 -0
  880. /package/templates/skills/{debugging → debug}/references/defense-in-depth.md +0 -0
  881. /package/templates/skills/{debugging → debug}/references/root-cause-tracing.md +0 -0
  882. /package/templates/skills/{debugging → debug}/references/systematic-debugging.md +0 -0
  883. /package/templates/skills/{debugging → debug}/references/verification.md +0 -0
  884. /package/templates/skills/{debugging → debug}/scripts/find-polluter.sh +0 -0
  885. /package/templates/skills/{debugging → debug}/scripts/find-polluter.test.md +0 -0
  886. /package/templates/skills/{planning → plan}/references/solution-design.md +0 -0
@@ -1,482 +1,902 @@
1
1
  # Polar Best Practices
2
2
 
3
- Security, patterns, and monitoring for production Polar integrations.
3
+ Production-proven patterns from real SaaS implementations covering SDK initialization, checkout flows, webhooks, discounts, fee calculations, and error handling.
4
4
 
5
- ## Security
5
+ ## Environment Configuration
6
6
 
7
- ### Credential Management
8
- ```typescript
9
- // Good: Environment variables
10
- const polar = new Polar({
11
- accessToken: process.env.POLAR_ACCESS_TOKEN
12
- });
7
+ ### Required Environment Variables
8
+ ```bash
9
+ # Core API
10
+ POLAR_API_KEY=polar_at_xxx # Access token from Polar Dashboard
11
+ POLAR_ORGANIZATION_ID=org_xxx # Your organization ID
12
+ POLAR_WEBHOOK_SECRET=whsec_xxx # Webhook signature verification
13
13
 
14
- // Bad: Hardcoded
15
- const polar = new Polar({
16
- accessToken: 'polar_live_abc123'
17
- });
14
+ # Product IDs (one per product)
15
+ POLAR_PRODUCT_ENGINEER_ID=prod_xxx
16
+ POLAR_PRODUCT_MARKETING_ID=prod_xxx
17
+ POLAR_PRODUCT_COMBO_ID=prod_xxx
18
+
19
+ # Environment (optional, defaults to production)
20
+ POLAR_ENV=production # 'production' or 'sandbox'
18
21
  ```
19
22
 
20
- ### Webhook Security
23
+ ### Lazy Initialization Pattern
21
24
  ```typescript
22
- // Always verify signatures
23
- app.post('/webhook/polar', async (req, res) => {
24
- try {
25
- const event = validateEvent(req.body, req.headers, secret);
26
- // Process verified event
27
- } catch (error) {
28
- return res.status(400).json({ error: 'Invalid signature' });
29
- }
25
+ // lib/polar.ts - Defer validation until first access
26
+ import { Polar } from '@polar-sh/sdk';
27
+ import { z } from 'zod';
28
+
29
+ const polarEnvSchema = z.object({
30
+ POLAR_API_KEY: z.string().min(1),
31
+ POLAR_ORGANIZATION_ID: z.string().min(1),
32
+ POLAR_WEBHOOK_SECRET: z.string().min(1),
30
33
  });
31
- ```
32
34
 
33
- ### Never Expose Tokens Client-Side
34
- ```typescript
35
- // ✓ Good: Server-side API route
36
- export async function POST(req: Request) {
37
- const polar = new Polar({ accessToken: process.env.POLAR_ACCESS_TOKEN });
38
- const checkout = await polar.checkouts.create(...);
39
- return Response.json({ url: checkout.url });
35
+ let _polar: Polar | null = null;
36
+ let _env: z.infer<typeof polarEnvSchema> | null = null;
37
+
38
+ export function getPolarEnv() {
39
+ if (!_env) {
40
+ _env = polarEnvSchema.parse({
41
+ POLAR_API_KEY: process.env.POLAR_API_KEY,
42
+ POLAR_ORGANIZATION_ID: process.env.POLAR_ORGANIZATION_ID,
43
+ POLAR_WEBHOOK_SECRET: process.env.POLAR_WEBHOOK_SECRET,
44
+ });
45
+ }
46
+ return _env;
40
47
  }
41
48
 
42
- // Bad: Client-side
43
- const polar = new Polar({ accessToken: 'visible_in_browser' });
49
+ export function getPolar() {
50
+ if (!_polar) {
51
+ const env = getPolarEnv();
52
+ const polarEnv = process.env.POLAR_ENV || 'production';
53
+ _polar = new Polar({
54
+ accessToken: env.POLAR_API_KEY,
55
+ server: polarEnv as 'production' | 'sandbox',
56
+ });
57
+ }
58
+ return _polar;
59
+ }
44
60
  ```
45
61
 
46
- ## Implementation Patterns
62
+ **Key Benefit:** Module imports succeed at build time; validation deferred until runtime when env vars are available.
63
+
64
+ ## Checkout Flow Implementation
47
65
 
48
- ### Complete Payment Flow
66
+ ### Standard Checkout API
49
67
  ```typescript
50
- class PaymentService {
51
- async createCheckout(userId, priceId) {
52
- // 1. Create checkout session
53
- const session = await polar.checkouts.create({
54
- product_price_id: priceId,
55
- external_customer_id: userId,
56
- success_url: `${baseUrl}/success?checkout_id={CHECKOUT_ID}`,
57
- metadata: {
58
- user_id: userId,
59
- source: 'web'
60
- }
61
- });
68
+ // app/api/checkout/polar/route.ts
69
+ import { NextResponse } from 'next/server';
70
+ import { z } from 'zod';
71
+ import { getPolar, getPolarEnv } from '@/lib/polar';
72
+
73
+ const checkoutSchema = z.object({
74
+ email: z.string().email(),
75
+ name: z.string().optional(),
76
+ productType: z.enum(['engineer_kit', 'marketing_kit', 'combo']),
77
+ githubUsername: z.string().min(1),
78
+ referralCode: z.string().regex(/^[A-Z0-9]{8}$/).optional(),
79
+ couponCode: z.string().optional(),
80
+ });
62
81
 
63
- // 2. Log checkout creation
64
- await db.checkouts.insert({
65
- checkout_id: session.id,
66
- user_id: userId,
67
- status: 'pending'
68
- });
82
+ // Pricing in cents
83
+ const PRODUCT_PRICES = {
84
+ engineer_kit: 9900, // $99
85
+ marketing_kit: 9900, // $99
86
+ combo: 14900, // $149
87
+ } as const;
69
88
 
70
- return session.url;
71
- }
89
+ export async function POST(request: Request) {
90
+ try {
91
+ const body = await request.json();
92
+ const data = checkoutSchema.parse(body);
93
+ const polar = getPolar();
94
+ const env = getPolarEnv();
95
+
96
+ // 1. Normalize email
97
+ const normalizedEmail = data.email.toLowerCase().trim();
98
+
99
+ // 2. Validate GitHub username against GitHub API
100
+ const githubValid = await validateGitHubUsername(data.githubUsername);
101
+ if (!githubValid) {
102
+ return NextResponse.json(
103
+ { error: 'Invalid GitHub username' },
104
+ { status: 400 }
105
+ );
106
+ }
72
107
 
73
- async handleWebhook(event) {
74
- switch (event.type) {
75
- case 'order.paid':
76
- await this.fulfillOrder(event.data);
77
- break;
108
+ // 3. Get product ID and base price
109
+ const productId = getProductId(data.productType);
110
+ const originalAmount = PRODUCT_PRICES[data.productType];
111
+
112
+ // 4. Apply discount hierarchy (order matters!)
113
+ let finalAmount = originalAmount;
114
+ let polarDiscountId: string | undefined;
115
+ let discountMetadata: Record<string, any> = {};
116
+
117
+ // Step A: Apply coupon FIRST (if provided)
118
+ if (data.couponCode) {
119
+ const couponResult = await validateAndApplyCoupon(
120
+ data.couponCode,
121
+ productId,
122
+ originalAmount
123
+ );
124
+ if (couponResult.valid) {
125
+ finalAmount = originalAmount - couponResult.discountAmount;
126
+ discountMetadata.couponCode = data.couponCode;
127
+ discountMetadata.couponDiscountAmount = couponResult.discountAmount;
128
+ }
129
+ }
78
130
 
79
- case 'subscription.active':
80
- await this.grantAccess(event.data.customer.external_id);
81
- break;
131
+ // Step B: Apply referral discount SECOND (on post-coupon price)
132
+ if (data.referralCode) {
133
+ const referralResult = await calculateReferralDiscount(
134
+ data.referralCode,
135
+ finalAmount, // Applied to post-coupon amount
136
+ normalizedEmail
137
+ );
138
+
139
+ if (referralResult.valid && referralResult.discountAmount > 0) {
140
+ // Validate discount calculation
141
+ if (referralResult.discountAmount <= 0) {
142
+ return NextResponse.json(
143
+ { error: 'Invalid discount calculation - contact support' },
144
+ { status: 400 }
145
+ );
146
+ }
147
+
148
+ finalAmount -= referralResult.discountAmount;
149
+ discountMetadata.referralCode = data.referralCode;
150
+ discountMetadata.referralDiscountAmount = referralResult.discountAmount;
151
+ discountMetadata.referrerId = referralResult.referrerId;
152
+ }
153
+ }
82
154
 
83
- case 'subscription.revoked':
84
- await this.revokeAccess(event.data.customer.external_id);
85
- break;
155
+ // 5. Create order record BEFORE Polar checkout
156
+ const order = await db.insert(orders).values({
157
+ id: crypto.randomUUID(),
158
+ email: normalizedEmail,
159
+ productType: data.productType,
160
+ amount: finalAmount,
161
+ originalAmount,
162
+ currency: 'USD',
163
+ status: 'pending',
164
+ paymentProvider: 'polar',
165
+ referredBy: discountMetadata.referrerId,
166
+ discountAmount: originalAmount - finalAmount,
167
+ metadata: JSON.stringify({
168
+ ...discountMetadata,
169
+ githubUsername: data.githubUsername,
170
+ }),
171
+ }).returning();
172
+
173
+ // 6. Create dynamic Polar discount (if referral applied)
174
+ if (discountMetadata.referrerId && discountMetadata.referralDiscountAmount > 0) {
175
+ try {
176
+ const discount = await polar.discounts.create({
177
+ type: 'fixed',
178
+ name: `referral-${order[0].id.slice(0, 8)}`,
179
+ amount: discountMetadata.referralDiscountAmount,
180
+ currency: 'usd',
181
+ duration: 'once',
182
+ maxRedemptions: 1,
183
+ products: [productId],
184
+ metadata: {
185
+ orderId: order[0].id,
186
+ type: 'referral',
187
+ referrerId: discountMetadata.referrerId,
188
+ },
189
+ });
190
+ polarDiscountId = discount.id;
191
+ } catch (error) {
192
+ // FAIL-OPEN: Proceed with full price, flag for manual refund
193
+ console.error('⚠️ Failed to create Polar discount:', error);
194
+ }
86
195
  }
87
- }
88
196
 
89
- async fulfillOrder(order) {
90
- // Verify not already fulfilled
91
- const existing = await db.orders.findOne({ polar_id: order.id });
92
- if (existing) return;
93
-
94
- // Save order
95
- await db.orders.insert({
96
- polar_id: order.id,
97
- user_id: order.customer.external_id,
98
- amount: order.amount,
99
- status: 'paid'
197
+ // 7. Create Polar checkout session
198
+ const checkout = await polar.checkouts.create({
199
+ productPriceId: productId,
200
+ customerEmail: normalizedEmail,
201
+ successUrl: `${process.env.NEXT_PUBLIC_URL}/checkout/success?orderId=${order[0].id}`,
202
+ discountId: polarDiscountId,
203
+ allowDiscountCodes: !polarDiscountId, // Prevent stacking
204
+ metadata: {
205
+ orderId: order[0].id,
206
+ githubUsername: data.githubUsername,
207
+ referredBy: discountMetadata.referrerId,
208
+ },
100
209
  });
101
210
 
102
- // Grant access
103
- await this.grantAccess(order.customer.external_id);
211
+ return NextResponse.json({
212
+ checkoutUrl: checkout.url,
213
+ orderId: order[0].id,
214
+ });
104
215
 
105
- // Send confirmation
106
- await this.sendConfirmation(order);
216
+ } catch (error) {
217
+ if (error instanceof z.ZodError) {
218
+ return NextResponse.json({ error: error.errors }, { status: 400 });
219
+ }
220
+ console.error('Checkout error:', error);
221
+ return NextResponse.json(
222
+ { error: 'Failed to create checkout' },
223
+ { status: 500 }
224
+ );
107
225
  }
108
226
  }
109
227
  ```
110
228
 
111
- ### Customer Portal Integration
112
- ```typescript
113
- app.get('/portal', async (req, res) => {
114
- const session = await polar.customerSessions.create({
115
- external_customer_id: req.user.id
116
- });
229
+ ### Discount Application Order (Critical)
230
+ ```
231
+ 1. Original price (e.g., $99)
232
+ 2. Apply coupon discount FIRST → post-coupon price (e.g., $79)
233
+ 3. Apply referral discount SECOND → final price (e.g., $63.20)
117
234
 
118
- res.redirect(session.url);
119
- });
235
+ Never apply referral to original price if coupon was used!
120
236
  ```
121
237
 
122
- ### Usage-Based Tracking
238
+ ## Webhook Handling
239
+
240
+ ### Signature Verification
123
241
  ```typescript
124
- class UsageTracker {
125
- async trackUsage(userId, eventName, properties) {
126
- // Track in your system
127
- await db.usage.insert({
128
- user_id: userId,
129
- event_name: eventName,
130
- properties: properties,
131
- timestamp: new Date()
132
- });
242
+ // app/api/webhooks/polar/route.ts
243
+ import { validateEvent } from '@polar-sh/sdk/webhooks';
244
+ import { NextResponse } from 'next/server';
133
245
 
134
- // Send to Polar for billing
135
- await polar.events.create({
136
- external_customer_id: userId,
137
- event_name: eventName,
138
- properties: properties
139
- });
246
+ export async function POST(request: Request) {
247
+ const payload = await request.text();
248
+ const headers = Object.fromEntries(request.headers);
249
+ const secret = process.env.POLAR_WEBHOOK_SECRET!;
250
+
251
+ let webhookEvent;
252
+ try {
253
+ webhookEvent = validateEvent(payload, headers, secret);
254
+ } catch (error) {
255
+ console.error('Invalid webhook signature:', error);
256
+ return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
140
257
  }
141
258
 
142
- async getBalance(userId, meterId) {
143
- const balance = await polar.meters.getBalance({
144
- external_customer_id: userId,
145
- meter_id: meterId
146
- });
259
+ // Extract event ID for idempotency
260
+ const parsedPayload = JSON.parse(payload);
261
+ const eventId = parsedPayload.id || `${parsedPayload.type}-${Date.now()}`;
147
262
 
148
- return balance.amount;
263
+ // Check for duplicate processing
264
+ const existingEvent = await db.select()
265
+ .from(webhookEvents)
266
+ .where(eq(webhookEvents.eventId, eventId))
267
+ .limit(1);
268
+
269
+ if (existingEvent.length > 0) {
270
+ console.log(`Duplicate webhook ignored: ${eventId}`);
271
+ return NextResponse.json({ received: true });
149
272
  }
150
273
 
151
- async showUsage(userId) {
152
- // Show customer their usage
153
- const usage = await db.usage.aggregate({
154
- user_id: userId,
155
- date: { $gte: startOfMonth() }
156
- });
274
+ // Record event BEFORE processing (idempotency)
275
+ await db.insert(webhookEvents).values({
276
+ id: crypto.randomUUID(),
277
+ provider: 'polar',
278
+ eventType: webhookEvent.type,
279
+ eventId,
280
+ payload,
281
+ processed: false,
282
+ });
157
283
 
158
- const balance = await this.getBalance(userId, meterId);
284
+ try {
285
+ await handleWebhookEvent(webhookEvent);
286
+
287
+ // Mark as processed
288
+ await db.update(webhookEvents)
289
+ .set({ processed: true, processedAt: new Date() })
290
+ .where(eq(webhookEvents.eventId, eventId));
159
291
 
160
- return { usage, remaining: balance };
292
+ } catch (error) {
293
+ // Log error but don't fail the webhook
294
+ await db.update(webhookEvents)
295
+ .set({
296
+ processed: true,
297
+ processedAt: new Date(),
298
+ error: error instanceof Error ? error.message : 'Unknown error',
299
+ })
300
+ .where(eq(webhookEvents.eventId, eventId));
161
301
  }
302
+
303
+ return NextResponse.json({ received: true });
162
304
  }
163
305
  ```
164
306
 
165
- ## Data Management
166
-
167
- ### External ID Strategy
307
+ ### Event Handlers
168
308
  ```typescript
169
- // Good: Set external_id consistently
170
- await polar.checkouts.create({
171
- external_customer_id: user.id, // Your user ID
172
- // ...
173
- });
309
+ async function handleWebhookEvent(event: WebhookEvent) {
310
+ switch (event.type) {
311
+ case 'checkout.created':
312
+ // Order already exists from API - just log
313
+ console.log(`Checkout created: ${event.data.id}`);
314
+ break;
315
+
316
+ case 'checkout.updated':
317
+ await handleCheckoutUpdated(event.data);
318
+ break;
319
+
320
+ case 'order.created':
321
+ await handleOrderCreated(event.data);
322
+ break;
323
+
324
+ case 'order.refunded':
325
+ await handleOrderRefunded(event.data);
326
+ break;
327
+
328
+ default:
329
+ console.log(`Unhandled event type: ${event.type}`);
330
+ }
331
+ }
174
332
 
175
- // Query by external_id
176
- const customer = await polar.customers.get({
177
- external_id: user.id
178
- });
333
+ async function handleOrderCreated(order: PolarOrder) {
334
+ const orderId = order.metadata?.orderId;
335
+ if (!orderId) {
336
+ console.error('Order missing orderId in metadata');
337
+ return;
338
+ }
179
339
 
180
- // Bad: Storing Polar customer IDs
181
- // Don't store polar_customer_id in your database
182
- // Use external_id for all lookups
183
- ```
340
+ const dbOrder = await db.select()
341
+ .from(orders)
342
+ .where(eq(orders.id, orderId))
343
+ .limit(1);
184
344
 
185
- ### Metadata Best Practices
186
- ```typescript
187
- // Use metadata for:
188
- {
189
- metadata: {
190
- user_id: '123', // Internal ID
191
- source: 'web', // Traffic source
192
- campaign: 'summer_sale', // Marketing campaign
193
- referrer: 'partner_123' // Referral tracking
345
+ if (!dbOrder[0]) {
346
+ console.error(`Order not found: ${orderId}`);
347
+ return;
348
+ }
349
+
350
+ // 1. Update order status
351
+ await db.update(orders)
352
+ .set({
353
+ status: 'completed',
354
+ paymentId: order.id,
355
+ updatedAt: new Date(),
356
+ })
357
+ .where(eq(orders.id, orderId));
358
+
359
+ // 2. Create license (non-blocking)
360
+ try {
361
+ await createLicense(dbOrder[0]);
362
+ } catch (error) {
363
+ console.error('Failed to create license:', error);
364
+ }
365
+
366
+ // 3. Send confirmation email (non-blocking)
367
+ try {
368
+ await sendOrderConfirmation(dbOrder[0], order);
369
+ } catch (error) {
370
+ console.error('Failed to send confirmation:', error);
371
+ }
372
+
373
+ // 4. Create referral commission (non-blocking)
374
+ if (dbOrder[0].referredBy) {
375
+ try {
376
+ await createCommission(dbOrder[0]);
377
+ } catch (error) {
378
+ console.error('Failed to create commission:', error);
379
+ }
380
+ }
381
+
382
+ // 5. Grant GitHub access (non-blocking)
383
+ try {
384
+ const metadata = JSON.parse(dbOrder[0].metadata || '{}');
385
+ await inviteToGitHub(metadata.githubUsername, dbOrder[0].productType);
386
+ } catch (error) {
387
+ console.error('Failed to invite to GitHub:', error);
194
388
  }
195
- }
196
389
 
197
- // Don't store sensitive data in metadata
198
- // ✗ Bad: PII, passwords, payment details
390
+ // 6. Send Discord notification (non-blocking)
391
+ try {
392
+ await sendSalesNotification(dbOrder[0]);
393
+ } catch (error) {
394
+ console.error('Failed to send Discord notification:', error);
395
+ }
396
+ }
199
397
  ```
200
398
 
201
- ### Database Sync
399
+ ### Status Mapping
202
400
  ```typescript
203
- async function syncSubscription(subscription) {
204
- await db.subscriptions.upsert({
205
- where: { polar_id: subscription.id },
206
- update: {
207
- status: subscription.status,
208
- current_period_end: subscription.current_period_end,
209
- cancel_at_period_end: subscription.cancel_at_period_end
210
- },
211
- create: {
212
- polar_id: subscription.id,
213
- user_id: subscription.customer.external_id,
214
- status: subscription.status,
215
- // ... other fields
216
- }
217
- });
401
+ function mapPolarStatusToAppStatus(polarStatus: string): string | null {
402
+ switch (polarStatus) {
403
+ case 'succeeded':
404
+ return 'completed';
405
+ case 'failed':
406
+ case 'expired':
407
+ return 'failed';
408
+ case 'open':
409
+ case 'confirmed':
410
+ return null; // Don't update - still pending
411
+ default:
412
+ return null;
413
+ }
218
414
  }
219
415
  ```
220
416
 
221
- ## Performance Optimization
417
+ ## Fee Calculation
222
418
 
223
- ### Caching
419
+ ### Platform Fee Structure (Dec 2025)
224
420
  ```typescript
225
- // Cache products list
226
- const productCache = new Map();
227
-
228
- async function getProducts(orgId) {
229
- if (!productCache.has(orgId)) {
230
- const products = await polar.products.list({
231
- organization_id: orgId,
232
- is_archived: false
233
- });
234
- productCache.set(orgId, products);
235
- setTimeout(() => productCache.delete(orgId), 300000); // 5 min
421
+ // lib/polar-fees.ts
422
+ interface PolarFeeConfig {
423
+ basePercentage: number; // 4%
424
+ baseFlatCents: number; // $0.40 per transaction
425
+ internationalSurcharge: number; // +1.5% for non-US cards
426
+ subscriptionSurcharge: number; // +0.5% (not for one-time)
427
+ }
428
+
429
+ const POLAR_FEES: PolarFeeConfig = {
430
+ basePercentage: 0.04,
431
+ baseFlatCents: 40,
432
+ internationalSurcharge: 0.015,
433
+ subscriptionSurcharge: 0.005,
434
+ };
435
+
436
+ export function calculatePolarFees(
437
+ amountCents: number,
438
+ isInternational: boolean = true, // Conservative default
439
+ isSubscription: boolean = false
440
+ ): {
441
+ baseFee: number;
442
+ internationalFee: number;
443
+ subscriptionFee: number;
444
+ totalFee: number;
445
+ netRevenue: number;
446
+ } {
447
+ // Handle zero/negative
448
+ if (amountCents <= 0) {
449
+ return { baseFee: 0, internationalFee: 0, subscriptionFee: 0, totalFee: 0, netRevenue: 0 };
450
+ }
451
+
452
+ const baseFee = Math.round(amountCents * POLAR_FEES.basePercentage + POLAR_FEES.baseFlatCents);
453
+ const internationalFee = isInternational
454
+ ? Math.round(amountCents * POLAR_FEES.internationalSurcharge)
455
+ : 0;
456
+ const subscriptionFee = isSubscription
457
+ ? Math.round(amountCents * POLAR_FEES.subscriptionSurcharge)
458
+ : 0;
459
+
460
+ const totalFee = baseFee + internationalFee + subscriptionFee;
461
+ const netRevenue = amountCents - totalFee;
462
+
463
+ return { baseFee, internationalFee, subscriptionFee, totalFee, netRevenue };
464
+ }
465
+
466
+ // Aggregate fees preserve per-transaction flat fees
467
+ export function calculateAggregatePolarFees(transactionAmounts: number[]): {
468
+ totalFees: number;
469
+ totalNetRevenue: number;
470
+ } {
471
+ let totalFees = 0;
472
+ let totalNetRevenue = 0;
473
+
474
+ for (const amount of transactionAmounts) {
475
+ const { totalFee, netRevenue } = calculatePolarFees(amount);
476
+ totalFees += totalFee;
477
+ totalNetRevenue += netRevenue;
236
478
  }
237
479
 
238
- return productCache.get(orgId);
480
+ return { totalFees, totalNetRevenue };
239
481
  }
240
482
  ```
241
483
 
242
- ### Batch Operations
484
+ ## Discount Management
485
+
486
+ ### Discount Validation with Timeout
243
487
  ```typescript
244
- // Batch event ingestion
245
- const eventQueue = [];
488
+ // lib/polar-discounts.ts
489
+ const VALIDATION_TIMEOUT_MS = 15000;
490
+
491
+ export async function validateDiscount(
492
+ code: string,
493
+ productId: string
494
+ ): Promise<{ valid: boolean; discount?: PolarDiscount; reason?: string }> {
495
+ const sanitizedCode = code.trim().toUpperCase();
496
+ if (!sanitizedCode) {
497
+ return { valid: false, reason: 'Code cannot be empty' };
498
+ }
499
+
500
+ const polar = getPolar();
501
+ const env = getPolarEnv();
502
+
503
+ try {
504
+ // Race against timeout
505
+ const timeoutPromise = new Promise<never>((_, reject) => {
506
+ setTimeout(() => reject(new Error('Validation timeout')), VALIDATION_TIMEOUT_MS);
507
+ });
508
+
509
+ const searchPromise = polar.discounts.list({
510
+ organizationId: env.POLAR_ORGANIZATION_ID,
511
+ query: sanitizedCode,
512
+ limit: 100,
513
+ });
246
514
 
247
- async function trackEvent(userId, event) {
248
- eventQueue.push({ external_customer_id: userId, ...event });
515
+ const result = await Promise.race([searchPromise, timeoutPromise]);
249
516
 
250
- if (eventQueue.length >= 100) {
251
- await flushEvents();
517
+ // Find exact match
518
+ const discount = result.items.find(d =>
519
+ d.code?.toUpperCase() === sanitizedCode
520
+ );
521
+
522
+ if (!discount) {
523
+ return { valid: false, reason: 'Code not found' };
524
+ }
525
+
526
+ // Check eligibility
527
+ const now = new Date();
528
+ if (discount.startsAt && now < new Date(discount.startsAt)) {
529
+ return { valid: false, reason: `Code starts on ${discount.startsAt}` };
530
+ }
531
+ if (discount.endsAt && now > new Date(discount.endsAt)) {
532
+ return { valid: false, reason: 'Code has expired' };
533
+ }
534
+ if (discount.maxRedemptions && discount.redemptionsCount >= discount.maxRedemptions) {
535
+ return { valid: false, reason: 'Code redemption limit reached' };
536
+ }
537
+ if (!discount.products?.some(p => p.id === productId)) {
538
+ return { valid: false, reason: 'Code not valid for this product' };
539
+ }
540
+
541
+ return { valid: true, discount };
542
+
543
+ } catch (error) {
544
+ console.error('Discount validation error:', error);
545
+ return { valid: false, reason: 'Validation failed - please try again' };
252
546
  }
253
547
  }
548
+ ```
254
549
 
255
- async function flushEvents() {
256
- const batch = eventQueue.splice(0, 100);
257
- await Promise.all(
258
- batch.map(event => polar.events.create(event))
259
- );
550
+ ### VND Conversion for Discounts
551
+ ```typescript
552
+ const VND_TO_USD_RATE = 25000; // 1 USD = 25,000 VND
553
+
554
+ export function convertDiscountToVND(discount: PolarDiscount, amountVND: number): number {
555
+ if (discount.type === 'percentage') {
556
+ // Basis points: 1000 = 10%, 10000 = 100%
557
+ const percentage = discount.basisPoints / 10000;
558
+ return Math.round(amountVND * percentage);
559
+ } else {
560
+ // Fixed amount in USD cents → VND
561
+ const amountUSD = discount.amount / 100;
562
+ return Math.round(amountUSD * VND_TO_USD_RATE);
563
+ }
260
564
  }
261
565
  ```
262
566
 
263
- ### Rate Limit Handling
567
+ ### Syncing SePay Redemptions to Polar
264
568
  ```typescript
265
- async function callWithRetry(fn, maxRetries = 3) {
266
- let attempt = 0;
569
+ // lib/polar-discount-sync.ts
570
+ // When SePay payment completes, decrement Polar discount redemptions
571
+
572
+ export async function syncPolarDiscountRedemption(
573
+ orderId: string,
574
+ discountId: string,
575
+ discountCode: string
576
+ ): Promise<{ success: boolean; action: string }> {
577
+ const order = await db.select().from(orders).where(eq(orders.id, orderId)).limit(1);
578
+ if (!order[0]) {
579
+ return { success: false, action: 'order_not_found' };
580
+ }
267
581
 
268
- while (attempt < maxRetries) {
269
- try {
270
- return await fn();
271
- } catch (error) {
272
- if (error.statusCode === 429) {
273
- const retryAfter = error.headers?.['retry-after'] || 1;
274
- await sleep(retryAfter * 1000);
275
- attempt++;
276
- } else {
277
- throw error;
278
- }
582
+ // Idempotency check
583
+ const metadata = order[0].metadata ? JSON.parse(order[0].metadata) : {};
584
+ if (metadata.polarDiscountSynced) {
585
+ return { success: true, action: 'already_synced' };
586
+ }
587
+
588
+ const polar = getPolar();
589
+
590
+ try {
591
+ const discount = await polar.discounts.get({ id: discountId });
592
+
593
+ if (discount.maxRedemptions === null || discount.maxRedemptions === undefined) {
594
+ return { success: true, action: 'skipped_unlimited' };
595
+ }
596
+
597
+ const currentMax = discount.maxRedemptions;
598
+
599
+ if (currentMax <= 1) {
600
+ await polar.discounts.delete({ id: discountId });
601
+ await markOrderSynced(orderId, 'deleted');
602
+ } else {
603
+ await polar.discounts.update({
604
+ id: discountId,
605
+ discountUpdate: { maxRedemptions: currentMax - 1 },
606
+ });
607
+ await markOrderSynced(orderId, 'decremented');
608
+ }
609
+
610
+ return { success: true, action: currentMax <= 1 ? 'deleted' : 'decremented' };
611
+
612
+ } catch (error: any) {
613
+ if (error.statusCode === 404) {
614
+ // Already deleted - treat as success
615
+ await markOrderSynced(orderId, 'already_deleted');
616
+ return { success: true, action: 'already_deleted' };
279
617
  }
618
+ throw error;
280
619
  }
281
620
  }
282
- ```
283
621
 
284
- ## Monitoring & Logging
622
+ async function markOrderSynced(orderId: string, action: string) {
623
+ const order = await db.select().from(orders).where(eq(orders.id, orderId)).limit(1);
624
+ const metadata = order[0].metadata ? JSON.parse(order[0].metadata) : {};
285
625
 
286
- ### Essential Metrics
287
- ```typescript
288
- const metrics = {
289
- checkouts_created: counter('polar_checkouts_created_total'),
290
- orders_completed: counter('polar_orders_completed_total'),
291
- subscriptions_active: gauge('polar_subscriptions_active'),
292
- revenue: counter('polar_revenue_total'),
293
- webhook_processing_time: histogram('polar_webhook_duration_seconds')
294
- };
626
+ metadata.polarDiscountSynced = true;
627
+ metadata.polarDiscountSyncAction = action;
628
+ metadata.polarDiscountSyncedAt = new Date().toISOString();
295
629
 
296
- // Track metrics
297
- metrics.checkouts_created.inc({ product: productId });
298
- metrics.orders_completed.inc({ amount: order.amount });
299
- metrics.revenue.inc(order.amount);
630
+ await db.update(orders)
631
+ .set({ metadata: JSON.stringify(metadata) })
632
+ .where(eq(orders.id, orderId));
633
+ }
300
634
  ```
301
635
 
302
- ### Structured Logging
636
+ ## Revenue Tracking with Caching
637
+
303
638
  ```typescript
304
- logger.info('Checkout created', {
305
- checkout_id: session.id,
306
- user_id: userId,
307
- product_id: priceId,
308
- amount: amount
309
- });
639
+ // lib/polar.ts
640
+ const REVENUE_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
641
+
642
+ let revenueCache: {
643
+ data: { totalRevenueCents: number; orderCount: number } | null;
644
+ timestamp: number;
645
+ } = { data: null, timestamp: 0 };
646
+
647
+ export async function getPolarApiRevenue(): Promise<{
648
+ totalRevenueCents: number;
649
+ orderCount: number;
650
+ fromCache: boolean;
651
+ }> {
652
+ const now = Date.now();
653
+
654
+ // Return cache if valid
655
+ if (revenueCache.data && now - revenueCache.timestamp < REVENUE_CACHE_TTL_MS) {
656
+ return { ...revenueCache.data, fromCache: true };
657
+ }
310
658
 
311
- logger.info('Order paid', {
312
- order_id: order.id,
313
- user_id: order.customer.external_id,
314
- amount: order.amount,
315
- billing_reason: order.billing_reason
316
- });
659
+ const polar = getPolar();
660
+ const env = getPolarEnv();
317
661
 
318
- logger.error('Webhook processing failed', {
319
- event_type: event.type,
320
- error: error.message,
321
- stack: error.stack
322
- });
323
- ```
662
+ try {
663
+ let totalRevenueCents = 0;
664
+ let orderCount = 0;
665
+ let page = 1;
666
+ const maxPages = 100; // Safety limit
667
+
668
+ while (page <= maxPages) {
669
+ const response = await polar.orders.list({
670
+ organizationId: env.POLAR_ORGANIZATION_ID,
671
+ page,
672
+ limit: 100,
673
+ });
674
+
675
+ for (const order of response.items) {
676
+ if (order.status === 'succeeded') {
677
+ totalRevenueCents += order.netAmount; // After discounts, before tax
678
+ orderCount++;
679
+ }
680
+ }
324
681
 
325
- ### Alerting
326
- ```typescript
327
- // Alert on failed webhooks
328
- if (webhookFailures > threshold) {
329
- alert.send({
330
- severity: 'high',
331
- message: 'Polar webhook failures exceed threshold',
332
- details: { failures: webhookFailures, threshold }
333
- });
334
- }
682
+ if (!response.pagination.hasMore) break;
683
+ page++;
684
+ }
335
685
 
336
- // Alert on subscription churn
337
- if (churnRate > 0.05) { // 5%
338
- alert.send({
339
- severity: 'medium',
340
- message: 'Subscription churn rate elevated',
341
- details: { churnRate, period: 'month' }
342
- });
686
+ revenueCache = { data: { totalRevenueCents, orderCount }, timestamp: now };
687
+ return { totalRevenueCents, orderCount, fromCache: false };
688
+
689
+ } catch (error) {
690
+ // Return stale cache on error
691
+ if (revenueCache.data) {
692
+ console.warn('Using stale revenue cache due to API error');
693
+ return { ...revenueCache.data, fromCache: true };
694
+ }
695
+ throw error;
696
+ }
343
697
  }
344
698
  ```
345
699
 
346
- ## Testing Strategy
700
+ ## Error Handling Patterns
347
701
 
348
- ### Sandbox Testing
702
+ ### Fail-Open for Non-Critical Operations
349
703
  ```typescript
350
- // Use sandbox for development
351
- const polar = new Polar({
352
- accessToken: process.env.POLAR_SANDBOX_TOKEN,
353
- server: "sandbox"
354
- });
355
-
356
- // Test scenarios:
357
- // 1. Successful purchase
358
- // 2. Failed payment
359
- // 3. Subscription creation
360
- // 4. Subscription upgrade/downgrade
361
- // 5. Subscription cancellation
362
- // 6. Refund processing
363
- // 7. Webhook delivery
364
- // 8. Benefit granting/revoking
704
+ // Discount creation fails → proceed with full price
705
+ try {
706
+ const discount = await createReferralDiscount(productId, amount, referralCode);
707
+ polarDiscountId = discount.id;
708
+ } catch (error) {
709
+ console.error('⚠️ Discount creation failed - proceeding with full price:', error);
710
+ // Flag for manual refund investigation
711
+ await flagOrderForReview(orderId, 'discount_creation_failed');
712
+ }
365
713
  ```
366
714
 
367
- ### Test Cards
715
+ ### Graceful Degradation in Webhooks
368
716
  ```typescript
369
- const testCards = {
370
- success: '4242 4242 4242 4242',
371
- decline: '4000 0000 0000 0002',
372
- authRequired: '4000 0025 0000 3155'
373
- };
717
+ // Non-critical operations don't block order completion
718
+ const operations = [
719
+ { name: 'GitHub invite', fn: () => inviteToGitHub(username, productType) },
720
+ { name: 'Welcome email', fn: () => sendWelcomeEmail(order) },
721
+ { name: 'Discord notification', fn: () => sendSalesNotification(order) },
722
+ { name: 'Tier update', fn: () => updateReferrerTier(referrerId, revenueUsd) },
723
+ ];
724
+
725
+ for (const op of operations) {
726
+ try {
727
+ await op.fn();
728
+ } catch (error) {
729
+ console.error(`❌ ${op.name} failed:`, error);
730
+ // Continue processing - don't block order
731
+ }
732
+ }
374
733
  ```
375
734
 
376
- ### Integration Tests
735
+ ### Rate Limit Handling with Exponential Backoff
377
736
  ```typescript
378
- describe('Polar Integration', () => {
379
- it('creates checkout and processes payment', async () => {
380
- const session = await polar.checkouts.create({...});
381
- expect(session.url).toBeDefined();
737
+ async function callWithRetry<T>(
738
+ fn: () => Promise<T>,
739
+ maxRetries: number = 3
740
+ ): Promise<T> {
741
+ let attempt = 0;
382
742
 
383
- // Simulate successful payment (webhook)
384
- await simulateWebhook('order.paid', { ... });
743
+ while (attempt < maxRetries) {
744
+ try {
745
+ return await fn();
746
+ } catch (error: any) {
747
+ if (error.statusCode === 429) {
748
+ const retryAfter = parseInt(error.headers?.['retry-after'] || '1', 10);
749
+ const delay = retryAfter * 1000 * Math.pow(2, attempt);
750
+ console.log(`Rate limited, retrying in ${delay}ms...`);
751
+ await sleep(delay);
752
+ attempt++;
753
+ } else {
754
+ throw error;
755
+ }
756
+ }
757
+ }
385
758
 
386
- // Verify order fulfilled
387
- const order = await db.orders.findOne({ polar_id: orderId });
388
- expect(order.status).toBe('paid');
389
- });
390
- });
759
+ throw new Error('Max retries exceeded');
760
+ }
391
761
  ```
392
762
 
393
- ## Production Checklist
394
-
395
- - [ ] Environment variables configured
396
- - [ ] Sandbox testing completed
397
- - [ ] Production tokens obtained
398
- - [ ] Webhook endpoint configured and tested
399
- - [ ] Webhook signature verification implemented
400
- - [ ] Error monitoring enabled
401
- - [ ] Logging infrastructure ready
402
- - [ ] Metrics collection configured
403
- - [ ] Alerting rules set up
404
- - [ ] Database indexes created
405
- - [ ] Rate limiting handled
406
- - [ ] Customer portal linked
407
- - [ ] Email notifications configured
408
- - [ ] Refund policy documented
409
- - [ ] Support process established
410
- - [ ] Team trained on platform
411
- - [ ] Documentation updated
412
- - [ ] Compliance requirements met (if applicable)
413
- - [ ] Acceptable use policy reviewed
763
+ ## Database Schema
414
764
 
415
- ## Common Pitfalls
416
-
417
- ### 1. Not Verifying Webhooks
765
+ ### Orders Table
418
766
  ```typescript
419
- // ✗ Bad: Trusting webhook data without verification
420
- app.post('/webhook/polar', async (req, res) => {
421
- await handleEvent(req.body); // Vulnerable!
422
- });
423
-
424
- // ✓ Good: Always verify
425
- app.post('/webhook/polar', async (req, res) => {
426
- const event = validateEvent(req.body, req.headers, secret);
427
- await handleEvent(event);
767
+ // db/schema/orders.ts
768
+ export const orders = pgTable('orders', {
769
+ id: uuid('id').primaryKey().defaultRandom(),
770
+ userId: uuid('user_id').references(() => users.id),
771
+ email: text('email').notNull(),
772
+ productType: text('product_type').notNull(),
773
+ amount: integer('amount').notNull(), // Final amount in cents
774
+ originalAmount: integer('original_amount'), // Before discounts
775
+ currency: text('currency').default('USD'),
776
+ status: text('status').default('pending'), // pending, completed, failed, refunded
777
+ paymentProvider: text('payment_provider').notNull(), // 'polar' or 'sepay'
778
+ paymentId: text('payment_id'), // External payment ID
779
+ referredBy: uuid('referred_by').references(() => users.id),
780
+ discountAmount: integer('discount_amount').default(0),
781
+ discountRate: numeric('discount_rate', { precision: 5, scale: 2 }),
782
+ metadata: text('metadata'), // JSON with audit trail
783
+ createdAt: timestamp('created_at').defaultNow(),
784
+ updatedAt: timestamp('updated_at').defaultNow(),
428
785
  });
429
786
  ```
430
787
 
431
- ### 2. Trusting Only Success Redirects
788
+ ### Webhook Events Table (Idempotency)
432
789
  ```typescript
433
- // Bad: Fulfilling based on redirect
434
- app.get('/success', async (req, res) => {
435
- await fulfillOrder(req.query.checkout_id); // Insecure!
436
- });
437
-
438
- // ✓ Good: Verify via API or wait for webhook
439
- app.get('/success', async (req, res) => {
440
- const checkout = await polar.checkouts.get(req.query.checkout_id);
441
- if (checkout.status === 'confirmed') {
442
- // Safe to show success page
443
- }
444
- // Still wait for webhook for fulfillment
790
+ export const webhookEvents = pgTable('webhook_events', {
791
+ id: uuid('id').primaryKey().defaultRandom(),
792
+ provider: text('provider').notNull(), // 'polar' or 'sepay'
793
+ eventType: text('event_type').notNull(),
794
+ eventId: text('event_id').notNull().unique(), // Idempotency key
795
+ payload: text('payload').notNull(),
796
+ processed: boolean('processed').default(false),
797
+ processedAt: timestamp('processed_at'),
798
+ error: text('error'),
799
+ createdAt: timestamp('created_at').defaultNow(),
445
800
  });
446
801
  ```
447
802
 
448
- ### 3. Not Handling Duplicate Webhooks
449
- ```typescript
450
- // ✓ Good: Idempotent webhook handling
451
- async function handleOrderPaid(order) {
452
- const existing = await db.orders.findOne({ polar_id: order.id });
453
- if (existing) {
454
- console.log('Order already processed');
455
- return;
456
- }
803
+ ## Metadata Best Practices
457
804
 
458
- await fulfillOrder(order);
459
- }
805
+ ### Comprehensive Audit Trail
806
+ ```typescript
807
+ // Store everything needed for debugging and reconciliation
808
+ metadata: JSON.stringify({
809
+ // Pricing history
810
+ originalAmount: 9900,
811
+
812
+ // Coupon tracking
813
+ couponCode: 'LAUNCH20',
814
+ couponDiscountAmount: 1980,
815
+
816
+ // Referral tracking
817
+ referralCode: 'ABC12345',
818
+ referralDiscountAmount: 1584,
819
+ referrerId: 'user-uuid',
820
+
821
+ // Customer context
822
+ githubUsername: 'customer',
823
+
824
+ // Polar integration
825
+ polarDiscountId: 'disc_xxx',
826
+ polarDiscountSynced: true,
827
+ polarDiscountSyncAction: 'decremented',
828
+ polarDiscountSyncedAt: '2025-01-15T10:30:00Z',
829
+
830
+ // Team context (if applicable)
831
+ isTeamPurchase: false,
832
+ teamId: null,
833
+ quantity: 1,
834
+ })
460
835
  ```
461
836
 
462
- ### 4. Hardcoding External IDs
837
+ ## Testing
838
+
839
+ ### Unit Tests for Fee Calculation
463
840
  ```typescript
464
- // ✗ Bad: Using Polar customer IDs
465
- const customerId = 'cust_abc123';
841
+ // __tests__/lib/polar-fees.test.ts
842
+ describe('calculatePolarFees', () => {
843
+ it('handles zero amount', () => {
844
+ const result = calculatePolarFees(0);
845
+ expect(result.totalFee).toBe(0);
846
+ expect(result.netRevenue).toBe(0);
847
+ });
466
848
 
467
- // Good: Using your user IDs
468
- const userId = user.id;
469
- await polar.checkouts.create({
470
- external_customer_id: userId
849
+ it('calculates international one-time correctly', () => {
850
+ // $100 transaction
851
+ const result = calculatePolarFees(10000, true, false);
852
+ expect(result.baseFee).toBe(440); // 4% + $0.40
853
+ expect(result.internationalFee).toBe(150); // 1.5%
854
+ expect(result.totalFee).toBe(590);
855
+ expect(result.netRevenue).toBe(9410); // $94.10
856
+ });
857
+
858
+ it('preserves per-transaction flat fees in aggregate', () => {
859
+ // Two $100 transactions should each have $0.40 flat fee
860
+ const aggregate = calculateAggregatePolarFees([10000, 10000]);
861
+ const single = calculatePolarFees(20000);
862
+
863
+ expect(aggregate.totalFees).toBeGreaterThan(single.totalFee);
864
+ // Difference should be one extra flat fee ($0.40)
865
+ expect(aggregate.totalFees - single.totalFee).toBe(40);
866
+ });
471
867
  });
472
868
  ```
473
869
 
474
- ### 5. Not Handling Failed Payments
475
- ```typescript
476
- // Listen to subscription.past_due
477
- if (event.type === 'subscription.past_due') {
478
- // Notify customer
479
- // Provide grace period
480
- // Update UI to show payment issue
481
- }
482
- ```
870
+ ## Production Checklist
871
+
872
+ - [ ] Environment variables configured in all environments
873
+ - [ ] Sandbox testing completed for all checkout flows
874
+ - [ ] Production API key obtained and secured
875
+ - [ ] Webhook endpoint deployed and reachable
876
+ - [ ] Webhook signature verification implemented
877
+ - [ ] Idempotency handling tested with duplicate webhooks
878
+ - [ ] Fee calculations verified against Polar dashboard
879
+ - [ ] Discount validation timeout configured
880
+ - [ ] Error monitoring enabled (Sentry, etc.)
881
+ - [ ] Structured logging in place
882
+ - [ ] Database indexes on orders.status, orders.paymentProvider
883
+ - [ ] Revenue caching configured
884
+ - [ ] Rate limit handling implemented
885
+ - [ ] Fail-open patterns for non-critical operations
886
+ - [ ] Customer email notifications working
887
+ - [ ] Refund flow tested end-to-end
888
+ - [ ] GitHub access grant/revoke tested
889
+ - [ ] Discord sales notifications configured
890
+
891
+ ## Common Pitfalls
892
+
893
+ 1. **Applying discounts in wrong order** - Always coupon first, then referral
894
+ 2. **Trusting success redirect without verification** - Always verify via API or webhook
895
+ 3. **Not handling duplicate webhooks** - Use eventId for idempotency
896
+ 4. **Blocking webhook on non-critical failures** - Wrap in try-catch, log, continue
897
+ 5. **Hardcoding Polar customer IDs** - Use external_id (your user ID) for lookups
898
+ 6. **Not setting timeout on discount validation** - API can be slow
899
+ 7. **Calculating aggregate fees as single transaction** - Each transaction has flat fee
900
+ 8. **Exposing API keys client-side** - Always server-side
901
+ 9. **Not preserving original amount in metadata** - Need for audit/debugging
902
+ 10. **Syncing discount redemptions synchronously** - Can fail; use retry with backoff