@clawpro/node 0.1.0 → 0.1.1
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 +54 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +54 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -47,6 +47,7 @@ var ClawPro = class {
|
|
|
47
47
|
base;
|
|
48
48
|
fetchImpl;
|
|
49
49
|
timeoutMs;
|
|
50
|
+
maxRetries;
|
|
50
51
|
constructor(opts) {
|
|
51
52
|
if (!opts?.apiKey) throw new Error("ClawPro: `apiKey` is required");
|
|
52
53
|
this.apiKey = opts.apiKey;
|
|
@@ -55,6 +56,7 @@ var ClawPro = class {
|
|
|
55
56
|
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
56
57
|
if (!this.fetchImpl) throw new Error("ClawPro: no fetch available \u2014 pass `fetch` (Node <18)");
|
|
57
58
|
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
59
|
+
this.maxRetries = opts.maxRetries ?? 2;
|
|
58
60
|
this.accounts = new AccountsResource(this);
|
|
59
61
|
this.campaigns = new CampaignsResource(this);
|
|
60
62
|
this.leads = new LeadsResource(this);
|
|
@@ -70,35 +72,51 @@ var ClawPro = class {
|
|
|
70
72
|
if (v !== void 0 && v !== null && v !== "") url.searchParams.set(k, String(v));
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
res
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
75
|
+
const idempotent = method === "GET" || method === "DELETE" || method === "PUT";
|
|
76
|
+
for (let attempt = 0; ; attempt++) {
|
|
77
|
+
const ctrl = new AbortController();
|
|
78
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
79
|
+
let res;
|
|
80
|
+
try {
|
|
81
|
+
res = await this.fetchImpl(url.toString(), {
|
|
82
|
+
method,
|
|
83
|
+
headers: {
|
|
84
|
+
"X-API-Key": this.apiKey,
|
|
85
|
+
Accept: "application/json",
|
|
86
|
+
...opts.body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
87
|
+
},
|
|
88
|
+
body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0,
|
|
89
|
+
signal: ctrl.signal
|
|
90
|
+
});
|
|
91
|
+
} catch (err) {
|
|
92
|
+
clearTimeout(timer);
|
|
93
|
+
if (idempotent && attempt < this.maxRetries) {
|
|
94
|
+
await sleep(backoff(attempt));
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
throw new ClawProError(`Network error: ${err.message}`, { status: 0, code: "network_error" });
|
|
98
|
+
}
|
|
88
99
|
clearTimeout(timer);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
101
|
+
const transient = res.status === 429 || res.status >= 500;
|
|
102
|
+
const retryable = res.status === 429 || idempotent;
|
|
103
|
+
if (transient && retryable && attempt < this.maxRetries) {
|
|
104
|
+
const ra = Number(res.headers.get("retry-after"));
|
|
105
|
+
await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1e3 : backoff(attempt));
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const text = await res.text();
|
|
109
|
+
const data = text ? safeJson(text) : void 0;
|
|
110
|
+
if (!res.ok) {
|
|
111
|
+
const message = data && (data.message || data.error) || `HTTP ${res.status}`;
|
|
112
|
+
throw new ClawProError(message, { status: res.status, code: data && data.error || "error", requestId });
|
|
113
|
+
}
|
|
114
|
+
return data;
|
|
98
115
|
}
|
|
99
|
-
return data;
|
|
100
116
|
}
|
|
101
117
|
};
|
|
118
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
119
|
+
var backoff = (attempt) => Math.round(250 * 2 ** attempt * (0.8 + Math.random() * 0.4));
|
|
102
120
|
function safeJson(text) {
|
|
103
121
|
try {
|
|
104
122
|
return JSON.parse(text);
|
|
@@ -213,10 +231,20 @@ var UsageResource = class {
|
|
|
213
231
|
summary() {
|
|
214
232
|
return this.c.request("GET", "/usage");
|
|
215
233
|
}
|
|
216
|
-
/**
|
|
234
|
+
/** A single page of request logs (`limit` + `offset`). */
|
|
217
235
|
logs(filter = {}) {
|
|
218
236
|
return this.c.request("GET", "/logs", { query: filter }).then((r) => r.logs);
|
|
219
237
|
}
|
|
238
|
+
/** Auto-paginate every matching log:
|
|
239
|
+
* `for await (const log of clawpro.usage.iterateLogs()) { … }` */
|
|
240
|
+
async *iterateLogs(filter = {}) {
|
|
241
|
+
const pageSize = filter.limit ?? 100;
|
|
242
|
+
for (let offset = 0; ; offset += pageSize) {
|
|
243
|
+
const page = await this.logs({ ...filter, limit: pageSize, offset });
|
|
244
|
+
for (const row of page) yield row;
|
|
245
|
+
if (page.length < pageSize) return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
220
248
|
};
|
|
221
249
|
// Annotate the CommonJS export names for ESM import in node:
|
|
222
250
|
0 && (module.exports = {
|
package/dist/index.cjs.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}\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\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\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 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 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 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\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; limit?: 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 /** Filterable request log for the developer API. */\n logs(filter: LogFilter = {}) {\n return this.c.request<{ logs: RequestLog[] }>('GET', '/logs', { query: filter as Query }).then((r) => r.logs);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwIO,IAAM,eAAN,cAA2B,MAAM;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY,SAAiB,MAA6D;AACxF,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS,KAAK;AACnB,SAAK,OAAO,KAAK,QAAQ;AACzB,SAAK,YAAY,KAAK;AAAA,EACxB;AACF;AAiBO,IAAM,UAAN,MAAc;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEQ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,MAAsB;AAChC,QAAI,CAAC,MAAM,OAAQ,OAAM,IAAI,MAAM,+BAA+B;AAClE,SAAK,SAAS,KAAK;AACnB,UAAM,UAAU,KAAK,WAAW,8BAA8B,QAAQ,OAAO,EAAE;AAC/E,SAAK,OAAO,GAAG,MAAM;AACrB,SAAK,YAAY,KAAK,SAAS,WAAW;AAC1C,QAAI,CAAC,KAAK,UAAW,OAAM,IAAI,MAAM,4DAAuD;AAC5F,SAAK,YAAY,KAAK,aAAa;AAEnC,SAAK,WAAW,IAAI,iBAAiB,IAAI;AACzC,SAAK,YAAY,IAAI,kBAAkB,IAAI;AAC3C,SAAK,QAAQ,IAAI,cAAc,IAAI;AACnC,SAAK,WAAW,IAAI,iBAAiB,IAAI;AACzC,SAAK,OAAO,IAAI,gBAAgB,IAAI;AACpC,SAAK,QAAQ,IAAI,cAAc,IAAI;AAAA,EACrC;AAAA;AAAA,EAGA,MAAM,QAAW,QAAgB,MAAc,OAA0C,CAAC,GAAe;AACvG,UAAM,MAAM,IAAI,IAAI,KAAK,OAAO,IAAI;AACpC,QAAI,KAAK,OAAO;AACd,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AAC/C,YAAI,MAAM,UAAa,MAAM,QAAQ,MAAM,GAAI,KAAI,aAAa,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,MAClF;AAAA,IACF;AACA,UAAM,OAAO,IAAI,gBAAgB;AACjC,UAAM,QAAQ,WAAW,MAAM,KAAK,MAAM,GAAG,KAAK,SAAS;AAC3D,QAAI;AACJ,QAAI;AACF,YAAM,MAAM,KAAK,UAAU,IAAI,SAAS,GAAG;AAAA,QACzC;AAAA,QACA,SAAS;AAAA,UACP,aAAa,KAAK;AAAA,UAClB,QAAQ;AAAA,UACR,GAAI,KAAK,SAAS,SAAY,EAAE,gBAAgB,mBAAmB,IAAI,CAAC;AAAA,QAC1E;AAAA,QACA,MAAM,KAAK,SAAS,SAAY,KAAK,UAAU,KAAK,IAAI,IAAI;AAAA,QAC5D,QAAQ,KAAK;AAAA,MACf,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,mBAAa,KAAK;AAClB,YAAM,IAAI,aAAa,kBAAmB,IAAc,OAAO,IAAI,EAAE,QAAQ,GAAG,MAAM,gBAAgB,CAAC;AAAA,IACzG;AACA,iBAAa,KAAK;AAElB,UAAM,YAAY,IAAI,QAAQ,IAAI,cAAc,KAAK;AACrD,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,UAAM,OAAO,OAAO,SAAS,IAAI,IAAI;AACrC,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,UAAW,SAAS,KAAK,WAAW,KAAK,UAAW,QAAQ,IAAI,MAAM;AAC5E,YAAM,IAAI,aAAa,SAAS,EAAE,QAAQ,IAAI,QAAQ,MAAO,QAAQ,KAAK,SAAU,SAAS,UAAU,CAAC;AAAA,IAC1G;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,SAAS,MAAmB;AACnC,MAAI;AAAE,WAAO,KAAK,MAAM,IAAI;AAAA,EAAG,QAAQ;AAAE,WAAO,EAAE,KAAK,KAAK;AAAA,EAAG;AACjE;AAIA,IAAM,mBAAN,MAAuB;AAAA,EACrB,YAAoB,GAAY;AAAZ;AAAA,EAAa;AAAA,EAAb;AAAA;AAAA,EAEpB,OAAO;AAAE,WAAO,KAAK,EAAE,QAAiC,OAAO,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ;AAAA,EAAG;AAAA;AAAA,EAErG,OAAO,OAA4G;AACjH,WAAO,KAAK,EAAE,QAA8B,QAAQ,aAAa,EAAE,MAAM,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,EACzG;AAAA;AAAA,EAEA,OAAO,IAAY;AAAE,WAAO,KAAK,EAAE,QAAsB,UAAU,aAAa,EAAE,EAAE;AAAA,EAAG;AACzF;AAEA,IAAM,oBAAN,MAAwB;AAAA,EACtB,YAAoB,GAAY;AAAZ;AAAA,EAAa;AAAA,EAAb;AAAA,EACpB,OAAO;AAAE,WAAO,KAAK,EAAE,QAAmC,OAAO,YAAY,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS;AAAA,EAAG;AAAA,EACzG,OAAO,OAA6H;AAClI,WAAO,KAAK,EAAE,QAAgC,QAAQ,cAAc,EAAE,MAAM,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ;AAAA,EAC7G;AAAA,EACA,OAAO,IAAY,OAAwI;AACzJ,WAAO,KAAK,EAAE,QAAgC,SAAS,cAAc,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ;AAAA,EACpH;AAAA;AAAA,EAEA,IAAI,IAAY;AAAE,WAAO,KAAK,EAAE,QAAgE,QAAQ,cAAc,EAAE,MAAM;AAAA,EAAG;AAAA;AAAA,EAEjI,MAAM,IAAY,OAAgC,CAAC,GAAG;AACpD,WAAO,KAAK,EAAE,QAA2B,OAAO,cAAc,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,KAAK,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK;AAAA,EACnI;AAAA;AAAA,EAEA,MAAM,IAAY;AAAE,WAAO,KAAK,EAAE,QAA6B,OAAO,cAAc,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,EAAG;AAC1H;AAEA,IAAM,gBAAN,MAAoB;AAAA,EAClB,YAAoB,GAAY;AAAZ;AAAA,EAAa;AAAA,EAAb;AAAA;AAAA,EAEpB,OAAO,IAAY,OAAwD;AACzE,WAAO,KAAK,EAAE,QAAwB,SAAS,UAAU,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI;AAAA,EACpG;AACF;AAEA,IAAM,mBAAN,MAAuB;AAAA,EACrB,YAAoB,GAAY;AAAZ;AAAA,EAAa;AAAA,EAAb;AAAA;AAAA,EAEpB,SAAS;AAAE,WAAO,KAAK,EAAE,QAAoC,OAAO,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM;AAAA,EAAG;AAAA,EAC/G,OAAO;AAAE,WAAO,KAAK,EAAE,QAAiC,OAAO,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ;AAAA,EAAG;AAAA;AAAA,EAErG,OAAO,OAA6F;AAClG,WAAO,KAAK,EAAE,QAA8B,QAAQ,aAAa,EAAE,MAAM,EAAE,MAAM,WAAW,QAAQ,CAAC,GAAG,GAAG,GAAG,MAAM,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,EAChJ;AAAA,EACA,OAAO,IAAY;AAAE,WAAO,KAAK,EAAE,QAAsB,UAAU,aAAa,EAAE,EAAE;AAAA,EAAG;AAAA;AAAA,EAEvF,KAAK,IAAY;AAAE,WAAO,KAAK,EAAE,QAAiB,QAAQ,aAAa,EAAE,OAAO;AAAA,EAAG;AAAA,EACnF,WAAW,IAAY;AAAE,WAAO,KAAK,EAAE,QAA2C,OAAO,aAAa,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU;AAAA,EAAG;AACpJ;AAEA,IAAM,kBAAN,MAAsB;AAAA,EACpB,YAAoB,GAAY;AAAZ;AAAA,EAAa;AAAA,EAAb;AAAA,EACpB,OAAO;AAAE,WAAO,KAAK,EAAE,QAA4B,OAAO,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI;AAAA,EAAG;AAAA;AAAA,EAExF,OAAO,OAAoG;AACzG,WAAO,KAAK,EAAE,QAAyC,QAAQ,SAAS,EAAE,MAAM,MAAM,CAAC;AAAA,EACzF;AAAA,EACA,OAAO,IAAY;AAAE,WAAO,KAAK,EAAE,QAAsB,UAAU,SAAS,EAAE,EAAE;AAAA,EAAG;AACrF;AAOA,IAAM,gBAAN,MAAoB;AAAA,EAClB,YAAoB,GAAY;AAAZ;AAAA,EAAa;AAAA,EAAb;AAAA;AAAA,EAEpB,UAAU;AAAE,WAAO,KAAK,EAAE,QAAsB,OAAO,QAAQ;AAAA,EAAG;AAAA;AAAA,EAElE,KAAK,SAAoB,CAAC,GAAG;AAC3B,WAAO,KAAK,EAAE,QAAgC,OAAO,SAAS,EAAE,OAAO,OAAgB,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI;AAAA,EAC9G;AACF;","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\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":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -128,6 +128,10 @@ interface ClawProOptions {
|
|
|
128
128
|
fetch?: typeof fetch;
|
|
129
129
|
/** Per-request timeout in ms (default 30000). */
|
|
130
130
|
timeoutMs?: number;
|
|
131
|
+
/** Auto-retry transient failures (network, 429, 5xx) with exponential backoff.
|
|
132
|
+
* Default 2. 429s honor the `Retry-After` header; only idempotent methods
|
|
133
|
+
* (GET/DELETE/PUT) are retried on network/5xx. */
|
|
134
|
+
maxRetries?: number;
|
|
131
135
|
}
|
|
132
136
|
type Query = Record<string, string | number | boolean | undefined | null>;
|
|
133
137
|
declare class ClawPro {
|
|
@@ -141,6 +145,7 @@ declare class ClawPro {
|
|
|
141
145
|
private readonly base;
|
|
142
146
|
private readonly fetchImpl;
|
|
143
147
|
private readonly timeoutMs;
|
|
148
|
+
private readonly maxRetries;
|
|
144
149
|
constructor(opts: ClawProOptions);
|
|
145
150
|
/** @internal */
|
|
146
151
|
request<T>(method: string, path: string, opts?: {
|
|
@@ -255,14 +260,18 @@ interface LogFilter {
|
|
|
255
260
|
requestId?: string;
|
|
256
261
|
search?: string;
|
|
257
262
|
limit?: number;
|
|
263
|
+
offset?: number;
|
|
258
264
|
}
|
|
259
265
|
declare class UsageResource {
|
|
260
266
|
private c;
|
|
261
267
|
constructor(c: ClawPro);
|
|
262
268
|
/** Calls this month / 24h / errors / avg latency. */
|
|
263
269
|
summary(): Promise<UsageSummary>;
|
|
264
|
-
/**
|
|
270
|
+
/** A single page of request logs (`limit` + `offset`). */
|
|
265
271
|
logs(filter?: LogFilter): Promise<RequestLog[]>;
|
|
272
|
+
/** Auto-paginate every matching log:
|
|
273
|
+
* `for await (const log of clawpro.usage.iterateLogs()) { … }` */
|
|
274
|
+
iterateLogs(filter?: Omit<LogFilter, 'offset'>): AsyncGenerator<RequestLog, void, unknown>;
|
|
266
275
|
}
|
|
267
276
|
|
|
268
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -128,6 +128,10 @@ interface ClawProOptions {
|
|
|
128
128
|
fetch?: typeof fetch;
|
|
129
129
|
/** Per-request timeout in ms (default 30000). */
|
|
130
130
|
timeoutMs?: number;
|
|
131
|
+
/** Auto-retry transient failures (network, 429, 5xx) with exponential backoff.
|
|
132
|
+
* Default 2. 429s honor the `Retry-After` header; only idempotent methods
|
|
133
|
+
* (GET/DELETE/PUT) are retried on network/5xx. */
|
|
134
|
+
maxRetries?: number;
|
|
131
135
|
}
|
|
132
136
|
type Query = Record<string, string | number | boolean | undefined | null>;
|
|
133
137
|
declare class ClawPro {
|
|
@@ -141,6 +145,7 @@ declare class ClawPro {
|
|
|
141
145
|
private readonly base;
|
|
142
146
|
private readonly fetchImpl;
|
|
143
147
|
private readonly timeoutMs;
|
|
148
|
+
private readonly maxRetries;
|
|
144
149
|
constructor(opts: ClawProOptions);
|
|
145
150
|
/** @internal */
|
|
146
151
|
request<T>(method: string, path: string, opts?: {
|
|
@@ -255,14 +260,18 @@ interface LogFilter {
|
|
|
255
260
|
requestId?: string;
|
|
256
261
|
search?: string;
|
|
257
262
|
limit?: number;
|
|
263
|
+
offset?: number;
|
|
258
264
|
}
|
|
259
265
|
declare class UsageResource {
|
|
260
266
|
private c;
|
|
261
267
|
constructor(c: ClawPro);
|
|
262
268
|
/** Calls this month / 24h / errors / avg latency. */
|
|
263
269
|
summary(): Promise<UsageSummary>;
|
|
264
|
-
/**
|
|
270
|
+
/** A single page of request logs (`limit` + `offset`). */
|
|
265
271
|
logs(filter?: LogFilter): Promise<RequestLog[]>;
|
|
272
|
+
/** Auto-paginate every matching log:
|
|
273
|
+
* `for await (const log of clawpro.usage.iterateLogs()) { … }` */
|
|
274
|
+
iterateLogs(filter?: Omit<LogFilter, 'offset'>): AsyncGenerator<RequestLog, void, unknown>;
|
|
266
275
|
}
|
|
267
276
|
|
|
268
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 };
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var ClawPro = class {
|
|
|
22
22
|
base;
|
|
23
23
|
fetchImpl;
|
|
24
24
|
timeoutMs;
|
|
25
|
+
maxRetries;
|
|
25
26
|
constructor(opts) {
|
|
26
27
|
if (!opts?.apiKey) throw new Error("ClawPro: `apiKey` is required");
|
|
27
28
|
this.apiKey = opts.apiKey;
|
|
@@ -30,6 +31,7 @@ var ClawPro = class {
|
|
|
30
31
|
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
31
32
|
if (!this.fetchImpl) throw new Error("ClawPro: no fetch available \u2014 pass `fetch` (Node <18)");
|
|
32
33
|
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
34
|
+
this.maxRetries = opts.maxRetries ?? 2;
|
|
33
35
|
this.accounts = new AccountsResource(this);
|
|
34
36
|
this.campaigns = new CampaignsResource(this);
|
|
35
37
|
this.leads = new LeadsResource(this);
|
|
@@ -45,35 +47,51 @@ var ClawPro = class {
|
|
|
45
47
|
if (v !== void 0 && v !== null && v !== "") url.searchParams.set(k, String(v));
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
res
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
50
|
+
const idempotent = method === "GET" || method === "DELETE" || method === "PUT";
|
|
51
|
+
for (let attempt = 0; ; attempt++) {
|
|
52
|
+
const ctrl = new AbortController();
|
|
53
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
54
|
+
let res;
|
|
55
|
+
try {
|
|
56
|
+
res = await this.fetchImpl(url.toString(), {
|
|
57
|
+
method,
|
|
58
|
+
headers: {
|
|
59
|
+
"X-API-Key": this.apiKey,
|
|
60
|
+
Accept: "application/json",
|
|
61
|
+
...opts.body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
62
|
+
},
|
|
63
|
+
body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0,
|
|
64
|
+
signal: ctrl.signal
|
|
65
|
+
});
|
|
66
|
+
} catch (err) {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
if (idempotent && attempt < this.maxRetries) {
|
|
69
|
+
await sleep(backoff(attempt));
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
throw new ClawProError(`Network error: ${err.message}`, { status: 0, code: "network_error" });
|
|
73
|
+
}
|
|
63
74
|
clearTimeout(timer);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
76
|
+
const transient = res.status === 429 || res.status >= 500;
|
|
77
|
+
const retryable = res.status === 429 || idempotent;
|
|
78
|
+
if (transient && retryable && attempt < this.maxRetries) {
|
|
79
|
+
const ra = Number(res.headers.get("retry-after"));
|
|
80
|
+
await sleep(Number.isFinite(ra) && ra > 0 ? ra * 1e3 : backoff(attempt));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const text = await res.text();
|
|
84
|
+
const data = text ? safeJson(text) : void 0;
|
|
85
|
+
if (!res.ok) {
|
|
86
|
+
const message = data && (data.message || data.error) || `HTTP ${res.status}`;
|
|
87
|
+
throw new ClawProError(message, { status: res.status, code: data && data.error || "error", requestId });
|
|
88
|
+
}
|
|
89
|
+
return data;
|
|
73
90
|
}
|
|
74
|
-
return data;
|
|
75
91
|
}
|
|
76
92
|
};
|
|
93
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
94
|
+
var backoff = (attempt) => Math.round(250 * 2 ** attempt * (0.8 + Math.random() * 0.4));
|
|
77
95
|
function safeJson(text) {
|
|
78
96
|
try {
|
|
79
97
|
return JSON.parse(text);
|
|
@@ -188,10 +206,20 @@ var UsageResource = class {
|
|
|
188
206
|
summary() {
|
|
189
207
|
return this.c.request("GET", "/usage");
|
|
190
208
|
}
|
|
191
|
-
/**
|
|
209
|
+
/** A single page of request logs (`limit` + `offset`). */
|
|
192
210
|
logs(filter = {}) {
|
|
193
211
|
return this.c.request("GET", "/logs", { query: filter }).then((r) => r.logs);
|
|
194
212
|
}
|
|
213
|
+
/** Auto-paginate every matching log:
|
|
214
|
+
* `for await (const log of clawpro.usage.iterateLogs()) { … }` */
|
|
215
|
+
async *iterateLogs(filter = {}) {
|
|
216
|
+
const pageSize = filter.limit ?? 100;
|
|
217
|
+
for (let offset = 0; ; offset += pageSize) {
|
|
218
|
+
const page = await this.logs({ ...filter, limit: pageSize, offset });
|
|
219
|
+
for (const row of page) yield row;
|
|
220
|
+
if (page.length < pageSize) return;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
195
223
|
};
|
|
196
224
|
export {
|
|
197
225
|
ClawPro,
|
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}\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\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\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 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 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 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\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; limit?: 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 /** Filterable request log for the developer API. */\n logs(filter: LogFilter = {}) {\n return this.c.request<{ logs: RequestLog[] }>('GET', '/logs', { query: filter as Query }).then((r) => r.logs);\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\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":[]}
|