@polymorphism-tech/morph-spec 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/CLAUDE.md +68 -400
  2. package/README.md +198 -76
  3. package/bin/detect-agents.js +227 -225
  4. package/bin/morph-spec.js +10 -0
  5. package/bin/render-template.js +303 -302
  6. package/bin/semantic-detect-agents.js +247 -246
  7. package/bin/{task-manager.js → task-manager.cjs} +12 -1
  8. package/bin/validate-agents-skills.js +257 -251
  9. package/bin/validate-agents.js +70 -69
  10. package/bin/validate-phase.js +263 -263
  11. package/docs/getting-started.md +3 -3
  12. package/package.json +3 -4
  13. package/scripts/reorganize-skills.cjs +175 -0
  14. package/scripts/validate-agents-structure.cjs +52 -0
  15. package/scripts/validate-skills.cjs +180 -0
  16. package/src/commands/create-story.js +354 -351
  17. package/src/commands/detect-agents.js +13 -2
  18. package/src/commands/detect.js +104 -104
  19. package/src/commands/state.js +334 -333
  20. package/src/commands/sync.js +167 -167
  21. package/src/commands/task.js +1 -1
  22. package/src/commands/update.js +13 -1
  23. package/src/lib/context-generator.js +7 -4
  24. package/{detectors → src/lib/detectors}/config-detector.js +223 -223
  25. package/{detectors → src/lib/detectors}/conversation-analyzer.js +163 -163
  26. package/{detectors → src/lib/detectors}/index.js +84 -84
  27. package/{detectors → src/lib/detectors}/standards-generator.js +275 -275
  28. package/src/lib/hook-executor.js +2 -1
  29. package/src/lib/stack-resolver.js +148 -0
  30. package/src/lib/standards-context-injector.js +4 -3
  31. package/src/lib/state-manager.js +21 -4
  32. package/src/lib/team-orchestrator.js +2 -1
  33. package/src/lib/troubleshoot-grep.js +13 -3
  34. package/src/lib/validation-runner.js +2 -1
  35. package/src/utils/file-copier.js +3 -1
  36. package/{content → stacks/blazor-azure}/.azure/README.md +293 -293
  37. package/{content → stacks/blazor-azure}/.azure/docs/azure-devops-setup.md +454 -454
  38. package/{content → stacks/blazor-azure}/.azure/docs/branch-strategy.md +398 -398
  39. package/{content → stacks/blazor-azure}/.azure/docs/local-development.md +515 -515
  40. package/{content → stacks/blazor-azure}/.azure/pipelines/pipeline-variables.yml +34 -34
  41. package/{content → stacks/blazor-azure}/.azure/pipelines/prod-pipeline.yml +319 -319
  42. package/{content → stacks/blazor-azure}/.azure/pipelines/staging-pipeline.yml +234 -234
  43. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/build-dotnet.yml +75 -75
  44. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-app-service.yml +94 -94
  45. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-container-app.yml +120 -120
  46. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/infra-deploy.yml +90 -90
  47. package/{content → stacks/blazor-azure}/.claude/commands/morph-archive.md +79 -79
  48. package/{content → stacks/blazor-azure}/.claude/commands/morph-deploy.md +529 -529
  49. package/{content → stacks/blazor-azure}/.claude/commands/morph-infra.md +209 -209
  50. package/{content → stacks/blazor-azure}/.claude/commands/morph-troubleshoot.md +1 -1
  51. package/{content → stacks/blazor-azure}/.claude/settings.local.json +15 -15
  52. package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-setup.md +1 -1
  53. package/{content/.claude/skills/specialists → stacks/blazor-azure/.claude/skills/level-2-domains/architecture}/prompt-engineer.md +189 -189
  54. package/{content/.claude/skills/specialists → stacks/blazor-azure/.claude/skills/level-2-domains/architecture}/seo-growth-hacker.md +320 -320
  55. package/{content/.claude/skills/infra → stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure}/azure-deploy-specialist.md +699 -699
  56. package/{content → stacks/blazor-azure}/.morph/.morphversion +5 -5
  57. package/{content → stacks/blazor-azure}/.morph/archive/.gitkeep +25 -25
  58. package/{content → stacks/blazor-azure}/.morph/config/agents.json +7 -5
  59. package/{content → stacks/blazor-azure}/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
  60. package/{content → stacks/blazor-azure}/.morph/docs/workflows/enforcement-pipeline.md +3 -3
  61. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/README.md +241 -241
  62. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/contracts.ts +307 -307
  63. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/spec.md +399 -399
  64. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/tasks.md +168 -168
  65. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/README.md +125 -125
  66. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/contracts.cs +358 -358
  67. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/decisions.md +246 -246
  68. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/spec.md +236 -236
  69. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/tasks.md +150 -150
  70. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/README.md +309 -309
  71. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/contracts.cs +433 -433
  72. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/spec.md +479 -479
  73. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/tasks.md +185 -185
  74. package/{content → stacks/blazor-azure}/.morph/examples/state-v3.json +188 -188
  75. package/{content → stacks/blazor-azure}/.morph/features/.gitkeep +25 -25
  76. package/{content → stacks/blazor-azure}/.morph/hooks/README.md +12 -12
  77. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-all.sh +48 -48
  78. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-specs.sh +49 -49
  79. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-tests.sh +60 -60
  80. package/{content → stacks/blazor-azure}/.morph/project.md +160 -160
  81. package/{content → stacks/blazor-azure}/.morph/schemas/agent.schema.json +296 -296
  82. package/{content → stacks/blazor-azure}/.morph/specs/.gitkeep +20 -20
  83. package/{content → stacks/blazor-azure}/.morph/standards/agent-teams-workflow.md +2 -2
  84. package/{content → stacks/blazor-azure}/.morph/standards/coding.md +377 -377
  85. package/{content → stacks/blazor-azure}/.morph/standards/fluent-ui-setup.md +590 -590
  86. package/{content → stacks/blazor-azure}/.morph/standards/migration-guide.md +514 -514
  87. package/{content → stacks/blazor-azure}/.morph/standards/passkeys-auth.md +423 -423
  88. package/{content → stacks/blazor-azure}/.morph/standards/vector-search-rag.md +536 -536
  89. package/{content → stacks/blazor-azure}/.morph/state.json +17 -17
  90. package/{content → stacks/blazor-azure}/.morph/templates/FluentDesignTheme.cs +149 -149
  91. package/{content → stacks/blazor-azure}/.morph/templates/MudTheme.cs +281 -281
  92. package/{content → stacks/blazor-azure}/.morph/templates/component.razor +239 -239
  93. package/{content → stacks/blazor-azure}/.morph/templates/contracts.cs +217 -217
  94. package/{content → stacks/blazor-azure}/.morph/templates/design-system.css +226 -226
  95. package/{content → stacks/blazor-azure}/.morph/templates/infra/.dockerignore.example +89 -89
  96. package/{content → stacks/blazor-azure}/.morph/templates/infra/Dockerfile.example +82 -82
  97. package/{content → stacks/blazor-azure}/.morph/templates/infra/README.md +286 -286
  98. package/{content → stacks/blazor-azure}/.morph/templates/infra/app-insights.bicep +63 -63
  99. package/{content → stacks/blazor-azure}/.morph/templates/infra/app-service.bicep +164 -164
  100. package/{content → stacks/blazor-azure}/.morph/templates/infra/azure-pipelines-deploy.yml +480 -480
  101. package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app-env.bicep +49 -49
  102. package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app.bicep +156 -156
  103. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.ps1 +229 -229
  104. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.sh +208 -208
  105. package/{content → stacks/blazor-azure}/.morph/templates/infra/key-vault.bicep +91 -91
  106. package/{content → stacks/blazor-azure}/.morph/templates/infra/main.bicep +189 -189
  107. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.dev.json +29 -29
  108. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.prod.json +29 -29
  109. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.staging.json +29 -29
  110. package/{content → stacks/blazor-azure}/.morph/templates/infra/sql-database.bicep +103 -103
  111. package/{content → stacks/blazor-azure}/.morph/templates/infra/storage.bicep +106 -106
  112. package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-client.cs +387 -387
  113. package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-webhook.cs +351 -351
  114. package/{content → stacks/blazor-azure}/.morph/templates/integrations/azure-identity-config.cs +288 -288
  115. package/{content → stacks/blazor-azure}/.morph/templates/integrations/clerk-config.cs +258 -258
  116. package/{content → stacks/blazor-azure}/.morph/templates/job.cs +171 -171
  117. package/{content → stacks/blazor-azure}/.morph/templates/migration.cs +83 -83
  118. package/{content → stacks/blazor-azure}/.morph/templates/repository.cs +141 -141
  119. package/{content → stacks/blazor-azure}/.morph/templates/saas/subscription.cs +347 -347
  120. package/{content → stacks/blazor-azure}/.morph/templates/saas/tenant.cs +338 -338
  121. package/{content → stacks/blazor-azure}/.morph/templates/service.cs +139 -139
  122. package/{content → stacks/blazor-azure}/.morph/templates/sprint-status.yaml +68 -68
  123. package/{content → stacks/blazor-azure}/.morph/templates/story.md +143 -143
  124. package/{content → stacks/blazor-azure}/.morph/templates/test.cs +239 -239
  125. package/{content → stacks/blazor-azure}/.morph/templates/ui-design-system.md +286 -286
  126. package/{content → stacks/blazor-azure}/.morph/templates/ui-flows.md +336 -336
  127. package/{content → stacks/blazor-azure}/.morph/templates/ui-mockups.md +133 -133
  128. package/{content → stacks/blazor-azure}/.morph/test-infra/example.bicep +59 -59
  129. package/{content → stacks/blazor-azure}/README.md +79 -79
  130. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +244 -0
  131. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +335 -0
  132. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +189 -0
  133. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +170 -0
  134. package/stacks/nextjs-supabase/.morph/config/agents.json +345 -0
  135. package/stacks/nextjs-supabase/.morph/config/config.template.json +92 -0
  136. package/stacks/nextjs-supabase/.morph/docs/easypanel-setup.md +169 -0
  137. package/stacks/nextjs-supabase/.morph/docs/supabase-mcp-setup.md +247 -0
  138. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/README.md +697 -0
  139. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/spec.md +85 -0
  140. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/tasks.md +86 -0
  141. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/README.md +498 -0
  142. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/decisions.md +121 -0
  143. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/spec.md +138 -0
  144. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/tasks.md +162 -0
  145. package/stacks/nextjs-supabase/.morph/project.md +168 -0
  146. package/stacks/nextjs-supabase/.morph/standards/easypanel-deploy.md +191 -0
  147. package/stacks/nextjs-supabase/.morph/standards/nextjs-patterns.md +193 -0
  148. package/stacks/nextjs-supabase/.morph/standards/supabase-auth.md +171 -0
  149. package/stacks/nextjs-supabase/.morph/standards/supabase-pgvector.md +164 -0
  150. package/stacks/nextjs-supabase/.morph/standards/supabase-rls.md +179 -0
  151. package/stacks/nextjs-supabase/.morph/standards/supabase-storage.md +148 -0
  152. package/stacks/nextjs-supabase/.morph/templates/contracts.cs +173 -0
  153. package/stacks/nextjs-supabase/.morph/templates/contracts.ts +168 -0
  154. package/stacks/nextjs-supabase/.morph/templates/decisions.md +115 -0
  155. package/stacks/nextjs-supabase/.morph/templates/dockerfile-api.dockerfile +38 -0
  156. package/stacks/nextjs-supabase/.morph/templates/dockerfile-web.dockerfile +48 -0
  157. package/stacks/nextjs-supabase/.morph/templates/proposal.md +145 -0
  158. package/stacks/nextjs-supabase/.morph/templates/recap.md +134 -0
  159. package/stacks/nextjs-supabase/.morph/templates/rls-policy.sql +57 -0
  160. package/stacks/nextjs-supabase/.morph/templates/spec.md +231 -0
  161. package/stacks/nextjs-supabase/.morph/templates/supabase-migration.sql +100 -0
  162. package/stacks/nextjs-supabase/.morph/templates/tasks.md +257 -0
  163. package/stacks/nextjs-supabase/CLAUDE.md +149 -0
  164. package/stacks/nextjs-supabase/README.md +112 -0
  165. /package/{detectors → src/lib/detectors}/structure-detector.js +0 -0
  166. /package/{content → stacks/blazor-azure}/.claude/commands/morph-apply.md +0 -0
  167. /package/{content → stacks/blazor-azure}/.claude/commands/morph-preflight.md +0 -0
  168. /package/{content → stacks/blazor-azure}/.claude/commands/morph-proposal.md +0 -0
  169. /package/{content → stacks/blazor-azure}/.claude/commands/morph-status.md +0 -0
  170. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/README.md +0 -0
  171. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/code-review.md +0 -0
  172. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/morph-checklist.md +0 -0
  173. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/simulation-checklist.md +0 -0
  174. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/README.md +0 -0
  175. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/morph-replicate.md +0 -0
  176. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-clarify.md +0 -0
  177. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-design.md +0 -0
  178. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-tasks.md +0 -0
  179. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-uiux.md +0 -0
  180. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/README.md +0 -0
  181. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -0
  182. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -0
  183. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -0
  184. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -0
  185. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -0
  186. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -0
  187. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -0
  188. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -0
  189. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -0
  190. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -0
  191. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -0
  192. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -0
  193. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -0
  194. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -0
  195. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -0
  196. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -0
  197. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -0
  198. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/resend-email.md +0 -0
  199. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -0
  200. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -0
  201. /package/{content → stacks/blazor-azure}/.claude/skills/level-3-technologies/README.md +0 -0
  202. /package/{content → stacks/blazor-azure}/.claude/skills/level-4-patterns/README.md +0 -0
  203. /package/{content → stacks/blazor-azure}/.morph/config/config.template.json +0 -0
  204. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/design-impl.md +0 -0
  205. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/fast-track.md +0 -0
  206. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/full-morph.md +0 -0
  207. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/standard.md +0 -0
  208. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/ui-refresh.md +0 -0
  209. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/decisions.md +0 -0
  210. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/proposal.md +0 -0
  211. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/spec.md +0 -0
  212. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-agents.sh +0 -0
  213. /package/{content → stacks/blazor-azure}/.morph/hooks/task-completed.js +0 -0
  214. /package/{content → stacks/blazor-azure}/.morph/hooks/teammate-idle.js +0 -0
  215. /package/{content → stacks/blazor-azure}/.morph/schemas/tasks.schema.json +0 -0
  216. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-blazor-ui.md +0 -0
  217. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-production.md +0 -0
  218. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-setup.md +0 -0
  219. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-workflows.md +0 -0
  220. /package/{content → stacks/blazor-azure}/.morph/standards/architecture.md +0 -0
  221. /package/{content → stacks/blazor-azure}/.morph/standards/azure.md +0 -0
  222. /package/{content → stacks/blazor-azure}/.morph/standards/dotnet10-migration.md +0 -0
  223. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT-FEATURE.md +0 -0
  224. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT.md +0 -0
  225. /package/{content → stacks/blazor-azure}/.morph/templates/agent.cs +0 -0
  226. /package/{content → stacks/blazor-azure}/.morph/templates/clarify-questions.md +0 -0
  227. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Commands.cs +0 -0
  228. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Entities.cs +0 -0
  229. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Queries.cs +0 -0
  230. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/README.md +0 -0
  231. /package/{content → stacks/blazor-azure}/.morph/templates/decisions.md +0 -0
  232. /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy-checklist.md +0 -0
  233. /package/{content → stacks/blazor-azure}/.morph/templates/proposal.md +0 -0
  234. /package/{content → stacks/blazor-azure}/.morph/templates/recap.md +0 -0
  235. /package/{content → stacks/blazor-azure}/.morph/templates/simulation.md +0 -0
  236. /package/{content → stacks/blazor-azure}/.morph/templates/spec.md +0 -0
  237. /package/{content → stacks/blazor-azure}/.morph/templates/state.template.json +0 -0
  238. /package/{content → stacks/blazor-azure}/.morph/templates/tasks.md +0 -0
  239. /package/{content → stacks/blazor-azure}/.morph/templates/ui-components.md +0 -0
  240. /package/{content → stacks/blazor-azure}/CLAUDE.md +0 -0
