geodedo 0.1.0

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.js ADDED
@@ -0,0 +1,1021 @@
1
+ // src/core/errors.ts
2
+ var GeoDedoError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "GeoDedoError";
6
+ Object.setPrototypeOf(this, new.target.prototype);
7
+ }
8
+ };
9
+ var APIError = class _APIError extends GeoDedoError {
10
+ /** HTTP status code. */
11
+ status;
12
+ /** Machine-readable error code from the response body, if present. */
13
+ code;
14
+ /** Request ID from the X-Request-Id response header, if present. */
15
+ requestId;
16
+ /** Raw response body. */
17
+ body;
18
+ constructor(status, body, message, code, requestId) {
19
+ super(message);
20
+ this.name = "APIError";
21
+ this.status = status;
22
+ this.code = code;
23
+ this.requestId = requestId;
24
+ this.body = body;
25
+ }
26
+ /**
27
+ * Factory that maps an HTTP status code to the appropriate error subclass.
28
+ */
29
+ static fromResponse(status, body, headers) {
30
+ const parsed = typeof body === "object" && body !== null ? body : {};
31
+ const message = typeof parsed.error === "string" ? parsed.error : `Request failed with status ${status}`;
32
+ const code = typeof parsed.code === "string" ? parsed.code : void 0;
33
+ let requestId;
34
+ if (headers) {
35
+ if (typeof headers.get === "function") {
36
+ requestId = headers.get("x-request-id") ?? void 0;
37
+ } else {
38
+ requestId = headers["x-request-id"];
39
+ }
40
+ }
41
+ switch (status) {
42
+ case 401:
43
+ return new AuthenticationError(body, message, code, requestId);
44
+ case 402:
45
+ return new InsufficientCreditsError(
46
+ body,
47
+ message,
48
+ code,
49
+ requestId,
50
+ typeof parsed.credits_needed === "number" ? parsed.credits_needed : void 0,
51
+ typeof parsed.credits_remaining === "number" ? parsed.credits_remaining : void 0
52
+ );
53
+ case 403:
54
+ return new PermissionDeniedError(body, message, code, requestId);
55
+ case 404:
56
+ return new NotFoundError(body, message, code, requestId);
57
+ case 422:
58
+ return new ValidationError(body, message, code, requestId);
59
+ case 429: {
60
+ let retryAfter;
61
+ if (headers) {
62
+ const raw = typeof headers.get === "function" ? headers.get("retry-after") : headers["retry-after"];
63
+ if (raw) {
64
+ const parsed2 = Number(raw);
65
+ if (!Number.isNaN(parsed2)) retryAfter = parsed2;
66
+ }
67
+ }
68
+ return new RateLimitError(body, message, code, requestId, retryAfter);
69
+ }
70
+ default:
71
+ if (status >= 500) {
72
+ return new InternalServerError(status, body, message, code, requestId);
73
+ }
74
+ return new _APIError(status, body, message, code, requestId);
75
+ }
76
+ }
77
+ };
78
+ var AuthenticationError = class extends APIError {
79
+ constructor(body, message, code, requestId) {
80
+ super(401, body, message, code, requestId);
81
+ this.name = "AuthenticationError";
82
+ }
83
+ };
84
+ var InsufficientCreditsError = class extends APIError {
85
+ /** Number of credits required for the operation. */
86
+ creditsRequired;
87
+ /** Current credit balance. */
88
+ creditsRemaining;
89
+ constructor(body, message, code, requestId, creditsRequired, creditsRemaining) {
90
+ super(402, body, message, code, requestId);
91
+ this.name = "InsufficientCreditsError";
92
+ this.creditsRequired = creditsRequired;
93
+ this.creditsRemaining = creditsRemaining;
94
+ }
95
+ };
96
+ var PermissionDeniedError = class extends APIError {
97
+ constructor(body, message, code, requestId) {
98
+ super(403, body, message, code, requestId);
99
+ this.name = "PermissionDeniedError";
100
+ }
101
+ };
102
+ var NotFoundError = class extends APIError {
103
+ constructor(body, message, code, requestId) {
104
+ super(404, body, message, code, requestId);
105
+ this.name = "NotFoundError";
106
+ }
107
+ };
108
+ var ValidationError = class extends APIError {
109
+ constructor(body, message, code, requestId) {
110
+ super(422, body, message, code, requestId);
111
+ this.name = "ValidationError";
112
+ }
113
+ };
114
+ var RateLimitError = class extends APIError {
115
+ /** Seconds to wait before retrying, from the Retry-After header. */
116
+ retryAfter;
117
+ constructor(body, message, code, requestId, retryAfter) {
118
+ super(429, body, message, code, requestId);
119
+ this.name = "RateLimitError";
120
+ this.retryAfter = retryAfter;
121
+ }
122
+ };
123
+ var InternalServerError = class extends APIError {
124
+ constructor(status, body, message, code, requestId) {
125
+ super(status, body, message, code, requestId);
126
+ this.name = "InternalServerError";
127
+ }
128
+ };
129
+ var APIConnectionError = class extends GeoDedoError {
130
+ /** The underlying error that caused the connection failure. */
131
+ cause;
132
+ constructor(message, cause) {
133
+ super(message);
134
+ this.name = "APIConnectionError";
135
+ this.cause = cause;
136
+ }
137
+ };
138
+ var APITimeoutError = class extends APIConnectionError {
139
+ constructor(message = "Request timed out") {
140
+ super(message);
141
+ this.name = "APITimeoutError";
142
+ }
143
+ };
144
+
145
+ // src/core/api-client.ts
146
+ var VERSION = "0.1.0";
147
+ var DEFAULT_BASE_URL = "https://geodedo-api.vercel.app";
148
+ var DEFAULT_TIMEOUT = 6e4;
149
+ var DEFAULT_MAX_RETRIES = 2;
150
+ var MIN_RETRY_DELAY = 500;
151
+ var MAX_RETRY_DELAY = 5e3;
152
+ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 409, 500, 502, 503, 504]);
153
+ var APIClient = class {
154
+ apiKey;
155
+ userId;
156
+ baseURL;
157
+ maxRetries;
158
+ timeout;
159
+ constructor(options) {
160
+ this.apiKey = options.apiKey;
161
+ this.userId = options.userId;
162
+ this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
163
+ this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
164
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
165
+ }
166
+ /**
167
+ * Core request method. All convenience methods delegate here.
168
+ */
169
+ async request(method, path, body, options) {
170
+ const url = `${this.baseURL}${path}`;
171
+ const apiKey = options?.apiKey ?? this.apiKey;
172
+ const userId = options?.userId ?? this.userId;
173
+ const timeout = options?.timeout ?? this.timeout;
174
+ const headers = {
175
+ "Authorization": `Bearer ${apiKey}`,
176
+ "Content-Type": "application/json",
177
+ "User-Agent": `geodedo-node/${VERSION}`,
178
+ ...options?.headers
179
+ };
180
+ if (userId) {
181
+ headers["X-User-Id"] = userId;
182
+ }
183
+ const maxRetries = this.maxRetries;
184
+ let lastError;
185
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
186
+ const controller = new AbortController();
187
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
188
+ const externalSignal = options?.signal;
189
+ let onExternalAbort;
190
+ if (externalSignal) {
191
+ if (externalSignal.aborted) {
192
+ clearTimeout(timeoutId);
193
+ throw new APITimeoutError("Request aborted");
194
+ }
195
+ onExternalAbort = () => controller.abort();
196
+ externalSignal.addEventListener("abort", onExternalAbort, { once: true });
197
+ }
198
+ try {
199
+ const fetchOptions = {
200
+ method,
201
+ headers,
202
+ signal: controller.signal
203
+ };
204
+ if (body !== void 0 && method !== "GET") {
205
+ fetchOptions.body = JSON.stringify(body);
206
+ }
207
+ let response;
208
+ try {
209
+ response = await fetch(url, fetchOptions);
210
+ } catch (err) {
211
+ if (controller.signal.aborted) {
212
+ throw new APITimeoutError();
213
+ }
214
+ throw new APIConnectionError(
215
+ `Connection error: ${err instanceof Error ? err.message : String(err)}`,
216
+ err
217
+ );
218
+ } finally {
219
+ clearTimeout(timeoutId);
220
+ if (externalSignal && onExternalAbort) {
221
+ externalSignal.removeEventListener("abort", onExternalAbort);
222
+ }
223
+ }
224
+ if (response.ok) {
225
+ if (response.status === 204) {
226
+ return void 0;
227
+ }
228
+ return await response.json();
229
+ }
230
+ let errorBody;
231
+ try {
232
+ errorBody = await response.json();
233
+ } catch {
234
+ errorBody = { error: response.statusText };
235
+ }
236
+ const apiError = APIError.fromResponse(response.status, errorBody, response.headers);
237
+ if (RETRYABLE_STATUS_CODES.has(response.status) && attempt < maxRetries) {
238
+ lastError = apiError;
239
+ await this.sleep(this.retryDelay(attempt));
240
+ continue;
241
+ }
242
+ throw apiError;
243
+ } catch (err) {
244
+ if ((err instanceof APIConnectionError || err instanceof APITimeoutError) && attempt < maxRetries) {
245
+ lastError = err;
246
+ await this.sleep(this.retryDelay(attempt));
247
+ continue;
248
+ }
249
+ if (err instanceof APIError || err instanceof APIConnectionError) {
250
+ throw err;
251
+ }
252
+ throw new APIConnectionError(
253
+ `Unexpected error: ${err instanceof Error ? err.message : String(err)}`,
254
+ err
255
+ );
256
+ }
257
+ }
258
+ throw lastError;
259
+ }
260
+ /** Calculate retry delay with exponential backoff and jitter. */
261
+ retryDelay(attempt) {
262
+ const base = MIN_RETRY_DELAY * Math.pow(2, attempt);
263
+ const capped = Math.min(base, MAX_RETRY_DELAY);
264
+ const jitter = Math.random() * capped;
265
+ return Math.min(capped + jitter, MAX_RETRY_DELAY);
266
+ }
267
+ sleep(ms) {
268
+ return new Promise((resolve) => setTimeout(resolve, ms));
269
+ }
270
+ // ── Convenience methods ─────────────────────────────────────────────
271
+ async get(path, options) {
272
+ return this.request("GET", path, void 0, options);
273
+ }
274
+ async post(path, body, options) {
275
+ return this.request("POST", path, body, options);
276
+ }
277
+ async put(path, body, options) {
278
+ return this.request("PUT", path, body, options);
279
+ }
280
+ async delete(path, options) {
281
+ return this.request("DELETE", path, void 0, options);
282
+ }
283
+ };
284
+
285
+ // src/core/pagination.ts
286
+ var Page = class {
287
+ /** The items on this page. */
288
+ data;
289
+ /** Total number of items across all pages. */
290
+ total;
291
+ /** Current page number (1-indexed). */
292
+ page;
293
+ /** Number of items per page (inferred from the current page size). */
294
+ perPage;
295
+ _requestOptions;
296
+ constructor(data, total, page, perPage, requestOptions) {
297
+ this.data = data;
298
+ this.total = total;
299
+ this.page = page;
300
+ this.perPage = perPage;
301
+ this._requestOptions = requestOptions;
302
+ }
303
+ /**
304
+ * Whether there is a next page available.
305
+ */
306
+ hasNextPage() {
307
+ return this.page * this.perPage < this.total;
308
+ }
309
+ /**
310
+ * Fetch the next page. Throws if there is no next page.
311
+ */
312
+ async getNextPage() {
313
+ if (!this.hasNextPage()) {
314
+ throw new Error("No more pages available");
315
+ }
316
+ return fetchPage({
317
+ ...this._requestOptions,
318
+ query: {
319
+ ...this._requestOptions.query,
320
+ page: this.page + 1
321
+ },
322
+ body: this._requestOptions.body ? { ...this._requestOptions.body, page: this.page + 1 } : void 0
323
+ });
324
+ }
325
+ /**
326
+ * Async iterator that yields every item across all pages,
327
+ * automatically fetching subsequent pages as needed.
328
+ */
329
+ async *[Symbol.asyncIterator]() {
330
+ let page = this;
331
+ while (true) {
332
+ for (const item of page.data) {
333
+ yield item;
334
+ }
335
+ if (!page.hasNextPage()) break;
336
+ page = await page.getNextPage();
337
+ }
338
+ }
339
+ };
340
+ async function fetchPage(opts) {
341
+ const { client, method, path, body, query, responseKey, options } = opts;
342
+ let fullPath = path;
343
+ if (query && Object.keys(query).length > 0) {
344
+ const params = new URLSearchParams();
345
+ for (const [key, value] of Object.entries(query)) {
346
+ if (value !== void 0 && value !== null) {
347
+ params.set(key, String(value));
348
+ }
349
+ }
350
+ const qs = params.toString();
351
+ if (qs) {
352
+ fullPath += (fullPath.includes("?") ? "&" : "?") + qs;
353
+ }
354
+ }
355
+ let raw;
356
+ if (method === "POST") {
357
+ raw = await client.post(fullPath, body, options);
358
+ } else {
359
+ raw = await client.get(fullPath, options);
360
+ }
361
+ const data = raw[responseKey] ?? [];
362
+ const total = typeof raw.total === "number" ? raw.total : data.length;
363
+ const page = typeof raw.page === "number" ? raw.page : 1;
364
+ const perPage = typeof raw.pageSize === "number" ? raw.pageSize : typeof raw.perPage === "number" ? raw.perPage : data.length > 0 ? data.length : 25;
365
+ return new Page(data, total, page, perPage, opts);
366
+ }
367
+
368
+ // src/resources/contacts.ts
369
+ var Contacts = class {
370
+ client;
371
+ constructor(client) {
372
+ this.client = client;
373
+ }
374
+ /**
375
+ * Search for contacts matching the given ICP criteria.
376
+ * Returns a paginated list of enriched contacts.
377
+ */
378
+ async search(params, options) {
379
+ const { page, perPage, ...body } = params;
380
+ return fetchPage({
381
+ client: this.client,
382
+ method: "POST",
383
+ path: "/api/contacts/search",
384
+ body: { ...body, page: page ?? 1, perPage: perPage ?? 25 },
385
+ responseKey: "contacts",
386
+ options
387
+ });
388
+ }
389
+ /**
390
+ * Enrich a single contact by email, LinkedIn URL, or name+company.
391
+ */
392
+ async enrich(params, options) {
393
+ const raw = await this.client.post(
394
+ "/api/contacts/enrich",
395
+ params,
396
+ options
397
+ );
398
+ return raw.contact;
399
+ }
400
+ /**
401
+ * Import a batch of contacts (CSV-like).
402
+ */
403
+ async importCsv(params, options) {
404
+ return this.client.post("/api/contacts/import", params, options);
405
+ }
406
+ /**
407
+ * List stored contacts for the current user. Paginated.
408
+ */
409
+ async list(params, options) {
410
+ const query = {};
411
+ if (params?.page) query.page = params.page;
412
+ if (params?.perPage) query.perPage = params.perPage;
413
+ return fetchPage({
414
+ client: this.client,
415
+ method: "GET",
416
+ path: "/api/contacts",
417
+ query,
418
+ responseKey: "contacts",
419
+ options
420
+ });
421
+ }
422
+ /**
423
+ * List all CSV lists (imports) for the current user.
424
+ */
425
+ async csvLists(options) {
426
+ const raw = await this.client.get(
427
+ "/api/contacts/csv-lists",
428
+ options
429
+ );
430
+ return raw.lists;
431
+ }
432
+ };
433
+
434
+ // src/resources/sequences.ts
435
+ var Sequences = class {
436
+ client;
437
+ constructor(client) {
438
+ this.client = client;
439
+ }
440
+ /**
441
+ * Create a new outreach sequence.
442
+ */
443
+ async create(params, options) {
444
+ const raw = await this.client.post(
445
+ "/api/sequences",
446
+ params,
447
+ options
448
+ );
449
+ return raw.sequence;
450
+ }
451
+ /**
452
+ * List all sequences for the current user. Paginated.
453
+ */
454
+ async list(params, options) {
455
+ const query = {};
456
+ if (params?.page) query.page = params.page;
457
+ if (params?.perPage) query.perPage = params.perPage;
458
+ return fetchPage({
459
+ client: this.client,
460
+ method: "GET",
461
+ path: "/api/sequences",
462
+ query,
463
+ responseKey: "sequences",
464
+ options
465
+ });
466
+ }
467
+ /**
468
+ * Get a single sequence by ID.
469
+ */
470
+ async get(sequenceId, options) {
471
+ const raw = await this.client.get(
472
+ `/api/sequences/${sequenceId}`,
473
+ options
474
+ );
475
+ return raw.sequence;
476
+ }
477
+ /**
478
+ * Pause a running sequence.
479
+ */
480
+ async pause(sequenceId, options) {
481
+ const raw = await this.client.post(
482
+ `/api/sequences/${sequenceId}/pause`,
483
+ void 0,
484
+ options
485
+ );
486
+ return raw.sequence;
487
+ }
488
+ /**
489
+ * Resume a paused sequence.
490
+ */
491
+ async resume(sequenceId, options) {
492
+ const raw = await this.client.post(
493
+ `/api/sequences/${sequenceId}/resume`,
494
+ void 0,
495
+ options
496
+ );
497
+ return raw.sequence;
498
+ }
499
+ /**
500
+ * Stop (terminate) a sequence.
501
+ */
502
+ async stop(sequenceId, options) {
503
+ const raw = await this.client.post(
504
+ `/api/sequences/${sequenceId}/stop`,
505
+ void 0,
506
+ options
507
+ );
508
+ return raw.sequence;
509
+ }
510
+ /**
511
+ * Get the current status of a sequence.
512
+ */
513
+ async status(sequenceId, options) {
514
+ const raw = await this.client.get(
515
+ `/api/sequences/${sequenceId}/status`,
516
+ options
517
+ );
518
+ return raw.sequence;
519
+ }
520
+ };
521
+
522
+ // src/resources/drafts.ts
523
+ var Drafts = class {
524
+ client;
525
+ constructor(client) {
526
+ this.client = client;
527
+ }
528
+ /**
529
+ * Generate outreach drafts for a list of contacts.
530
+ */
531
+ async generate(params, options) {
532
+ return this.client.post("/api/drafts/generate", params, options);
533
+ }
534
+ /**
535
+ * List drafts, optionally filtered by conversation, batch, or status. Paginated.
536
+ */
537
+ async list(params, options) {
538
+ const query = {};
539
+ if (params?.conversationId) query.conversationId = params.conversationId;
540
+ if (params?.batchId) query.batchId = params.batchId;
541
+ if (params?.status) query.status = params.status;
542
+ if (params?.page) query.page = params.page;
543
+ if (params?.perPage) query.perPage = params.perPage;
544
+ return fetchPage({
545
+ client: this.client,
546
+ method: "GET",
547
+ path: "/api/drafts",
548
+ query,
549
+ responseKey: "drafts",
550
+ options
551
+ });
552
+ }
553
+ /**
554
+ * Update a specific draft's subject and/or body.
555
+ */
556
+ async update(draftId, params, options) {
557
+ const raw = await this.client.put(
558
+ `/api/drafts/${draftId}`,
559
+ params,
560
+ options
561
+ );
562
+ return raw.draft;
563
+ }
564
+ /**
565
+ * Approve drafts by their IDs.
566
+ */
567
+ async approve(params, options) {
568
+ return this.client.post("/api/drafts/approve", params, options);
569
+ }
570
+ /**
571
+ * Send approved drafts.
572
+ */
573
+ async send(params, options) {
574
+ return this.client.post("/api/drafts/send", params, options);
575
+ }
576
+ };
577
+
578
+ // src/resources/messages.ts
579
+ var Messages = class {
580
+ client;
581
+ constructor(client) {
582
+ this.client = client;
583
+ }
584
+ /**
585
+ * Send an email via Gmail or AgentMail.
586
+ */
587
+ async sendEmail(params, options) {
588
+ return this.client.post("/api/messages/email", params, options);
589
+ }
590
+ /**
591
+ * Send a LinkedIn message or connection request.
592
+ */
593
+ async sendLinkedIn(params, options) {
594
+ return this.client.post("/api/messages/linkedin", params, options);
595
+ }
596
+ /**
597
+ * Send an Instagram DM.
598
+ */
599
+ async sendInstagram(params, options) {
600
+ return this.client.post("/api/messages/instagram", params, options);
601
+ }
602
+ /**
603
+ * Send an SMS message.
604
+ */
605
+ async sendSms(params, options) {
606
+ return this.client.post("/api/messages/sms", params, options);
607
+ }
608
+ /**
609
+ * Get the unified inbox for a specific channel.
610
+ */
611
+ async inbox(channel, options) {
612
+ return this.client.get(
613
+ `/api/messages/inbox/${channel}`,
614
+ options
615
+ );
616
+ }
617
+ };
618
+
619
+ // src/resources/chat.ts
620
+ var ConversationsResource = class {
621
+ client;
622
+ constructor(client) {
623
+ this.client = client;
624
+ }
625
+ /**
626
+ * List all conversations.
627
+ */
628
+ async list(options) {
629
+ const raw = await this.client.get(
630
+ "/api/chat/conversations",
631
+ options
632
+ );
633
+ return raw.conversations;
634
+ }
635
+ /**
636
+ * Get messages for a specific conversation.
637
+ */
638
+ async get(conversationId, options) {
639
+ const raw = await this.client.get(
640
+ `/api/chat/conversations/${conversationId}`,
641
+ options
642
+ );
643
+ return raw.messages;
644
+ }
645
+ /**
646
+ * Delete a conversation.
647
+ */
648
+ async delete(conversationId, options) {
649
+ await this.client.delete(
650
+ `/api/chat/conversations/${conversationId}`,
651
+ options
652
+ );
653
+ }
654
+ };
655
+ var Chat = class {
656
+ client;
657
+ /** Sub-resource for managing conversations. */
658
+ conversations;
659
+ constructor(client) {
660
+ this.client = client;
661
+ this.conversations = new ConversationsResource(client);
662
+ }
663
+ /**
664
+ * Send a message to the AI assistant.
665
+ */
666
+ async create(params, options) {
667
+ return this.client.post("/api/chat", params, options);
668
+ }
669
+ };
670
+
671
+ // src/resources/channels.ts
672
+ var GmailChannel = class {
673
+ client;
674
+ constructor(client) {
675
+ this.client = client;
676
+ }
677
+ /**
678
+ * Initiate Gmail OAuth flow. Returns an authUrl for the user to visit.
679
+ */
680
+ async connect(options) {
681
+ return this.client.post("/api/channels/gmail/connect", void 0, options);
682
+ }
683
+ };
684
+ var LinkedInChannel = class {
685
+ client;
686
+ constructor(client) {
687
+ this.client = client;
688
+ }
689
+ /**
690
+ * Connect a LinkedIn account with credentials.
691
+ */
692
+ async connect(params, options) {
693
+ return this.client.post("/api/channels/linkedin/connect", params, options);
694
+ }
695
+ /**
696
+ * Resolve a LinkedIn 2FA checkpoint.
697
+ */
698
+ async checkpoint(params, options) {
699
+ return this.client.post("/api/channels/linkedin/checkpoint", params, options);
700
+ }
701
+ };
702
+ var InstagramChannel = class {
703
+ client;
704
+ constructor(client) {
705
+ this.client = client;
706
+ }
707
+ /**
708
+ * Connect an Instagram account with credentials.
709
+ */
710
+ async connect(params, options) {
711
+ return this.client.post("/api/channels/instagram/connect", params, options);
712
+ }
713
+ /**
714
+ * Resolve an Instagram 2FA checkpoint.
715
+ */
716
+ async checkpoint(params, options) {
717
+ return this.client.post("/api/channels/instagram/checkpoint", params, options);
718
+ }
719
+ };
720
+ var AgentMailChannel = class {
721
+ client;
722
+ constructor(client) {
723
+ this.client = client;
724
+ }
725
+ /**
726
+ * Create a new AgentMail address.
727
+ */
728
+ async create(params, options) {
729
+ return this.client.post("/api/channels/agentmail/create", params, options);
730
+ }
731
+ };
732
+ var SmsChannel = class {
733
+ client;
734
+ constructor(client) {
735
+ this.client = client;
736
+ }
737
+ /**
738
+ * Initiate SMS verification for a phone number.
739
+ */
740
+ async verify(params, options) {
741
+ return this.client.post("/api/channels/sms/verify", params, options);
742
+ }
743
+ /**
744
+ * Confirm SMS verification with the code.
745
+ */
746
+ async confirm(params, options) {
747
+ return this.client.post("/api/channels/sms/confirm", params, options);
748
+ }
749
+ };
750
+ var Channels = class {
751
+ client;
752
+ /** Gmail channel operations. */
753
+ gmail;
754
+ /** LinkedIn channel operations. */
755
+ linkedin;
756
+ /** Instagram channel operations. */
757
+ instagram;
758
+ /** AgentMail channel operations. */
759
+ agentmail;
760
+ /** SMS channel operations. */
761
+ sms;
762
+ constructor(client) {
763
+ this.client = client;
764
+ this.gmail = new GmailChannel(client);
765
+ this.linkedin = new LinkedInChannel(client);
766
+ this.instagram = new InstagramChannel(client);
767
+ this.agentmail = new AgentMailChannel(client);
768
+ this.sms = new SmsChannel(client);
769
+ }
770
+ /**
771
+ * Get the connection status of all channels.
772
+ */
773
+ async status(options) {
774
+ return this.client.get("/api/channels/status", options);
775
+ }
776
+ /**
777
+ * Disconnect a specific channel.
778
+ */
779
+ async disconnect(channel, options) {
780
+ await this.client.post(`/api/channels/${channel}/disconnect`, void 0, options);
781
+ }
782
+ };
783
+
784
+ // src/resources/documents.ts
785
+ var Documents = class {
786
+ client;
787
+ constructor(client) {
788
+ this.client = client;
789
+ }
790
+ /**
791
+ * Upload a document.
792
+ */
793
+ async upload(params, options) {
794
+ const raw = await this.client.post(
795
+ "/api/documents",
796
+ params,
797
+ options
798
+ );
799
+ return raw.document;
800
+ }
801
+ /**
802
+ * List all documents. Paginated.
803
+ */
804
+ async list(params, options) {
805
+ const query = {};
806
+ if (params?.page) query.page = params.page;
807
+ if (params?.perPage) query.perPage = params.perPage;
808
+ return fetchPage({
809
+ client: this.client,
810
+ method: "GET",
811
+ path: "/api/documents",
812
+ query,
813
+ responseKey: "documents",
814
+ options
815
+ });
816
+ }
817
+ /**
818
+ * Delete a document by ID.
819
+ */
820
+ async delete(documentId, options) {
821
+ await this.client.delete(`/api/documents/${documentId}`, options);
822
+ }
823
+ };
824
+
825
+ // src/resources/recommendations.ts
826
+ var Recommendations = class {
827
+ client;
828
+ constructor(client) {
829
+ this.client = client;
830
+ }
831
+ /**
832
+ * Get an ICP analysis recommendation.
833
+ */
834
+ async icpAnalysis(options) {
835
+ return this.client.get("/api/recommendations/icp", options);
836
+ }
837
+ /**
838
+ * Get a channel recommendation.
839
+ */
840
+ async channel(options) {
841
+ return this.client.get("/api/recommendations/channel", options);
842
+ }
843
+ /**
844
+ * Get a sequence strategy recommendation.
845
+ */
846
+ async sequenceStrategy(options) {
847
+ return this.client.get("/api/recommendations/sequence-strategy", options);
848
+ }
849
+ };
850
+
851
+ // src/resources/billing.ts
852
+ var Billing = class {
853
+ client;
854
+ constructor(client) {
855
+ this.client = client;
856
+ }
857
+ /**
858
+ * Get the current credit balance.
859
+ */
860
+ async balance(options) {
861
+ return this.client.get("/api/billing/balance", options);
862
+ }
863
+ /**
864
+ * List usage entries. Paginated.
865
+ */
866
+ async usage(params, options) {
867
+ const query = {};
868
+ if (params?.from) query.from = params.from;
869
+ if (params?.to) query.to = params.to;
870
+ if (params?.page) query.page = params.page;
871
+ return fetchPage({
872
+ client: this.client,
873
+ method: "GET",
874
+ path: "/api/billing/usage",
875
+ query,
876
+ responseKey: "usage",
877
+ options
878
+ });
879
+ }
880
+ /**
881
+ * Get an aggregated usage summary.
882
+ */
883
+ async usageSummary(options) {
884
+ return this.client.get("/api/billing/usage/summary", options);
885
+ }
886
+ };
887
+
888
+ // src/resources/users.ts
889
+ var Users = class {
890
+ client;
891
+ constructor(client) {
892
+ this.client = client;
893
+ }
894
+ /**
895
+ * Register a new user.
896
+ */
897
+ async register(params, options) {
898
+ const raw = await this.client.post(
899
+ "/api/users/register",
900
+ params,
901
+ options
902
+ );
903
+ return raw.user;
904
+ }
905
+ /**
906
+ * Get the current user's profile.
907
+ */
908
+ async me(options) {
909
+ const raw = await this.client.get("/api/users/me", options);
910
+ return raw.user;
911
+ }
912
+ /**
913
+ * Update the current user's profile.
914
+ */
915
+ async update(params, options) {
916
+ const raw = await this.client.put(
917
+ "/api/users/me",
918
+ params,
919
+ options
920
+ );
921
+ return raw.user;
922
+ }
923
+ };
924
+
925
+ // src/client.ts
926
+ function isBrowser() {
927
+ return typeof window !== "undefined" && typeof window.document !== "undefined";
928
+ }
929
+ var GeoDedo = class {
930
+ _client;
931
+ /** Contact search, enrichment, and import. */
932
+ contacts;
933
+ /** Outreach sequence management. */
934
+ sequences;
935
+ /** Draft generation, review, and sending. */
936
+ drafts;
937
+ /** Direct message sending (email, LinkedIn, Instagram, SMS). */
938
+ messages;
939
+ /** AI chat assistant. */
940
+ chat;
941
+ /** Channel connection management. */
942
+ channels;
943
+ /** Document upload and management. */
944
+ documents;
945
+ /** AI-powered recommendations. */
946
+ recommendations;
947
+ /** Credit balance and usage tracking. */
948
+ billing;
949
+ /** User registration and profile management. */
950
+ users;
951
+ constructor(options) {
952
+ let envKey;
953
+ try {
954
+ if (typeof globalThis !== "undefined" && "process" in globalThis) {
955
+ envKey = globalThis.process?.env?.GEODEDO_API_KEY;
956
+ }
957
+ } catch {
958
+ }
959
+ const apiKey = options?.apiKey ?? envKey;
960
+ if (!apiKey) {
961
+ throw new GeoDedoError(
962
+ "The GEODEDO_API_KEY environment variable is missing or empty; either provide it, or pass the `apiKey` option to the GeoDedo constructor."
963
+ );
964
+ }
965
+ if (isBrowser() && !options?.dangerouslyAllowBrowser) {
966
+ throw new GeoDedoError(
967
+ "It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API key to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew GeoDedo({ apiKey: '...', dangerouslyAllowBrowser: true })"
968
+ );
969
+ }
970
+ this._client = new APIClient({
971
+ apiKey,
972
+ userId: options?.userId,
973
+ baseURL: options?.baseURL,
974
+ maxRetries: options?.maxRetries,
975
+ timeout: options?.timeout
976
+ });
977
+ this.contacts = new Contacts(this._client);
978
+ this.sequences = new Sequences(this._client);
979
+ this.drafts = new Drafts(this._client);
980
+ this.messages = new Messages(this._client);
981
+ this.chat = new Chat(this._client);
982
+ this.channels = new Channels(this._client);
983
+ this.documents = new Documents(this._client);
984
+ this.recommendations = new Recommendations(this._client);
985
+ this.billing = new Billing(this._client);
986
+ this.users = new Users(this._client);
987
+ }
988
+ };
989
+ export {
990
+ APIClient,
991
+ APIConnectionError,
992
+ APIError,
993
+ APITimeoutError,
994
+ AgentMailChannel,
995
+ AuthenticationError,
996
+ Billing,
997
+ Channels,
998
+ Chat,
999
+ Contacts,
1000
+ ConversationsResource,
1001
+ Documents,
1002
+ Drafts,
1003
+ GeoDedo,
1004
+ GeoDedoError,
1005
+ GmailChannel,
1006
+ InstagramChannel,
1007
+ InsufficientCreditsError,
1008
+ InternalServerError,
1009
+ LinkedInChannel,
1010
+ Messages,
1011
+ NotFoundError,
1012
+ Page,
1013
+ PermissionDeniedError,
1014
+ RateLimitError,
1015
+ Recommendations,
1016
+ Sequences,
1017
+ SmsChannel,
1018
+ Users,
1019
+ ValidationError
1020
+ };
1021
+ //# sourceMappingURL=index.js.map