@zindua/sdk 1.2.3 → 1.2.4

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 (3) hide show
  1. package/README.md +247 -172
  2. package/dist/client.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,261 +1,350 @@
1
1
  # @zindua/sdk
2
2
 
3
- Official **server-side** SDK for [Zindua](https://zindua.run): one API for transactional **email** and **WhatsApp** (`POST /api/v1/send`).
3
+ Official **server-side** SDK for [Zindua](https://zindua.run): send transactional **email** and **WhatsApp** messages with one API.
4
4
 
5
- | Resource | Link |
6
- |----------|------|
7
- | Website & docs | [zindua.run/developers](https://zindua.run/developers) |
8
- | HTTP / cURL (no SDK) | [zindua.run/developers#http](https://zindua.run/developers#http) |
9
- | Pricing & plans | [zindua.run/pricing](https://zindua.run/pricing) |
10
- | Dashboard | [zindua.run/login](https://zindua.run/login) |
5
+ | | |
6
+ |---|---|
7
+ | Full API reference | [zindua.run/developers](https://zindua.run/developers) |
8
+ | Dashboard (keys, templates, services) | [zindua.run/login](https://zindua.run/login) |
9
+ | Pricing | [zindua.run/pricing](https://zindua.run/pricing) |
11
10
 
12
- Install: `npm install @zindua/sdk`
11
+ ```bash
12
+ npm install @zindua/sdk
13
+ ```
14
+
15
+ **Requirements:** Node.js 18+, run only on your **backend** (not in the browser).
13
16
 
14
17
  ---
15
18
 
16
- ## Templates and languages
19
+ ## Quick start
17
20
 
18
- Create templates in the **dashboard** (one **slug** per template, e.g. `welcome`, `otp-verification`). Each template can include **email HTML** and **WhatsApp text** for the same slug.
21
+ ### 1. Create a Zindua project
19
22
 
20
- Send in a locale with the `lang` field (ISO code: `fr`, `en`, `sw`, …). If you omit `lang`, Zindua uses your project default.
23
+ 1. Sign in at [zindua.run/login](https://zindua.run/login).
24
+ 2. Open **Projects** → create a project (or use an existing one).
25
+ 3. Copy the API key (`znd_live_…` for production, `znd_test_…` for sandbox).
26
+ 4. In the project: connect **Service** (Gmail, SMTP, …) for email, and/or link **WhatsApp** for OTP.
27
+ 5. Create at least one **template** (e.g. slug `otp`, `welcome`).
21
28
 
22
- | Plan | Templates per project | Languages per template (email + WhatsApp) |
23
- |------|----------------------|-------------------------------------------|
24
- | **Free** | 5 | 3 |
25
- | **Pro** | 50 | 10 |
26
- | **Team** | 1000 | 100 |
29
+ ### 2. Install and configure
30
+
31
+ ```bash
32
+ npm install @zindua/sdk
33
+ ```
27
34
 
28
- On **Free**, **email API** works when you connect a **Service** (Gmail, SMTP, etc.) on the project. **WhatsApp OTP** works on Free (quota applies). **Pro/Team** raise template and volume limits. See [pricing](https://zindua.run/pricing).
35
+ ```bash
36
+ # .env — never commit real keys; never expose in frontend code
37
+ ZINDUA_API_KEY=znd_live_xxxxxxxxxxxxxxxxxxxxxxxx
38
+ ```
29
39
 
30
40
  ```typescript
31
- // French version of the same template slug
41
+ import { Zindua } from "@zindua/sdk";
42
+
43
+ export const zindua = new Zindua({
44
+ apiKey: process.env.ZINDUA_API_KEY!,
45
+ });
46
+ ```
47
+
48
+ ### 3. Send a message
49
+
50
+ ```typescript
51
+ // Email (default channel)
32
52
  await zindua.send({
33
53
  to: "user@example.com",
34
54
  template: "welcome",
35
- lang: "fr",
36
55
  variables: { name: "Alex" },
37
56
  });
38
57
 
39
- // WhatsApp: same slug, different channel + E.164 phone
58
+ // WhatsApp phone in E.164 with +
40
59
  await zindua.send({
41
60
  to: "+243812345678",
42
61
  channel: "whatsapp",
43
- template: "otp-verification",
44
- lang: "fr",
45
- variables: { code: "4592", app: "MonApp" },
62
+ template: "otp",
63
+ variables: { code: "482910" },
46
64
  });
47
65
  ```
48
66
 
49
67
  ---
50
68
 
51
- ## Requirements
69
+ ## Plans and channels
52
70
 
53
- Before using the SDK, set up your Zindua project in the dashboard:
71
+ | Plan | Email API | WhatsApp | Email / month | WhatsApp OTP / month |
72
+ |------|-----------|----------|---------------|----------------------|
73
+ | **Free** | Yes, if a **Service** is connected on the project | Yes | 25,000 | 200 |
74
+ | **Pro** | Yes | Yes | 160,000 | 20,000 |
75
+ | **Team** | Yes | Yes | High volume | Unlimited |
54
76
 
55
- | Requirement | Required for | Where |
56
- |-------------|--------------|--------|
57
- | Zindua account | All | [Sign up / login](https://zindua.run/login) |
58
- | Project + API key (`znd_live_…` or `znd_test_…`) | All | Dashboard → **Projects** → your project |
59
- | Email **Service** connected (Gmail, Outlook, SendGrid, SMTP, …) | `channel: "email"` | Dashboard → **Service** |
60
- | WhatsApp connected (QR) | `channel: "whatsapp"` | Dashboard → **WhatsApp** |
61
- | Template slug (e.g. `welcome`, `otp-verification`) | All | Dashboard → **Templates** |
62
- | **Service** on Free or **Pro/Team** plan | Email via API when Service is connected (Free) or full quotas (paid) | Dashboard → **Service** / **Billing** |
77
+ On **Free**, email works through **your** connected provider (Gmail, SMTP, etc.). **Pro** and **Team** raise template counts and monthly limits. Details: [pricing](https://zindua.run/pricing).
63
78
 
64
- **Runtime**
79
+ | | Free | Pro / Team |
80
+ |---|------|------------|
81
+ | Templates per project | 5 | 50+ |
82
+ | Languages per template | 3 | 10+ |
65
83
 
66
- - **Node.js 18+** (uses native `fetch`)
67
- - **Server only** — do not bundle this package for the browser (see [Mobile & SPA](#mobile--spa))
84
+ Use `znd_test_…` keys to try the API without consuming live quota (sandbox behaviour).
68
85
 
69
86
  ---
70
87
 
71
- ## Install
88
+ ## One project or several?
72
89
 
73
- ```bash
74
- npm install @zindua/sdk
75
- ```
90
+ | Setup | When it fits |
91
+ |-------|----------------|
92
+ | **One Zindua project, one API key** | One product, one sender, shared templates and quota. |
93
+ | **Several Zindua projects, one key each** | Several clients or brands: separate templates, Gmail accounts, logs, and quotas. |
76
94
 
77
- ```bash
78
- yarn add @zindua/sdk
79
- ```
95
+ ### Several keys in one backend
80
96
 
81
97
  ```bash
82
- pnpm add @zindua/sdk
98
+ ZINDUA_KEY_CLIENT_A=znd_live_aaaaaaaaaaaaaaaaaaaaaaaa
99
+ ZINDUA_KEY_CLIENT_B=znd_live_bbbbbbbbbbbbbbbbbbbbbbbb
83
100
  ```
84
101
 
85
- ---
86
-
87
- ## Configure
88
-
89
- ### 1. API key
102
+ ```typescript
103
+ import { Zindua } from "@zindua/sdk";
90
104
 
91
- Copy your project key from the dashboard. Format: `znd_live_` + 24 characters, or `znd_test_` for test mode.
105
+ const clients = {
106
+ clientA: new Zindua({ apiKey: process.env.ZINDUA_KEY_CLIENT_A! }),
107
+ clientB: new Zindua({ apiKey: process.env.ZINDUA_KEY_CLIENT_B! }),
108
+ };
92
109
 
93
- ```bash
94
- # .env (example — load with dotenv or your framework)
95
- ZINDUA_API_KEY=znd_live_xxxxxxxxxxxxxxxxxxxxxxxx
110
+ await clients.clientA.send({
111
+ to: "user@example.com",
112
+ template: "otp",
113
+ variables: { code: "123456" },
114
+ });
96
115
  ```
97
116
 
98
- The SDK does **not** read `ZINDUA_API_KEY` automatically. Pass it to the constructor explicitly.
117
+ Each key only accesses **its** Zindua project (templates, service, usage).
99
118
 
100
- ### 2. Base URL (optional)
101
-
102
- | Variable | Default | Notes |
103
- |----------|---------|--------|
104
- | `ZINDUA_API_BASE_URL` | `https://zindua.run/api/v1` | Used when `baseUrl` is omitted in constructor |
105
- | Constructor `baseUrl` | env or default | Overrides env; must be **HTTPS** in production (`http://localhost` allowed for local dev) |
119
+ ---
106
120
 
107
- ### 3. Timeout (optional)
121
+ ## Framework examples
108
122
 
109
- | Option | Default | Max |
110
- |--------|---------|-----|
111
- | `timeoutMs` | `30000` | `120000` |
123
+ Use the same pattern everywhere: **your server** holds the API key; the client app calls **your** API.
112
124
 
113
- ### Minimal setup
125
+ ### Next.js (App Router)
114
126
 
115
127
  ```typescript
128
+ // lib/zindua.ts
116
129
  import { Zindua } from "@zindua/sdk";
117
130
 
118
- export const zindua = new Zindua({
119
- apiKey: process.env.ZINDUA_API_KEY!,
120
- // baseUrl: process.env.ZINDUA_API_BASE_URL, // optional
121
- // timeoutMs: 30_000,
122
- });
131
+ export const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
123
132
  ```
124
133
 
125
- ---
126
-
127
- ## Usage
134
+ ```typescript
135
+ // app/api/notify/route.ts
136
+ import { zindua } from "@/lib/zindua";
137
+ import { NextResponse } from "next/server";
138
+
139
+ export async function POST(req: Request) {
140
+ const { email, code } = await req.json();
141
+ const result = await zindua.send({
142
+ to: email,
143
+ template: "otp",
144
+ variables: { code },
145
+ });
146
+ return NextResponse.json(result, { status: 202 });
147
+ }
148
+ ```
128
149
 
129
- ### Send email
150
+ ### Express
130
151
 
131
152
  ```typescript
132
- await zindua.send({
133
- to: "user@example.com",
134
- template: "welcome",
135
- variables: { name: "Alex" },
153
+ import express from "express";
154
+ import { Zindua } from "@zindua/sdk";
155
+
156
+ const app = express();
157
+ app.use(express.json());
158
+
159
+ const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
160
+
161
+ app.post("/api/notify", async (req, res) => {
162
+ try {
163
+ const result = await zindua.send({
164
+ to: req.body.email,
165
+ template: req.body.template ?? "otp",
166
+ variables: req.body.variables ?? {},
167
+ });
168
+ res.status(202).json(result);
169
+ } catch (err) {
170
+ res.status(500).json({ error: "Send failed" });
171
+ }
136
172
  });
137
173
  ```
138
174
 
139
- ### Send WhatsApp OTP
140
-
141
- Phone numbers must be **E.164** with a leading `+` (e.g. `+243812345678`).
175
+ ### Fastify
142
176
 
143
177
  ```typescript
144
- await zindua.send({
145
- to: "+243812345678",
146
- channel: "whatsapp",
147
- template: "otp-verification",
148
- variables: { code: "4592", app: "MyApp" },
178
+ import Fastify from "fastify";
179
+ import { Zindua } from "@zindua/sdk";
180
+
181
+ const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
182
+ const app = Fastify();
183
+
184
+ app.post<{ Body: { email: string; code: string } }>("/notify", async (req, reply) => {
185
+ const result = await zindua.send({
186
+ to: req.body.email,
187
+ template: "otp",
188
+ variables: { code: req.body.code },
189
+ });
190
+ return reply.status(202).send(result);
149
191
  });
150
192
  ```
151
193
 
152
- ### Optional fields (email only)
194
+ ### Hono
153
195
 
154
196
  ```typescript
155
- await zindua.send({
156
- to: "user@example.com",
157
- template: "invoice",
158
- lang: "fr",
159
- cc: "billing@example.com",
160
- replyTo: "support@example.com",
161
- variables: { amount: "99" },
197
+ import { Hono } from "hono";
198
+ import { Zindua } from "@zindua/sdk";
199
+
200
+ const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! });
201
+ const app = new Hono();
202
+
203
+ app.post("/notify", async (c) => {
204
+ const { email, code } = await c.req.json();
205
+ const result = await zindua.send({
206
+ to: email,
207
+ template: "otp",
208
+ variables: { code },
209
+ });
210
+ return c.json(result, 202);
162
211
  });
163
212
  ```
164
213
 
165
- ### Response
214
+ ### Mobile apps (React Native, Flutter)
215
+
216
+ Do **not** embed `@zindua/sdk` or `znd_live_…` in the app. Call your backend route above from the device.
217
+
218
+ ---
219
+
220
+ ## Configuration options
221
+
222
+ | Option | Default | Description |
223
+ |--------|---------|-------------|
224
+ | `apiKey` | — | **Required.** `znd_live_…` or `znd_test_…` from the dashboard. |
225
+ | `baseUrl` | `https://zindua.run/api/v1` | Override only for local testing (`http://localhost:3000/api/v1`). |
226
+ | `timeoutMs` | `30000` | Request timeout (max `120000`). |
166
227
 
167
228
  ```typescript
168
- const result = await zindua.send({ /* … */ });
169
- // {
170
- // success: true,
171
- // status: "queued",
172
- // logId: "…",
173
- // channel: "email",
174
- // context: { project, apiKey: { mode, suffix }, plan, channels }
175
- // }
229
+ const zindua = new Zindua({
230
+ apiKey: process.env.ZINDUA_API_KEY!,
231
+ baseUrl: process.env.ZINDUA_API_BASE_URL, // optional
232
+ timeoutMs: 45_000,
233
+ });
176
234
  ```
177
235
 
178
- The API never returns your full API key. `context.apiKey.suffix` is the last 4 characters (match in Dashboard).
179
-
180
236
  ---
181
237
 
182
- ## Several clients (multi-project)
238
+ ## Send options
183
239
 
184
- **Recommended:** one Zindua project per client → one `znd_live_…` per project.
240
+ | Field | Required | Description |
241
+ |-------|----------|-------------|
242
+ | `to` | Yes | Email address, or E.164 phone (`+243…`) for WhatsApp. |
243
+ | `template` | Yes | Template slug from your dashboard. |
244
+ | `channel` | No | `"email"` (default) or `"whatsapp"`. |
245
+ | `lang` | No | `fr`, `en`, … — falls back to project default. |
246
+ | `variables` | No | `{{placeholders}}` in the template. |
247
+ | `cc`, `bcc`, `replyTo` | No | Email only. |
185
248
 
186
- ```bash
187
- # .env — server only
188
- ZINDUA_KEY_MELLIA=znd_live_xxxxxxxxxxxxxxxxxxxxxxxx
189
- ZINDUA_KEY_OVERLOOK=znd_live_yyyyyyyyyyyyyyyyyyyyyyyy
190
- ```
249
+ ---
191
250
 
192
- ```typescript
193
- import { Zindua } from "@zindua/sdk";
251
+ ## Successful response
194
252
 
195
- const zinduaByTenant = {
196
- mellia: new Zindua({ apiKey: process.env.ZINDUA_KEY_MELLIA! }),
197
- overlook: new Zindua({ apiKey: process.env.ZINDUA_KEY_OVERLOOK! }),
198
- };
253
+ ```typescript
254
+ const result = await zindua.send({ /* */ });
255
+ ```
199
256
 
200
- await zinduaByTenant[tenantId].send({
201
- to: "user@example.com",
202
- template: "otp",
203
- variables: { code: "482910" },
204
- });
257
+ | Field | Meaning |
258
+ |-------|---------|
259
+ | `success` | `true` |
260
+ | `status` | `queued`, `processing`, or `sent` (test keys often return `sent` immediately). |
261
+ | `logId` | Id for support / logs in the dashboard. |
262
+ | `channel` | `email` or `whatsapp` |
263
+ | `context` | Workspace snapshot (see below). |
264
+
265
+ ### `context` object
266
+
267
+ The API returns metadata so you can log or debug without exposing secrets:
268
+
269
+ ```json
270
+ {
271
+ "context": {
272
+ "project": { "name": "My App", "slug": "my-app" },
273
+ "apiKey": { "mode": "live", "suffix": "ejho" },
274
+ "plan": { "slug": "free", "name": "Free", "emailQuota": 25000, "emailsUsed": 12 },
275
+ "channels": { "email": true, "whatsapp": false }
276
+ }
277
+ }
205
278
  ```
206
279
 
207
- | Approach | When to use |
208
- |----------|-------------|
209
- | **2+ Zindua projects** | Different clients, senders, templates, or quotas |
210
- | **1 Zindua project** | Same sender and templates for everyone (one key) |
280
+ - **`context.apiKey.suffix`** last 4 characters of the key (match in the dashboard).
281
+ - **`context.plan`** — current plan and usage for the workspace linked to this key.
282
+ - **`context.channels`** whether email / WhatsApp is ready for this project.
211
283
 
212
- More detail: [zindua.run/developers#multi-project](https://zindua.run/developers#multi-project) and repo `config/API-SECURITY-MULTI-PROJECT-FR.md`.
284
+ The full API key is **never** returned in responses.
213
285
 
214
286
  ---
215
287
 
216
288
  ## Errors
217
289
 
290
+ Wrap sends in `try/catch` and handle `ZinduaError`:
291
+
218
292
  ```typescript
219
293
  import { Zindua, ZinduaError } from "@zindua/sdk";
220
294
 
221
295
  try {
222
- await zindua.send({ to: "+243…", channel: "whatsapp", template: "otp-verification" });
296
+ await zindua.send({ to: "user@example.com", template: "otp", variables: { code: "1" } });
223
297
  } catch (e) {
224
298
  if (e instanceof ZinduaError) {
225
- console.error(e.status, e.code, e.message);
226
- // Platform codes may include: WHATSAPP_NOT_CONNECTED, RATE_LIMIT_EXCEEDED, …
299
+ console.log(e.status); // HTTP status
300
+ console.log(e.code); // machine-readable code
301
+ console.log(e.message); // human-readable
302
+ console.log(e.details); // optional: hint, context, retryAfterSec, …
227
303
  }
228
- throw e;
229
304
  }
230
305
  ```
231
306
 
232
- `ZinduaError` never includes your API key in the message.
233
-
234
- ---
235
-
236
- ## Security
237
-
238
- - **Server only** throws in browser environments (`BROWSER_FORBIDDEN`).
239
- - **Bearer header only** `Authorization: Bearer znd_live_…`. Keys in URL, JSON body, or `X-Api-Key` are rejected by the platform API.
240
- - **HTTPS** for `baseUrl` except `http://localhost` in development.
241
- - **No credentials in URL** rejects `baseUrl` with embedded username/password.
242
- - **Input validation** E.164 phones, email format, template slug, variable size limits (aligned with the platform API).
243
- - **Redirects disabled** `fetch` uses `redirect: "error"`.
244
- - **CORS** optional origin allowlist in Dashboard → SettingsIntegrations (browser calls only).
307
+ ### Error codes
308
+
309
+ | Code | HTTP | What it means | What to do |
310
+ |------|------|---------------|------------|
311
+ | `INVALID_API_KEY` | 401 | Missing or malformed key. | Use `Authorization: Bearer znd_live_…` (24 chars after prefix). |
312
+ | `API_KEY_NOT_FOUND` | 401 | Key not linked to a project. | Copy the key from Dashboard → your project. |
313
+ | `ORIGIN_NOT_ALLOWED` | 403 | Browser origin blocked. | Prefer server-side SDK; or add origin in Dashboard Settings → Integrations. |
314
+ | `MISSING_FIELDS` | 400 | `to` or `template` missing. | Send both in the request body. |
315
+ | `INVALID_EMAIL` | 400 | Bad email format. | Use `user@domain.com`. |
316
+ | `INVALID_PHONE` | 400 | Bad WhatsApp number. | Use E.164 with `+`, e.g. `+243812345678`. |
317
+ | `NO_SUBSCRIPTION` | 403 | Workspace has no active plan. | Open Dashboard Billing or contact support. |
318
+ | `EMAIL_NOT_AVAILABLE` | 403 | Email not allowed on current plan setup. | Connect a Service on the project (Free), or upgrade plan. |
319
+ | `EMAIL_SERVICE_NOT_CONFIGURED` | 422 | No Gmail/SMTP connected. | Dashboard → project**Service**. |
320
+ | `QUOTA_EXCEEDED` | 429 | Monthly email limit reached. | Upgrade plan or wait for reset. |
321
+ | `WHATSAPP_NOT_AVAILABLE` | 403 | WhatsApp not on plan. | Check [pricing](https://zindua.run/pricing). |
322
+ | `WHATSAPP_NOT_CONNECTED` | 422 | WhatsApp not linked. | Dashboard → project → **WhatsApp** → scan QR. |
323
+ | `WHATSAPP_PAUSED` | 422 | WhatsApp session paused. | Resume in the dashboard. |
324
+ | `WHATSAPP_QUOTA_EXCEEDED` | 429 | Monthly WhatsApp limit reached. | Upgrade or wait. |
325
+ | `RATE_LIMIT_EXCEEDED` | 429 | Sending too fast (WhatsApp). | Wait `retryAfterSec` from `e.details`, then retry. |
326
+ | `TEMPLATE_NOT_FOUND` | 404 | Unknown template slug. | Create template or fix slug; check `availableTemplateSlugs` in details. |
327
+ | `TEMPLATE_NO_CONTENT` | 404 | Template has no language version. | Add content in Dashboard → Templates. |
328
+ | `TEMPLATE_NO_WHATSAPP_BODY` | 422 | No plain text for WhatsApp. | Add a text body for that language. |
329
+ | `QUEUE_UNAVAILABLE` | 503 | Temporary delivery queue issue. | Retry shortly; contact support if it persists. |
330
+ | `BROWSER_FORBIDDEN` | — | SDK used in browser. | Move the call to your backend. |
331
+ | `REQUEST_TIMEOUT` | — | Request exceeded `timeoutMs`. | Increase timeout or retry. |
332
+
333
+ Many errors include a **`context`** field (same shape as success) with `plan` and `project` to help you debug.
245
334
 
246
335
  ---
247
336
 
248
- ## Mobile & SPA
249
-
250
- Never put `znd_live_` keys in React Native, Flutter, or browser code. Call your own backend; your backend uses this SDK.
337
+ ## Best practices
251
338
 
252
- See [Developer docs Quickstart](https://zindua.run/developers#setup).
339
+ 1. Store the API key in environment variables or a secrets manager.
340
+ 2. Call Zindua from your **API routes** only, not from React/Vue/mobile bundles.
341
+ 3. Use **`znd_test_…`** in staging; **`znd_live_…`** in production.
342
+ 4. Pin the SDK version in `package.json`, e.g. `"@zindua/sdk": "1.2.4"`.
343
+ 5. One Zindua project per client when quotas, senders, or templates must stay isolated.
253
344
 
254
345
  ---
255
346
 
256
- ## HTTP without the SDK
257
-
258
- Any language can call the same endpoint:
347
+ ## Without the SDK (HTTP)
259
348
 
260
349
  ```bash
261
350
  curl -X POST https://zindua.run/api/v1/send \
@@ -264,34 +353,20 @@ curl -X POST https://zindua.run/api/v1/send \
264
353
  -d '{"to":"user@example.com","template":"welcome","variables":{"name":"Alex"}}'
265
354
  ```
266
355
 
267
- Full reference: [HTTP / cURL](https://zindua.run/developers#http).
356
+ See [HTTP / cURL](https://zindua.run/developers#http).
268
357
 
269
358
  ---
270
359
 
271
- ## API surface
360
+ ## API reference
272
361
 
273
362
  | Export | Description |
274
363
  |--------|-------------|
275
364
  | `Zindua` | Client class |
276
- | `ZinduaError` | Typed error |
365
+ | `ZinduaError` | Error type (`status`, `code`, `message`, `details`) |
366
+ | `ZinduaSendResult` | Success payload type |
367
+ | `ZinduaSendContext` | Type of `result.context` |
277
368
  | `DEFAULT_API_BASE` | `https://zindua.run/api/v1` |
278
- | `LIMITS` | Validation limits (documented constants) |
279
-
280
- ---
281
-
282
- ## Local development (monorepo)
283
-
284
- ```bash
285
- cd packages/zindua-js
286
- npm run build
287
- npm test
288
- ```
289
-
290
- From the app repo root:
291
-
292
- ```bash
293
- npm install file:./packages/zindua-js
294
- ```
369
+ | `LIMITS` | Client-side validation limits |
295
370
 
296
371
  ---
297
372
 
package/dist/client.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Zindua = void 0;
4
4
  const errors_1 = require("./errors");
5
5
  const validate_1 = require("./validate");
6
- const SDK_VERSION = "1.2.3";
6
+ const SDK_VERSION = "1.2.4";
7
7
  const USER_AGENT = `Zindua-JS/${SDK_VERSION}`;
8
8
  function buildPayload(options, channel) {
9
9
  const to = (0, validate_1.validateRecipient)(options.to, channel);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zindua/sdk",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "Official Zindua SDK for Node.js — transactional email and WhatsApp via POST /api/v1/send.",
5
5
  "author": "Zindua",
6
6
  "license": "MIT",