@clawpro/node 0.1.2 → 0.1.3

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.
package/dist/index.cjs CHANGED
@@ -21,9 +21,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ClawPro: () => ClawPro,
24
- ClawProError: () => ClawProError
24
+ ClawProError: () => ClawProError,
25
+ verifyWebhook: () => verifyWebhook
25
26
  });
26
27
  module.exports = __toCommonJS(index_exports);
28
+ var import_node_crypto = require("crypto");
27
29
  var ClawProError = class extends Error {
28
30
  status;
29
31
  code;
@@ -246,9 +248,26 @@ var UsageResource = class {
246
248
  }
247
249
  }
248
250
  };
251
+ function verifyWebhook(opts) {
252
+ const { payload, signature, secret, toleranceSec = 300 } = opts;
253
+ const parts = {};
254
+ for (const p of signature.split(",")) {
255
+ const i = p.indexOf("=");
256
+ if (i > 0) parts[p.slice(0, i).trim()] = p.slice(i + 1).trim();
257
+ }
258
+ const t = Number(parts.t);
259
+ const v1 = parts.v1;
260
+ if (!t || !v1) return false;
261
+ if (toleranceSec > 0 && Math.abs(Date.now() / 1e3 - t) > toleranceSec) return false;
262
+ const expected = (0, import_node_crypto.createHmac)("sha256", secret).update(`${t}.${payload}`).digest("hex");
263
+ const a = Buffer.from(expected);
264
+ const b = Buffer.from(v1);
265
+ return a.length === b.length && (0, import_node_crypto.timingSafeEqual)(a, b);
266
+ }
249
267
  // Annotate the CommonJS export names for ESM import in node:
250
268
  0 && (module.exports = {
251
269
  ClawPro,
252
- ClawProError
270
+ ClawProError,
271
+ verifyWebhook
253
272
  });
