notiformer 1.0.3 → 1.0.5
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/README.md +236 -62
- package/dist/index.d.ts +18 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -47
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +2 -1
- package/dist/logger.js.map +1 -1
- package/dist/types.d.ts +22 -42
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# notiformer
|
|
2
2
|
|
|
3
|
-
Real-time
|
|
3
|
+
Real-time push notifications and feature gates for your code.
|
|
4
4
|
|
|
5
|
-
Get notified
|
|
5
|
+
Know the moment something important happens in your app — a new sale, an error, a spike in costs. Get notified on your phone via the **Notiformer app** (iOS & Android), or in your inbox.
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> **Works everywhere.** Use in Node.js, Express, Next.js API routes, serverless functions, Python, Go, or any HTTP client.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -21,69 +21,142 @@ npm install notiformer
|
|
|
21
21
|
```ts
|
|
22
22
|
import { Notiformer } from 'notiformer';
|
|
23
23
|
|
|
24
|
-
// Get your API key at https://app.notiformer.com/projects
|
|
25
24
|
const n = new Notiformer({
|
|
26
|
-
apiKey: '
|
|
25
|
+
apiKey: 'ntf_live_...', // from app.notiformer.com/projects
|
|
27
26
|
});
|
|
28
27
|
|
|
29
28
|
await n.event({
|
|
30
|
-
channel: 'payments',
|
|
31
|
-
event: 'payment_success',
|
|
32
|
-
description: '$49.00 — john@example.com',
|
|
33
|
-
icon: '💳',
|
|
34
|
-
|
|
29
|
+
channel: 'payments', // groups related events — auto-created on first use
|
|
30
|
+
event: 'payment_success', // machine-readable event name
|
|
31
|
+
description: '$49.00 — john@example.com', // optional human-readable detail
|
|
32
|
+
icon: '💳', // optional emoji shown in the feed and notification
|
|
33
|
+
tags: { userId: 'usr_123', plan: 'pro' }, // optional key-value metadata
|
|
34
|
+
value: '$49.00', // optional value highlighted in the feed
|
|
35
|
+
notify: true, // true → push notification | false → silent log only
|
|
36
|
+
recipients: ['you@company.com'], // optional — notify specific people only (see below)
|
|
35
37
|
});
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
>
|
|
40
|
+
> **Tip:** Use `apiKey: 'ntf_live_test'` to get started without a real key. The SDK will print setup instructions in your console and skip all API calls.
|
|
39
41
|
|
|
40
42
|
---
|
|
41
43
|
|
|
42
44
|
## Get your API key
|
|
43
45
|
|
|
44
|
-
1. Go to [app.notiformer.com
|
|
45
|
-
2. Create
|
|
46
|
-
3. Copy the API key
|
|
47
|
-
4. Replace `'ntf_live_test'` in your code
|
|
46
|
+
1. Go to [app.notiformer.com](https://app.notiformer.com) and create an account (free)
|
|
47
|
+
2. Create a project
|
|
48
|
+
3. Copy the API key from the project overview
|
|
49
|
+
4. Replace `'ntf_live_test'` in your code with your real key
|
|
48
50
|
|
|
49
51
|
---
|
|
50
52
|
|
|
51
|
-
##
|
|
53
|
+
## `event()` — Send an event
|
|
52
54
|
|
|
53
55
|
```ts
|
|
54
56
|
await n.event({
|
|
55
|
-
channel:
|
|
56
|
-
event:
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
channel: 'payments', // required — string, lowercase, a-z 0-9 - _
|
|
58
|
+
event: 'payment_success', // required — machine-readable event name
|
|
59
|
+
|
|
60
|
+
description: '$49.00 — john@example.com', // optional
|
|
61
|
+
icon: '💳', // optional — emoji
|
|
62
|
+
tags: { plan: 'pro', userId: '123' }, // optional — displayed in the event feed
|
|
63
|
+
value: '$49.00', // optional — highlighted value in the feed
|
|
64
|
+
notify: true, // optional — default: true
|
|
65
|
+
recipients: ['alice@company.com'], // optional — see "Targeting specific people"
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `notify`
|
|
70
|
+
|
|
71
|
+
| Value | Behaviour |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `true` (default) | Sends push notification to subscribed members |
|
|
74
|
+
| `false` | Stores the event silently for analytics — no notification sent |
|
|
75
|
+
|
|
76
|
+
### Return value
|
|
59
77
|
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
```ts
|
|
79
|
+
const result = await n.event({ ... });
|
|
80
|
+
// result is null if the call failed (never throws by default)
|
|
81
|
+
// result.rateLimited === true if you exceeded 60 events/minute (event is stored, notification skipped)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`event()` **never throws by default.** A failed notification will never crash your app. If you prefer it to throw, pass `throwOnError: true` in the config.
|
|
85
|
+
|
|
86
|
+
---
|
|
62
87
|
|
|
63
|
-
|
|
64
|
-
|
|
88
|
+
## Targeting specific people — `recipients`
|
|
89
|
+
|
|
90
|
+
By default, when `notify: true`, all members of the project who are subscribed to that channel receive a notification.
|
|
91
|
+
|
|
92
|
+
You can override this and target specific people by email:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
await n.event({
|
|
96
|
+
channel: 'payments',
|
|
97
|
+
event: 'large_order',
|
|
98
|
+
description: '$2,400 — enterprise@client.com',
|
|
99
|
+
notify: true,
|
|
100
|
+
recipients: ['cto@company.com', 'billing@company.com'], // only these two are notified
|
|
65
101
|
});
|
|
66
102
|
```
|
|
67
103
|
|
|
68
|
-
|
|
104
|
+
**How it works:**
|
|
105
|
+
- If a recipient has a Notiformer account linked to that email and has installed the app, they receive a **push notification**
|
|
106
|
+
- Email notifications are **coming soon** — recipients will receive emails once this feature launches
|
|
107
|
+
- If you don't specify `recipients`, all project members subscribed to the channel are notified
|
|
108
|
+
|
|
109
|
+
**Plan limits for `recipients`:**
|
|
110
|
+
|
|
111
|
+
| Plan | Max recipients per event |
|
|
112
|
+
|---|---|
|
|
113
|
+
| Free | 1 |
|
|
114
|
+
| Starter | 3 |
|
|
115
|
+
| Pro | 10 |
|
|
116
|
+
| Business | 30 |
|
|
117
|
+
|
|
118
|
+
> Members are managed from the project dashboard at [app.notiformer.com](https://app.notiformer.com/projects).
|
|
69
119
|
|
|
70
120
|
---
|
|
71
121
|
|
|
72
|
-
## Feature
|
|
122
|
+
## `gate()` — Feature gates
|
|
73
123
|
|
|
74
|
-
Toggle features remotely from
|
|
124
|
+
Toggle features in your code remotely from the Notiformer dashboard — no redeploy needed.
|
|
75
125
|
|
|
76
126
|
```ts
|
|
77
127
|
const isEnabled = await n.gate('new-checkout-flow');
|
|
78
128
|
|
|
79
129
|
if (isEnabled) {
|
|
80
|
-
//
|
|
130
|
+
// new behaviour
|
|
81
131
|
} else {
|
|
82
|
-
//
|
|
132
|
+
// old behaviour
|
|
83
133
|
}
|
|
84
134
|
```
|
|
85
135
|
|
|
86
|
-
Gates are cached for 30 seconds by default to
|
|
136
|
+
Gates are **cached locally for 30 seconds** by default to avoid hammering the API on every request.
|
|
137
|
+
|
|
138
|
+
### Options
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const isEnabled = await n.gate('my-gate', {
|
|
142
|
+
fallback: false, // optional — returned if the gate can't be fetched (default: false)
|
|
143
|
+
cacheTtl: 60, // optional — cache duration in seconds (default: 30)
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Full gate result
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const result = await n.gateDetails('my-gate');
|
|
151
|
+
// { key: 'my-gate', enabled: true, cached: false, fetchedAt: '2025-...' }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Clear the cache
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
n.clearGateCache('my-gate'); // clear a specific gate
|
|
158
|
+
n.clearGateCache(); // clear all gates
|
|
159
|
+
```
|
|
87
160
|
|
|
88
161
|
---
|
|
89
162
|
|
|
@@ -91,12 +164,11 @@ Gates are cached for 30 seconds by default to minimise API calls.
|
|
|
91
164
|
|
|
92
165
|
```ts
|
|
93
166
|
const n = new Notiformer({
|
|
94
|
-
apiKey:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
console.error(err.message);
|
|
167
|
+
apiKey: 'ntf_live_...', // required — from app.notiformer.com/projects
|
|
168
|
+
silent: false, // optional — true = no API calls (great for local dev)
|
|
169
|
+
throwOnError: false, // optional — true = throws instead of returning null
|
|
170
|
+
onError: (err) => { // optional — called when any call fails
|
|
171
|
+
Sentry.captureException(err);
|
|
100
172
|
},
|
|
101
173
|
});
|
|
102
174
|
```
|
|
@@ -106,65 +178,165 @@ const n = new Notiformer({
|
|
|
106
178
|
```ts
|
|
107
179
|
const n = new Notiformer({
|
|
108
180
|
apiKey: process.env.NOTIFORMER_API_KEY!,
|
|
109
|
-
silent: process.env.NODE_ENV !== 'production',
|
|
181
|
+
silent: process.env.NODE_ENV !== 'production', // no calls in dev/test
|
|
110
182
|
});
|
|
111
183
|
```
|
|
112
184
|
|
|
113
185
|
---
|
|
114
186
|
|
|
187
|
+
## Rate limits & quotas
|
|
188
|
+
|
|
189
|
+
| Limit | Value |
|
|
190
|
+
|---|---|
|
|
191
|
+
| Events per minute (per project) | 60 |
|
|
192
|
+
| Events per month (Free plan) | 500 |
|
|
193
|
+
| Events per month (Starter) | 20,000 |
|
|
194
|
+
| Events per month (Pro) | 75,000 |
|
|
195
|
+
| Events per month (Business) | 300,000 |
|
|
196
|
+
|
|
197
|
+
If you exceed **60 events/minute**: the event is stored and visible in your feed, but no notification is sent. The API response includes `rateLimited: true`.
|
|
198
|
+
|
|
199
|
+
If you exceed your **monthly quota**: the event is rejected with HTTP 429. Upgrade your plan at [app.notiformer.com/settings](https://app.notiformer.com/settings).
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
115
203
|
## Common patterns
|
|
116
204
|
|
|
205
|
+
### Alert on payment success
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
await n.event({
|
|
209
|
+
channel: 'payments',
|
|
210
|
+
event: 'payment_success',
|
|
211
|
+
description: `${amount} — ${user.email}`,
|
|
212
|
+
icon: '💳',
|
|
213
|
+
value: amount,
|
|
214
|
+
notify: true,
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
117
218
|
### Alert on unhandled errors
|
|
118
219
|
|
|
119
220
|
```ts
|
|
221
|
+
// Express error middleware
|
|
120
222
|
app.use(async (err, req, res, next) => {
|
|
121
223
|
await n.event({
|
|
122
|
-
channel:
|
|
123
|
-
event:
|
|
224
|
+
channel: 'errors',
|
|
225
|
+
event: 'unhandled_error',
|
|
124
226
|
description: err.message,
|
|
125
|
-
icon:
|
|
126
|
-
tags:
|
|
127
|
-
notify:
|
|
227
|
+
icon: '🔴',
|
|
228
|
+
tags: { path: req.path, method: req.method },
|
|
229
|
+
notify: true,
|
|
128
230
|
});
|
|
129
231
|
res.status(500).json({ error: 'Internal server error' });
|
|
130
232
|
});
|
|
131
233
|
```
|
|
132
234
|
|
|
133
|
-
###
|
|
235
|
+
### Silent analytics (no notification)
|
|
134
236
|
|
|
135
237
|
```ts
|
|
136
238
|
await n.event({
|
|
137
|
-
channel: '
|
|
138
|
-
event:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
value: amount,
|
|
142
|
-
notify: true,
|
|
239
|
+
channel: 'analytics',
|
|
240
|
+
event: 'page_view',
|
|
241
|
+
tags: { path: req.path, userId: session.userId },
|
|
242
|
+
notify: false, // stored in feed, no push notification sent
|
|
143
243
|
});
|
|
144
244
|
```
|
|
145
245
|
|
|
146
|
-
### Feature gate
|
|
246
|
+
### Feature gate in an API route
|
|
147
247
|
|
|
148
248
|
```ts
|
|
149
|
-
|
|
249
|
+
// Next.js API route
|
|
250
|
+
export async function POST(req: Request) {
|
|
150
251
|
const useNewFlow = await n.gate('new-checkout-flow');
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
252
|
+
|
|
253
|
+
if (useNewFlow) {
|
|
254
|
+
return newCheckoutHandler(req);
|
|
255
|
+
}
|
|
256
|
+
return legacyCheckoutHandler(req);
|
|
257
|
+
}
|
|
155
258
|
```
|
|
156
259
|
|
|
157
|
-
###
|
|
260
|
+
### Notify a specific person
|
|
158
261
|
|
|
159
262
|
```ts
|
|
263
|
+
// Only notify the CTO for large orders
|
|
160
264
|
await n.event({
|
|
161
|
-
channel:
|
|
162
|
-
event:
|
|
163
|
-
|
|
164
|
-
|
|
265
|
+
channel: 'sales',
|
|
266
|
+
event: 'enterprise_signup',
|
|
267
|
+
description: `${company} — ${mrr}/mo`,
|
|
268
|
+
icon: '🏢',
|
|
269
|
+
value: mrr,
|
|
270
|
+
notify: true,
|
|
271
|
+
recipients: ['cto@yourcompany.com'], // only they get the push
|
|
165
272
|
});
|
|
166
273
|
```
|
|
167
274
|
|
|
275
|
+
### Using with Python (REST API)
|
|
276
|
+
|
|
277
|
+
Notiformer works from any language via the REST API:
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
import requests
|
|
281
|
+
|
|
282
|
+
requests.post(
|
|
283
|
+
'https://api.notiformer.com/v1/events',
|
|
284
|
+
headers={ 'Authorization': f'Bearer {NF_KEY}' },
|
|
285
|
+
json={
|
|
286
|
+
'channel': 'ai-costs',
|
|
287
|
+
'event': 'cost_spike',
|
|
288
|
+
'description': '🤖 $180 spent in 10 min',
|
|
289
|
+
'notify': True,
|
|
290
|
+
'recipients': ['cto@company.com'], # optional
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Receiving notifications
|
|
298
|
+
|
|
299
|
+
Push notifications are delivered via the **Notiformer app**, available for iOS and Android.
|
|
300
|
+
|
|
301
|
+
1. Download the Notiformer app from the App Store or Google Play
|
|
302
|
+
2. Sign in with your Notiformer account
|
|
303
|
+
3. You'll automatically receive push notifications for projects you own or are a member of
|
|
304
|
+
4. Manage which channels you're subscribed to from the app settings
|
|
305
|
+
|
|
306
|
+
> **Email notifications** are in development and coming soon. Sign up at [notiformer.com](https://notiformer.com) to be notified when they launch.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## REST API
|
|
311
|
+
|
|
312
|
+
The same `event()` call maps to this endpoint:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
POST https://api.notiformer.com/v1/events
|
|
316
|
+
Authorization: Bearer ntf_live_...
|
|
317
|
+
Content-Type: application/json
|
|
318
|
+
|
|
319
|
+
{
|
|
320
|
+
"channel": "payments",
|
|
321
|
+
"event": "payment_success",
|
|
322
|
+
"description": "$49.00 — john@example.com",
|
|
323
|
+
"icon": "💳",
|
|
324
|
+
"tags": { "plan": "pro" },
|
|
325
|
+
"value": "$49.00",
|
|
326
|
+
"notify": true,
|
|
327
|
+
"recipients": ["you@company.com"]
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Response:
|
|
332
|
+
```json
|
|
333
|
+
{
|
|
334
|
+
"id": "evt_abc123",
|
|
335
|
+
"createdAt": "2025-01-15T10:30:00.000Z",
|
|
336
|
+
"rateLimited": false
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
168
340
|
---
|
|
169
341
|
|
|
170
342
|
## Requirements
|
|
@@ -176,5 +348,7 @@ await n.event({
|
|
|
176
348
|
|
|
177
349
|
## Links
|
|
178
350
|
|
|
179
|
-
- Dashboard
|
|
180
|
-
- Docs
|
|
351
|
+
- **Dashboard:** [app.notiformer.com](https://app.notiformer.com)
|
|
352
|
+
- **Docs:** [docs.notiformer.com](https://docs.notiformer.com)
|
|
353
|
+
- **Status:** [status.notiformer.com](https://status.notiformer.com)
|
|
354
|
+
- **Pricing:** [notiformer.com/#pricing](https://notiformer.com/#pricing)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Notiformer — Real-time alerts and feature gates for your code.
|
|
3
3
|
*
|
|
4
|
+
* Works in Node.js (backend) and the browser (frontend).
|
|
5
|
+
*
|
|
4
6
|
* @example
|
|
5
7
|
* import { Notiformer } from 'notiformer';
|
|
6
8
|
*
|
|
7
|
-
* const n = new Notiformer({
|
|
8
|
-
*
|
|
9
|
-
*
|
|
9
|
+
* const n = new Notiformer({ apiKey: 'ntf_live_...' });
|
|
10
|
+
*
|
|
11
|
+
* // Notify everyone subscribed to the 'payments' channel
|
|
12
|
+
* await n.event({ channel: 'payments', event: 'new_sale', notify: true });
|
|
10
13
|
*
|
|
14
|
+
* // Notify specific people only
|
|
11
15
|
* await n.event({
|
|
12
16
|
* channel: 'payments',
|
|
13
|
-
* event: '
|
|
14
|
-
* description: '$49.00 — john@example.com',
|
|
15
|
-
* icon: '💳',
|
|
17
|
+
* event: 'refund_requested',
|
|
16
18
|
* notify: true,
|
|
19
|
+
* recipients: ['admin@company.com', 'billing@company.com'],
|
|
17
20
|
* });
|
|
18
21
|
*/
|
|
19
22
|
import type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult } from "./types";
|
|
@@ -30,22 +33,23 @@ export declare class Notiformer {
|
|
|
30
33
|
private readonly isPlaceholder;
|
|
31
34
|
constructor(config: NotiformerConfig);
|
|
32
35
|
/**
|
|
33
|
-
* Send an event and optionally
|
|
36
|
+
* Send an event and optionally notify recipients.
|
|
34
37
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
38
|
+
* - Without `recipients`: notifies the project owner + all members
|
|
39
|
+
* subscribed to the event's channel.
|
|
40
|
+
* - With `recipients`: notifies only the specified email addresses
|
|
41
|
+
* (must be project members). Overrides the default behaviour.
|
|
42
|
+
*
|
|
43
|
+
* Never throws by default — returns null if the call fails.
|
|
37
44
|
*/
|
|
38
45
|
event(payload: EventPayload): Promise<EventResponse | null>;
|
|
39
46
|
/**
|
|
40
47
|
* Check whether a feature gate is enabled.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* Returns fallback (false) if the call fails.
|
|
48
|
+
* Results are cached locally for 30 seconds by default.
|
|
49
|
+
* Returns false if the call fails.
|
|
44
50
|
*/
|
|
45
51
|
gate(key: string, options?: GateOptions): Promise<boolean>;
|
|
46
|
-
/** Full gate result with metadata */
|
|
47
52
|
gateDetails(key: string, options?: GateOptions): Promise<GateResult>;
|
|
48
|
-
/** Clear cached gate values */
|
|
49
53
|
clearGateCache(key?: string): void;
|
|
50
54
|
private post;
|
|
51
55
|
private get;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACX,MAAM,SAAS,CAAC;AAIjB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,GACX,CAAC;AAOF,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAE5B,MAAM,EAAE,gBAAgB;IAoCpC;;;;;;;;;OASG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAiDjE;;;;OAIG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB9D,WAAW,CACf,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;IAKtB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;YAIpB,IAAI;YAIJ,GAAG;YAIH,OAAO;IAmBrB,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,oBAAoB;CAmB7B;AAED,eAAe,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,26 +2,28 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Notiformer — Real-time alerts and feature gates for your code.
|
|
4
4
|
*
|
|
5
|
+
* Works in Node.js (backend) and the browser (frontend).
|
|
6
|
+
*
|
|
5
7
|
* @example
|
|
6
8
|
* import { Notiformer } from 'notiformer';
|
|
7
9
|
*
|
|
8
|
-
* const n = new Notiformer({
|
|
9
|
-
* apiKey: 'ntf_live_xxxxxxxxxxxxxxxx', // from app.notiformer.com/projects
|
|
10
|
-
* });
|
|
10
|
+
* const n = new Notiformer({ apiKey: 'ntf_live_...' });
|
|
11
11
|
*
|
|
12
|
+
* // Notify everyone subscribed to the 'payments' channel
|
|
13
|
+
* await n.event({ channel: 'payments', event: 'new_sale', notify: true });
|
|
14
|
+
*
|
|
15
|
+
* // Notify specific people only
|
|
12
16
|
* await n.event({
|
|
13
17
|
* channel: 'payments',
|
|
14
|
-
* event: '
|
|
15
|
-
* description: '$49.00 — john@example.com',
|
|
16
|
-
* icon: '💳',
|
|
18
|
+
* event: 'refund_requested',
|
|
17
19
|
* notify: true,
|
|
20
|
+
* recipients: ['admin@company.com', 'billing@company.com'],
|
|
18
21
|
* });
|
|
19
22
|
*/
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
exports.Notiformer = void 0;
|
|
22
25
|
const logger_1 = require("./logger");
|
|
23
26
|
const cache_1 = require("./cache");
|
|
24
|
-
// The placeholder key shown in docs — triggers a friendly setup message
|
|
25
27
|
const PLACEHOLDER_KEY = "ntf_live_test";
|
|
26
28
|
const API_URL = "https://api.notiformer.com";
|
|
27
29
|
const DEFAULT_TIMEOUT = 8000;
|
|
@@ -47,7 +49,7 @@ class Notiformer {
|
|
|
47
49
|
"┌─────────────────────────────────────────────────────┐\n" +
|
|
48
50
|
"│ notiformer — setup required │\n" +
|
|
49
51
|
"├─────────────────────────────────────────────────────┤\n" +
|
|
50
|
-
'│ You are using the example
|
|
52
|
+
'│ You are using the example key "ntf_live_test". │\n' +
|
|
51
53
|
"│ Events will not be sent until you use a real key. │\n" +
|
|
52
54
|
"│ │\n" +
|
|
53
55
|
"│ 1. Go to https://app.notiformer.com/projects │\n" +
|
|
@@ -57,14 +59,15 @@ class Notiformer {
|
|
|
57
59
|
"└─────────────────────────────────────────────────────┘\n");
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
|
-
// ─────────────────────────────────────────────────────────────
|
|
61
|
-
// event()
|
|
62
|
-
// ─────────────────────────────────────────────────────────────
|
|
63
62
|
/**
|
|
64
|
-
* Send an event and optionally
|
|
63
|
+
* Send an event and optionally notify recipients.
|
|
64
|
+
*
|
|
65
|
+
* - Without `recipients`: notifies the project owner + all members
|
|
66
|
+
* subscribed to the event's channel.
|
|
67
|
+
* - With `recipients`: notifies only the specified email addresses
|
|
68
|
+
* (must be project members). Overrides the default behaviour.
|
|
65
69
|
*
|
|
66
|
-
*
|
|
67
|
-
* Returns null if the call fails (and calls onError if configured).
|
|
70
|
+
* Never throws by default — returns null if the call fails.
|
|
68
71
|
*/
|
|
69
72
|
async event(payload) {
|
|
70
73
|
var _a, _b;
|
|
@@ -72,31 +75,36 @@ class Notiformer {
|
|
|
72
75
|
throw new Error("[notiformer] event.channel is required.");
|
|
73
76
|
if (!payload.event)
|
|
74
77
|
throw new Error("[notiformer] event.event is required.");
|
|
75
|
-
// Placeholder key — log a clear message, do not attempt the call
|
|
76
78
|
if (this.isPlaceholder) {
|
|
77
|
-
console.warn('[notiformer] Event not sent —
|
|
78
|
-
"→ Replace it with your real
|
|
79
|
+
console.warn('[notiformer] Event not sent — using example key "ntf_live_test".\n' +
|
|
80
|
+
"→ Replace it with your real key from https://app.notiformer.com/projects");
|
|
79
81
|
return null;
|
|
80
82
|
}
|
|
81
|
-
if (this.silent)
|
|
82
|
-
this.logger.info("Silent mode: event suppressed.");
|
|
83
|
+
if (this.silent)
|
|
83
84
|
return null;
|
|
84
|
-
}
|
|
85
85
|
try {
|
|
86
|
-
const
|
|
86
|
+
const body = {
|
|
87
87
|
channel: payload.channel,
|
|
88
88
|
event: payload.event,
|
|
89
|
-
description: payload.description,
|
|
90
|
-
icon: payload.icon,
|
|
91
|
-
tags: payload.tags,
|
|
92
|
-
value: payload.value,
|
|
93
89
|
notify: (_a = payload.notify) !== null && _a !== void 0 ? _a : true,
|
|
94
|
-
}
|
|
90
|
+
};
|
|
91
|
+
if (payload.description !== undefined)
|
|
92
|
+
body.description = payload.description;
|
|
93
|
+
if (payload.icon !== undefined)
|
|
94
|
+
body.icon = payload.icon;
|
|
95
|
+
if (payload.tags !== undefined)
|
|
96
|
+
body.tags = payload.tags;
|
|
97
|
+
if (payload.value !== undefined)
|
|
98
|
+
body.value = payload.value;
|
|
99
|
+
if (payload.recipients !== undefined && payload.recipients.length > 0) {
|
|
100
|
+
body.recipients = payload.recipients;
|
|
101
|
+
}
|
|
102
|
+
const res = await this.post("/v1/events", body);
|
|
95
103
|
if (!res.ok) {
|
|
96
|
-
const
|
|
104
|
+
const data = await res
|
|
97
105
|
.json()
|
|
98
106
|
.catch(() => ({ error: `HTTP ${res.status}` }));
|
|
99
|
-
return this.fail(new Error(`[notiformer] ${(_b =
|
|
107
|
+
return this.fail(new Error(`[notiformer] ${(_b = data.error) !== null && _b !== void 0 ? _b : res.statusText}`));
|
|
100
108
|
}
|
|
101
109
|
return (await res.json());
|
|
102
110
|
}
|
|
@@ -104,14 +112,10 @@ class Notiformer {
|
|
|
104
112
|
return this.fail(this.friendlyNetworkError(err));
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
|
-
// ─────────────────────────────────────────────────────────────
|
|
108
|
-
// gate()
|
|
109
|
-
// ─────────────────────────────────────────────────────────────
|
|
110
115
|
/**
|
|
111
116
|
* Check whether a feature gate is enabled.
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* Returns fallback (false) if the call fails.
|
|
117
|
+
* Results are cached locally for 30 seconds by default.
|
|
118
|
+
* Returns false if the call fails.
|
|
115
119
|
*/
|
|
116
120
|
async gate(key, options = {}) {
|
|
117
121
|
var _a, _b;
|
|
@@ -136,23 +140,15 @@ class Notiformer {
|
|
|
136
140
|
return fallback;
|
|
137
141
|
}
|
|
138
142
|
}
|
|
139
|
-
/** Full gate result with metadata */
|
|
140
143
|
async gateDetails(key, options = {}) {
|
|
141
144
|
const enabled = await this.gate(key, options);
|
|
142
145
|
return { key, enabled, cached: false, fetchedAt: new Date().toISOString() };
|
|
143
146
|
}
|
|
144
|
-
/** Clear cached gate values */
|
|
145
147
|
clearGateCache(key) {
|
|
146
148
|
key ? this.gateCache.delete(key) : this.gateCache.clear();
|
|
147
149
|
}
|
|
148
|
-
// ─────────────────────────────────────────────────────────────
|
|
149
|
-
// Private
|
|
150
|
-
// ─────────────────────────────────────────────────────────────
|
|
151
150
|
async post(path, body) {
|
|
152
|
-
return this.request(path, {
|
|
153
|
-
method: "POST",
|
|
154
|
-
body: JSON.stringify(body),
|
|
155
|
-
});
|
|
151
|
+
return this.request(path, { method: "POST", body: JSON.stringify(body) });
|
|
156
152
|
}
|
|
157
153
|
async get(path) {
|
|
158
154
|
return this.request(path, { method: "GET" });
|
|
@@ -168,7 +164,7 @@ class Notiformer {
|
|
|
168
164
|
headers: {
|
|
169
165
|
"Content-Type": "application/json",
|
|
170
166
|
Authorization: `Bearer ${this.apiKey}`,
|
|
171
|
-
"X-SDK-Version": "1.0.
|
|
167
|
+
"X-SDK-Version": "1.0.5",
|
|
172
168
|
...((_a = init.headers) !== null && _a !== void 0 ? _a : {}),
|
|
173
169
|
},
|
|
174
170
|
});
|
|
@@ -188,14 +184,13 @@ class Notiformer {
|
|
|
188
184
|
friendlyNetworkError(err) {
|
|
189
185
|
const msg = err instanceof Error ? err.message.toLowerCase() : "";
|
|
190
186
|
if (msg.includes("aborted") || msg.includes("timeout")) {
|
|
191
|
-
return new Error(`[notiformer] Request timed out after ${this.timeout / 1000}s
|
|
192
|
-
"Check your internet connection or try again later.");
|
|
187
|
+
return new Error(`[notiformer] Request timed out after ${this.timeout / 1000}s.`);
|
|
193
188
|
}
|
|
194
189
|
if (msg.includes("failed to fetch") ||
|
|
195
190
|
msg.includes("enotfound") ||
|
|
196
191
|
msg.includes("network")) {
|
|
197
192
|
return new Error("[notiformer] Cannot reach the Notiformer API.\n" +
|
|
198
|
-
"Check your
|
|
193
|
+
"Check your connection. If the issue persists: https://status.notiformer.com");
|
|
199
194
|
}
|
|
200
195
|
return err instanceof Error ? err : new Error(String(err));
|
|
201
196
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/logger.d.ts
CHANGED
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAWxC,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,GAAE,QAAkB;IAIrC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAK5C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI3C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI3C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;CAI7C"}
|
package/dist/logger.js
CHANGED
package/dist/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;AAEA,MAAM,MAAM,GAA6B;IACvC,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;AAEA,MAAM,MAAM,GAA6B;IACvC,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAa,MAAM;IAGjB,YAAY,QAAkB,OAAO;QACnC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,GAAW,EAAE,GAAG,IAAe;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK;YAC5B,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,CAAC,GAAW,EAAE,GAAG,IAAe;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,CAAC,GAAW,EAAE,GAAG,IAAe;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,GAAW,EAAE,GAAG,IAAe;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK;YAC5B,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAClD,CAAC;CACF;AAxBD,wBAwBC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,67 +1,47 @@
|
|
|
1
1
|
export interface NotiformerConfig {
|
|
2
|
-
/**
|
|
3
|
-
* Your Notiformer API key.
|
|
4
|
-
* Find it at: https://app.notiformer.com/projects
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* const n = new Notiformer({ apiKey: 'ntf_live_xxxxxxxxxxxxxxxx' })
|
|
8
|
-
*/
|
|
9
2
|
apiKey: string;
|
|
10
|
-
/**
|
|
11
|
-
* Silence all SDK calls. Useful for local development.
|
|
12
|
-
* No events will be sent, no network calls made.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* const n = new Notiformer({
|
|
16
|
-
* apiKey: process.env.NOTIFORMER_API_KEY,
|
|
17
|
-
* silent: process.env.NODE_ENV !== 'production',
|
|
18
|
-
* })
|
|
19
|
-
*/
|
|
20
3
|
silent?: boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Called when an event() or gate() call fails.
|
|
23
|
-
* Use this to forward errors to your own logging system.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* onError: (err) => console.error('[notiformer]', err.message)
|
|
27
|
-
*/
|
|
28
|
-
onError?: (error: Error) => void;
|
|
29
|
-
/**
|
|
30
|
-
* If true, throws on failure instead of returning null silently.
|
|
31
|
-
* Default: false — a failed notification should never crash your app.
|
|
32
|
-
*/
|
|
33
4
|
throwOnError?: boolean;
|
|
34
|
-
|
|
5
|
+
onError?: (err: Error) => void;
|
|
35
6
|
_baseUrl?: string;
|
|
36
7
|
}
|
|
37
8
|
export interface EventPayload {
|
|
38
|
-
/** Channel name
|
|
9
|
+
/** Channel name (lowercase, letters, numbers, hyphens, underscores). */
|
|
39
10
|
channel: string;
|
|
40
|
-
/**
|
|
11
|
+
/** Short event name. */
|
|
41
12
|
event: string;
|
|
42
|
-
/** Human-readable description shown in the dashboard */
|
|
43
13
|
description?: string;
|
|
44
|
-
/** Emoji icon shown in the feed */
|
|
45
14
|
icon?: string;
|
|
46
|
-
/** Optional key/value metadata for filtering */
|
|
47
15
|
tags?: Record<string, string | number | boolean>;
|
|
48
|
-
/** A value to display alongside the event. e.g. '$49.00' */
|
|
49
16
|
value?: string | number;
|
|
50
17
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* @default true
|
|
18
|
+
* Whether to send push/email notifications.
|
|
19
|
+
* Defaults to true.
|
|
54
20
|
*/
|
|
55
21
|
notify?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Specific email addresses to notify.
|
|
24
|
+
*
|
|
25
|
+
* If set, **only** these emails receive notifications — the default
|
|
26
|
+
* (owner + channel subscribers) is ignored.
|
|
27
|
+
*
|
|
28
|
+
* Each email must belong to a member of your project
|
|
29
|
+
* (added from the Notiformer dashboard).
|
|
30
|
+
*
|
|
31
|
+
* Plan limits: Free=1, Starter=3, Pro=10, Business=30.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* recipients: ['alice@company.com', 'bob@company.com']
|
|
35
|
+
*/
|
|
36
|
+
recipients?: string[];
|
|
56
37
|
}
|
|
57
38
|
export interface EventResponse {
|
|
58
39
|
id: string;
|
|
59
40
|
createdAt: string;
|
|
41
|
+
rateLimited?: boolean;
|
|
60
42
|
}
|
|
61
43
|
export interface GateOptions {
|
|
62
|
-
/** Returned if the request fails. @default false */
|
|
63
44
|
fallback?: boolean;
|
|
64
|
-
/** Cache duration in seconds. 0 to disable. @default 30 */
|
|
65
45
|
cacheTtl?: number;
|
|
66
46
|
}
|
|
67
47
|
export interface GateResult {
|
|
@@ -70,5 +50,5 @@ export interface GateResult {
|
|
|
70
50
|
cached: boolean;
|
|
71
51
|
fetchedAt: string;
|
|
72
52
|
}
|
|
73
|
-
export type LogLevel =
|
|
53
|
+
export type LogLevel = "debug" | "info" | "warn" | "error" | "none" | "silent";
|
|
74
54
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC"}
|
package/dist/types.js
CHANGED
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|