@isnap/sdk 0.1.0 → 1.1.0-next.38

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.
Files changed (104) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +173 -167
  3. package/dist/client.d.ts +48 -50
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +258 -89
  6. package/dist/client.js.map +1 -1
  7. package/dist/config.d.ts +43 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +55 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/errors.d.ts +53 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +100 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/generated/openapi.d.ts +10924 -0
  16. package/dist/idempotency.d.ts +2 -0
  17. package/dist/idempotency.d.ts.map +1 -0
  18. package/dist/idempotency.js +4 -0
  19. package/dist/idempotency.js.map +1 -0
  20. package/dist/index.d.ts +26 -8
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +12 -6
  23. package/dist/index.js.map +1 -1
  24. package/dist/internal/sleep.d.ts +10 -0
  25. package/dist/internal/sleep.d.ts.map +1 -0
  26. package/dist/internal/sleep.js +37 -0
  27. package/dist/internal/sleep.js.map +1 -0
  28. package/dist/pagination.d.ts +10 -0
  29. package/dist/pagination.d.ts.map +1 -0
  30. package/dist/pagination.js +16 -0
  31. package/dist/pagination.js.map +1 -0
  32. package/dist/resources/attachments.d.ts +45 -0
  33. package/dist/resources/attachments.d.ts.map +1 -0
  34. package/dist/resources/attachments.js +120 -0
  35. package/dist/resources/attachments.js.map +1 -0
  36. package/dist/resources/base.d.ts +6 -0
  37. package/dist/resources/base.d.ts.map +1 -0
  38. package/dist/resources/base.js +7 -0
  39. package/dist/resources/base.js.map +1 -0
  40. package/dist/resources/byod.d.ts +15 -0
  41. package/dist/resources/byod.d.ts.map +1 -0
  42. package/dist/resources/byod.js +13 -0
  43. package/dist/resources/byod.js.map +1 -0
  44. package/dist/resources/chats.d.ts +29 -0
  45. package/dist/resources/chats.d.ts.map +1 -0
  46. package/dist/resources/chats.js +28 -0
  47. package/dist/resources/chats.js.map +1 -0
  48. package/dist/resources/lines.d.ts +64 -27
  49. package/dist/resources/lines.d.ts.map +1 -1
  50. package/dist/resources/lines.js +77 -37
  51. package/dist/resources/lines.js.map +1 -1
  52. package/dist/resources/lookup.d.ts +15 -0
  53. package/dist/resources/lookup.d.ts.map +1 -0
  54. package/dist/resources/lookup.js +13 -0
  55. package/dist/resources/lookup.js.map +1 -0
  56. package/dist/resources/messages.d.ts +36 -67
  57. package/dist/resources/messages.d.ts.map +1 -1
  58. package/dist/resources/messages.js +37 -94
  59. package/dist/resources/messages.js.map +1 -1
  60. package/dist/resources/trial.d.ts +28 -0
  61. package/dist/resources/trial.d.ts.map +1 -0
  62. package/dist/resources/trial.js +31 -0
  63. package/dist/resources/trial.js.map +1 -0
  64. package/dist/resources/webhooks.d.ts +49 -39
  65. package/dist/resources/webhooks.d.ts.map +1 -1
  66. package/dist/resources/webhooks.js +52 -39
  67. package/dist/resources/webhooks.js.map +1 -1
  68. package/dist/retry.d.ts +14 -0
  69. package/dist/retry.d.ts.map +1 -0
  70. package/dist/retry.js +47 -0
  71. package/dist/retry.js.map +1 -0
  72. package/dist/types.d.ts +30 -196
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/types.js +1 -28
  75. package/dist/types.js.map +1 -1
  76. package/dist/version.d.ts +3 -0
  77. package/dist/version.d.ts.map +1 -0
  78. package/dist/version.js +20 -0
  79. package/dist/version.js.map +1 -0
  80. package/dist/webhooks/parse.d.ts +15 -0
  81. package/dist/webhooks/parse.d.ts.map +1 -0
  82. package/dist/webhooks/parse.js +47 -0
  83. package/dist/webhooks/parse.js.map +1 -0
  84. package/dist/webhooks/types.d.ts +93 -0
  85. package/dist/webhooks/types.d.ts.map +1 -0
  86. package/dist/webhooks/types.js +20 -0
  87. package/dist/webhooks/types.js.map +1 -0
  88. package/dist/webhooks/verify.d.ts +41 -0
  89. package/dist/webhooks/verify.d.ts.map +1 -0
  90. package/dist/webhooks/verify.js +110 -0
  91. package/dist/webhooks/verify.js.map +1 -0
  92. package/package.json +45 -30
  93. package/dist/paginate.d.ts +0 -33
  94. package/dist/paginate.d.ts.map +0 -1
  95. package/dist/paginate.js +0 -40
  96. package/dist/paginate.js.map +0 -1
  97. package/dist/webhook-events.d.ts +0 -61
  98. package/dist/webhook-events.d.ts.map +0 -1
  99. package/dist/webhook-events.js +0 -44
  100. package/dist/webhook-events.js.map +0 -1
  101. package/dist/webhook-verify.d.ts +0 -27
  102. package/dist/webhook-verify.d.ts.map +0 -1
  103. package/dist/webhook-verify.js +0 -42
  104. package/dist/webhook-verify.js.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@isnap/sdk` will be documented in this file. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Pre-1.0 versions may introduce breaking changes between 0.x → 0.(x+1) minor bumps.
4
+
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+ - Initial public surface targeting iSnap API contract `v1.0.0`.
9
+ - `ISnapClient` with retries (jittered exponential backoff on 429/5xx), per-attempt timeout, auto-`Idempotency-Key` for mutating verbs, header injection, abortable requests.
10
+ - Resource classes: `messages`, `chats`, `lines`, `lookup`, `attachments`, `webhooks`, `byod`, `trial`.
11
+ - `attachments.upload()` — transparent 3-step (POST register → presigned R2 PUT → poll until `ready`) with 5 GB cap and four typed failure modes.
12
+ - Cursor pagination as `AsyncIterable` with optional `AbortSignal` on `messages.list`, `webhooks.deliveries`, `webhooks.events`.
13
+ - Webhook helpers: `verifyWebhook` (HMAC-SHA256 + 5min replay window + multi-secret rotation), `parseWebhookEvent`, prefix-based type guards (`isMessageEvent`, `isReactionEvent`, `isLineEvent`, `isTypingEvent`, `isTrialEvent`).
14
+ - Error hierarchy mirroring contract §6: `APIError` + 13 subclasses, all carrying `status`, `code`, `traceId`, `requestId`. Connection failures surface as `APIConnectionError` with native `Error.cause`.
15
+ - Generated TypeScript types (`src/generated/openapi.d.ts`) compiled from the backend's frozen `openapi.json`.
package/README.md CHANGED
@@ -1,236 +1,242 @@
1
1
  # @isnap/sdk
2
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)
3
+ Official TypeScript SDK for the [iSnap](https://isnap.ai) P2P telephony API — real iMessage / SMS / RCS lines from real handsets, exposed as a single typed client.
6
4
 
7
- Official Node.js/TypeScript SDK for the [iSnap](https://isnap.dev) messaging API. Zero runtime dependencies.
5
+ > Pre-1.0. Targets contract `docs/api-contract.md` v1.0.0. Public surface is stable across the v0.x line; breaking changes will bump 0.x 0.(x+1) until 1.0.0.
8
6
 
9
- ## Installation
7
+ ## Install
10
8
 
11
9
  ```bash