254
273
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @clawpro/node — official SDK for the ClawPro Instagram outbound API.\n *\n * ```ts\n * import { ClawPro } from '@clawpro/node'\n * const clawpro = new ClawPro({ apiKey: process.env.CLAWPRO_API_KEY! })\n * const { accounts } = await clawpro.accounts.list()\n * ```\n */\n\n// ─────────────────────────────── Types ───────────────────────────────────────\n\nexport type AccountStatus = 'new' | 'warming' | 'active' | 'challenged' | 'banned' | 'disconnected';\nexport type ProxyType = 'mobile' | 'isp' | 'residential' | 'none';\n\nexport interface Account {\n id: string;\n username: string;\n status: AccountStatus;\n warmupTier?: number;\n dailyDmCap?: number;\n}\n\nexport type CampaignStatus = 'draft' | 'active' | 'paused';\n\nexport interface CampaignTarget {\n username: string;\n lastCheckedPostId: string | null;\n}\n\nexport interface Campaign {\n id: string;\n accountId: string;\n name: string;\n status: CampaignStatus;\n targets: CampaignTarget[];\n offer: string;\n icpCriteria: string;\n dailyDmTarget: number;\n}\n\nexport type LeadStatus =\n | 'discovered' | 'enriched' | 'scored' | 'qualified' | 'rejected'\n | 'queued' | 'dmed' | 'replied' | 'booked';\n\nexport interface Message {\n id: string;\n direction: 'out' | 'in';\n body: string;\n status: string;\n sentAt: string | null;\n createdAt: string;\n}\n\nexport interface Lead {\n id: string;\n igUsername: string;\n fullName: string | null;\n sourceTargetUsername: string;\n engagementType: 'like' | 'comment';\n commentText: string | null;\n score: number | null;\n scoreReason: string | null;\n status: LeadStatus;\n messages?: Message[];\n}\n\nexport type WebhookType = 'generic' | 'slack';\nexport type WebhookEvent =\n | 'reply.received' | 'dm.sent' | 'dm.failed'\n | 'lead.qualified' | 'lead.booked'\n | 'account.active' | 'account.challenged' | 'account.banned';\n\nexport interface Webhook {\n id: string;\n label: string;\n url: string;\n type: WebhookType;\n events: (WebhookEvent | '*')[];\n active: boolean;\n lastStatus: number | null;\n lastDeliveryAt: string | null;\n lastError: string | null;\n /** Present only on the create response (generic HMAC secret). */\n secret?: string;\n}\n\nexport interface WebhookDelivery {\n id: string;\n event: string;\n status: 'pending' | 'delivered' | 'dead';\n attempts: number;\n lastStatusCode: number | null;\n lastError: string | null;\n nextRetryAt: string | null;\n deliveredAt: string | null;\n createdAt: string;\n}\n\nexport type ApiKeyEnv = 'production' | 'development';\nexport type ApiKeyAccess = 'full' | 'read' | 'write';\n\nexport interface ApiKey {\n id: string;\n name: string;\n environment: ApiKeyEnv;\n access: ApiKeyAccess;\n keyPrefix: string;\n createdAt: string;\n expiresAt: string | null;\n lastUsedAt: string | null;\n}\n\nexport interface UsageSummary {\n callsThisMonth: number;\n calls24h: number;\n errors: number;\n avgLatencyMs: number;\n}\n\nexport interface RequestLog {\n id: string;\n requestId: string;\n method: string;\n path: string;\n status: number;\n latencyMs: number;\n error: string | null;\n createdAt: string;\n keyName: string | null;\n keyPrefix: string | null;\n}\n\n// ─────────────────────────────── Errors ──────────────────────────────────────\n\n/** Thrown for any non-2xx API response. Inspect `status` / `requestId`. */\nexport class ClawProError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId?: string;\n constructor(message: string, opts: { status: number; code?: string; requestId?: string }) {\n super(message);\n this.name = 'ClawProError';\n this.status = opts.status;\n this.code = opts.code ?? 'error';\n this.requestId = opts.requestId;\n }\n}\n\n// ─────────────────────────────── Client ──────────────────────────────────────\n\nexport interface ClawProOptions {\n /** A `sk_live_…` / `sk_test_…` key from the developer portal. Sent as `X-API-Key`. */\n apiKey: string;\n /** API origin (no trailing slash). Defaults to https://api.tryclawpro.com */\n baseUrl?: string;\n /** Override the fetch implementation (defaults to global fetch). */\n fetch?: typeof fetch;\n /** Per-request timeout in ms (default 30000). */\n timeoutMs?: number;\n /** Auto-retry transient failures (network, 429, 5xx) with exponential backoff.\n * Default 2. 429s honor the `Retry-After` header; only idempotent methods\n * (GET/DELETE/PUT) are retried on network/5xx. */\n maxRetries?: number;\n}\n\ntype Query = Record<string, string | number | boolean | undefined | null>;\n\nexport class ClawPro {\n readonly accounts: AccountsResource;\n readonly campaigns: CampaignsResource;\n readonly leads: LeadsResource;\n readonly webhooks: WebhooksResource;\n readonly keys: ApiKeysResource;\n readonly usage: UsageResource;\n\n private readonly apiKey: string;\n private readonly base: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly maxRetries: number;\n\n constructor(opts: ClawProOptions) {\n if (!opts?.apiKey) throw new Error('ClawPro: `apiKey` is required');\n this.apiKey = opts.apiKey;\n const origin = (opts.baseUrl ?? 'https://api.tryclawpro.com').replace(/\\/$/, '');\n this.base = `${origin}/api/instagram`;\n this.fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!this.fetchImpl) throw new Error('ClawPro: no fetch available — pass `fetch` (Node <18)');\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n this.maxRetries = opts.maxRetries ?? 2;\n\n this.accounts = new AccountsResource(this);\n this.campaigns = new CampaignsResource(this);\n this.leads = new LeadsResource(this);\n this.webhooks = new WebhooksResource(this);\n this.keys = new ApiKeysResource(this);\n this.usage = new UsageResource(this);\n }\n\n /** @internal */\n async request<T>(method: string, path: string, opts: { body?: unknown; query?: Query } = {}): Promise<T> {\n const url = new URL(this.base + path);\n if (opts.query) {\n for (const [k, v] of Object.entries(opts.query)) {\n if (v !== undefined && v !== null && v !== '') url.searchParams.set(k, String(v));\n }\n }\n const idempotent = method === 'GET' || method === 'DELETE' || method === 'PUT';\n\n for (let attempt = 0; ; attempt++) {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n let res: Response;\n try {\n res = await this.fetchImpl(url.toString(), {\n method,\n headers: {\n 'X-API-Key': this.apiKey,\n Accept: 'application/json',\n ...(opts.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n },\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n signal: ctrl.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n // Network/timeout: safe to retry only idempotent methods.\n if (idempotent && attempt < this.maxRetries) { await sleep(backoff(attempt)); continue; }\n throw new ClawProError(`Network error: ${(err as Error).message}`, { status: 0, code: 'network_error' });\n }\n clearTimeout(timer);\n\n const requestId = res.headers.get('x-request-id') ?? undefined;\n // Transient server-side: 429 (didn't process → retry any method) or 5xx (idempotent only).\n const transient = res.status === 429 || res.status >= 500;\n const retryable = res.status === 429 || idempotent;\n if (transient && retryable && attempt < this.maxRetries) {\n const ra = Number(res.headers.get('retry-after'));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n\n const text = await res.text();\n const data = text ? safeJson(text) : undefined;\n if (!res.ok) {\n const message = (data && (data.message || data.error)) || `HTTP ${res.status}`;\n throw new ClawProError(message, { status: res.status, code: (data && data.error) || 'error', requestId });\n }\n return data as T;\n }\n }\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n/** Exponential backoff with jitter: ~250ms, ~500ms, ~1s … */\nconst backoff = (attempt: number) => Math.round((250 * 2 ** attempt) * (0.8 + Math.random() * 0.4));\n\nfunction safeJson(text: string): any {\n try { return JSON.parse(text); } catch { return { raw: text }; }\n}\n\n// ───────────────────────────── Resources ─────────────────────────────────────\n\nclass AccountsResource {\n constructor(private c: ClawPro) {}\n /** List connected sending accounts. */\n list() { return this.c.request<{ accounts: Account[] }>('GET', '/accounts').then((r) => r.accounts); }\n /** Connect a new sending account (a geo-matched mobile proxy is assigned). */\n create(input: { username: string; country?: string; proxyType?: ProxyType; proxyUrl?: string; timezone?: string }) {\n return this.c.request<{ account: Account }>('POST', '/accounts', { body: input }).then((r) => r.account);\n }\n /** Remove an account (cascades to its campaigns/leads/messages). */\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/accounts/${id}`); }\n}\n\nclass CampaignsResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ campaigns: Campaign[] }>('GET', '/campaigns').then((r) => r.campaigns); }\n create(input: { accountId: string; name: string; targets: string[]; offer?: string; icpCriteria?: string; dailyDmTarget?: number }) {\n return this.c.request<{ campaign: Campaign }>('POST', '/campaigns', { body: input }).then((r) => r.campaign);\n }\n update(id: string, patch: Partial<{ status: CampaignStatus; targets: string[]; offer: string; icpCriteria: string; dailyDmTarget: number; name: string }>) {\n return this.c.request<{ campaign: Campaign }>('PATCH', `/campaigns/${id}`, { body: patch }).then((r) => r.campaign);\n }\n /** Kick a discovery/scoring/queue run for a campaign. */\n run(id: string) { return this.c.request<{ discovered: number; scored: number; queued: number }>('POST', `/campaigns/${id}/run`); }\n /** Leads for a campaign, optionally filtered by status. */\n leads(id: string, opts: { status?: LeadStatus } = {}) {\n return this.c.request<{ leads: Lead[] }>('GET', `/campaigns/${id}/leads`, { query: { status: opts.status } }).then((r) => r.leads);\n }\n /** Threads with at least one message (the unified inbox). */\n inbox(id: string) { return this.c.request<{ threads: Lead[] }>('GET', `/campaigns/${id}/inbox`).then((r) => r.threads); }\n}\n\nclass LeadsResource {\n constructor(private c: ClawPro) {}\n /** Advance a lead — e.g. `{ status: 'booked' }` once a call is set (fires `lead.booked`). */\n update(id: string, patch: { status: 'qualified' | 'rejected' | 'booked' }) {\n return this.c.request<{ lead: Lead }>('PATCH', `/leads/${id}`, { body: patch }).then((r) => r.lead);\n }\n}\n\nclass WebhooksResource {\n constructor(private c: ClawPro) {}\n /** The catalog of subscribable event types. */\n events() { return this.c.request<{ events: WebhookEvent[] }>('GET', '/webhooks/events').then((r) => r.events); }\n list() { return this.c.request<{ webhooks: Webhook[] }>('GET', '/webhooks').then((r) => r.webhooks); }\n /** Create an endpoint. The generic HMAC `secret` is returned once, here. */\n create(input: { url: string; type?: WebhookType; events?: (WebhookEvent | '*')[]; label?: string }) {\n return this.c.request<{ webhook: Webhook }>('POST', '/webhooks', { body: { type: 'generic', events: ['*'], ...input } }).then((r) => r.webhook);\n }\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/webhooks/${id}`); }\n /** Send a `webhook.test` delivery. */\n test(id: string) { return this.c.request<unknown>('POST', `/webhooks/${id}/test`); }\n deliveries(id: string) { return this.c.request<{ deliveries: WebhookDelivery[] }>('GET', `/webhooks/${id}/deliveries`).then((r) => r.deliveries); }\n}\n\nclass ApiKeysResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ keys: ApiKey[] }>('GET', '/keys').then((r) => r.keys); }\n /** Returns `{ secret, key }` — the plaintext `secret` is shown only here. */\n create(input: { name: string; environment?: ApiKeyEnv; access?: ApiKeyAccess; expiresAt?: string | null }) {\n return this.c.request<{ secret: string; key: ApiKey }>('POST', '/keys', { body: input });\n }\n revoke(id: string) { return this.c.request<{ ok: true }>('DELETE', `/keys/${id}`); }\n}\n\nexport interface LogFilter {\n key?: string; method?: string; status?: '2xx' | '4xx' | '5xx';\n from?: string; to?: string; endpoint?: string; requestId?: string; search?: string;\n limit?: number; offset?: number;\n}\n\nclass UsageResource {\n constructor(private c: ClawPro) {}\n /** Calls this month / 24h / errors / avg latency. */\n summary() { return this.c.request<UsageSummary>('GET', '/usage'); }\n /** A single page of request logs (`limit` + `offset`). */\n logs(filter: LogFilter = {}) {\n return this.c.request<{ logs: RequestLog[] }>('GET', '/logs', { query: filter as Query }).then((r) => r.logs);\n }\n /** Auto-paginate every matching log:\n * `for await (const log of clawpro.usage.iterateLogs()) { … }` */\n async *iterateLogs(filter: Omit<LogFilter, 'offset'> = {}): AsyncGenerator<RequestLog, void, unknown> {\n const pageSize = filter.limit ?? 100;\n for (let offset = 0; ; offset += pageSize) {\n const page = await this.logs({ ...filter, limit: pageSize, offset });\n for (const row of page) yield row;\n if (page.length < pageSize) return;\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @clawpro/node — official SDK for the ClawPro Instagram outbound API.\n *\n * ```ts\n * import { ClawPro } from '@clawpro/node'\n * const clawpro = new ClawPro({ apiKey: process.env.CLAWPRO_API_KEY! })\n * const { accounts } = await clawpro.accounts.list()\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\n// ─────────────────────────────── Types ───────────────────────────────────────\n\nexport type AccountStatus = 'new' | 'warming' | 'active' | 'challenged' | 'banned' | 'disconnected';\nexport type ProxyType = 'mobile' | 'isp' | 'residential' | 'none';\n\nexport interface Account {\n id: string;\n username: string;\n status: AccountStatus;\n warmupTier?: number;\n dailyDmCap?: number;\n}\n\nexport type CampaignStatus = 'draft' | 'active' | 'paused';\n\nexport interface CampaignTarget {\n username: string;\n lastCheckedPostId: string | null;\n}\n\nexport interface Campaign {\n id: string;\n accountId: string;\n name: string;\n status: CampaignStatus;\n targets: CampaignTarget[];\n offer: string;\n icpCriteria: string;\n dailyDmTarget: number;\n}\n\nexport type LeadStatus =\n | 'discovered' | 'enriched' | 'scored' | 'qualified' | 'rejected'\n | 'queued' | 'dmed' | 'replied' | 'booked';\n\nexport interface Message {\n id: string;\n direction: 'out' | 'in';\n body: string;\n status: string;\n sentAt: string | null;\n createdAt: string;\n}\n\nexport interface Lead {\n id: string;\n igUsername: string;\n fullName: string | null;\n sourceTargetUsername: string;\n engagementType: 'like' | 'comment';\n commentText: string | null;\n score: number | null;\n scoreReason: string | null;\n status: LeadStatus;\n messages?: Message[];\n}\n\nexport type WebhookType = 'generic' | 'slack';\nexport type WebhookEvent =\n | 'reply.received' | 'dm.sent' | 'dm.failed'\n | 'lead.qualified' | 'lead.booked'\n | 'account.active' | 'account.challenged' | 'account.banned';\n\nexport interface Webhook {\n id: string;\n label: string;\n url: string;\n type: WebhookType;\n events: (WebhookEvent | '*')[];\n active: boolean;\n lastStatus: number | null;\n lastDeliveryAt: string | null;\n lastError: string | null;\n /** Present only on the create response (generic HMAC secret). */\n secret?: string;\n}\n\nexport interface WebhookDelivery {\n id: string;\n event: string;\n status: 'pending' | 'delivered' | 'dead';\n attempts: number;\n lastStatusCode: number | null;\n lastError: string | null;\n nextRetryAt: string | null;\n deliveredAt: string | null;\n createdAt: string;\n}\n\nexport type ApiKeyEnv = 'production' | 'development';\nexport type ApiKeyAccess = 'full' | 'read' | 'write';\n\nexport interface ApiKey {\n id: string;\n name: string;\n environment: ApiKeyEnv;\n access: ApiKeyAccess;\n keyPrefix: string;\n createdAt: string;\n expiresAt: string | null;\n lastUsedAt: string | null;\n}\n\nexport interface UsageSummary {\n callsThisMonth: number;\n calls24h: number;\n errors: number;\n avgLatencyMs: number;\n}\n\nexport interface RequestLog {\n id: string;\n requestId: string;\n method: string;\n path: string;\n status: number;\n latencyMs: number;\n error: string | null;\n createdAt: string;\n keyName: string | null;\n keyPrefix: string | null;\n}\n\n// ─────────────────────────────── Errors ──────────────────────────────────────\n\n/** Thrown for any non-2xx API response. Inspect `status` / `requestId`. */\nexport class ClawProError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId?: string;\n constructor(message: string, opts: { status: number; code?: string; requestId?: string }) {\n super(message);\n this.name = 'ClawProError';\n this.status = opts.status;\n this.code = opts.code ?? 'error';\n this.requestId = opts.requestId;\n }\n}\n\n// ─────────────────────────────── Client ──────────────────────────────────────\n\nexport interface ClawProOptions {\n /** A `sk_live_…` / `sk_test_…` key from the developer portal. Sent as `X-API-Key`. */\n apiKey: string;\n /** API origin (no trailing slash). Defaults to https://api.tryclawpro.com */\n baseUrl?: string;\n /** Override the fetch implementation (defaults to global fetch). */\n fetch?: typeof fetch;\n /** Per-request timeout in ms (default 30000). */\n timeoutMs?: number;\n /** Auto-retry transient failures (network, 429, 5xx) with exponential backoff.\n * Default 2. 429s honor the `Retry-After` header; only idempotent methods\n * (GET/DELETE/PUT) are retried on network/5xx. */\n maxRetries?: number;\n}\n\ntype Query = Record<string, string | number | boolean | undefined | null>;\n\nexport class ClawPro {\n readonly accounts: AccountsResource;\n readonly campaigns: CampaignsResource;\n readonly leads: LeadsResource;\n readonly webhooks: WebhooksResource;\n readonly keys: ApiKeysResource;\n readonly usage: UsageResource;\n\n private readonly apiKey: string;\n private readonly base: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly maxRetries: number;\n\n constructor(opts: ClawProOptions) {\n if (!opts?.apiKey) throw new Error('ClawPro: `apiKey` is required');\n this.apiKey = opts.apiKey;\n const origin = (opts.baseUrl ?? 'https://api.tryclawpro.com').replace(/\\/$/, '');\n this.base = `${origin}/api/instagram`;\n this.fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!this.fetchImpl) throw new Error('ClawPro: no fetch available — pass `fetch` (Node <18)');\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n this.maxRetries = opts.maxRetries ?? 2;\n\n this.accounts = new AccountsResource(this);\n this.campaigns = new CampaignsResource(this);\n this.leads = new LeadsResource(this);\n this.webhooks = new WebhooksResource(this);\n this.keys = new ApiKeysResource(this);\n this.usage = new UsageResource(this);\n }\n\n /** @internal */\n async request<T>(method: string, path: string, opts: { body?: unknown; query?: Query } = {}): Promise<T> {\n const url = new URL(this.base + path);\n if (opts.query) {\n for (const [k, v] of Object.entries(opts.query)) {\n if (v !== undefined && v !== null && v !== '') url.searchParams.set(k, String(v));\n }\n }\n const idempotent = method === 'GET' || method === 'DELETE' || method === 'PUT';\n\n for (let attempt = 0; ; attempt++) {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n let res: Response;\n try {\n res = await this.fetchImpl(url.toString(), {\n method,\n headers: {\n 'X-API-Key': this.apiKey,\n Accept: 'application/json',\n ...(opts.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n },\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n signal: ctrl.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n // Network/timeout: safe to retry only idempotent methods.\n if (idempotent && attempt < this.maxRetries) { await sleep(backoff(attempt)); continue; }\n throw new ClawProError(`Network error: ${(err as Error).message}`, { status: 0, code: 'network_error' });\n }\n clearTimeout(timer);\n\n const requestId = res.headers.get('x-request-id') ?? undefined;\n // Transient server-side: 429 (didn't process → retry any method) or 5xx (idempotent only).\n const transient = res.status === 429 || res.status >= 500;\n const retryable = res.status === 429 || idempotent;\n if (transient && retryable && attempt < this.maxRetries) {\n const ra = Number(res.headers.get('retry-after'));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n\n const text = await res.text();\n const data = text ? safeJson(text) : undefined;\n if (!res.ok) {\n const message = (data && (data.message || data.error)) || `HTTP ${res.status}`;\n throw new ClawProError(message, { status: res.status, code: (data && data.error) || 'error', requestId });\n }\n return data as T;\n }\n }\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n/** Exponential backoff with jitter: ~250ms, ~500ms, ~1s … */\nconst backoff = (attempt: number) => Math.round((250 * 2 ** attempt) * (0.8 + Math.random() * 0.4));\n\nfunction safeJson(text: string): any {\n try { return JSON.parse(text); } catch { return { raw: text }; }\n}\n\n// ───────────────────────────── Resources ─────────────────────────────────────\n\nclass AccountsResource {\n constructor(private c: ClawPro) {}\n /** List connected sending accounts. */\n list() { return this.c.request<{ accounts: Account[] }>('GET', '/accounts').then((r) => r.accounts); }\n /** Connect a new sending account (a geo-matched mobile proxy is assigned). */\n create(input: { username: string; country?: string; proxyType?: ProxyType; proxyUrl?: string; timezone?: string }) {\n return this.c.request<{ account: Account }>('POST', '/accounts', { body: input }).then((r) => r.account);\n }\n /** Remove an account (cascades to its campaigns/leads/messages). */\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/accounts/${id}`); }\n}\n\nclass CampaignsResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ campaigns: Campaign[] }>('GET', '/campaigns').then((r) => r.campaigns); }\n create(input: { accountId: string; name: string; targets: string[]; offer?: string; icpCriteria?: string; dailyDmTarget?: number }) {\n return this.c.request<{ campaign: Campaign }>('POST', '/campaigns', { body: input }).then((r) => r.campaign);\n }\n update(id: string, patch: Partial<{ status: CampaignStatus; targets: string[]; offer: string; icpCriteria: string; dailyDmTarget: number; name: string }>) {\n return this.c.request<{ campaign: Campaign }>('PATCH', `/campaigns/${id}`, { body: patch }).then((r) => r.campaign);\n }\n /** Kick a discovery/scoring/queue run for a campaign. */\n run(id: string) { return this.c.request<{ discovered: number; scored: number; queued: number }>('POST', `/campaigns/${id}/run`); }\n /** Leads for a campaign, optionally filtered by status. */\n leads(id: string, opts: { status?: LeadStatus } = {}) {\n return this.c.request<{ leads: Lead[] }>('GET', `/campaigns/${id}/leads`, { query: { status: opts.status } }).then((r) => r.leads);\n }\n /** Threads with at least one message (the unified inbox). */\n inbox(id: string) { return this.c.request<{ threads: Lead[] }>('GET', `/campaigns/${id}/inbox`).then((r) => r.threads); }\n}\n\nclass LeadsResource {\n constructor(private c: ClawPro) {}\n /** Advance a lead — e.g. `{ status: 'booked' }` once a call is set (fires `lead.booked`). */\n update(id: string, patch: { status: 'qualified' | 'rejected' | 'booked' }) {\n return this.c.request<{ lead: Lead }>('PATCH', `/leads/${id}`, { body: patch }).then((r) => r.lead);\n }\n}\n\nclass WebhooksResource {\n constructor(private c: ClawPro) {}\n /** The catalog of subscribable event types. */\n events() { return this.c.request<{ events: WebhookEvent[] }>('GET', '/webhooks/events').then((r) => r.events); }\n list() { return this.c.request<{ webhooks: Webhook[] }>('GET', '/webhooks').then((r) => r.webhooks); }\n /** Create an endpoint. The generic HMAC `secret` is returned once, here. */\n create(input: { url: string; type?: WebhookType; events?: (WebhookEvent | '*')[]; label?: string }) {\n return this.c.request<{ webhook: Webhook }>('POST', '/webhooks', { body: { type: 'generic', events: ['*'], ...input } }).then((r) => r.webhook);\n }\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/webhooks/${id}`); }\n /** Send a `webhook.test` delivery. */\n test(id: string) { return this.c.request<unknown>('POST', `/webhooks/${id}/test`); }\n deliveries(id: string) { return this.c.request<{ deliveries: WebhookDelivery[] }>('GET', `/webhooks/${id}/deliveries`).then((r) => r.deliveries); }\n}\n\nclass ApiKeysResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ keys: ApiKey[] }>('GET', '/keys').then((r) => r.keys); }\n /** Returns `{ secret, key }` — the plaintext `secret` is shown only here. */\n create(input: { name: string; environment?: ApiKeyEnv; access?: ApiKeyAccess; expiresAt?: string | null }) {\n return this.c.request<{ secret: string; key: ApiKey }>('POST', '/keys', { body: input });\n }\n revoke(id: string) { return this.c.request<{ ok: true }>('DELETE', `/keys/${id}`); }\n}\n\nexport interface LogFilter {\n key?: string; method?: string; status?: '2xx' | '4xx' | '5xx';\n from?: string; to?: string; endpoint?: string; requestId?: string; search?: string;\n limit?: number; offset?: number;\n}\n\nclass UsageResource {\n constructor(private c: ClawPro) {}\n /** Calls this month / 24h / errors / avg latency. */\n summary() { return this.c.request<UsageSummary>('GET', '/usage'); }\n /** A single page of request logs (`limit` + `offset`). */\n logs(filter: LogFilter = {}) {\n return this.c.request<{ logs: RequestLog[] }>('GET', '/logs', { query: filter as Query }).then((r) => r.logs);\n }\n /** Auto-paginate every matching log:\n * `for await (const log of clawpro.usage.iterateLogs()) { … }` */\n async *iterateLogs(filter: Omit<LogFilter, 'offset'> = {}): AsyncGenerator<RequestLog, void, unknown> {\n const pageSize = filter.limit ?? 100;\n for (let offset = 0; ; offset += pageSize) {\n const page = await this.logs({ ...filter, limit: pageSize, offset });\n for (const row of page) yield row;\n if (page.length < pageSize) return;\n }\n }\n}\n\n// ─────────────────────────── Webhook verification ────────────────────────────\n\nexport interface VerifyWebhookOptions {\n /** The raw request body, exactly as received (string). */\n payload: string;\n /** The `X-Souk-Signature` header value (`t=…,v1=…`). */\n signature: string;\n /** The endpoint's signing secret (shown once on webhook creation). */\n secret: string;\n /** Reject signatures older than this many seconds (default 300; 0 disables). */\n toleranceSec?: number;\n}\n\n/** Verify a ClawPro webhook's HMAC signature (timing-safe). Returns true if valid.\n *\n * ```ts\n * if (!verifyWebhook({ payload: rawBody, signature: req.headers['x-souk-signature'], secret })) return res.sendStatus(400)\n * ```\n */\nexport function verifyWebhook(opts: VerifyWebhookOptions): boolean {\n const { payload, signature, secret, toleranceSec = 300 } = opts;\n const parts: Record<string, string> = {};\n for (const p of signature.split(',')) {\n const i = p.indexOf('=');\n if (i > 0) parts[p.slice(0, i).trim()] = p.slice(i + 1).trim();\n }\n const t = Number(parts.t);\n const v1 = parts.v1;\n if (!t || !v1) return false;\n if (toleranceSec > 0 && Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;\n const expected = createHmac('sha256', secret).update(`${t}.${payload}`).digest('hex');\n const a = Buffer.from(expected);\n const b = Buffer.from(v1);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -273,5 +273,22 @@ declare class UsageResource {
273
273
  * `for await (const log of clawpro.usage.iterateLogs()) { … }` */
