create-aron-app 0.1.0 → 0.1.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 (156) hide show
  1. package/package.json +5 -2
  2. package/templates/_base/.cursor/agents/skills/clerk/SKILL.md +89 -0
  3. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/SKILL.md +142 -0
  4. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/api-specs-context.sh +30 -0
  5. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/execute-request.sh +88 -0
  6. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-endpoint-detail.sh +165 -0
  7. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-tag-endpoints.sh +208 -0
  8. package/templates/_base/.cursor/agents/skills/clerk/clerk-backend-api/scripts/extract-tags.js +14 -0
  9. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/SKILL.md +157 -0
  10. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-in.md +224 -0
  11. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-up.md +190 -0
  12. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-in.md +314 -0
  13. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-up.md +259 -0
  14. package/templates/_base/.cursor/agents/skills/clerk/clerk-custom-ui/core-3/show-component.md +125 -0
  15. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/SKILL.md +94 -0
  16. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/api-routes.md +50 -0
  17. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/caching-auth.md +56 -0
  18. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/middleware-strategies.md +68 -0
  19. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/server-actions.md +56 -0
  20. package/templates/_base/.cursor/agents/skills/clerk/clerk-nextjs-patterns/references/server-vs-client.md +104 -0
  21. package/templates/_base/.cursor/agents/skills/clerk/clerk-webhooks/SKILL.md +131 -0
  22. package/templates/_base/.cursor/agents/skills/shadcn/SKILL.md +241 -0
  23. package/templates/_base/.cursor/agents/skills/shadcn/agents/openai.yml +5 -0
  24. package/templates/_base/.cursor/agents/skills/shadcn/assets/shadcn-small.png +0 -0
  25. package/templates/_base/.cursor/agents/skills/shadcn/assets/shadcn.png +0 -0
  26. package/templates/_base/.cursor/agents/skills/shadcn/cli.md +257 -0
  27. package/templates/_base/.cursor/agents/skills/shadcn/customization.md +202 -0
  28. package/templates/_base/.cursor/agents/skills/shadcn/evals/evals.json +47 -0
  29. package/templates/_base/.cursor/agents/skills/shadcn/mcp.md +94 -0
  30. package/templates/_base/.cursor/agents/skills/shadcn/rules/base-vs-radix.md +306 -0
  31. package/templates/_base/.cursor/agents/skills/shadcn/rules/composition.md +195 -0
  32. package/templates/_base/.cursor/agents/skills/shadcn/rules/forms.md +192 -0
  33. package/templates/_base/.cursor/agents/skills/shadcn/rules/icons.md +101 -0
  34. package/templates/_base/.cursor/agents/skills/shadcn/rules/styling.md +162 -0
  35. package/templates/_base/.cursor/commands/builder.md +0 -0
  36. package/templates/_base/.cursor/commands/pr.md +7 -0
  37. package/templates/_base/.cursor/rules/api_architecture.mdc +268 -0
  38. package/templates/_base/.cursor/rules/coding_standards.mdc +64 -0
  39. package/templates/_base/.cursor/rules/convex_rules.mdc +675 -0
  40. package/templates/_base/.cursor/rules/frontend_rules.mdc +268 -0
  41. package/templates/_base/.env.convex.example +3 -0
  42. package/templates/_base/.github/workflows/ci.yml +29 -0
  43. package/templates/_base/.nvmrc +1 -0
  44. package/templates/_base/.vscode/settings.json +9 -0
  45. package/templates/_base/apps/api/auth.config.ts +18 -0
  46. package/templates/_base/apps/api/functions.ts +99 -0
  47. package/templates/_base/apps/api/project.json +22 -0
  48. package/templates/_base/apps/api/schema.ts +11 -0
  49. package/templates/_base/apps/api/todos/crud.ts +81 -0
  50. package/templates/_base/apps/api/todos/schema.ts +11 -0
  51. package/templates/_base/apps/api/todos/types.ts +22 -0
  52. package/templates/_base/apps/api/tsconfig.json +23 -0
  53. package/templates/_base/apps/api/types.ts +16 -0
  54. package/templates/_base/biome.json +114 -0
  55. package/templates/_base/convex.json +4 -0
  56. package/templates/_base/emails/project.json +16 -0
  57. package/templates/_base/emails/tsconfig.json +5 -0
  58. package/templates/_base/emails/welcome_email.tsx +53 -0
  59. package/templates/_base/nx.json +29 -0
  60. package/templates/_base/package.json +73 -0
  61. package/templates/_base/scripts/sync_convex_env.ts +63 -0
  62. package/templates/_base/shared/assets/image.d.ts +4 -0
  63. package/templates/_base/shared/assets/src/styles/global.css +73 -0
  64. package/templates/_base/shared/assets/tsconfig.json +5 -0
  65. package/templates/_base/shared/ui/src/base/alert_dialog.tsx +139 -0
  66. package/templates/_base/shared/ui/src/base/badge.tsx +33 -0
  67. package/templates/_base/shared/ui/src/base/basic_data_table.tsx +61 -0
  68. package/templates/_base/shared/ui/src/base/button.tsx +69 -0
  69. package/templates/_base/shared/ui/src/base/button_group.tsx +82 -0
  70. package/templates/_base/shared/ui/src/base/card.tsx +79 -0
  71. package/templates/_base/shared/ui/src/base/checkbox.tsx +26 -0
  72. package/templates/_base/shared/ui/src/base/command.tsx +165 -0
  73. package/templates/_base/shared/ui/src/base/dialog.tsx +129 -0
  74. package/templates/_base/shared/ui/src/base/dropdown_menu.tsx +232 -0
  75. package/templates/_base/shared/ui/src/base/form.tsx +161 -0
  76. package/templates/_base/shared/ui/src/base/input.tsx +129 -0
  77. package/templates/_base/shared/ui/src/base/label.tsx +19 -0
  78. package/templates/_base/shared/ui/src/base/popover.tsx +46 -0
  79. package/templates/_base/shared/ui/src/base/radio_group.tsx +49 -0
  80. package/templates/_base/shared/ui/src/base/resizable.tsx +55 -0
  81. package/templates/_base/shared/ui/src/base/scroll_area.tsx +44 -0
  82. package/templates/_base/shared/ui/src/base/select.tsx +151 -0
  83. package/templates/_base/shared/ui/src/base/separator.tsx +32 -0
  84. package/templates/_base/shared/ui/src/base/sheet.tsx +130 -0
  85. package/templates/_base/shared/ui/src/base/side_bar.tsx +688 -0
  86. package/templates/_base/shared/ui/src/base/skeleton.tsx +7 -0
  87. package/templates/_base/shared/ui/src/base/spinner.tsx +20 -0
  88. package/templates/_base/shared/ui/src/base/switch.tsx +27 -0
  89. package/templates/_base/shared/ui/src/base/table.tsx +91 -0
  90. package/templates/_base/shared/ui/src/base/text_area.tsx +21 -0
  91. package/templates/_base/shared/ui/src/base/tooltip.tsx +31 -0
  92. package/templates/_base/shared/ui/src/base/utils.ts +17 -0
  93. package/templates/_base/shared/ui/src/hooks/use_keyboard_press.tsx +48 -0
  94. package/templates/_base/shared/ui/src/hooks/use_keyboard_release.tsx +48 -0
  95. package/templates/_base/shared/ui/src/hooks/use_mobile.tsx +25 -0
  96. package/templates/_base/shared/ui/src/hooks/use_mouse_click.tsx +44 -0
  97. package/templates/_base/shared/ui/src/hooks/use_mouse_location.tsx +55 -0
  98. package/templates/_base/shared/ui/src/hooks/use_outside_click.tsx +29 -0
  99. package/templates/_base/shared/ui/src/hooks/use_query_params.tsx +33 -0
  100. package/templates/_base/shared/ui/tsconfig.json +8 -0
  101. package/templates/_base/shared/utils/src/convex.ts +3 -0
  102. package/templates/_base/shared/utils/src/time.ts +12 -0
  103. package/templates/_base/shared/utils/tsconfig.json +5 -0
  104. package/templates/_base/skills-lock.json +35 -0
  105. package/templates/_base/tsconfig.base.json +34 -0
  106. package/templates/nextjs/.env.example +8 -0
  107. package/templates/nextjs/index.d.ts +6 -0
  108. package/templates/nextjs/next-env.d.ts +5 -0
  109. package/templates/nextjs/next.config.js +22 -0
  110. package/templates/nextjs/postcss.config.js +17 -0
  111. package/templates/nextjs/project.json +22 -0
  112. package/templates/nextjs/src/app/(auth)/layout.tsx +21 -0
  113. package/templates/nextjs/src/app/(auth)/not-allowed/page.tsx +22 -0
  114. package/templates/nextjs/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +15 -0
  115. package/templates/nextjs/src/app/(dashboard)/layout.tsx +27 -0
  116. package/templates/nextjs/src/app/(dashboard)/page.tsx +5 -0
  117. package/templates/nextjs/src/app/(dashboard)/todos/[id]/page.tsx +23 -0
  118. package/templates/nextjs/src/app/(dashboard)/todos/page.tsx +16 -0
  119. package/templates/nextjs/src/app/app.css +3 -0
  120. package/templates/nextjs/src/app/layout.tsx +26 -0
  121. package/templates/nextjs/src/convex.ts +11 -0
  122. package/templates/nextjs/src/middleware.ts +18 -0
  123. package/templates/nextjs/src/providers/convex_provider.tsx +44 -0
  124. package/templates/nextjs/src/surfaces/home_surface.tsx +22 -0
  125. package/templates/nextjs/src/surfaces/todos/all_todos_surface.tsx +97 -0
  126. package/templates/nextjs/src/surfaces/todos/create_todo_sheet.tsx +107 -0
  127. package/templates/nextjs/src/surfaces/todos/single_todo_surface.tsx +90 -0
  128. package/templates/nextjs/src/ui/sidebar/nav_link.tsx +36 -0
  129. package/templates/nextjs/src/ui/sidebar/sidebar.tsx +125 -0
  130. package/templates/nextjs/src/utils/font.ts +9 -0
  131. package/templates/nextjs/tsconfig.json +42 -0
  132. package/templates/react-router/.env.example +8 -0
  133. package/templates/react-router/postcss.config.js +15 -0
  134. package/templates/react-router/project.json +23 -0
  135. package/templates/react-router/public/favicon.ico +0 -0
  136. package/templates/react-router/react-router.config.ts +9 -0
  137. package/templates/react-router/src/app.css +3 -0
  138. package/templates/react-router/src/components/error_boundary.tsx +33 -0
  139. package/templates/react-router/src/layouts/sidebar/sidebar_aside/sidebar_aside.tsx +76 -0
  140. package/templates/react-router/src/layouts/sidebar/sidebar_aside/user_menu.tsx +36 -0
  141. package/templates/react-router/src/layouts/sidebar/sidebar_layout.tsx +22 -0
  142. package/templates/react-router/src/providers/api_auth_provider.tsx +38 -0
  143. package/templates/react-router/src/root.tsx +37 -0
  144. package/templates/react-router/src/routes/auth/layout.tsx +13 -0
  145. package/templates/react-router/src/routes/auth/sign-in.tsx +13 -0
  146. package/templates/react-router/src/routes/index.tsx +9 -0
  147. package/templates/react-router/src/routes/layout.tsx +26 -0
  148. package/templates/react-router/src/routes/todos/[id].tsx +22 -0
  149. package/templates/react-router/src/routes/todos/index.tsx +13 -0
  150. package/templates/react-router/src/routes.ts +12 -0
  151. package/templates/react-router/src/surfaces/home_surface.tsx +20 -0
  152. package/templates/react-router/src/surfaces/todos/all_todos_surface.tsx +87 -0
  153. package/templates/react-router/src/surfaces/todos/create_todo_sheet.tsx +102 -0
  154. package/templates/react-router/src/surfaces/todos/single_todo_surface.tsx +81 -0
  155. package/templates/react-router/tsconfig.json +20 -0
  156. package/templates/react-router/vite.config.ts +40 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-aron-app",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Scaffold a new Convex + Next.js + Clerk full-stack project",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,11 +8,14 @@
