@isnap/sdk 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 iSnap
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,236 @@
1
+ # @isnap/sdk
2
+
3
+ [![CI](https://github.com/isnap-dev/isnap-node/actions/workflows/ci.yml/badge.svg)](https://github.com/isnap-dev/isnap-node/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/@isnap/sdk.svg)](https://www.npmjs.com/package/@isnap/sdk)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
+
7
+ Official Node.js/TypeScript SDK for the [iSnap](https://isnap.dev) messaging API. Zero runtime dependencies.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @isnap/sdk
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```ts
18
+ import { init } from '@isnap/sdk';
19
+
20
+ const client = init({ apiKey: 'isnap_your_api_key' });
21
+
22
+ const msg = await client.messages.send({
23
+ line_id: 'ln-1',
24
+ to: '+15551234567',
25
+ body: 'Hello from iSnap!',
26
+ });
27
+
28
+ console.log(msg.id, msg.status);
29
+ ```
30
+
31
+ ## Messages
32
+
33
+ ```ts
34
+ // Send a message
35
+ const msg = await client.messages.send({
36
+ line_id: 'ln-1',
37
+ to: '+15551234567',
38
+ body: 'Hello!',
39
+ channel: 'sms', // optional: 'auto' | 'imessage' | 'sms' | 'whatsapp'
40
+ webhook_url: 'https://...', // optional: delivery status callback
41
+ metadata: { order_id: '42' },
42
+ });
43
+
44
+ // Get a message by ID
45
+ const message = await client.messages.get('msg-abc123');
46
+
47
+ // List messages with filters
48
+ const { messages, total } = await client.messages.list({
49
+ status: 'delivered',
50
+ direction: 'outbound',
51
+ page: 1,
52
+ limit: 50,
53
+ });
54
+
55
+ // List conversations
56
+ const { conversations } = await client.messages.listConversations({
57
+ line_id: 'ln-1',
58
+ });
59
+
60
+ // Get a full conversation thread
61
+ const thread = await client.messages.getConversation('conv-abc123', {
62
+ page: 1,
63
+ limit: 25,
64
+ });
65
+ console.log(thread.conversation.contact_number);
66
+ console.log(thread.messages);
67
+ ```
68
+
69
+ ## Lines
70
+
71
+ ```ts
72
+ // List lines with filters
73
+ const { lines } = await client.lines.list({
74
+ type: 'iphone',
75
+ area_code: '415',
76
+ });
77
+
78
+ // Get a line by ID
79
+ const line = await client.lines.get('ln-abc123');
80
+ console.log(line.phone_number, line.status);
81
+ ```
82
+
83
+ ## Webhooks
84
+
85
+ ### Managing webhook endpoints
86
+
87
+ ```ts
88
+ // Create a webhook
89
+ const wh = await client.webhooks.create({
90
+ url: 'https://example.com/webhooks/isnap',
91
+ events: ['message.sent', 'message.delivered', 'message.received'],
92
+ });
93
+ // Save wh.secret for signature verification
94
+
95
+ // List webhooks
96
+ const { webhooks } = await client.webhooks.list();
97
+
98
+ // Delete a webhook
99
+ await client.webhooks.delete('wh-abc123');
100
+ ```
101
+
102
+ ### Receiving webhooks
103
+
104
+ Use `parseWebhook` to verify signatures and get typed events in one call:
105
+
106
+ ```ts
107
+ import { parseWebhook } from '@isnap/sdk';
108
+ // or: import { parseWebhook } from '@isnap/sdk/webhooks';
109
+
110
+ app.post('/webhooks/isnap', express.text({ type: '*/*' }), (req, res) => {
111
+ const { verified, event } = parseWebhook({
112
+ secret: process.env.WEBHOOK_SECRET!,
113
+ signature: req.headers['x-isnap-signature'] as string,
114
+ timestamp: req.headers['x-isnap-timestamp'] as string,
115
+ body: req.body,
116
+ });
117
+
118
+ if (!verified) return res.status(401).send('Invalid signature');
119
+
120
+ switch (event.event) {
121
+ case 'message.sent':
122
+ console.log('Sent:', event.data.id);
123
+ break;
124
+ case 'message.delivered':
125
+ console.log('Delivered:', event.data.id);
126
+ break;
127
+ case 'message.received':
128
+ console.log('Inbound:', event.data.from_number, event.data.body);
129
+ break;
130
+ case 'message.read':
131
+ console.log('Read:', event.data.id);
132
+ break;
133
+ case 'message.failed':
134
+ console.log('Failed:', event.data.id, event.data.error_message);
135
+ break;
136
+ }
137
+
138
+ res.sendStatus(200);
139
+ });
140
+ ```
141
+
142
+ You can also verify signatures manually:
143
+
144
+ ```ts
145
+ import { verifyWebhookSignature } from '@isnap/sdk';
146
+
147
+ const valid = verifyWebhookSignature(
148
+ secret,
149
+ req.headers['x-isnap-signature'],
150
+ req.headers['x-isnap-timestamp'],
151
+ req.body,
152
+ );
153
+ ```
154
+
155
+ ## Pagination
156
+
157
+ Use the `paginate` async generator to iterate over large collections:
158
+
159
+ ```ts
160
+ import { init, paginate } from '@isnap/sdk';
161
+
162
+ const client = init({ apiKey: 'isnap_your_key' });
163
+
164
+ // Iterate over all delivered messages
165
+ for await (const msg of paginate(
166
+ (p) => client.messages.list(p),
167
+ { status: 'delivered' },
168
+ 'messages',
169
+ )) {
170
+ console.log(msg.id, msg.body);
171
+ }
172
+
173
+ // Iterate over all conversations
174
+ for await (const conv of paginate(
175
+ (p) => client.messages.listConversations(p),
176
+ { line_id: 'ln-1' },
177
+ 'conversations',
178
+ )) {
179
+ console.log(conv.contact_number, conv.message_count);
180
+ }
181
+ ```
182
+
183
+ ## Error Handling
184
+
185
+ ```ts
186
+ import { iSnapError, RateLimitError } from '@isnap/sdk';
187
+
188
+ try {
189
+ await client.messages.send({ line_id: 'ln-1', to: '+15551234567', body: 'Hello' });
190
+ } catch (err) {
191
+ if (err instanceof RateLimitError) {
192
+ console.log(`Rate limited — retry after ${err.retryAfter}s`);
193
+ } else if (err instanceof iSnapError) {
194
+ console.log(`API error ${err.statusCode}: ${err.message} (${err.code})`);
195
+ }
196
+ }
197
+ ```
198
+
199
+ ### Retry configuration
200
+
201
+ The client automatically retries on 429 responses. Customize the behavior:
202
+
203
+ ```ts
204
+ const client = init({
205
+ apiKey: 'isnap_your_key',
206
+ maxRetries: 5, // default: 3
207
+ retryDelayMs: 2000, // default: 5000 (fallback when no Retry-After header)
208
+ });
209
+ ```
210
+
211
+ ## TypeScript
212
+
213
+ All types are exported from the main entry point:
214
+
215
+ ```ts
216
+ import type {
217
+ Message,
218
+ SendMessageParams,
219
+ Line,
220
+ Webhook,
221
+ Conversation,
222
+ ConversationThreadResponse,
223
+ WebhookEvent,
224
+ WebhookEventType,
225
+ MessageSentEvent,
226
+ iSnapConfig,
227
+ } from '@isnap/sdk';
228
+ ```
229
+
230
+ ## Contributing
231
+
232
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
233
+
234
+ ## License
235
+
236
+ [MIT](LICENSE)
@@ -0,0 +1,61 @@
1
+ import type { iSnapConfig } from './types.js';
2
+ import { MessagesResource } from './resources/messages.js';
3
+ import { LinesResource } from './resources/lines.js';
4
+ import { WebhooksResource } from './resources/webhooks.js';
5
+ /**
6
+ * The iSnap SDK client. Provides access to all API resources.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { init } from '@isnap/sdk';
11
+ *
12
+ * const client = init({ apiKey: 'isnap_your_key' });
13
+ * const msg = await client.messages.send({ line_id: 'ln-1', to: '+15551234567', body: 'Hello' });
14
+ * ```
15
+ */
16
+ export declare class iSnapClient {
17
+ private apiKey;
18
+ private baseUrl;
19
+ private maxRetries;
20
+ private retryDelayMs;
21
+ /** Message sending, retrieval, and conversation management. */
22
+ messages: MessagesResource;
23
+ /** Phone line listing and lookup. */
24
+ lines: LinesResource;
25
+ /** Webhook endpoint management. */
26
+ webhooks: WebhooksResource;
27
+ constructor(config: iSnapConfig);
28
+ /**
29
+ * Send an HTTP request to the iSnap API.
30
+ *
31
+ * Handles authorization, JSON serialization, rate-limit retries, and error mapping.
32
+ *
33
+ * @param method - HTTP method (GET, POST, DELETE, etc.)
34
+ * @param path - API path (e.g. `/v1/messages`)
35
+ * @param body - Optional request body (will be JSON-stringified)
36
+ * @param query - Optional query parameters
37
+ * @returns Parsed JSON response
38
+ * @throws {iSnapError} On non-2xx responses
39
+ * @throws {RateLimitError} When rate-limited after exhausting retries
40
+ */
41
+ request<T>(method: string, path: string, body?: unknown, query?: Record<string, string>): Promise<T>;
42
+ }
43
+ /**
44
+ * Create a new iSnap SDK client.
45
+ *
46
+ * @param config - API key and optional settings
47
+ * @returns A configured {@link iSnapClient} instance
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * import { init } from '@isnap/sdk';
52
+ *
53
+ * const client = init({
54
+ * apiKey: 'isnap_your_key',
55
+ * maxRetries: 5,
56
+ * retryDelayMs: 2000,
57
+ * });
58
+ * ```
59
+ */
60
+ export declare function init(config: iSnapConfig): iSnapClient;
61
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAE7B,+DAA+D;IACxD,QAAQ,EAAE,gBAAgB,CAAC;IAClC,qCAAqC;IAC9B,KAAK,EAAE,aAAa,CAAC;IAC5B,mCAAmC;IAC5B,QAAQ,EAAE,gBAAgB,CAAC;gBAEtB,MAAM,EAAE,WAAW;IAW/B;;;;;;;;;;;;OAYG;IACG,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAsD3G;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAErD"}
package/dist/client.js ADDED
@@ -0,0 +1,115 @@
1
+ import { iSnapError, RateLimitError } from './types.js';
2
+ import { MessagesResource } from './resources/messages.js';
3
+ import { LinesResource } from './resources/lines.js';
4
+ import { WebhooksResource } from './resources/webhooks.js';
5
+ /**
6
+ * The iSnap SDK client. Provides access to all API resources.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { init } from '@isnap/sdk';
11
+ *
12
+ * const client = init({ apiKey: 'isnap_your_key' });
13
+ * const msg = await client.messages.send({ line_id: 'ln-1', to: '+15551234567', body: 'Hello' });
14
+ * ```
15
+ */
16
+ export class iSnapClient {
17
+ apiKey;
18
+ baseUrl;
19
+ maxRetries;
20
+ retryDelayMs;
21
+ /** Message sending, retrieval, and conversation management. */
22
+ messages;
23
+ /** Phone line listing and lookup. */
24
+ lines;
25
+ /** Webhook endpoint management. */
26
+ webhooks;
27
+ constructor(config) {
28
+ this.apiKey = config.apiKey;
29
+ this.baseUrl = (config.baseUrl ?? 'https://api.isnap.dev').replace(/\/$/, '');
30
+ this.maxRetries = config.maxRetries ?? 3;
31
+ this.retryDelayMs = config.retryDelayMs ?? 5000;
32
+ this.messages = new MessagesResource(this);
33
+ this.lines = new LinesResource(this);
34
+ this.webhooks = new WebhooksResource(this);
35
+ }
36
+ /**
37
+ * Send an HTTP request to the iSnap API.
38
+ *
39
+ * Handles authorization, JSON serialization, rate-limit retries, and error mapping.
40
+ *
41
+ * @param method - HTTP method (GET, POST, DELETE, etc.)
42
+ * @param path - API path (e.g. `/v1/messages`)
43
+ * @param body - Optional request body (will be JSON-stringified)
44
+ * @param query - Optional query parameters
45
+ * @returns Parsed JSON response
46
+ * @throws {iSnapError} On non-2xx responses
47
+ * @throws {RateLimitError} When rate-limited after exhausting retries
48
+ */
49
+ async request(method, path, body, query) {
50
+ let url = `${this.baseUrl}${path}`;
51
+ if (query) {
52
+ const params = new URLSearchParams();
53
+ for (const [key, value] of Object.entries(query)) {
54
+ if (value !== undefined && value !== '')
55
+ params.set(key, value);
56
+ }
57
+ const qs = params.toString();
58
+ if (qs)
59
+ url += `?${qs}`;
60
+ }
61
+ const headers = {
62
+ Authorization: this.apiKey,
63
+ };
64
+ if (body !== undefined) {
65
+ headers['Content-Type'] = 'application/json';
66
+ }
67
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
68
+ const res = await fetch(url, {
69
+ method,
70
+ headers,
71
+ body: body ? JSON.stringify(body) : undefined,
72
+ });
73
+ if (res.status === 429) {
74
+ const retryAfterHeader = res.headers.get('Retry-After');
75
+ const retryAfter = retryAfterHeader !== null
76
+ ? parseInt(retryAfterHeader, 10)
77
+ : this.retryDelayMs / 1000;
78
+ if (attempt < this.maxRetries) {
79
+ await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
80
+ continue;
81
+ }
82
+ throw new RateLimitError(`Rate limit exceeded`, retryAfter);
83
+ }
84
+ if (!res.ok) {
85
+ const err = await res.json().catch(() => ({ message: `HTTP ${res.status}` }));
86
+ throw new iSnapError(err.message || `HTTP ${res.status}`, res.status, err.code);
87
+ }
88
+ if (res.status === 204)
89
+ return undefined;
90
+ return res.json();
91
+ }
92
+ throw new iSnapError('Max retries exceeded', 429);
93
+ }
94
+ }
95
+ /**
96
+ * Create a new iSnap SDK client.
97
+ *
98
+ * @param config - API key and optional settings
99
+ * @returns A configured {@link iSnapClient} instance
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { init } from '@isnap/sdk';
104
+ *
105
+ * const client = init({
106
+ * apiKey: 'isnap_your_key',
107
+ * maxRetries: 5,
108
+ * retryDelayMs: 2000,
109
+ * });
110
+ * ```
111
+ */
112
+ export function init(config) {
113
+ return new iSnapClient(config);
114
+ }
115
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export { iSnapClient, init } from './client.js';
2
+ export { MessagesResource } from './resources/messages.js';
3
+ export { LinesResource } from './resources/lines.js';
4
+ export { WebhooksResource } from './resources/webhooks.js';
5
+ export type { iSnapConfig, Message, SendMessageParams, ListMessagesParams, ListMessagesResponse, Line, ListLinesParams, ListLinesResponse, Webhook, CreateWebhookParams, Conversation, ListConversationsParams, ListConversationsResponse, ConversationThreadParams, ConversationThreadResponse, WebhookEventType, WebhookEvent, MessageSentEvent, MessageDeliveredEvent, MessageReadEvent, MessageFailedEvent, MessageReceivedEvent, } from './types.js';
6
+ export { iSnapError, RateLimitError } from './types.js';
7
+ export { verifyWebhookSignature } from './webhook-verify.js';
8
+ export { parseWebhook } from './webhook-events.js';
9
+ export type { ParseWebhookOptions, ParseWebhookResult } from './webhook-events.js';
10
+ export { paginate } from './paginate.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,YAAY,EACV,WAAW,EACX,OAAO,EACP,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,IAAI,EACJ,eAAe,EACf,iBAAiB,EACjB,OAAO,EACP,mBAAmB,EACnB,YAAY,EACZ,uBAAuB,EACvB,yBAAyB,EACzB,wBAAwB,EACxB,0BAA0B,EAC1B,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export { iSnapClient, init } from './client.js';
2
+ export { MessagesResource } from './resources/messages.js';
3
+ export { LinesResource } from './resources/lines.js';
4
+ export { WebhooksResource } from './resources/webhooks.js';
5
+ export { iSnapError, RateLimitError } from './types.js';
6
+ export { verifyWebhookSignature } from './webhook-verify.js';
7
+ export { parseWebhook } from './webhook-events.js';
8
+ export { paginate } from './paginate.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAyB3D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Generic async generator that paginates over any SDK list endpoint.
3
+ *
4
+ * Yields individual items from each page until all pages have been consumed.
5
+ *
6
+ * @param fetcher - A function that accepts `{ page, limit }` and returns a paginated response
7
+ * @param params - Initial pagination parameters (defaults: `page = 1`, `limit = 100`)
8
+ * @param dataKey - The key in the response object that holds the array of items
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { init, paginate } from '@isnap/sdk';
13
+ *
14
+ * const client = init({ apiKey: 'isnap_your_key' });
15
+ *
16
+ * for await (const msg of paginate(
17
+ * (p) => client.messages.list(p),
18
+ * { status: 'delivered' },
19
+ * 'messages',
20
+ * )) {
21
+ * console.log(msg.id, msg.body);
22
+ * }
23
+ * ```
24
+ */
25
+ export declare function paginate<TItem, TParams extends {
26
+ page?: number;
27
+ limit?: number;
28
+ }, TKey extends string>(fetcher: (params: TParams) => Promise<{
29
+ total: number;
30
+ page: number;
31
+ limit: number;
32
+ } & Record<TKey, TItem[]>>, params: TParams, dataKey: TKey): AsyncGenerator<TItem, void, undefined>;
33
+ //# sourceMappingURL=paginate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginate.d.ts","sourceRoot":"","sources":["../src/paginate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAuB,QAAQ,CAC7B,KAAK,EACL,OAAO,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACjD,IAAI,SAAS,MAAM,EAEnB,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAC7G,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,IAAI,GACZ,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAkBxC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Generic async generator that paginates over any SDK list endpoint.
3
+ *
4
+ * Yields individual items from each page until all pages have been consumed.
5
+ *
6
+ * @param fetcher - A function that accepts `{ page, limit }` and returns a paginated response
7
+ * @param params - Initial pagination parameters (defaults: `page = 1`, `limit = 100`)
8
+ * @param dataKey - The key in the response object that holds the array of items
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { init, paginate } from '@isnap/sdk';
13
+ *
14
+ * const client = init({ apiKey: 'isnap_your_key' });
15
+ *
16
+ * for await (const msg of paginate(
17
+ * (p) => client.messages.list(p),
18
+ * { status: 'delivered' },
19
+ * 'messages',
20
+ * )) {
21
+ * console.log(msg.id, msg.body);
22
+ * }
23
+ * ```
24
+ */
25
+ export async function* paginate(fetcher, params, dataKey) {
26
+ let page = params.page ?? 1;
27
+ const limit = params.limit ?? 100;
28
+ while (true) {
29
+ const response = await fetcher({ ...params, page, limit });
30
+ const items = response[dataKey];
31
+ for (const item of items) {
32
+ yield item;
33
+ }
34
+ if (items.length < limit || page * limit >= response.total) {
35
+ break;
36
+ }
37
+ page++;
38
+ }
39
+ }
40
+ //# sourceMappingURL=paginate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginate.js","sourceRoot":"","sources":["../src/paginate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,QAAQ,CAK7B,OAA6G,EAC7G,MAAe,EACf,OAAa;IAEb,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC;IAElC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,KAAK,EAAa,CAAC,CAAC;QACtE,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC;QACb,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAC3D,MAAM;QACR,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC;AACH,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { iSnapClient } from '../client.js';
2
+ import type { Line, ListLinesParams, ListLinesResponse } from '../types.js';
3
+ export declare class LinesResource {
4
+ private client;
5
+ constructor(client: iSnapClient);
6
+ /**
7
+ * List phone lines with optional filters and pagination.
8
+ *
9
+ * @param params - Optional filters (type, area_code) and pagination
10
+ * @returns Paginated list of lines
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const { lines } = await client.lines.list({ type: 'iphone', limit: 10 });
15
+ * ```
16
+ */
17
+ list(params?: ListLinesParams): Promise<ListLinesResponse>;
18
+ /**
19
+ * Retrieve a single line by ID.
20
+ *
21
+ * @param lineId - The line ID
22
+ * @returns The line
23
+ * @throws {iSnapError} If the line is not found
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const line = await client.lines.get('ln-abc123');
28
+ * console.log(line.phone_number);
29
+ * ```
30
+ */
31
+ get(lineId: string): Promise<Line>;
32
+ }
33
+ //# sourceMappingURL=lines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../src/resources/lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE5E,qBAAa,aAAa;IACZ,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAEvC;;;;;;;;;;OAUG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAUhE;;;;;;;;;;;;OAYG;IACG,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGzC"}
@@ -0,0 +1,46 @@
1
+ export class LinesResource {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ /**
7
+ * List phone lines with optional filters and pagination.
8
+ *
9
+ * @param params - Optional filters (type, area_code) and pagination
10
+ * @returns Paginated list of lines
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const { lines } = await client.lines.list({ type: 'iphone', limit: 10 });
15
+ * ```
16
+ */
17
+ async list(params) {
18
+ const query = {};
19
+ if (params?.type)
20
+ query.type = params.type;
21
+ if (params?.area_code)
22
+ query.area_code = params.area_code;
23
+ if (params?.page)
24
+ query.page = String(params.page);
25
+ if (params?.limit)
26
+ query.limit = String(params.limit);
27
+ return this.client.request('GET', '/lines', undefined, query);
28
+ }
29
+ /**
30
+ * Retrieve a single line by ID.
31
+ *
32
+ * @param lineId - The line ID
33
+ * @returns The line
34
+ * @throws {iSnapError} If the line is not found
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const line = await client.lines.get('ln-abc123');
39
+ * console.log(line.phone_number);
40
+ * ```
41
+ */
42
+ async get(lineId) {
43
+ return this.client.request('GET', `/lines/${lineId}`);
44
+ }
45
+ }
46
+ //# sourceMappingURL=lines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lines.js","sourceRoot":"","sources":["../../src/resources/lines.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,aAAa;IACJ;IAApB,YAAoB,MAAmB;QAAnB,WAAM,GAAN,MAAM,CAAa;IAAG,CAAC;IAE3C;;;;;;;;;;OAUG;IACH,KAAK,CAAC,IAAI,CAAC,MAAwB;QACjC,MAAM,KAAK,GAA2B,EAAE,CAAC;QACzC,IAAI,MAAM,EAAE,IAAI;YAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QAC3C,IAAI,MAAM,EAAE,SAAS;YAAE,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAC1D,IAAI,MAAM,EAAE,IAAI;YAAE,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,MAAM,EAAE,KAAK;YAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEtD,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAoB,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACnF,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,GAAG,CAAC,MAAc;QACtB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAO,KAAK,EAAE,UAAU,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;CACF"}