274
274
  iterateLogs(filter?: Omit<LogFilter, 'offset'>): AsyncGenerator<RequestLog, void, unknown>;
275
275
  }
276
+ interface VerifyWebhookOptions {
277
+ /** The raw request body, exactly as received (string). */
278
+ payload: string;
279
+ /** The `X-Souk-Signature` header value (`t=…,v1=…`). */
280
+ signature: string;
281
+ /** The endpoint's signing secret (shown once on webhook creation). */
282
+ secret: string;
283
+ /** Reject signatures older than this many seconds (default 300; 0 disables). */
284
+ toleranceSec?: number;
285
+ }
286
+ /** Verify a ClawPro webhook's HMAC signature (timing-safe). Returns true if valid.
287
+ *
288
+ * ```ts
289
+ * if (!verifyWebhook({ payload: rawBody, signature: req.headers['x-souk-signature'], secret })) return res.sendStatus(400)
290
+ * ```
291
+ */
292
+ declare function verifyWebhook(opts: VerifyWebhookOptions): boolean;
276
293
 
277
- export { type Account, type AccountStatus, type ApiKey, type ApiKeyAccess, type ApiKeyEnv, type Campaign, type CampaignStatus, type CampaignTarget, ClawPro, ClawProError, type ClawProOptions, type Lead, type LeadStatus, type LogFilter, type Message, type ProxyType, type RequestLog, type UsageSummary, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookType };
294
+ export { type Account, type AccountStatus, type ApiKey, type ApiKeyAccess, type ApiKeyEnv, type Campaign, type CampaignStatus, type CampaignTarget, ClawPro, ClawProError, type ClawProOptions, type Lead, type LeadStatus, type LogFilter, type Message, type ProxyType, type RequestLog, type UsageSummary, type VerifyWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookType, verifyWebhook };
package/dist/index.d.ts CHANGED
@@ -273,5 +273,22 @@ declare class UsageResource {
273
273
  * `for await (const log of clawpro.usage.iterateLogs()) { … }` */
274
274
  iterateLogs(filter?: Omit<LogFilter, 'offset'>): AsyncGenerator<RequestLog, void, unknown>;
275
275
  }