10
+ bun add @isnap/sdk
11
+ # or
12
12
  npm install @isnap/sdk
13
13
  ```
14
14
 
15
- ## Quick Start
15
+ Requires Node 20+ (or Bun 1.2+). The SDK uses native `fetch`, `node:crypto`, and ES2022 `Error.cause` — no polyfills.
16
+
17
+ ## Quick start
16
18
 
17
19
  ```ts
18
- import { init } from '@isnap/sdk';
20
+ import { ISnapClient } from '@isnap/sdk'
19
21
 
20
- const client = init({ apiKey: 'isnap_your_api_key' });
22
+ const client = new ISnapClient({ apiKey: process.env.ISNAP_API_KEY! })
21
23
 
22
- const msg = await client.messages.send({
23
- line_id: 'ln-1',
24
+ const message = await client.messages.send({
25
+ line_id: 'line_01HX...',
24
26
  to: '+15551234567',
25
- body: 'Hello from iSnap!',
26
- });
27
+ body: 'Hello from iSnap'
28
+ })
27
29
 
28
- console.log(msg.id, msg.status);
30
+ console.log(message.id, message.status)
29
31
  ```
30
32
 
31
- ## Messages
33
+ ## Configuration
32
34
 
33
35
  ```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);
36
+ new ISnapClient({
37
+ apiKey: 'sk_live_...', // required
38
+ baseUrl: 'https://api.isnap.ai', // default
39
+ maxRetries: 3, // default 3 — retries on 429/5xx with jittered backoff
40
+ timeoutMs: 30_000, // per-attempt timeout
41
+ idempotencyKey: 'auto', // 'auto' generates UUIDs for POST/PATCH/PUT/DELETE; 'manual' = pass via opts
42
+ fetch: undefined, // override (e.g. an instrumented fetch)
43
+ onRetry: (info) => console.warn('retry', info)
44
+ })
67
45
  ```
68
46
 
69
- ## Lines
47
+ Every resource method accepts an optional `RequestOptions` final argument: `{ signal, idempotencyKey, headers, query, maxRetries }`.
48
+
49
+ ## Resources
50
+
51
+ | Resource | What it does |
52
+ |---|---|
53
+ | `client.messages` | Send / get / cancel / list messages, add reactions |
54
+ | `client.chats` | Mark a chat read, send typing indicators, share a contact card |
55
+ | `client.lines` | List, configure, and inspect rented + BYOD lines, plus quota and queue snapshots |
56
+ | `client.lookup` | Test if a number is iMessage-capable before sending |
57
+ | `client.attachments` | Upload images / video / files (transparent 3-step flow) |
58
+ | `client.webhooks` | CRUD subscriptions, rotate secrets, list deliveries, replay events |
59
+ | `client.byod` | Pair a customer-owned Mac+iPhone or Android device |
60
+ | `client.trial` | Start, check, and convert trial sessions |
61
+
62
+ ## Sending a message
70
63
 
71
64
  ```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);