8
8
  "create-aron-app": "./dist/index.js"
9
9
  },
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "templates"
12
13
  ],
13
14
  "scripts": {
14
15
  "build": "bun build src/index.ts --target=node --outfile=dist/index.js --minify && echo '#!/usr/bin/env node' | cat - dist/index.js > /tmp/create-tmp.js && mv /tmp/create-tmp.js dist/index.js && chmod +x dist/index.js",
15
16
  "start": "bun run src/index.ts",
17
+ "patch": "npm version patch",
18
+ "publish": "npm publish --access public",
16
19
  "prepublishOnly": "bun run build"
17
20
  },
18
21
  "dependencies": {
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: clerk
3
+ description: Clerk authentication router. Use when user asks about adding authentication, setting up Clerk, custom sign-in flows, Swift or native iOS auth, native Android auth, Next.js patterns, organizations, syncing users, or testing. Automatically routes to the specific skill based on their task.
4
+ ---
5
+
6
+ # Clerk Skills Router
7
+
8
+ ## Version Detection
9
+
10
+ Check `package.json` to determine the Clerk SDK version. This determines which patterns to use:
11
+
12
+ | Package | Core 2 (LTS until Jan 2027) | Current |
13
+ |---------|----------------------------|---------|
14
+ | `@clerk/nextjs` | v5–v6 | v7+ |
15
+ | `@clerk/react` or `@clerk/clerk-react` | v5–v6 | v7+ |
16
+ | `@clerk/expo` or `@clerk/clerk-expo` | v1–v2 | v3+ |
17
+ | `@clerk/react-router` | v1–v2 | v3+ |
18
+ | `@clerk/tanstack-react-start` | < v0.26.0 | v0.26.0+ |
19
+
20
+ **Default to current** if the version is unclear or the project is new. Core 2 packages use `@clerk/clerk-react` and `@clerk/clerk-expo` (with `clerk-` prefix); current packages use `@clerk/react` and `@clerk/expo`.
21
+
22
+ All skills are written for the current SDK. When something differs in Core 2, it's noted inline with `> **Core 2 ONLY (skip if current SDK):**` callouts. The exception is `clerk-custom-ui`, which has separate `core-2/` and `core-3/` directories for custom flow hooks since those APIs are entirely different between versions.
23
+
24
+ ---
25
+
26
+ ## By Task
27
+
28
+ **Adding Clerk to your project** → Use `clerk-setup`
29
+ - Framework detection and quickstart
30
+ - Environment setup, API keys, Keyless flow
31
+ - Migration from other auth providers
32
+
33
+ **Custom sign-in/sign-up UI** → Use `clerk-custom-ui`
34
+ - Custom authentication flows with `useSignIn` / `useSignUp` hooks
35
+ - Appearance and styling (themes, colors, layout)
36
+ - `<Show>` component for conditional rendering
37
+
38
+ **Advanced Next.js patterns** → Use `clerk-nextjs-patterns`
39
+ - Server vs Client auth APIs
40
+ - Middleware strategies
41
+ - Server Actions, caching
42
+ - API route protection
43
+
44
+ **B2B / Organizations** → Use `clerk-orgs`
45
+ - Multi-tenant apps
46
+ - Organization slugs in URLs
47
+ - Roles, permissions, RBAC
48
+ - Member management
49
+
50
+ **Webhooks** → Use `clerk-webhooks`
51
+ - Real-time events
52
+ - Data syncing
53
+ - Notifications & integrations
54
+
55
+ **E2E Testing** → Use `clerk-testing`
56
+ - Playwright/Cypress setup
57
+ - Auth flow testing
58
+ - Test utilities
59
+
60
+ **Swift / native iOS auth** → Use `clerk-swift`
61
+ - Native iOS Swift and SwiftUI projects
62
+ - ClerkKit and ClerkKitUI implementation guidance
63
+ - Source-driven patterns from `clerk-ios`
64
+
65
+ **Android / native mobile auth** → Use `clerk-android`
66
+ - Native Android Kotlin and Jetpack Compose projects
67
+ - `clerk-android-api` and `clerk-android-ui` implementation guidance
68
+ - Source-driven patterns from `clerk-android`
69
+ - Do not use for Expo or React Native projects
70
+
71
+ **Backend REST API** → Use `clerk-backend-api`
72
+ - Browse API tags and endpoints
73
+ - Inspect endpoint schemas
74
+ - Execute API requests with scope enforcement
75
+
76
+ ## Quick Navigation
77
+
78
+ If you know your task, you can directly access:
79
+ - `/clerk-setup` - Framework setup
80
+ - `/clerk-custom-ui` - Custom flows & appearance
81
+ - `/clerk-nextjs-patterns` - Next.js patterns
82
+ - `/clerk-orgs` - Organizations
83
+ - `/clerk-webhooks` - Webhooks
84
+ - `/clerk-testing` - Testing
85
+ - `/clerk-swift` - Swift/native iOS
86
+ - `/clerk-android` - Native Android
87
+ - `/clerk-backend-api` - Backend REST API
88
+
89
+ Or describe what you need and I'll recommend the right one.
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: clerk-backend-api
3
+ description: "Clerk backend REST API"
4
+ argument-hint: "[endpointOrTag] [method]"
5
+ allowed-tools: Bash, Read, Grep, Skill, WebFetch
6
+ ---
7
+
8
+ ## Options context
9
+
10
+ User Prompt: $ARGUMENTS
11
+
12
+ ## API specs context
13
+
14
+ Before doing anything, fetch the available spec versions and tags by running:
15
+ ```bash
16
+ bash scripts/api-specs-context.sh
17
+ ```
18
+
19
+ Use the output to determine the latest version and available tags.
20
+
21
+ **Caching:** If you already fetched the spec context earlier in this conversation, do NOT fetch it again. Reuse the version and tags from the previous call.
22
+
23
+ ## Rules
24
+
25
+ - Always disregard endpoints/schemas related to `platform`.
26
+ - Always confirm before performing write requests.
27
+ - For write operations (POST/PUT/PATCH/DELETE), check if `CLERK_BAPI_SCOPES` includes the required scope. If not, ask the user upfront: "This is a write/delete operation and your current scopes don't allow it. Run with --admin to bypass?" Do NOT attempt the request first and fail — ask before executing.
28
+
29
+ ## Modes
30
+
31
+ Determine the active mode based on the user prompt in [Options context](#options-context):
32
+
33
+ | Mode | Trigger | Behavior |
34
+ |------|---------|----------|
35
+ | `help` | Prompt is empty, or contains only `help` / `-h` / `--help` | Print usage examples (step 0) |
36
+ | `browse` | Prompt is `tags`, or a tag name (e.g. `Users`) | List all tags or endpoints for a tag |
37
+ | `execute` | Specific endpoint (e.g. `GET /users`) or natural language action (e.g. "get user john_doe") | Look up endpoint, execute request |
38
+ | `detail` | Endpoint + `help` / `-h` / `--help` (e.g. `GET /users help`) | Show endpoint schema, don't execute |
39
+
40
+ ## Your Task
41
+
42
+ Use the **LATEST VERSION** from [API specs context](#api-specs-context) by default. If the user specifies a different version (e.g. `--version 2024-10-01`), use that version instead.
43
+
44
+ Determine the active mode, then follow the applicable steps below.
45
+
46
+ ---
47
+
48
+ ### 0. Print usage
49
+
50
+ **Modes:** `help` only — **Skip** for `browse`, `execute`, and `detail`.
51
+
52
+ Print the following examples to the user verbatim:
53
+
54
+ ```
55
+ Browse
56
+ /clerk-backend-api tags — list all tags
57
+ /clerk-backend-api Users — browse endpoints for the Users tag
58
+ /clerk-backend-api Users version 2025-11-10.yml — browse using a different version
59
+
60
+ Execute
61
+ /clerk-backend-api GET /users — fetch all users
62
+ /clerk-backend-api get user john_doe — natural language works too
63
+ /clerk-backend-api POST /invitations — create an invitation
64
+
65
+ Inspect
66
+ /clerk-backend-api GET /users help — show endpoint schema without executing
67
+ /clerk-backend-api POST /invitations -h — view request/response details
68
+
69
+ Options
70
+ --admin — bypass scope restrictions for write/delete
71
+ --version [date], version [date] — use a specific spec version
72
+ --help, -h, help — inspect endpoint instead of executing
73
+ ```
74
+
75
+ Stop here.
76
+
77
+ ---
78
+
79
+ ### 1. Fetch tags
80
+
81
+ **Modes:** `browse` (when prompt is `tags` or no tag specified) — **Skip** for `help`, `execute`, and `detail`.
82
+
83
+ If using a non-latest version, fetch tags for that version:
84
+ ```bash
85
+ curl -s https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi/${version_name} | node scripts/extract-tags.js
86
+ ```
87
+ Otherwise, use the **TAGS** already in [API specs context](#api-specs-context).
88
+
89
+ Share tags in a table and prompt the user to select a query.
90
+
91
+ ---
92
+
93
+ ### 2. Fetch tag endpoints
94
+
95
+ **Modes:** `browse` (when a tag name is provided) — **Skip** for `help`, `execute`, and `detail`.
96
+
97
+ Fetch all endpoints for the identified tag:
98
+ ```bash
99
+ curl -s https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi/${version_name} | bash scripts/extract-tag-endpoints.sh "${tag_name}"
100
+ ```
101
+
102
+ Share the results (endpoints, schemas, parameters) with the user.
103
+
104
+ ---
105
+
106
+ ### 3. Fetch endpoint detail
107
+
108
+ **Modes:** `execute`, `detail` — **Skip** for `help` and `browse`.
109
+
110
+ For natural language prompts in `execute` mode, first identify the matching endpoint by searching the tags in context. Fetch tag endpoints if needed to resolve the exact path and method.
111
+
112
+ Extract the full endpoint definition:
113
+ ```bash
114
+ curl -s https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi/${version_name} | bash scripts/extract-endpoint-detail.sh "${path}" "${method}"
115
+ ```
116
+ - `${path}` — e.g. `/users/{user_id}`
117
+ - `${method}` — lowercase, e.g. `get`
118
+
119
+ **`detail` mode:** Share the endpoint definition and schemas with the user. Stop here.
120
+
121
+ **`execute` mode:** Continue to step 4.
122
+
123
+ ---
124
+
125
+ ### 4. Execute request
126
+
127
+ **Modes:** `execute` only.
128
+
129
+ Use the endpoint definition from step 3 to build the request:
130
+
131
+ 1. Identify required and optional parameters from the spec.
132
+ 2. Ask the user for any required path/query/body parameters.
133
+ 3. Execute via the request script:
134
+ ```bash
135
+ bash scripts/execute-request.sh [--admin] ${METHOD} "${path}" ['${body_json}']
136
+ ```
137
+ - `--admin` — pass this if the user confirmed admin bypass (see Rules)
138
+ - `${METHOD}` — uppercase HTTP method
139
+ - `${path}` — resolved path with parameters filled in (e.g. `/users/user_abc123`)
140
+ - `${body_json}` — optional JSON body for POST/PUT/PATCH
141
+
142
+ 4. Share the response with the user.
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Fetches all available BAPI spec versions, determines the latest,
4
+ # and extracts tags from it. Output is used as skill context.
5
+
6
+ set -euo pipefail
7
+
8
+ API_URL="https://api.github.com/repos/clerk/openapi-specs/contents/bapi"
9
+ RAW_BASE="https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi"
10
+
11
+ # Fetch version list, parse dates, sort, pick latest
12
+ versions=$(curl -s "$API_URL" | node -e "
13
+ let d='';
14
+ process.stdin.on('data',c=>d+=c);
15
+ process.stdin.on('end',()=>{
16
+ const items = JSON.parse(d)
17
+ .map(i=>i.name)
18
+ .filter(n=>/^\d{4}-\d{2}-\d{2}\.yml$/.test(n))
19
+ .sort();
20
+ items.forEach(n=>console.log(n));
21
+ });
22
+ ")
23
+
24
+ latest=$(echo "$versions" | tail -1)
25
+
26
+ echo "AVAILABLE VERSIONS: $(echo "$versions" | tr '\n' ' ')"
27
+ echo "LATEST VERSION: $latest"
28
+ echo ""
29
+ echo "TAGS:"
30
+ curl -s "${RAW_BASE}/${latest}" | node "$(dirname "$0")/extract-tags.js"
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Execute a Clerk Backend API request with scope enforcement.
4
+ #
5
+ # Usage: bash execute-request.sh [--admin] <METHOD> <PATH> [BODY]
6
+ #
7
+ # Scope enforcement:
8
+ # GET — always allowed
9
+ # POST, PUT, PATCH — requires CLERK_BAPI_SCOPES="write" or --admin flag
10
+ # DELETE — requires CLERK_BAPI_SCOPES="write,delete" or --admin flag
11
+
12
+ set -euo pipefail
13
+
14
+ # Walk up from $PWD to find .env/.env.local (mirrors Clerk CLI behavior).
15
+ # Stops at the first directory that provides CLERK_SECRET_KEY.
16
+ _dir="$PWD"
17
+ while true; do
18
+ for _envfile in "$_dir/.env" "$_dir/.env.local"; do
19
+ if [[ -f "$_envfile" ]]; then
20
+ set -a
21
+ source "$_envfile"
22
+ set +a
23
+ fi
24
+ done
25
+ [[ -n "${CLERK_SECRET_KEY:-}" ]] && break
26
+ _parent="$(dirname "$_dir")"
27
+ [[ "$_parent" == "$_dir" ]] && break
28
+ _dir="$_parent"
29
+ done
30
+ unset _dir _parent _envfile
31
+
32
+ # Parse --admin flag
33
+ ADMIN=false
34
+ if [[ "${1:-}" == "--admin" ]]; then
35
+ ADMIN=true
36
+ shift
37
+ fi
38
+
39
+ METHOD="${1:?Usage: execute-request.sh [--admin] <METHOD> <PATH> [BODY]}"
40
+ PATH_ARG="${2:?Usage: execute-request.sh [--admin] <METHOD> <PATH> [BODY]}"
41
+ BODY="${3:-}"
42
+
43
+ METHOD_UPPER=$(echo "$METHOD" | tr '[:lower:]' '[:upper:]')
44
+ SCOPES="${CLERK_BAPI_SCOPES:-}"
45
+
46
+ # Scope check
47
+ if [[ "$ADMIN" == false ]]; then
48
+ case "$METHOD_UPPER" in
49
+ GET)
50
+ ;; # always allowed
51
+ POST|PUT|PATCH)
52
+ if [[ "$SCOPES" != *"write"* ]]; then
53
+ echo "ERROR: $METHOD_UPPER requests require CLERK_BAPI_SCOPES=\"write\" or --admin flag." >&2
54
+ echo "Current CLERK_BAPI_SCOPES: \"$SCOPES\"" >&2
55
+ exit 1
56
+ fi
57
+ ;;
58
+ DELETE)
59
+ if [[ "$SCOPES" != *"write"* ]] || [[ "$SCOPES" != *"delete"* ]]; then
60
+ echo "ERROR: DELETE requests require CLERK_BAPI_SCOPES=\"write,delete\" or --admin flag." >&2
61
+ echo "Current CLERK_BAPI_SCOPES: \"$SCOPES\"" >&2
62
+ exit 1
63
+ fi
64
+ ;;
65
+ *)
66
+ echo "ERROR: Unknown HTTP method: $METHOD_UPPER" >&2
67
+ exit 1
68
+ ;;
69
+ esac
70
+ fi
71
+
72
+ # Base URL: use CLERK_REST_API_URL if set, otherwise default to production
73
+ BASE_URL="${CLERK_REST_API_URL:-https://api.clerk.com}"
74
+
75
+ # Build curl command
76
+ CURL_ARGS=(
77
+ -s
78
+ -X "$METHOD_UPPER"
79
+ "${BASE_URL}/v1${PATH_ARG}"
80
+ -H "Authorization: Bearer ${CLERK_SECRET_KEY:?CLERK_SECRET_KEY is not set}"
81
+ -H "Content-Type: application/json"
82
+ )
83
+
84
+ if [[ -n "$BODY" ]]; then
85
+ CURL_ARGS+=(-d "$BODY")
86
+ fi
87
+
88
+ curl "${CURL_ARGS[@]}"
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env bash
2
+ # extract-endpoint-detail.sh
3
+ #
4
+ # Extracts full details for a specific endpoint from an OpenAPI YAML spec (stdin),
5
+ # including parameters, request body, responses, and all referenced component schemas.
6
+ #
7
+ # Usage:
8
+ # curl -s <spec-url> | bash extract-endpoint-detail.sh "/users/{user_id}/billing/subscription" "get"
9
+
10
+ set -euo pipefail
11
+
12
+ ENDPOINT="${1:?Usage: extract-endpoint-detail.sh <path> <method>}"
13
+ METHOD="${2:?Usage: extract-endpoint-detail.sh <path> <method>}"
14
+ TMPDIR_WORK=$(mktemp -d)
15
+ trap 'rm -rf "$TMPDIR_WORK"' EXIT
16
+
17
+ SPEC="$TMPDIR_WORK/spec.yml"
18
+ cat > "$SPEC"
19
+
20
+ node - "$ENDPOINT" "$METHOD" "$SPEC" <<'SCRIPT'
21
+ const fs = require("fs");
22
+ const endpoint = process.argv[2];
23
+ const method = process.argv[3].toLowerCase();
24
+ const specFile = process.argv[4];
25
+ const lines = fs.readFileSync(specFile, "utf8").split("\n");
26
+
27
+ const httpMethods = ["get", "post", "put", "patch", "delete", "options", "head"];
28
+
29
+ // Locate paths: and components: sections
30
+ let pathsStart = -1, pathsEnd = -1, componentsStart = -1;
31
+ for (let i = 0; i < lines.length; i++) {
32
+ if (/^paths:\s*$/.test(lines[i])) pathsStart = i;
33
+ else if (pathsStart >= 0 && pathsEnd < 0 && /^\S/.test(lines[i]) && i > pathsStart) pathsEnd = i;
34
+ if (/^components:\s*$/.test(lines[i])) componentsStart = i;
35
+ }
36
+ if (pathsEnd < 0) pathsEnd = lines.length;
37
+
38
+ // Find the target path + method block
39
+ let targetStart = -1, targetEnd = -1;
40
+ let currentPath = null;
41
+
42
+ for (let i = pathsStart + 1; i < pathsEnd; i++) {
43
+ const line = lines[i];
44
+
45
+ // Path line: exactly 2 spaces + /
46
+ if (/^ {2}\/\S/.test(line)) {
47
+ currentPath = line.trim().replace(/:$/, "");
48
+ continue;
49
+ }
50
+
51
+ // Method line: exactly 4 spaces + method name
52
+ const methodMatch = line.match(/^ {4}(\w+):\s*$/);
53
+ if (methodMatch && httpMethods.includes(methodMatch[1])) {
54
+ if (currentPath === endpoint && methodMatch[1] === method) {
55
+ targetStart = i;
56
+ // Find end of this method block
57
+ for (let j = i + 1; j < pathsEnd; j++) {
58
+ const nextLine = lines[j];
59
+ // New method or new path
60
+ if (/^ {2}\/\S/.test(nextLine) || (/^ {4}\w+:\s*$/.test(nextLine) && httpMethods.some(m => nextLine.trim().startsWith(m + ":")))) {
61
+ targetEnd = j;
62
+ break;
63
+ }
64
+ }
65
+ if (targetEnd < 0) targetEnd = pathsEnd;
66
+ break;
67
+ }
68
+ }
69
+ }
70
+
71
+ if (targetStart < 0) {
72
+ console.error(`Endpoint not found: ${method.toUpperCase()} ${endpoint}`);
73
+ process.exit(1);
74
+ }
75
+
76
+ const blockLines = lines.slice(targetStart, targetEnd);
77
+
78
+ // Collect all $refs from the block
79
+ const allRefs = new Set();
80
+ for (const bl of blockLines) {
81
+ const refMatch = bl.match(/\$ref:\s*['"]?(#\/[^'"}\s]+)['"]?/);
82
+ if (refMatch) allRefs.add(refMatch[1]);
83
+ }
84
+
85
+ // Resolve a $ref path to the raw YAML lines for that component
86
+ function resolveRef(ref) {
87
+ const parts = ref.replace("#/", "").split("/");
88
+ // Find the component in the file by walking indentation
89
+ let searchStart = 0;
90
+ for (let p = 0; p < parts.length; p++) {
91
+ const indent = p * 2;
92
+ const target = " ".repeat(indent) + parts[p] + ":";
93
+ let found = false;
94
+ for (let i = searchStart; i < lines.length; i++) {
95
+ if (lines[i].startsWith(target) && (lines[i] === target || lines[i][target.length] === " ")) {
96
+ searchStart = i + 1;
97
+ found = true;
98
+ break;
99
+ }
100
+ }
101
+ if (!found) return null;
102
+ }
103
+
104
+ // Collect lines for this component (until same or lower indent)
105
+ const componentStart = searchStart - 1;
106
+ const baseIndent = parts.length * 2;
107
+ const result = [];
108
+ for (let i = searchStart; i < lines.length; i++) {
109
+ const line = lines[i];
110
+ if (line.trim() === "") { result.push(line); continue; }
111
+ const lineIndent = line.length - line.trimStart().length;
112
+ if (lineIndent < baseIndent) break;
113
+ result.push(line);
114
+ }
115
+ return result;
116
+ }
117
+
118
+ // Recursively resolve refs from component bodies
119
+ function collectDeepRefs(refSet, visited) {
120
+ const toProcess = [...refSet].filter(r => !visited.has(r));
121
+ for (const ref of toProcess) {
122
+ visited.add(ref);
123
+ const body = resolveRef(ref);
124
+ if (!body) continue;
125
+ for (const bl of body) {
126
+ const refMatch = bl.match(/\$ref:\s*['"]?(#\/[^'"}\s]+)['"]?/);
127
+ if (refMatch && !visited.has(refMatch[1])) {
128
+ refSet.add(refMatch[1]);
129
+ }
130
+ }
131
+ }
132
+ // Recurse if new refs were found
133
+ const newRefs = [...refSet].filter(r => !visited.has(r));
134
+ if (newRefs.length > 0) collectDeepRefs(refSet, visited);
135
+ }
136
+
137
+ collectDeepRefs(allRefs, new Set());
138
+
139
+ // Output
140
+ console.log(`## \`${method.toUpperCase()}\` \`${endpoint}\`\n`);
141
+ console.log("### Endpoint Definition\n");
142
+ console.log("```yaml");
143
+ for (const bl of blockLines) {
144
+ console.log(bl);
145
+ }
146
+ console.log("```\n");
147
+
148
+ if (allRefs.size > 0) {
149
+ console.log(`### Referenced Components (${allRefs.size})\n`);
150
+ const sorted = [...allRefs].sort();
151
+ for (const ref of sorted) {
152
+ const name = ref.split("/").pop();
153
+ const category = ref.replace("#/", "").split("/").slice(0, -1).join("/");
154
+ console.log(`#### \`${name}\` (${category})\n`);
155
+ const body = resolveRef(ref);
156
+ if (body) {
157
+ console.log("```yaml");
158
+ for (const bl of body) console.log(bl);
159
+ console.log("```\n");
160
+ } else {
161
+ console.log("_(could not resolve)_\n");
162
+ }
163
+ }
164
+ }
165
+ SCRIPT