276
+ interface VerifyWebhookOptions {
277
+ /** The raw request body, exactly as received (string). */
278
+ payload: string;
279
+ /** The `X-Souk-Signature` header value (`t=…,v1=…`). */
280
+ signature: string;
281
+ /** The endpoint's signing secret (shown once on webhook creation). */
282
+ secret: string;
283
+ /** Reject signatures older than this many seconds (default 300; 0 disables). */
284
+ toleranceSec?: number;
285
+ }
286
+ /** Verify a ClawPro webhook's HMAC signature (timing-safe). Returns true if valid.
287
+ *
288
+ * ```ts
289
+ * if (!verifyWebhook({ payload: rawBody, signature: req.headers['x-souk-signature'], secret })) return res.sendStatus(400)
290
+ * ```
291
+ */
292
+ declare function verifyWebhook(opts: VerifyWebhookOptions): boolean;
276
293
 
277
- export { type Account, type AccountStatus, type ApiKey, type ApiKeyAccess, type ApiKeyEnv, type Campaign, type CampaignStatus, type CampaignTarget, ClawPro, ClawProError, type ClawProOptions, type Lead, type LeadStatus, type LogFilter, type Message, type ProxyType, type RequestLog, type UsageSummary, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookType };
294
+ export { type Account, type AccountStatus, type ApiKey, type ApiKeyAccess, type ApiKeyEnv, type Campaign, type CampaignStatus, type CampaignTarget, ClawPro, ClawProError, type ClawProOptions, type Lead, type LeadStatus, type LogFilter, type Message, type ProxyType, type RequestLog, type UsageSummary, type VerifyWebhookOptions, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookType, verifyWebhook };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/index.ts
2
+ import { createHmac, timingSafeEqual } from "crypto";
2
3
  var ClawProError = class extends Error {
3
4
  status;
4
5
  code;
@@ -221,8 +222,25 @@ var UsageResource = class {
221
222
  }
222
223
  }
