Skip to content

Commit 539f708

Browse files
committed
feat: implement marketplace readiness skill with 4 gap analysis checks
1 parent 82dfe98 commit 539f708

1 file changed

Lines changed: 195 additions & 23 deletions

File tree

  • plugin/skills/pipedrive-review-marketplace-readiness
Lines changed: 195 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,215 @@
11
---
22
name: pipedrive-review-marketplace-readiness
3-
description: Review a Pipedrive Marketplace integration project for readiness. Checks the project against the marketplace checklist and reports what passes, fails, or needs manual review.
3+
description: Review a Pipedrive Marketplace integration project for readiness. Checks the project for missing requirements and reports only what needs to be fixed before submission.
44
allowed-tools: [Read, Bash]
55
---
66

77
# Marketplace Readiness Review
88

9+
Checks 4 requirements for marketplace submission readiness. Reports only what is missing. If nothing is missing, the app is ready to submit.
10+
911
## Precondition
1012

11-
Read `marketplace-checklist.md` from the current directory. If it does not exist, tell the developer that this file is generated by `npx create-pipedrive-app` — they need to scaffold their project first with that command.
13+
Check that `src/app.ts` and `package.json` exist in the current directory. If they do not exist, tell the developer to run this skill from their project root and stop.
1214

1315
## Gather project context
1416

15-
Read the following files to understand the current state of the project:
17+
Read these files:
18+
19+
- `src/app.ts`
20+
- `package.json`
21+
- `src/pipedrive/client.ts` (if it exists)
22+
- `src/oauth/index.ts` (if it exists)
23+
24+
Find all TypeScript source files:
25+
26+
```bash
27+
find src -name "*.ts" | sort
28+
```
29+
30+
Read all files found.
31+
32+
## Run all 4 checks
33+
34+
Collect all failures before reporting. Do not stop at the first failure.
35+
36+
---
37+
38+
### Check 1: Token refresh for non-SDK API calls
39+
40+
Scan source files for `fetch(` or `axios` calls (including `axios.get`, `axios.post`, etc.) that include an Authorization header with a token value.
41+
42+
For each match:
43+
44+
1. Is it inside `src/pipedrive/client.ts`? → Skip. The SDK wrapper handles token refresh automatically via `onTokenUpdate`.
45+
2. Is the token taken directly from an OAuth response in the same function scope (e.g., `token.access_token` where `token` is the return value of `oauth2.authorize()`)? → Skip. This is a fresh token — no refresh needed.
46+
3. Is the token retrieved from the database (e.g., via `getTokenByCompany`, `stored.token`, `row.accessToken`, or similar)? → This is a stored token that can expire. Check if the same code path handles 401 responses by refreshing the token and retrying.
47+
48+
**Fail condition:** A stored token is used in a direct HTTP call without 401/refresh handling.
49+
50+
**Report if failing:**
51+
52+
Identify the specific file and line. Then output:
53+
54+
❌ Token refresh not handled for direct API calls
55+
56+
`src/path/to/file.ts` makes a direct HTTP call using a stored access token without handling 401 responses. When the token expires, this call will fail silently.
57+
58+
Fix: Either use `getClient(companyId)` from `src/pipedrive/client.ts` (which handles refresh automatically), or add a 401 retry that refreshes the token and retries the request.
59+
60+
---
61+
62+
### Check 2: HTTPS enforced
63+
64+
**Sub-check A — no hardcoded HTTP URLs:**
65+
66+
Run:
67+
68+
```bash
69+
grep -rn "http://" src --include="*.ts" | grep -v "localhost" | grep -v "127.0.0.1"
70+
```
71+
72+
Any output is a failure. List each match with file and line number.
73+
74+
**Report if sub-check A failing:**
75+
76+
❌ Hardcoded HTTP URLs found
77+
78+
The following URLs use HTTP instead of HTTPS:
79+
- `src/path/to/file.ts:42`: `http://example.com/endpoint`
80+
81+
Fix: Replace with `https://` URLs. Pipedrive requires all external calls to use HTTPS in production.
82+
83+
**Sub-check B — trust proxy configured:**
84+
85+
Run:
86+
87+
```bash
88+
grep -n "trust proxy" src/app.ts
89+
```
90+
91+
No output is a failure.
92+
93+
**Report if sub-check B failing:**
94+
95+
❌ trust proxy not configured
1696

17-
- `src/app.ts` — confirms OAuth and extension routers are mounted
18-
- `src/oauth/index.ts` — confirms OAuth flow is implemented
19-
- `.env.example` — confirms required env vars are documented
20-
- `docker-compose.yml` — confirms containerised dev setup
21-
- `package.json` — confirms project name, dependencies, and scripts
97+
`src/app.ts` does not set `trust proxy`. Without it, Express cannot detect the protocol used by the
98+
client when the app runs behind a reverse proxy (Nginx, load balancer, etc.). This breaks HTTPS
99+
enforcement and secure cookie handling in production.
22100

