Commit c94a41d
feat(adapters): tier-1 batch 2 — asana, clickup, intercom, zendesk (#40)
* feat(adapters): scaffold tier-1 batch 2 — asana, clickup, intercom, zendesk
Adds 4 Tier-1 SaaS adapter packages with full implementation, mirroring
the batch-1 shape (hubspot/salesforce/pipedrive/jira):
- @relayfile/adapter-asana (PM; X-Hook-Signature HMAC-SHA256, two-phase handshake)
- @relayfile/adapter-clickup (PM; X-Signature HMAC-SHA256)
- @relayfile/adapter-intercom (Support; X-Hub-Signature HMAC-SHA1)
- @relayfile/adapter-zendesk (Support; X-Zendesk-Webhook-Signature-256 HMAC-SHA256, 5-min tolerance)
Each package follows the @relayfile/adapter-linear shape:
- <slug>-adapter.ts extending IntegrationAdapter (ingestWebhook,
computePath, computeSemantics, per-object helpers)
- path-mapper.ts (deterministic VFS paths)
- queries.ts + writeback.ts (read/write API mappings)
- webhook-normalizer.ts (real createHmac + timingSafeEqual)
- types.ts (config + payload types)
- tests covering accept-valid + reject-tampered signature paths
Per-package gates passed:
- tsc --noEmit clean for all 4 packages
- npm test passing: asana 12/12, clickup 12/12, intercom 14/14, zendesk 12/12
- Required route anchors present in code
- Line floors met (adapter.ts ≥ 400 lines, webhook-normalizer.ts ≥ 200 lines)
Also registers the 4 packages in .github/workflows/publish.yml per the
"Adding a new adapter package" convention in AGENTS.md.
Follow-ups (separate PRs): batches 3 & 4 (8 more T1 SaaS adapters), then
the catalog finalize PR. Verify pass against these 4 packages will run
before merge to catch any signature-scheme drift like the salesforce bug
caught in PR #38.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(zendesk): correct webhook signature header name + empty-body handling
The verify pass against batch 2 flagged this as a blocker: our code looked
up the signature in 'X-Zendesk-Webhook-Signature-256', but Zendesk's
verifying-webhooks reference (and the NangoHQ template) name the actual
header 'X-Zendesk-Webhook-Signature' (no '-256' suffix). As written,
validateZendeskWebhookSignature() would have returned reason='missing-
signature' for every real Zendesk delivery in production.
Despite the algorithm being SHA-256, the header name does not include the
suffix. This is a frequent source of bugs.
Changes:
- Renamed ZENDESK_SIGNATURE_256_HEADER -> ZENDESK_SIGNATURE_HEADER with
the correct value 'X-Zendesk-Webhook-Signature'.
- Kept the old export name as a deprecated alias so any external caller
importing it continues to compile but resolves to the right header.
- toRawBodyBuffer now returns Buffer.alloc(0) for null/undefined raw
payloads instead of falling back to JSON.stringify (which produced the
literal string 'undefined' or 'null' and would mismatch a true empty
body sent on GET/DELETE webhook deliveries).
Tests: 12/12 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(intercom): correct writeback HTTP methods (auto-fixed by ricky)
The verify pass against batch 2 caught two writeback method bugs in
@relayfile/adapter-intercom; ricky's new code-drift auto-fix path
dispatched a code-fix agent that patched them in place, then the
re-verify came back clean (verdict=PASS for all 4 batch-2 adapters).
Changes against Intercom's actual REST API:
- update_conversation: PATCH -> PUT
Intercom's /conversations/:id endpoint is documented as PUT for
updates, not PATCH. PATCH would 405 in production.
- update_company: PUT /companies/:id -> POST /companies (upsert)
Intercom does not expose PUT /companies/:id. Companies are
upserted via POST /companies keyed by company_id in the request
body. Updated method + endpoint accordingly.
Tests: 14/14 still passing.
This is the first end-to-end test of ricky PR #69 (auto-fix code drift).
The fix → restart-from-root → re-verify cycle worked as designed:
attempt 1 found drift, agent edited writeback.ts in place, attempt 2
re-ran the verify agents against the patched source and got PASS.
"Auto-fix: repaired after 2/7 attempt(s)" in the run summary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(adapters): address PR review feedback
* fix(adapters): address remaining PR #40 review findings
[Critical, zendesk] Test fixture used millisecond timestamp; production breaks
Zendesk's verifying-webhooks reference documents the
X-Zendesk-Webhook-Signature-Timestamp header as ISO 8601 UTC
(e.g. "2021-03-25T05:09:27Z"). The HMAC input is the raw header string
concatenated with the body.
The previous test fixture used '1710000000000' (millisecond string). The
validator parses both formats for the freshness check, but the HMAC was
computed against the millisecond literal — meaning the test never
validated the actual format Zendesk sends. In production, signature
verification would fail on every real webhook because the computed HMAC
wouldn't match (test signs against ms; provider signs against ISO 8601).
Fixture now uses "2024-01-15T12:00:00Z" with the correctly recomputed
signature. Introduced timestampEpochMs constant for the now-arithmetic
the tests do (Number('2024-01-15T12:00:00Z') is NaN).
Same change opportunistically swaps tests off the deprecated
ZENDESK_SIGNATURE_256_HEADER import (added in b4a8b86 with a deprecation
notice) onto ZENDESK_SIGNATURE_HEADER. Header value is identical;
intent now matches the canonical export.
[Major, clickup] Restrict signature input type from `unknown` to raw body
computeClickUpWebhookSignature accepted `unknown`; toRawBodyBuffer
silently fell back to JSON.stringify for already-parsed objects.
Re-serializing produces bytes that differ from the original request
(whitespace, key order), so the HMAC mismatches even when the secret
is right. Tightened input type to ClickUpWebhookRawBody (string |
Buffer | Uint8Array | ArrayBuffer); fallback now throws a clear error
for callers who slip past the type system via `as any`.
[Minor] Stop tracking .trajectories/ runtime state
Added .trajectories/ to .gitignore and removed the two tracked files.
Local agent runtime state should not appear in feature PR diffs.
Skipped findings (with rationale):
- "Update lockfile for new workspaces" (P1 from chatgpt-codex):
package-lock.json was already updated in commit b4a8b86 when running
`npm install --workspace=@relayfile/adapter-zendesk` brought all four
batch-2 packages into the lockfile as workspaces. Verified:
`grep '"packages/(asana|clickup|intercom|zendesk)"' package-lock.json`
matches all four.
- "Don't bump version in feature PR" for intercom (Major from
coderabbit): the new packages all start at version 0.1.0, which
matches the established pattern from PR #38 batch-1 (hubspot,
salesforce, pipedrive, jira also started at 0.1.0 and were bumped to
0.1.1 by the post-merge release commit a02e7ca). Changing only
intercom would create inconsistency. The publish workflow continues
to own the bump.
Tests across all 4 batch-2 packages: 54/54 passing.
asana 13/13
clickup 13/13
intercom 15/15
zendesk 13/13
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a02e7ca commit c94a41d
49 files changed
Lines changed: 12466 additions & 290 deletions
File tree
- .github/workflows
- .trajectories
- active
- packages
- asana
- src
- __tests__
- clickup
- src
- __tests__
- intercom
- src
- __tests__
- zendesk
- src
- __tests__
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
23 | 27 | | |
24 | 28 | | |
25 | 29 | | |
| |||
84 | 88 | | |
85 | 89 | | |
86 | 90 | | |
87 | | - | |
| 91 | + | |
88 | 92 | | |
89 | 93 | | |
90 | 94 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
This file was deleted.
This file was deleted.
0 commit comments