223
224
  };
225
+ function verifyWebhook(opts) {
226
+ const { payload, signature, secret, toleranceSec = 300 } = opts;
227
+ const parts = {};
228
+ for (const p of signature.split(",")) {
229
+ const i = p.indexOf("=");
230
+ if (i > 0) parts[p.slice(0, i).trim()] = p.slice(i + 1).trim();
231
+ }
232
+ const t = Number(parts.t);
233
+ const v1 = parts.v1;
234
+ if (!t || !v1) return false;
235
+ if (toleranceSec > 0 && Math.abs(Date.now() / 1e3 - t) > toleranceSec) return false;
236
+ const expected = createHmac("sha256", secret).update(`${t}.${payload}`).digest("hex");
237
+ const a = Buffer.from(expected);
238
+ const b = Buffer.from(v1);
239
+ return a.length === b.length && timingSafeEqual(a, b);
240
+ }
224
241
  export {
225
242
  ClawPro,
226
- ClawProError
243
+ ClawProError,
244
+ verifyWebhook
227
245
  };
228
246
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @clawpro/node — official SDK for the ClawPro Instagram outbound API.\n *\n * ```ts\n * import { ClawPro } from '@clawpro/node'\n * const clawpro = new ClawPro({ apiKey: process.env.CLAWPRO_API_KEY! })\n * const { accounts } = await clawpro.accounts.list()\n * ```\n */\n\n// ─────────────────────────────── Types ───────────────────────────────────────\n\nexport type AccountStatus = 'new' | 'warming' | 'active' | 'challenged' | 'banned' | 'disconnected';\nexport type ProxyType = 'mobile' | 'isp' | 'residential' | 'none';\n\nexport interface Account {\n id: string;\n username: string;\n status: AccountStatus;\n warmupTier?: number;\n dailyDmCap?: number;\n}\n\nexport type CampaignStatus = 'draft' | 'active' | 'paused';\n\nexport interface CampaignTarget {\n username: string;\n lastCheckedPostId: string | null;\n}\n\nexport interface Campaign {\n id: string;\n accountId: string;\n name: string;\n status: CampaignStatus;\n targets: CampaignTarget[];\n offer: string;\n icpCriteria: string;\n dailyDmTarget: number;\n}\n\nexport type LeadStatus =\n | 'discovered' | 'enriched' | 'scored' | 'qualified' | 'rejected'\n | 'queued' | 'dmed' | 'replied' | 'booked';\n\nexport interface Message {\n id: string;\n direction: 'out' | 'in';\n body: string;\n status: string;\n sentAt: string | null;\n createdAt: string;\n}\n\nexport interface Lead {\n id: string;\n igUsername: string;\n fullName: string | null;\n sourceTargetUsername: string;\n engagementType: 'like' | 'comment';\n commentText: string | null;\n score: number | null;\n scoreReason: string | null;\n status: LeadStatus;\n messages?: Message[];\n}\n\nexport type WebhookType = 'generic' | 'slack';\nexport type WebhookEvent =\n | 'reply.received' | 'dm.sent' | 'dm.failed'\n | 'lead.qualified' | 'lead.booked'\n | 'account.active' | 'account.challenged' | 'account.banned';\n\nexport interface Webhook {\n id: string;\n label: string;\n url: string;\n type: WebhookType;\n events: (WebhookEvent | '*')[];\n active: boolean;\n lastStatus: number | null;\n lastDeliveryAt: string | null;\n lastError: string | null;\n /** Present only on the create response (generic HMAC secret). */\n secret?: string;\n}\n\nexport interface WebhookDelivery {\n id: string;\n event: string;\n status: 'pending' | 'delivered' | 'dead';\n attempts: number;\n lastStatusCode: number | null;\n lastError: string | null;\n nextRetryAt: string | null;\n deliveredAt: string | null;\n createdAt: string;\n}\n\nexport type ApiKeyEnv = 'production' | 'development';\nexport type ApiKeyAccess = 'full' | 'read' | 'write';\n\nexport interface ApiKey {\n id: string;\n name: string;\n environment: ApiKeyEnv;\n access: ApiKeyAccess;\n keyPrefix: string;\n createdAt: string;\n expiresAt: string | null;\n lastUsedAt: string | null;\n}\n\nexport interface UsageSummary {\n callsThisMonth: number;\n calls24h: number;\n errors: number;\n avgLatencyMs: number;\n}\n\nexport interface RequestLog {\n id: string;\n requestId: string;\n method: string;\n path: string;\n status: number;\n latencyMs: number;\n error: string | null;\n createdAt: string;\n keyName: string | null;\n keyPrefix: string | null;\n}\n\n// ─────────────────────────────── Errors ──────────────────────────────────────\n\n/** Thrown for any non-2xx API response. Inspect `status` / `requestId`. */\nexport class ClawProError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId?: string;\n constructor(message: string, opts: { status: number; code?: string; requestId?: string }) {\n super(message);\n this.name = 'ClawProError';\n this.status = opts.status;\n this.code = opts.code ?? 'error';\n this.requestId = opts.requestId;\n }\n}\n\n// ─────────────────────────────── Client ──────────────────────────────────────\n\nexport interface ClawProOptions {\n /** A `sk_live_…` / `sk_test_…` key from the developer portal. Sent as `X-API-Key`. */\n apiKey: string;\n /** API origin (no trailing slash). Defaults to https://api.tryclawpro.com */\n baseUrl?: string;\n /** Override the fetch implementation (defaults to global fetch). */\n fetch?: typeof fetch;\n /** Per-request timeout in ms (default 30000). */\n timeoutMs?: number;\n /** Auto-retry transient failures (network, 429, 5xx) with exponential backoff.\n * Default 2. 429s honor the `Retry-After` header; only idempotent methods\n * (GET/DELETE/PUT) are retried on network/5xx. */\n maxRetries?: number;\n}\n\ntype Query = Record<string, string | number | boolean | undefined | null>;\n\nexport class ClawPro {\n readonly accounts: AccountsResource;\n readonly campaigns: CampaignsResource;\n readonly leads: LeadsResource;\n readonly webhooks: WebhooksResource;\n readonly keys: ApiKeysResource;\n readonly usage: UsageResource;\n\n private readonly apiKey: string;\n private readonly base: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly maxRetries: number;\n\n constructor(opts: ClawProOptions) {\n if (!opts?.apiKey) throw new Error('ClawPro: `apiKey` is required');\n this.apiKey = opts.apiKey;\n const origin = (opts.baseUrl ?? 'https://api.tryclawpro.com').replace(/\\/$/, '');\n this.base = `${origin}/api/instagram`;\n this.fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!this.fetchImpl) throw new Error('ClawPro: no fetch available — pass `fetch` (Node <18)');\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n this.maxRetries = opts.maxRetries ?? 2;\n\n this.accounts = new AccountsResource(this);\n this.campaigns = new CampaignsResource(this);\n this.leads = new LeadsResource(this);\n this.webhooks = new WebhooksResource(this);\n this.keys = new ApiKeysResource(this);\n this.usage = new UsageResource(this);\n }\n\n /** @internal */\n async request<T>(method: string, path: string, opts: { body?: unknown; query?: Query } = {}): Promise<T> {\n const url = new URL(this.base + path);\n if (opts.query) {\n for (const [k, v] of Object.entries(opts.query)) {\n if (v !== undefined && v !== null && v !== '') url.searchParams.set(k, String(v));\n }\n }\n const idempotent = method === 'GET' || method === 'DELETE' || method === 'PUT';\n\n for (let attempt = 0; ; attempt++) {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n let res: Response;\n try {\n res = await this.fetchImpl(url.toString(), {\n method,\n headers: {\n 'X-API-Key': this.apiKey,\n Accept: 'application/json',\n ...(opts.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n },\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n signal: ctrl.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n // Network/timeout: safe to retry only idempotent methods.\n if (idempotent && attempt < this.maxRetries) { await sleep(backoff(attempt)); continue; }\n throw new ClawProError(`Network error: ${(err as Error).message}`, { status: 0, code: 'network_error' });\n }\n clearTimeout(timer);\n\n const requestId = res.headers.get('x-request-id') ?? undefined;\n // Transient server-side: 429 (didn't process → retry any method) or 5xx (idempotent only).\n const transient = res.status === 429 || res.status >= 500;\n const retryable = res.status === 429 || idempotent;\n if (transient && retryable && attempt < this.maxRetries) {\n const ra = Number(res.headers.get('retry-after'));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n\n const text = await res.text();\n const data = text ? safeJson(text) : undefined;\n if (!res.ok) {\n const message = (data && (data.message || data.error)) || `HTTP ${res.status}`;\n throw new ClawProError(message, { status: res.status, code: (data && data.error) || 'error', requestId });\n }\n return data as T;\n }\n }\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n/** Exponential backoff with jitter: ~250ms, ~500ms, ~1s … */\nconst backoff = (attempt: number) => Math.round((250 * 2 ** attempt) * (0.8 + Math.random() * 0.4));\n\nfunction safeJson(text: string): any {\n try { return JSON.parse(text); } catch { return { raw: text }; }\n}\n\n// ───────────────────────────── Resources ─────────────────────────────────────\n\nclass AccountsResource {\n constructor(private c: ClawPro) {}\n /** List connected sending accounts. */\n list() { return this.c.request<{ accounts: Account[] }>('GET', '/accounts').then((r) => r.accounts); }\n /** Connect a new sending account (a geo-matched mobile proxy is assigned). */\n create(input: { username: string; country?: string; proxyType?: ProxyType; proxyUrl?: string; timezone?: string }) {\n return this.c.request<{ account: Account }>('POST', '/accounts', { body: input }).then((r) => r.account);\n }\n /** Remove an account (cascades to its campaigns/leads/messages). */\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/accounts/${id}`); }\n}\n\nclass CampaignsResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ campaigns: Campaign[] }>('GET', '/campaigns').then((r) => r.campaigns); }\n create(input: { accountId: string; name: string; targets: string[]; offer?: string; icpCriteria?: string; dailyDmTarget?: number }) {\n return this.c.request<{ campaign: Campaign }>('POST', '/campaigns', { body: input }).then((r) => r.campaign);\n }\n update(id: string, patch: Partial<{ status: CampaignStatus; targets: string[]; offer: string; icpCriteria: string; dailyDmTarget: number; name: string }>) {\n return this.c.request<{ campaign: Campaign }>('PATCH', `/campaigns/${id}`, { body: patch }).then((r) => r.campaign);\n }\n /** Kick a discovery/scoring/queue run for a campaign. */\n run(id: string) { return this.c.request<{ discovered: number; scored: number; queued: number }>('POST', `/campaigns/${id}/run`); }\n /** Leads for a campaign, optionally filtered by status. */\n leads(id: string, opts: { status?: LeadStatus } = {}) {\n return this.c.request<{ leads: Lead[] }>('GET', `/campaigns/${id}/leads`, { query: { status: opts.status } }).then((r) => r.leads);\n }\n /** Threads with at least one message (the unified inbox). */\n inbox(id: string) { return this.c.request<{ threads: Lead[] }>('GET', `/campaigns/${id}/inbox`).then((r) => r.threads); }\n}\n\nclass LeadsResource {\n constructor(private c: ClawPro) {}\n /** Advance a lead — e.g. `{ status: 'booked' }` once a call is set (fires `lead.booked`). */\n update(id: string, patch: { status: 'qualified' | 'rejected' | 'booked' }) {\n return this.c.request<{ lead: Lead }>('PATCH', `/leads/${id}`, { body: patch }).then((r) => r.lead);\n }\n}\n\nclass WebhooksResource {\n constructor(private c: ClawPro) {}\n /** The catalog of subscribable event types. */\n events() { return this.c.request<{ events: WebhookEvent[] }>('GET', '/webhooks/events').then((r) => r.events); }\n list() { return this.c.request<{ webhooks: Webhook[] }>('GET', '/webhooks').then((r) => r.webhooks); }\n /** Create an endpoint. The generic HMAC `secret` is returned once, here. */\n create(input: { url: string; type?: WebhookType; events?: (WebhookEvent | '*')[]; label?: string }) {\n return this.c.request<{ webhook: Webhook }>('POST', '/webhooks', { body: { type: 'generic', events: ['*'], ...input } }).then((r) => r.webhook);\n }\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/webhooks/${id}`); }\n /** Send a `webhook.test` delivery. */\n test(id: string) { return this.c.request<unknown>('POST', `/webhooks/${id}/test`); }\n deliveries(id: string) { return this.c.request<{ deliveries: WebhookDelivery[] }>('GET', `/webhooks/${id}/deliveries`).then((r) => r.deliveries); }\n}\n\nclass ApiKeysResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ keys: ApiKey[] }>('GET', '/keys').then((r) => r.keys); }\n /** Returns `{ secret, key }` — the plaintext `secret` is shown only here. */\n create(input: { name: string; environment?: ApiKeyEnv; access?: ApiKeyAccess; expiresAt?: string | null }) {\n return this.c.request<{ secret: string; key: ApiKey }>('POST', '/keys', { body: input });\n }\n revoke(id: string) { return this.c.request<{ ok: true }>('DELETE', `/keys/${id}`); }\n}\n\nexport interface LogFilter {\n key?: string; method?: string; status?: '2xx' | '4xx' | '5xx';\n from?: string; to?: string; endpoint?: string; requestId?: string; search?: string;\n limit?: number; offset?: number;\n}\n\nclass UsageResource {\n constructor(private c: ClawPro) {}\n /** Calls this month / 24h / errors / avg latency. */\n summary() { return this.c.request<UsageSummary>('GET', '/usage'); }\n /** A single page of request logs (`limit` + `offset`). */\n logs(filter: LogFilter = {}) {\n return this.c.request<{ logs: RequestLog[] }>('GET', '/logs', { query: filter as Query }).then((r) => r.logs);\n }\n /** Auto-paginate every matching log:\n * `for await (const log of clawpro.usage.iterateLogs()) { … }` */\n async *iterateLogs(filter: Omit<LogFilter, 'offset'> = {}): AsyncGenerator<RequestLog, void, unknown> {\n const pageSize = filter.limit ?? 100;\n for (let offset = 0; ; offset += pageSize) {\n const page = await this.logs({ ...filter, limit: pageSize, offset });\n for (const row of page) yield row;\n if (page.length < pageSize) return;\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @clawpro/node — official SDK for the ClawPro Instagram outbound API.\n *\n * ```ts\n * import { ClawPro } from '@clawpro/node'\n * const clawpro = new ClawPro({ apiKey: process.env.CLAWPRO_API_KEY! })\n * const { accounts } = await clawpro.accounts.list()\n * ```\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\n// ─────────────────────────────── Types ───────────────────────────────────────\n\nexport type AccountStatus = 'new' | 'warming' | 'active' | 'challenged' | 'banned' | 'disconnected';\nexport type ProxyType = 'mobile' | 'isp' | 'residential' | 'none';\n\nexport interface Account {\n id: string;\n username: string;\n status: AccountStatus;\n warmupTier?: number;\n dailyDmCap?: number;\n}\n\nexport type CampaignStatus = 'draft' | 'active' | 'paused';\n\nexport interface CampaignTarget {\n username: string;\n lastCheckedPostId: string | null;\n}\n\nexport interface Campaign {\n id: string;\n accountId: string;\n name: string;\n status: CampaignStatus;\n targets: CampaignTarget[];\n offer: string;\n icpCriteria: string;\n dailyDmTarget: number;\n}\n\nexport type LeadStatus =\n | 'discovered' | 'enriched' | 'scored' | 'qualified' | 'rejected'\n | 'queued' | 'dmed' | 'replied' | 'booked';\n\nexport interface Message {\n id: string;\n direction: 'out' | 'in';\n body: string;\n status: string;\n sentAt: string | null;\n createdAt: string;\n}\n\nexport interface Lead {\n id: string;\n igUsername: string;\n fullName: string | null;\n sourceTargetUsername: string;\n engagementType: 'like' | 'comment';\n commentText: string | null;\n score: number | null;\n scoreReason: string | null;\n status: LeadStatus;\n messages?: Message[];\n}\n\nexport type WebhookType = 'generic' | 'slack';\nexport type WebhookEvent =\n | 'reply.received' | 'dm.sent' | 'dm.failed'\n | 'lead.qualified' | 'lead.booked'\n | 'account.active' | 'account.challenged' | 'account.banned';\n\nexport interface Webhook {\n id: string;\n label: string;\n url: string;\n type: WebhookType;\n events: (WebhookEvent | '*')[];\n active: boolean;\n lastStatus: number | null;\n lastDeliveryAt: string | null;\n lastError: string | null;\n /** Present only on the create response (generic HMAC secret). */\n secret?: string;\n}\n\nexport interface WebhookDelivery {\n id: string;\n event: string;\n status: 'pending' | 'delivered' | 'dead';\n attempts: number;\n lastStatusCode: number | null;\n lastError: string | null;\n nextRetryAt: string | null;\n deliveredAt: string | null;\n createdAt: string;\n}\n\nexport type ApiKeyEnv = 'production' | 'development';\nexport type ApiKeyAccess = 'full' | 'read' | 'write';\n\nexport interface ApiKey {\n id: string;\n name: string;\n environment: ApiKeyEnv;\n access: ApiKeyAccess;\n keyPrefix: string;\n createdAt: string;\n expiresAt: string | null;\n lastUsedAt: string | null;\n}\n\nexport interface UsageSummary {\n callsThisMonth: number;\n calls24h: number;\n errors: number;\n avgLatencyMs: number;\n}\n\nexport interface RequestLog {\n id: string;\n requestId: string;\n method: string;\n path: string;\n status: number;\n latencyMs: number;\n error: string | null;\n createdAt: string;\n keyName: string | null;\n keyPrefix: string | null;\n}\n\n// ─────────────────────────────── Errors ──────────────────────────────────────\n\n/** Thrown for any non-2xx API response. Inspect `status` / `requestId`. */\nexport class ClawProError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId?: string;\n constructor(message: string, opts: { status: number; code?: string; requestId?: string }) {\n super(message);\n this.name = 'ClawProError';\n this.status = opts.status;\n this.code = opts.code ?? 'error';\n this.requestId = opts.requestId;\n }\n}\n\n// ─────────────────────────────── Client ──────────────────────────────────────\n\nexport interface ClawProOptions {\n /** A `sk_live_…` / `sk_test_…` key from the developer portal. Sent as `X-API-Key`. */\n apiKey: string;\n /** API origin (no trailing slash). Defaults to https://api.tryclawpro.com */\n baseUrl?: string;\n /** Override the fetch implementation (defaults to global fetch). */\n fetch?: typeof fetch;\n /** Per-request timeout in ms (default 30000). */\n timeoutMs?: number;\n /** Auto-retry transient failures (network, 429, 5xx) with exponential backoff.\n * Default 2. 429s honor the `Retry-After` header; only idempotent methods\n * (GET/DELETE/PUT) are retried on network/5xx. */\n maxRetries?: number;\n}\n\ntype Query = Record<string, string | number | boolean | undefined | null>;\n\nexport class ClawPro {\n readonly accounts: AccountsResource;\n readonly campaigns: CampaignsResource;\n readonly leads: LeadsResource;\n readonly webhooks: WebhooksResource;\n readonly keys: ApiKeysResource;\n readonly usage: UsageResource;\n\n private readonly apiKey: string;\n private readonly base: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly maxRetries: number;\n\n constructor(opts: ClawProOptions) {\n if (!opts?.apiKey) throw new Error('ClawPro: `apiKey` is required');\n this.apiKey = opts.apiKey;\n const origin = (opts.baseUrl ?? 'https://api.tryclawpro.com').replace(/\\/$/, '');\n this.base = `${origin}/api/instagram`;\n this.fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!this.fetchImpl) throw new Error('ClawPro: no fetch available — pass `fetch` (Node <18)');\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n this.maxRetries = opts.maxRetries ?? 2;\n\n this.accounts = new AccountsResource(this);\n this.campaigns = new CampaignsResource(this);\n this.leads = new LeadsResource(this);\n this.webhooks = new WebhooksResource(this);\n this.keys = new ApiKeysResource(this);\n this.usage = new UsageResource(this);\n }\n\n /** @internal */\n async request<T>(method: string, path: string, opts: { body?: unknown; query?: Query } = {}): Promise<T> {\n const url = new URL(this.base + path);\n if (opts.query) {\n for (const [k, v] of Object.entries(opts.query)) {\n if (v !== undefined && v !== null && v !== '') url.searchParams.set(k, String(v));\n }\n }\n const idempotent = method === 'GET' || method === 'DELETE' || method === 'PUT';\n\n for (let attempt = 0; ; attempt++) {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n let res: Response;\n try {\n res = await this.fetchImpl(url.toString(), {\n method,\n headers: {\n 'X-API-Key': this.apiKey,\n Accept: 'application/json',\n ...(opts.body !== undefined ? { 'Content-Type': 'application/json' } : {}),\n },\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n signal: ctrl.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n // Network/timeout: safe to retry only idempotent methods.\n if (idempotent && attempt < this.maxRetries) { await sleep(backoff(attempt)); continue; }\n throw new ClawProError(`Network error: ${(err as Error).message}`, { status: 0, code: 'network_error' });\n }\n clearTimeout(timer);\n\n const requestId = res.headers.get('x-request-id') ?? undefined;\n // Transient server-side: 429 (didn't process → retry any method) or 5xx (idempotent only).\n const transient = res.status === 429 || res.status >= 500;\n const retryable = res.status === 429 || idempotent;\n if (transient && retryable && attempt < this.maxRetries) {\n const ra = Number(res.headers.get('retry-after'));\n await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1000 : backoff(attempt));\n continue;\n }\n\n const text = await res.text();\n const data = text ? safeJson(text) : undefined;\n if (!res.ok) {\n const message = (data && (data.message || data.error)) || `HTTP ${res.status}`;\n throw new ClawProError(message, { status: res.status, code: (data && data.error) || 'error', requestId });\n }\n return data as T;\n }\n }\n}\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));\n/** Exponential backoff with jitter: ~250ms, ~500ms, ~1s … */\nconst backoff = (attempt: number) => Math.round((250 * 2 ** attempt) * (0.8 + Math.random() * 0.4));\n\nfunction safeJson(text: string): any {\n try { return JSON.parse(text); } catch { return { raw: text }; }\n}\n\n// ───────────────────────────── Resources ─────────────────────────────────────\n\nclass AccountsResource {\n constructor(private c: ClawPro) {}\n /** List connected sending accounts. */\n list() { return this.c.request<{ accounts: Account[] }>('GET', '/accounts').then((r) => r.accounts); }\n /** Connect a new sending account (a geo-matched mobile proxy is assigned). */\n create(input: { username: string; country?: string; proxyType?: ProxyType; proxyUrl?: string; timezone?: string }) {\n return this.c.request<{ account: Account }>('POST', '/accounts', { body: input }).then((r) => r.account);\n }\n /** Remove an account (cascades to its campaigns/leads/messages). */\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/accounts/${id}`); }\n}\n\nclass CampaignsResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ campaigns: Campaign[] }>('GET', '/campaigns').then((r) => r.campaigns); }\n create(input: { accountId: string; name: string; targets: string[]; offer?: string; icpCriteria?: string; dailyDmTarget?: number }) {\n return this.c.request<{ campaign: Campaign }>('POST', '/campaigns', { body: input }).then((r) => r.campaign);\n }\n update(id: string, patch: Partial<{ status: CampaignStatus; targets: string[]; offer: string; icpCriteria: string; dailyDmTarget: number; name: string }>) {\n return this.c.request<{ campaign: Campaign }>('PATCH', `/campaigns/${id}`, { body: patch }).then((r) => r.campaign);\n }\n /** Kick a discovery/scoring/queue run for a campaign. */\n run(id: string) { return this.c.request<{ discovered: number; scored: number; queued: number }>('POST', `/campaigns/${id}/run`); }\n /** Leads for a campaign, optionally filtered by status. */\n leads(id: string, opts: { status?: LeadStatus } = {}) {\n return this.c.request<{ leads: Lead[] }>('GET', `/campaigns/${id}/leads`, { query: { status: opts.status } }).then((r) => r.leads);\n }\n /** Threads with at least one message (the unified inbox). */\n inbox(id: string) { return this.c.request<{ threads: Lead[] }>('GET', `/campaigns/${id}/inbox`).then((r) => r.threads); }\n}\n\nclass LeadsResource {\n constructor(private c: ClawPro) {}\n /** Advance a lead — e.g. `{ status: 'booked' }` once a call is set (fires `lead.booked`). */\n update(id: string, patch: { status: 'qualified' | 'rejected' | 'booked' }) {\n return this.c.request<{ lead: Lead }>('PATCH', `/leads/${id}`, { body: patch }).then((r) => r.lead);\n }\n}\n\nclass WebhooksResource {\n constructor(private c: ClawPro) {}\n /** The catalog of subscribable event types. */\n events() { return this.c.request<{ events: WebhookEvent[] }>('GET', '/webhooks/events').then((r) => r.events); }\n list() { return this.c.request<{ webhooks: Webhook[] }>('GET', '/webhooks').then((r) => r.webhooks); }\n /** Create an endpoint. The generic HMAC `secret` is returned once, here. */\n create(input: { url: string; type?: WebhookType; events?: (WebhookEvent | '*')[]; label?: string }) {\n return this.c.request<{ webhook: Webhook }>('POST', '/webhooks', { body: { type: 'generic', events: ['*'], ...input } }).then((r) => r.webhook);\n }\n delete(id: string) { return this.c.request<{ ok: true }>('DELETE', `/webhooks/${id}`); }\n /** Send a `webhook.test` delivery. */\n test(id: string) { return this.c.request<unknown>('POST', `/webhooks/${id}/test`); }\n deliveries(id: string) { return this.c.request<{ deliveries: WebhookDelivery[] }>('GET', `/webhooks/${id}/deliveries`).then((r) => r.deliveries); }\n}\n\nclass ApiKeysResource {\n constructor(private c: ClawPro) {}\n list() { return this.c.request<{ keys: ApiKey[] }>('GET', '/keys').then((r) => r.keys); }\n /** Returns `{ secret, key }` — the plaintext `secret` is shown only here. */\n create(input: { name: string; environment?: ApiKeyEnv; access?: ApiKeyAccess; expiresAt?: string | null }) {\n return this.c.request<{ secret: string; key: ApiKey }>('POST', '/keys', { body: input });\n }\n revoke(id: string) { return this.c.request<{ ok: true }>('DELETE', `/keys/${id}`); }\n}\n\nexport interface LogFilter {\n key?: string; method?: string; status?: '2xx' | '4xx' | '5xx';\n from?: string; to?: string; endpoint?: string; requestId?: string; search?: string;\n limit?: number; offset?: number;\n}\n\nclass UsageResource {\n constructor(private c: ClawPro) {}\n /** Calls this month / 24h / errors / avg latency. */\n summary() { return this.c.request<UsageSummary>('GET', '/usage'); }\n /** A single page of request logs (`limit` + `offset`). */\n logs(filter: LogFilter = {}) {\n return this.c.request<{ logs: RequestLog[] }>('GET', '/logs', { query: filter as Query }).then((r) => r.logs);\n }\n /** Auto-paginate every matching log:\n * `for await (const log of clawpro.usage.iterateLogs()) { … }` */\n async *iterateLogs(filter: Omit<LogFilter, 'offset'> = {}): AsyncGenerator<RequestLog, void, unknown> {\n const pageSize = filter.limit ?? 100;\n for (let offset = 0; ; offset += pageSize) {\n const page = await this.logs({ ...filter, limit: pageSize, offset });\n for (const row of page) yield row;\n if (page.length < pageSize) return;\n }\n }\n}\n\n// ─────────────────────────── Webhook verification ────────────────────────────\n\nexport interface VerifyWebhookOptions {\n /** The raw request body, exactly as received (string). */\n payload: string;\n /** The `X-Souk-Signature` header value (`t=…,v1=…`). */\n signature: string;\n /** The endpoint's signing secret (shown once on webhook creation). */\n secret: string;\n /** Reject signatures older than this many seconds (default 300; 0 disables). */\n toleranceSec?: number;\n}\n\n/** Verify a ClawPro webhook's HMAC signature (timing-safe). Returns true if valid.\n *\n * ```ts\n * if (!verifyWebhook({ payload: rawBody, signature: req.headers['x-souk-signature'], secret })) return res.sendStatus(400)\n * ```\n */\nexport function verifyWebhook(opts: VerifyWebhookOptions): boolean {\n const { payload, signature, secret, toleranceSec = 300 } = opts;\n const parts: Record<string, string> = {};\n for (const p of signature.split(',')) {\n const i = p.indexOf('=');\n if (i > 0) parts[p.slice(0, i).trim()] = p.slice(i + 1).trim();\n }\n const t = Number(parts.t);\n const v1 = parts.v1;\n if (!t || !v1) return false;\n if (toleranceSec > 0 && Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;\n const expected = createHmac('sha256', secret).update(`${t}.${payload}`).digest('hex');\n const a = Buffer.from(expected);\n const b = Buffer.from(v1);\n return a.length === b.length && timingSafeEqual(a, b);\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawpro/node",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Official Node.js / TypeScript SDK for the ClawPro Instagram outbound API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -24,10 +24,18 @@
24
24
  "author": "ClawPro",
25
25
  "license": "MIT",
26
26
  "homepage": "https://tryclawpro.com",
27
- "repository": { "type": "git", "url": "git+https://github.com/Bojale-Labs/clawpro-node.git" },
28
- "bugs": { "url": "https://github.com/Bojale-Labs/clawpro-node/issues" },
29
- "engines": { "node": ">=18" },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/Bojale-Labs/clawpro-node.git"
30
+ },
31
+ "bugs": {
32
+ "url": "https://github.com/Bojale-Labs/clawpro-node/issues"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
30
37
  "devDependencies": {
38
+ "@types/node": "^26.0.1",
31
39
  "tsup": "^8.3.0",
32
40
  "typescript": "^5.6.0"
33
41
  }