23-
## Review
101+
Fix: Add to `src/app.ts` before any route definitions:
24102

25-
For each item in `marketplace-checklist.md`, determine whether the project:
26-
-**Passes** — evidence found in the code
27-
-**Fails** — required code or config is missing or incorrect
28-
- ⚠️ **Unclear** — cannot be determined from static analysis alone (requires manual testing or runtime verification)
103+
```ts
104+
app.set('trust proxy', 1);
105+
```
29106

30-
## Report
107+
---
108+
109+
### Check 3: Error handling
110+
111+
**Sub-check A — Express error handler in app.ts:**
112+
113+
Run:
114+
115+
```bash
116+
grep -n "NextFunction" src/app.ts
117+
```
118+
119+
Look for a 4-argument middleware with the signature `(err: Error, _req: Request, res: Response, _next: NextFunction)`. If no such handler exists, this sub-check fails.
120+
121+
**Report if sub-check A failing:**
122+
123+
❌ No Express error handler
124+
125+
`src/app.ts` has no error-handling middleware. Unhandled errors will crash the process or send empty
126+
responses to the client.
127+
128+
Fix: Add before `export default app`:
129+
130+
```ts
131+
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
132+
console.error(err);
133+
res.status(500).json({ error: err.message });
134+
});
135+
```
136+
137+
**Sub-check B — async route handlers with try/catch:**
138+
139+
Run:
140+
141+
```bash
142+
grep -rn "async.*req.*res" src --include="*.ts"
143+
```
144+
145+
For each async route handler found, read the surrounding code and verify the function body has a try/catch block that calls `next(err)` in the catch. If any handler lacks it, this sub-check fails.
146+
147+
**Report if sub-check B failing:**
148+
149+
❌ Async route handlers without error handling
150+
151+
The following route handlers do not catch errors:
152+
- `src/path/to/file.ts:15`
153+
154+
Fix: Wrap each async handler body in try/catch and pass errors to next:
155+
156+
```ts
157+
router.get('/example', async (req, res, next) => {
158+
try {
159+
// handler logic
160+
} catch (err) {
161+
next(err);
162+
}
163+
});
164+
```
165+
166+
---
167+
168+
### Check 4: Rate limit handling
169+
170+
Run:
171+
172+
```bash
173+
grep -rn "429\|X-RateLimit\|Retry-After" src --include="*.ts"
174+
```
175+
176+
**Fail condition:** No matches found.
177+
178+
**Report if failing:**
179+
180+
❌ No rate limit handling
181+
182+
Pipedrive enforces API rate limits per OAuth token. When the limit is exceeded, the API returns HTTP
183+
429. Without handling this, your app will silently fail under load.
184+
185+
Headers returned on every API response:
186+
- `X-RateLimit-Limit` — requests allowed per 10 seconds
187+
- `X-RateLimit-Remaining` — requests remaining in the current window
188+
- `X-RateLimit-Reset` — Unix timestamp when the limit resets
189+
190+
Fix: Add 429 handling to your API calls. Example retry pattern:
191+
192+
```ts
193+
async function callWithRetry(fn: () => Promise<Response>): Promise<Response> {
194+
const response = await fn();
195+
if (response.status === 429) {
196+
const resetAt = Number(response.headers.get('X-RateLimit-Reset')) * 1000;
197+
const delay = Math.max(resetAt - Date.now(), 1000);
198+
await new Promise(resolve => setTimeout(resolve, delay));
199+
return fn();
200+
}
201+
return response;
202+
}
203+
```
204+
205+
Reference: https://pipedrive.readme.io/docs/core-api-concepts-rate-limiting#http-headers-and-response-codes
206+
207+
---
31208

32-
Present results in three sections:
209+
## Output
33210

34-
**Passing (✅)**
35-
List each passing item with a one-line explanation of what you found.
211+
If all 4 checks pass:
36212

37-
**Action required (❌)**
38-
For each failing item, provide:
39-
- What is missing or wrong
40-
- The specific change needed to fix it
213+
✅ All marketplace readiness checks passed. Your app is ready to submit.
41214

42-
**Manual review needed (⚠️)**
43-
List items that pass static checks but require the developer to verify at runtime (e.g. OAuth redirect actually works, extension iframe loads in Pipedrive).
215+
If any checks fail, output only the failing checks using the report formats above. Do not mention passing checks.

0 commit comments

Comments
 (0)