65
+ const msg = await client.messages.send({
66
+ line_id: 'line_01HX...',
67
+ to: '+15551234567',
68
+ body: 'Order #1242 is on its way',
69
+ service: 'iMessage' // optional — falls back to SMS/RCS via the line's degradation chain
70
+ })
81
71
  ```
82
72
 
83
- ## Webhooks
73
+ `messages.send` is **idempotent by default** — the SDK auto-generates an `Idempotency-Key` for every POST. Retrying the same call with the same key returns the original message without sending a duplicate.
84
74
 
85
- ### Managing webhook endpoints
75
+ ## Listing with cursor pagination
76
+
77
+ `list()` returns an `AsyncIterable` that threads cursors automatically:
86
78
 
87
79
  ```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');
80
+ for await (const msg of client.messages.list({ line_id: 'line_01HX...', limit: 100 })) {
81
+ console.log(msg.id, msg.created_at)
82
+ }
100
83
  ```
101
84
 
102
- ### Receiving webhooks
103
-
104
- Use `parseWebhook` to verify signatures and get typed events in one call:
85
+ To stop early, pass an `AbortSignal`. Aborting surfaces as a thrown `APIConnectionError` on the next page boundary, so wrap the loop:
105
86
 
106
87
  ```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
- }
88
+ import { APIConnectionError } from '@isnap/sdk'
89
+
90
+ const ac = new AbortController()
91
+ setTimeout(() => ac.abort(), 5_000)
137
92
 
138
- res.sendStatus(200);
139
- });
93
+ try {
94
+ for await (const msg of client.messages.list({}, { signal: ac.signal })) {
95
+ // ...
96
+ }
97
+ } catch (err) {
98
+ if (!(err instanceof APIConnectionError)) throw err
99
+ // expected — signal aborted the iterator
100
+ }
140
101
  ```
141
102
 
142
- You can also verify signatures manually:
103
+ ## Uploading an attachment
104
+
105
+ `attachments.upload()` wraps the 3-step contract (register → presigned PUT → poll) into one call:
143
106
 
144
107
  ```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
- );
108
+ import { readFile } from 'node:fs/promises'
109
+
110
+ const file = await readFile('./photo.jpg')
111
+
112
+ const attachment = await client.attachments.upload(file, {
113
+ filename: 'photo.jpg',
114
+ contentType: 'image/jpeg'
115
+ })
116
+
117
+ await client.messages.send({
118
+ line_id: 'line_01HX...',
119
+ to: '+15551234567',
120
+ body: 'Here you go',
121
+ attachment_ids: [attachment.id]
122
+ })
153
123
  ```
154
124
 
155
- ## Pagination
125
+ 5 GB cap. Four documented failure modes — note that the R2 PUT and the server-side `failed` transition share the same `upload_failed` code:
126
+
127
+ | Failure | `code` |
128
+ |---|---|
129
+ | `size_bytes` exceeds the 5 GB cap | `attachment_exceeds_storage_limit` |
130
+ | R2 presigned PUT returns non-2xx | `upload_failed` |
131
+ | Server transitions to `status: failed` | `upload_failed` |
132
+ | Polling exhausted before `status: ready` | `upload_timeout` |
156
133
 
157
- Use the `paginate` async generator to iterate over large collections:
134
+ ## Verifying webhooks
158
135
 
159
136
  ```ts