@@ -1,258 +1,258 @@
1
- // ==============================================================================
2
- // MORPH-SPEC - Clerk Authentication Configuration Template
3
- // Configuração de autenticação com Clerk para .NET
4
- // ==============================================================================
5
-
6
- using Microsoft.AspNetCore.Authentication;
7
- using Microsoft.AspNetCore.Components.Authorization;
8
- using System.Security.Claims;
9
-
10
- namespace {{Namespace}}.Infrastructure.Auth;
11
-
12
- // ==============================================================================
13
- // OPTIONS
14
- // ==============================================================================
15
-
16
- public class ClerkOptions
17
- {
18
- public const string SectionName = "Clerk";
19
-
20
- /// <summary>
21
- /// Clerk Secret Key (starts with sk_)
22
- /// </summary>
23
- public string SecretKey { get; set; } = string.Empty;
24
-
25
- /// <summary>
26
- /// Clerk Publishable Key (starts with pk_)
27
- /// </summary>
28
- public string PublishableKey { get; set; } = string.Empty;
29
-
30
- /// <summary>
31
- /// Clerk Frontend API URL
32
- /// </summary>
33
- public string FrontendApi { get; set; } = string.Empty;
34
- }
35
-
36
- // ==============================================================================
37
- // SERVICE EXTENSIONS
38
- // ==============================================================================
39
-
40
- public static class ClerkServiceExtensions
41
- {
42
- /// <summary>
43
- /// Adiciona autenticação Clerk ao projeto
44
- /// Requer: Clerk.Net.AspNetCore.Security
45
- /// </summary>
46
- public static IServiceCollection AddClerkAuthentication(
47
- this IServiceCollection services,
48
- IConfiguration configuration)
49
- {
50
- services.Configure<ClerkOptions>(configuration.GetSection(ClerkOptions.SectionName));
51
-
52
- // Opção 1: Usando Clerk.Net SDK oficial
53
- // services.AddClerk(configuration);
54
-
55
- // Opção 2: Configuração manual com JWT
56
- services.AddAuthentication("Clerk")
57
- .AddJwtBearer("Clerk", options =>
58
- {
59
- var clerkOptions = configuration.GetSection(ClerkOptions.SectionName).Get<ClerkOptions>()!;
60
-
61
- options.Authority = clerkOptions.FrontendApi;
62
- options.TokenValidationParameters = new()
63
- {
64
- ValidateIssuer = true,
65
- ValidateAudience = false,
66
- ValidateLifetime = true,
67
- ValidateIssuerSigningKey = true,
68
- NameClaimType = ClaimTypes.NameIdentifier
69
- };
70
- });
71
-
72
- services.AddAuthorization();
73
-
74
- return services;
75
- }
76
-
77
- /// <summary>
78
- /// Adiciona Clerk para Blazor Server
79
- /// </summary>
80
- public static IServiceCollection AddClerkBlazor(
81
- this IServiceCollection services,
82
- IConfiguration configuration)
83
- {
84
- services.AddClerkAuthentication(configuration);
85
- services.AddScoped<AuthenticationStateProvider, ClerkAuthenticationStateProvider>();
86
- services.AddCascadingAuthenticationState();
87
-
88
- return services;
89
- }
90
- }
91
-
92
- // ==============================================================================
93
- // AUTHENTICATION STATE PROVIDER (Blazor)
94
- // ==============================================================================
95
-
96
- public class ClerkAuthenticationStateProvider : AuthenticationStateProvider
97
- {
98
- private readonly IHttpContextAccessor _httpContextAccessor;
99
-
100
- public ClerkAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor)
101
- {
102
- _httpContextAccessor = httpContextAccessor;
103
- }
104
-
105
- public override Task<AuthenticationState> GetAuthenticationStateAsync()
106
- {
107
- var user = _httpContextAccessor.HttpContext?.User ?? new ClaimsPrincipal();
108
- return Task.FromResult(new AuthenticationState(user));
109
- }
110
-
111
- public void NotifyAuthenticationStateChanged()
112
- {
113
- NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
114
- }
115
- }
116
-
117
- // ==============================================================================
118
- // CLERK USER SERVICE
119
- // ==============================================================================
120
-
121
- public interface IClerkUserService
122
- {
123
- Task<ClerkUser?> GetCurrentUserAsync(CancellationToken ct = default);
124
- Task<ClerkUser?> GetUserByIdAsync(string userId, CancellationToken ct = default);
125
- Task UpdateUserMetadataAsync(string userId, Dictionary<string, object> metadata, CancellationToken ct = default);
126
- }
127
-
128
- public class ClerkUserService : IClerkUserService
129
- {
130
- private readonly HttpClient _httpClient;
131
- private readonly IHttpContextAccessor _httpContextAccessor;
132
- private readonly ILogger<ClerkUserService> _logger;
133
-
134
- public ClerkUserService(
135
- HttpClient httpClient,
136
- IHttpContextAccessor httpContextAccessor,
137
- ILogger<ClerkUserService> logger)
138
- {
139
- _httpClient = httpClient;
140
- _httpContextAccessor = httpContextAccessor;
141
- _logger = logger;
142
- }
143
-
144
- public async Task<ClerkUser?> GetCurrentUserAsync(CancellationToken ct = default)
145
- {
146
- var userId = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier);
147
- if (string.IsNullOrEmpty(userId)) return null;
148
-
149
- return await GetUserByIdAsync(userId, ct);
150
- }
151
-
152
- public async Task<ClerkUser?> GetUserByIdAsync(string userId, CancellationToken ct = default)
153
- {
154
- try
155
- {
156
- var response = await _httpClient.GetAsync($"users/{userId}", ct);
157
-
158
- if (!response.IsSuccessStatusCode)
159
- {
160
- _logger.LogWarning("Failed to get Clerk user {UserId}: {Status}", userId, response.StatusCode);
161
- return null;
162
- }
163
-
164
- return await response.Content.ReadFromJsonAsync<ClerkUser>(ct);
165
- }
166
- catch (Exception ex)
167
- {
168
- _logger.LogError(ex, "Error getting Clerk user {UserId}", userId);
169
- return null;
170
- }
171
- }
172
-
173
- public async Task UpdateUserMetadataAsync(string userId, Dictionary<string, object> metadata, CancellationToken ct = default)
174
- {
175
- var request = new { public_metadata = metadata };
176
- var response = await _httpClient.PatchAsJsonAsync($"users/{userId}", request, ct);
177
- response.EnsureSuccessStatusCode();
178
- }
179
- }
180
-
181
- // ==============================================================================
182
- // CLERK USER MODEL
183
- // ==============================================================================
184
-
185
- public record ClerkUser
186
- {
187
- public string Id { get; init; } = string.Empty;
188
- public string? FirstName { get; init; }
189
- public string? LastName { get; init; }
190
- public string? ImageUrl { get; init; }
191
- public List<ClerkEmailAddress>? EmailAddresses { get; init; }
192
- public string? PrimaryEmailAddressId { get; init; }
193
- public Dictionary<string, object>? PublicMetadata { get; init; }
194
- public long CreatedAt { get; init; }
195
- public long UpdatedAt { get; init; }
196
-
197
- public string? PrimaryEmail => EmailAddresses?
198
- .FirstOrDefault(e => e.Id == PrimaryEmailAddressId)?.EmailAddress;
199
-
200
- public string FullName => $"{FirstName} {LastName}".Trim();
201
- }
202
-
203
- public record ClerkEmailAddress
204
- {
205
- public string Id { get; init; } = string.Empty;
206
- public string EmailAddress { get; init; } = string.Empty;
207
- public bool Verified { get; init; }
208
- }
209
-
210
- // ==============================================================================
211
- // MIDDLEWARE PIPELINE
212
- // ==============================================================================
213
-
214
- public static class ClerkMiddlewareExtensions
215
- {
216
- public static IApplicationBuilder UseClerkAuthentication(this IApplicationBuilder app)
217
- {
218
- app.UseAuthentication();
219
- app.UseAuthorization();
220
- return app;
221
- }
222
- }
223
-
224
- // ==============================================================================
225
- // APPSETTINGS EXAMPLE
226
- // ==============================================================================
227
-
228
- /*
229
- {
230
- "Clerk": {
231
- "SecretKey": "sk_test_xxxxx",
232
- "PublishableKey": "pk_test_xxxxx",
233
- "FrontendApi": "https://your-app.clerk.accounts.dev"
234
- }
235
- }
236
- */
237
-
238
- // ==============================================================================
239
- // PROGRAM.CS EXAMPLE
240
- // ==============================================================================
241
-
242
- /*
243
- // Program.cs
244
- var builder = WebApplication.CreateBuilder(args);
245
-
246
- // Add Clerk authentication
247
- builder.Services.AddClerkAuthentication(builder.Configuration);
248
- // Or for Blazor:
249
- // builder.Services.AddClerkBlazor(builder.Configuration);
250
-
251
- var app = builder.Build();
252
-
253
- app.UseClerkAuthentication();
254
-
255
- app.MapControllers().RequireAuthorization();
256
-
257
- app.Run();
258
- */
1
+ // ==============================================================================
2
+ // MORPH-SPEC - Clerk Authentication Configuration Template
3
+ // Configuração de autenticação com Clerk para .NET
4
+ // ==============================================================================
5
+
6
+ using Microsoft.AspNetCore.Authentication;
7
+ using Microsoft.AspNetCore.Components.Authorization;
8
+ using System.Security.Claims;
9
+
10
+ namespace {{Namespace}}.Infrastructure.Auth;
11
+
12
+ // ==============================================================================
13
+ // OPTIONS
14
+ // ==============================================================================
15
+
16
+ public class ClerkOptions
17
+ {
18
+ public const string SectionName = "Clerk";
19
+
20
+ /// <summary>
21
+ /// Clerk Secret Key (starts with sk_)
22
+ /// </summary>
23
+ public string SecretKey { get; set; } = string.Empty;
24
+
25
+ /// <summary>
26
+ /// Clerk Publishable Key (starts with pk_)
27
+ /// </summary>
28
+ public string PublishableKey { get; set; } = string.Empty;
29
+
30
+ /// <summary>
31
+ /// Clerk Frontend API URL
32
+ /// </summary>
33
+ public string FrontendApi { get; set; } = string.Empty;
34
+ }
35
+
36
+ // ==============================================================================
37
+ // SERVICE EXTENSIONS
38
+ // ==============================================================================
39
+
40
+ public static class ClerkServiceExtensions
41
+ {
42
+ /// <summary>
43
+ /// Adiciona autenticação Clerk ao projeto
44
+ /// Requer: Clerk.Net.AspNetCore.Security
45
+ /// </summary>
46
+ public static IServiceCollection AddClerkAuthentication(
47
+ this IServiceCollection services,
48
+ IConfiguration configuration)
49
+ {
50
+ services.Configure<ClerkOptions>(configuration.GetSection(ClerkOptions.SectionName));
51
+
52
+ // Opção 1: Usando Clerk.Net SDK oficial
53
+ // services.AddClerk(configuration);
54
+
55
+ // Opção 2: Configuração manual com JWT
56
+ services.AddAuthentication("Clerk")
57
+ .AddJwtBearer("Clerk", options =>
58
+ {
59
+ var clerkOptions = configuration.GetSection(ClerkOptions.SectionName).Get<ClerkOptions>()!;
60
+
61
+ options.Authority = clerkOptions.FrontendApi;
62
+ options.TokenValidationParameters = new()
63
+ {
64
+ ValidateIssuer = true,
65
+ ValidateAudience = false,
66
+ ValidateLifetime = true,
67
+ ValidateIssuerSigningKey = true,
68
+ NameClaimType = ClaimTypes.NameIdentifier
69
+ };
70
+ });
71
+
72
+ services.AddAuthorization();
73
+
74
+ return services;
75
+ }
76
+
77
+ /// <summary>
78
+ /// Adiciona Clerk para Blazor Server
79
+ /// </summary>
80
+ public static IServiceCollection AddClerkBlazor(
81
+ this IServiceCollection services,
82
+ IConfiguration configuration)
83
+ {
84
+ services.AddClerkAuthentication(configuration);
85
+ services.AddScoped<AuthenticationStateProvider, ClerkAuthenticationStateProvider>();
86
+ services.AddCascadingAuthenticationState();
87
+
88
+ return services;
89
+ }
90
+ }
91
+
92
+ // ==============================================================================
93
+ // AUTHENTICATION STATE PROVIDER (Blazor)
94
+ // ==============================================================================
95
+
96
+ public class ClerkAuthenticationStateProvider : AuthenticationStateProvider
97
+ {
98
+ private readonly IHttpContextAccessor _httpContextAccessor;
99
+
100
+ public ClerkAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor)
101
+ {
102
+ _httpContextAccessor = httpContextAccessor;
103
+ }
104
+
105
+ public override Task<AuthenticationState> GetAuthenticationStateAsync()
106
+ {
107
+ var user = _httpContextAccessor.HttpContext?.User ?? new ClaimsPrincipal();
108
+ return Task.FromResult(new AuthenticationState(user));
109
+ }
110
+
111
+ public void NotifyAuthenticationStateChanged()
112
+ {
113
+ NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
114
+ }
115
+ }
116
+
117
+ // ==============================================================================
118
+ // CLERK USER SERVICE
119
+ // ==============================================================================
120
+
121
+ public interface IClerkUserService
122
+ {
123
+ Task<ClerkUser?> GetCurrentUserAsync(CancellationToken ct = default);
124
+ Task<ClerkUser?> GetUserByIdAsync(string userId, CancellationToken ct = default);
125
+ Task UpdateUserMetadataAsync(string userId, Dictionary<string, object> metadata, CancellationToken ct = default);
126
+ }
127
+
128
+ public class ClerkUserService : IClerkUserService
129
+ {
130
+ private readonly HttpClient _httpClient;
131
+ private readonly IHttpContextAccessor _httpContextAccessor;
132
+ private readonly ILogger<ClerkUserService> _logger;
133
+
134
+ public ClerkUserService(
135
+ HttpClient httpClient,
136
+ IHttpContextAccessor httpContextAccessor,
137
+ ILogger<ClerkUserService> logger)
138
+ {
139
+ _httpClient = httpClient;
140
+ _httpContextAccessor = httpContextAccessor;
141
+ _logger = logger;
142
+ }
143
+
144
+ public async Task<ClerkUser?> GetCurrentUserAsync(CancellationToken ct = default)
145
+ {
146
+ var userId = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier);
147
+ if (string.IsNullOrEmpty(userId)) return null;
148
+
149
+ return await GetUserByIdAsync(userId, ct);
150
+ }
151
+
152
+ public async Task<ClerkUser?> GetUserByIdAsync(string userId, CancellationToken ct = default)
153
+ {
154
+ try
155
+ {
156
+ var response = await _httpClient.GetAsync($"users/{userId}", ct);
157
+
158
+ if (!response.IsSuccessStatusCode)
159
+ {
160
+ _logger.LogWarning("Failed to get Clerk user {UserId}: {Status}", userId, response.StatusCode);
161
+ return null;
162
+ }
163
+
164
+ return await response.Content.ReadFromJsonAsync<ClerkUser>(ct);
165
+ }
166
+ catch (Exception ex)
167
+ {
168
+ _logger.LogError(ex, "Error getting Clerk user {UserId}", userId);
169
+ return null;
170
+ }
171
+ }
172
+
173
+ public async Task UpdateUserMetadataAsync(string userId, Dictionary<string, object> metadata, CancellationToken ct = default)
174
+ {
175
+ var request = new { public_metadata = metadata };
176
+ var response = await _httpClient.PatchAsJsonAsync($"users/{userId}", request, ct);
177
+ response.EnsureSuccessStatusCode();
178
+ }
179
+ }
180
+
181
+ // ==============================================================================
182
+ // CLERK USER MODEL
183
+ // ==============================================================================
184
+
185
+ public record ClerkUser
186
+ {
187
+ public string Id { get; init; } = string.Empty;
188
+ public string? FirstName { get; init; }
189
+ public string? LastName { get; init; }
190
+ public string? ImageUrl { get; init; }
191
+ public List<ClerkEmailAddress>? EmailAddresses { get; init; }
192
+ public string? PrimaryEmailAddressId { get; init; }
193
+ public Dictionary<string, object>? PublicMetadata { get; init; }
194
+ public long CreatedAt { get; init; }
195
+ public long UpdatedAt { get; init; }
196
+
197
+ public string? PrimaryEmail => EmailAddresses?
198
+ .FirstOrDefault(e => e.Id == PrimaryEmailAddressId)?.EmailAddress;
199
+
200
+ public string FullName => $"{FirstName} {LastName}".Trim();
201
+ }
202
+
203
+ public record ClerkEmailAddress
204
+ {
205
+ public string Id { get; init; } = string.Empty;
206
+ public string EmailAddress { get; init; } = string.Empty;
207
+ public bool Verified { get; init; }
208
+ }
209
+
210
+ // ==============================================================================
211
+ // MIDDLEWARE PIPELINE
212
+ // ==============================================================================
213
+
214
+ public static class ClerkMiddlewareExtensions
215
+ {
216
+ public static IApplicationBuilder UseClerkAuthentication(this IApplicationBuilder app)
217
+ {
218
+ app.UseAuthentication();
219
+ app.UseAuthorization();
220
+ return app;
221
+ }
222
+ }
223
+
224
+ // ==============================================================================
225
+ // APPSETTINGS EXAMPLE
226
+ // ==============================================================================
227
+
228
+ /*
229
+ {
230
+ "Clerk": {
231
+ "SecretKey": "sk_test_xxxxx",
232
+ "PublishableKey": "pk_test_xxxxx",
233
+ "FrontendApi": "https://your-app.clerk.accounts.dev"
234
+ }
235
+ }
236
+ */
237
+
238
+ // ==============================================================================
239
+ // PROGRAM.CS EXAMPLE
240
+ // ==============================================================================
241
+
242
+ /*
243
+ // Program.cs
244
+ var builder = WebApplication.CreateBuilder(args);
245
+
246
+ // Add Clerk authentication
247
+ builder.Services.AddClerkAuthentication(builder.Configuration);
248
+ // Or for Blazor:
249
+ // builder.Services.AddClerkBlazor(builder.Configuration);
250
+
251
+ var app = builder.Build();
252
+
253
+ app.UseClerkAuthentication();
254
+
255
+ app.MapControllers().RequireAuthorization();
256
+
257
+ app.Run();
258
+ */