160
- import { init, paginate } from '@isnap/sdk';
137
+ import { verifyWebhook, isMessageEvent } from '@isnap/sdk'
161
138
 
162
- const client = init({ apiKey: 'isnap_your_key' });
139
+ // Express / Hono / native handler — give us the RAW body bytes (string).
140
+ async function handle(rawBody: string, headers: Record<string, string>) {
141
+ const event = verifyWebhook(rawBody, headers, process.env.ISNAP_WEBHOOK_SECRET!)
163
142
 
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
- }
143
+ // Dedupe by event_id delivery is at-least-once.
144
+ if (await alreadyProcessed(event.event_id)) return
172
145
 
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);
146
+ if (isMessageEvent(event)) {
147
+ console.log(event.event_type, event.data.message.id)
148
+ }
180
149
  }
181
150
  ```
182
151
 
183
- ## Error Handling
152
+ During a `rotate-secret` grace window pass both secrets:
153
+
154
+ ```ts
155
+ verifyWebhook(rawBody, headers, [newSecret, oldSecret])
156
+ ```
157
+
158
+ Throws `WebhookSignatureError` on missing headers, expired timestamp (5min tolerance), or signature mismatch.
159
+
160
+ If verification happens behind a trusted gateway, use `parseWebhookEvent(rawBody)` to skip HMAC and just type the envelope.
161
+
162
+ ## Errors
163
+
164
+ All API errors extend `APIError` and carry `status`, `code`, `message`, `traceId`, `requestId`. Subclasses match the §6 contract codes:
184
165
 
185
166
  ```ts
186
- import { iSnapError, RateLimitError } from '@isnap/sdk';
167
+ import {
168
+ APIError,
169
+ APIConnectionError,
170
+ AuthenticationError,
171
+ BadRequestError,
172
+ ConflictError,
173
+ GoneError,
174
+ InternalServerError,
175
+ NotFoundError,
176
+ PaymentRequiredError,
177
+ PermissionDeniedError,
178
+ QuotaExceededError,
179
+ RateLimitError,
180
+ ServiceUnavailableError,
181
+ UnprocessableEntityError,
182
+ WebhookSignatureError
183
+ } from '@isnap/sdk'
187
184
 
188
185
  try {
189
- await client.messages.send({ line_id: 'ln-1', to: '+15551234567', body: 'Hello' });
186
+ await client.messages.send({
187
+ line_id: 'line_01HX...',
188
+ to: '+15551234567',
189
+ body: 'hello'
190
+ })
190
191
  } catch (err) {
191
192
  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})`);
193
+ // retry-after handled automatically by the retry loop, but visible here too
194
+ } else if (err instanceof QuotaExceededError) {
195
+ // pause sending until next quota window
196
+ } else if (err instanceof APIError) {
197
+ console.error(err.status, err.code, err.traceId)
198
+ } else if (err instanceof APIConnectionError) {
199
+ // network issue / timeout — already retried per `maxRetries`
200
+ } else {
201
+ throw err
195
202
  }
196
203
  }
197
204
  ```
198
205
 
199
- ### Retry configuration
206
+ Retries: 429 + 5xx are retried automatically with jittered exponential backoff up to `maxRetries`. The retry budget is per-call.
200
207
 
201
- The client automatically retries on 429 responses. Customize the behavior:
208
+ ## Examples
202
209
 
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
+ Runnable scripts in [`examples/`](https://github.com/WhatSnap/iSnap-App/tree/main/packages/sdk/examples) (browse on GitHub — they live in the repo, not the published tarball):
210
211
 
211
- ## TypeScript
212
+ - `send-message.ts` — minimal send
213
+ - `paginate-messages.ts` — async iterator + abort
214
+ - `upload-attachment.ts` — file upload + send with attachment
215
+ - `handle-webhook.ts` — `node:http` server that verifies and dispatches events
212
216
 
213
- All types are exported from the main entry point:
217
+ Run them against a local backend:
214
218
 
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';
219
+ ```bash
220
+ ISNAP_API_KEY=sk_test_... bun run examples/send-message.ts
221
+ ```
222
+
223
+ ## Development
224
+
225
+ ```bash
226
+ bun install
227
+ bun run --filter '@isnap/sdk' test
228
+ bun run --filter '@isnap/sdk' typecheck
229
+ bun run --filter '@isnap/sdk' lint
230
+ bun run --filter '@isnap/sdk' build
228
231
  ```
229
232
 
230
- ## Contributing
233
+ To regenerate types from the backend's frozen OpenAPI spec:
231
234
 
232
- Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
235
+ ```bash
236
+ bun run --filter '@isnap/backend' dump-openapi # writes packages/backend/openapi.json
237
+ bun run --filter '@isnap/sdk' generate # regenerates src/generated/openapi.d.ts
238
+ ```
233
239
 
234
240
  ## License
235
241
 
236
- [MIT](LICENSE)
242
+ MIT
package/dist/client.d.ts CHANGED
@@ -1,61 +1,59 @@
1
- import type { iSnapConfig } from './types.js';
2
- import { MessagesResource } from './resources/messages.js';
1
+ import { type ClientConfig } from './config.js';
2
+ import { AttachmentsResource } from './resources/attachments.js';
3
+ import { ByodResource } from './resources/byod.js';
4
+ import { ChatsResource } from './resources/chats.js';
3
5
  import { LinesResource } from './resources/lines.js';
6
+ import { LookupResource } from './resources/lookup.js';
7
+ import { MessagesResource } from './resources/messages.js';
8
+ import { TrialResource } from './resources/trial.js';
4
9
  import { WebhooksResource } from './resources/webhooks.js';
10
+ import type { HttpMethod, RequestOptions } from './types.js';
5
11
  /**
6
- * The iSnap SDK client. Provides access to all API resources.
7
- *
8
- * @example
9
- * ```ts
10
- * import { init } from '@isnap/sdk';
12
+ * Test-only escape hatch to clear the per-process dedup set between test
13
+ * cases. Not part of the public stability contract — flagged @internal so
14
+ * IDE auto-import doesn't surface it to consumers.
11
15
  *
12
- * const client = init({ apiKey: 'isnap_your_key' });
13
- * const msg = await client.messages.send({ line_id: 'ln-1', to: '+15551234567', body: 'Hello' });
14
- * ```
16
+ * @internal
15
17
  */
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);
18
+ export declare function _resetDeprecationWarnings(): void;
19
+ export declare class ISnapClient {
20
+ private readonly config;
21
+ readonly attachments: AttachmentsResource;
22
+ readonly byod: ByodResource;
23
+ readonly chats: ChatsResource;
24
+ readonly lines: LinesResource;
25
+ readonly lookup: LookupResource;
26
+ readonly messages: MessagesResource;
27
+ readonly trial: TrialResource;
28
+ readonly webhooks: WebhooksResource;
29
+ constructor(config: ClientConfig);
28
30
  /**
29
- * Send an HTTP request to the iSnap API.
31
+ * Direct fetch with no SDK auth, no envelope parsing, no retry — used
32
+ * internally by resource methods that must call URLs OUTSIDE the iSnap
33
+ * API surface (e.g. presigned R2 PUTs during `attachments.upload`).
30
34
  *
31
- * Handles authorization, JSON serialization, rate-limit retries, and error mapping.
35
+ * The leading underscore signals "internal but unavoidably public": it
36
+ * lives on the public class because resource classes cannot reach the
37
+ * private `config.fetch` otherwise. SDK consumers should use the typed
38
+ * resource methods or `request()` for everything in `/v1/*` — calling
39
+ * this directly bypasses the SDK contract.
32
40
  *
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
41
+ * Applies the same `config.timeoutMs` ceiling as `request()` so a
42
+ * stalled R2 PUT cannot hang the upload indefinitely.
43
+ *
44
+ * @internal
45
+ */
46
+ _externalFetch(url: string, init?: RequestInit): Promise<Response>;
47
+ /**
48
+ * Low-level request method. Resource classes wrap this with typed
49
+ * camelCase signatures; advanced users can call it directly for
50
+ * endpoints not yet covered by a resource.
40
51
  */
41
- request<T>(method: string, path: string, body?: unknown, query?: Record<string, string>): Promise<T>;
52
+ request<T>(method: HttpMethod, path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
53
+ private dispatch;
54
+ private buildUrl;
55
+ private buildHeaders;
56
+ private warnIfDeprecated;
57
+ private connectionErrorMessage;
42
58
  }
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
59
  //# sourceMappingURL=client.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,aAAa,CAAA;AAQpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAoB,MAAM,YAAY,CAAA;AAqB9E;;;;;;GAMG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IAEvC,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAA;IACzC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;gBAEvB,MAAM,EAAE,YAAY;IAYhC;;;;;;;;;;;;;;;OAeG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAoB5E;;;;OAIG;IACG,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,CAAC,CAAC;YAwBC,QAAQ;IA8GtB,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,sBAAsB;CAO/B"}