notiformer 1.0.7 → 1.0.8
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 +80 -77
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,21 +19,21 @@ npm install notiformer
|
|
|
19
19
|
## Quick start
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
import { Notiformer } from
|
|
22
|
+
import { Notiformer } from "notiformer";
|
|
23
23
|
|
|
24
24
|
const n = new Notiformer({
|
|
25
|
-
apiKey:
|
|
25
|
+
apiKey: "ntf_live_...", // from app.notiformer.com/projects
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
await n.event({
|
|
29
|
-
channel:
|
|
30
|
-
event:
|
|
31
|
-
description:
|
|
32
|
-
icon:
|
|
33
|
-
tags: { userId:
|
|
34
|
-
value:
|
|
35
|
-
notify: true,
|
|
36
|
-
recipients: [
|
|
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)
|
|
37
37
|
});
|
|
38
38
|
```
|
|
39
39
|
|
|
@@ -54,24 +54,24 @@ await n.event({
|
|
|
54
54
|
|
|
55
55
|
```ts
|
|
56
56
|
await n.event({
|
|
57
|
-
channel:
|
|
58
|
-
event:
|
|
59
|
-
|
|
60
|
-
description:
|
|
61
|
-
icon:
|
|
62
|
-
tags:
|
|
63
|
-
value:
|
|
64
|
-
notify:
|
|
65
|
-
recipients:
|
|
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
66
|
});
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
### `notify`
|
|
70
70
|
|
|
71
|
-
| Value
|
|
72
|
-
|
|
73
|
-
| `true` (default) | Sends push notification to subscribed members
|
|
74
|
-
| `false`
|
|
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
75
|
|
|
76
76
|
### Return value
|
|
77
77
|
|
|
@@ -93,27 +93,28 @@ You can override this and target specific people by email:
|
|
|
93
93
|
|
|
94
94
|
```ts
|
|
95
95
|
await n.event({
|
|
96
|
-
channel:
|
|
97
|
-
event:
|
|
98
|
-
description:
|
|
99
|
-
notify:
|
|
100
|
-
recipients:
|
|
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
|
|
101
101
|
});
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
**How it works:**
|
|
105
|
+
|
|
105
106
|
- If a recipient has a Notiformer account linked to that email and has installed the app, they receive a **push notification**
|
|
106
107
|
- Email notifications are **coming soon** — recipients will receive emails once this feature launches
|
|
107
108
|
- If you don't specify `recipients`, all project members subscribed to the channel are notified
|
|
108
109
|
|
|
109
110
|
**Plan limits for `recipients`:**
|
|
110
111
|
|
|
111
|
-
| Plan
|
|
112
|
-
|
|
113
|
-
| Free
|
|
114
|
-
| Starter
|
|
115
|
-
| Pro
|
|
116
|
-
| Business | 30
|
|
112
|
+
| Plan | Max recipients per event |
|
|
113
|
+
| -------- | ------------------------ |
|
|
114
|
+
| Free | 1 |
|
|
115
|
+
| Starter | 3 |
|
|
116
|
+
| Pro | 10 |
|
|
117
|
+
| Business | 30 |
|
|
117
118
|
|
|
118
119
|
> Members are managed from the project dashboard at [app.notiformer.com](https://app.notiformer.com/projects).
|
|
119
120
|
|
|
@@ -124,7 +125,7 @@ await n.event({
|
|
|
124
125
|
Toggle features in your code remotely from the Notiformer dashboard — no redeploy needed.
|
|
125
126
|
|
|
126
127
|
```ts
|
|
127
|
-
const isEnabled = await n.gate(
|
|
128
|
+
const isEnabled = await n.gate("new-checkout-flow");
|
|
128
129
|
|
|
129
130
|
if (isEnabled) {
|
|
130
131
|
// new behaviour
|
|
@@ -138,24 +139,24 @@ Gates are **cached locally for 30 seconds** by default to avoid hammering the AP
|
|
|
138
139
|
### Options
|
|
139
140
|
|
|
140
141
|
```ts
|
|
141
|
-
const isEnabled = await n.gate(
|
|
142
|
-
fallback:
|
|
143
|
-
cacheTtl:
|
|
142
|
+
const isEnabled = await n.gate("my-gate", {
|
|
143
|
+
fallback: false, // optional — returned if the gate can't be fetched (default: false)
|
|
144
|
+
cacheTtl: 60, // optional — cache duration in seconds (default: 30)
|
|
144
145
|
});
|
|
145
146
|
```
|
|
146
147
|
|
|
147
148
|
### Full gate result
|
|
148
149
|
|
|
149
150
|
```ts
|
|
150
|
-
const result = await n.gateDetails(
|
|
151
|
+
const result = await n.gateDetails("my-gate");
|
|
151
152
|
// { key: 'my-gate', enabled: true, cached: false, fetchedAt: '2025-...' }
|
|
152
153
|
```
|
|
153
154
|
|
|
154
155
|
### Clear the cache
|
|
155
156
|
|
|
156
157
|
```ts
|
|
157
|
-
n.clearGateCache(
|
|
158
|
-
n.clearGateCache();
|
|
158
|
+
n.clearGateCache("my-gate"); // clear a specific gate
|
|
159
|
+
n.clearGateCache(); // clear all gates
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
---
|
|
@@ -164,10 +165,11 @@ n.clearGateCache(); // clear all gates
|
|
|
164
165
|
|
|
165
166
|
```ts
|
|
166
167
|
const n = new Notiformer({
|
|
167
|
-
apiKey:
|
|
168
|
-
silent:
|
|
169
|
-
throwOnError: false,
|
|
170
|
-
onError:
|
|
168
|
+
apiKey: "ntf_live_...", // required — from app.notiformer.com/projects
|
|
169
|
+
silent: false, // optional — true = no API calls (great for local dev)
|
|
170
|
+
throwOnError: false, // optional — true = throws instead of returning null
|
|
171
|
+
onError: (err) => {
|
|
172
|
+
// optional — called when any call fails
|
|
171
173
|
Sentry.captureException(err);
|
|
172
174
|
},
|
|
173
175
|
});
|
|
@@ -178,7 +180,7 @@ const n = new Notiformer({
|
|
|
178
180
|
```ts
|
|
179
181
|
const n = new Notiformer({
|
|
180
182
|
apiKey: process.env.NOTIFORMER_API_KEY!,
|
|
181
|
-
silent: process.env.NODE_ENV !==
|
|
183
|
+
silent: process.env.NODE_ENV !== "production", // no calls in dev/test
|
|
182
184
|
});
|
|
183
185
|
```
|
|
184
186
|
|
|
@@ -186,13 +188,13 @@ const n = new Notiformer({
|
|
|
186
188
|
|
|
187
189
|
## Rate limits & quotas
|
|
188
190
|
|
|
189
|
-
| Limit
|
|
190
|
-
|
|
191
|
-
| Events per minute (per project) | 60
|
|
192
|
-
| Events per month (Free plan)
|
|
193
|
-
| Events per month (Starter)
|
|
194
|
-
| Events per month (Pro)
|
|
195
|
-
| Events per month (Business)
|
|
191
|
+
| Limit | Value |
|
|
192
|
+
| ------------------------------- | ------- |
|
|
193
|
+
| Events per minute (per project) | 60 |
|
|
194
|
+
| Events per month (Free plan) | 100 |
|
|
195
|
+
| Events per month (Starter) | 5,000 |
|
|
196
|
+
| Events per month (Pro) | 75,000 |
|
|
197
|
+
| Events per month (Business) | 300,000 |
|
|
196
198
|
|
|
197
199
|
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
200
|
|
|
@@ -206,12 +208,12 @@ If you exceed your **monthly quota**: the event is rejected with HTTP 429. Upgra
|
|
|
206
208
|
|
|
207
209
|
```ts
|
|
208
210
|
await n.event({
|
|
209
|
-
channel:
|
|
210
|
-
event:
|
|
211
|
+
channel: "payments",
|
|
212
|
+
event: "payment_success",
|
|
211
213
|
description: `${amount} — ${user.email}`,
|
|
212
|
-
icon:
|
|
213
|
-
value:
|
|
214
|
-
notify:
|
|
214
|
+
icon: "💳",
|
|
215
|
+
value: amount,
|
|
216
|
+
notify: true,
|
|
215
217
|
});
|
|
216
218
|
```
|
|
217
219
|
|
|
@@ -221,14 +223,14 @@ await n.event({
|
|
|
221
223
|
// Express error middleware
|
|
222
224
|
app.use(async (err, req, res, next) => {
|
|
223
225
|
await n.event({
|
|
224
|
-
channel:
|
|
225
|
-
event:
|
|
226
|
+
channel: "errors",
|
|
227
|
+
event: "unhandled_error",
|
|
226
228
|
description: err.message,
|
|
227
|
-
icon:
|
|
228
|
-
tags:
|
|
229
|
-
notify:
|
|
229
|
+
icon: "🔴",
|
|
230
|
+
tags: { path: req.path, method: req.method },
|
|
231
|
+
notify: true,
|
|
230
232
|
});
|
|
231
|
-
res.status(500).json({ error:
|
|
233
|
+
res.status(500).json({ error: "Internal server error" });
|
|
232
234
|
});
|
|
233
235
|
```
|
|
234
236
|
|
|
@@ -236,10 +238,10 @@ app.use(async (err, req, res, next) => {
|
|
|
236
238
|
|
|
237
239
|
```ts
|
|
238
240
|
await n.event({
|
|
239
|
-
channel:
|
|
240
|
-
event:
|
|
241
|
-
tags:
|
|
242
|
-
notify:
|
|
241
|
+
channel: "analytics",
|
|
242
|
+
event: "page_view",
|
|
243
|
+
tags: { path: req.path, userId: session.userId },
|
|
244
|
+
notify: false, // stored in feed, no push notification sent
|
|
243
245
|
});
|
|
244
246
|
```
|
|
245
247
|
|
|
@@ -248,7 +250,7 @@ await n.event({
|
|
|
248
250
|
```ts
|
|
249
251
|
// Next.js API route
|
|
250
252
|
export async function POST(req: Request) {
|
|
251
|
-
const useNewFlow = await n.gate(
|
|
253
|
+
const useNewFlow = await n.gate("new-checkout-flow");
|
|
252
254
|
|
|
253
255
|
if (useNewFlow) {
|
|
254
256
|
return newCheckoutHandler(req);
|
|
@@ -262,13 +264,13 @@ export async function POST(req: Request) {
|
|
|
262
264
|
```ts
|
|
263
265
|
// Only notify the CTO for large orders
|
|
264
266
|
await n.event({
|
|
265
|
-
channel:
|
|
266
|
-
event:
|
|
267
|
+
channel: "sales",
|
|
268
|
+
event: "enterprise_signup",
|
|
267
269
|
description: `${company} — ${mrr}/mo`,
|
|
268
|
-
icon:
|
|
269
|
-
value:
|
|
270
|
-
notify:
|
|
271
|
-
recipients:
|
|
270
|
+
icon: "🏢",
|
|
271
|
+
value: mrr,
|
|
272
|
+
notify: true,
|
|
273
|
+
recipients: ["cto@yourcompany.com"], // only they get the push
|
|
272
274
|
});
|
|
273
275
|
```
|
|
274
276
|
|
|
@@ -329,10 +331,11 @@ Content-Type: application/json
|
|
|
329
331
|
```
|
|
330
332
|
|
|
331
333
|
Response:
|
|
334
|
+
|
|
332
335
|
```json
|
|
333
336
|
{
|
|
334
|
-
"id":
|
|
335
|
-
"createdAt":
|
|
337
|
+
"id": "evt_abc123",
|
|
338
|
+
"createdAt": "2025-01-15T10:30:00.000Z",
|
|
336
339
|
"rateLimited": false
|
|
337
340
|
}
|
|
338
341
|
```
|
package/dist/index.js
CHANGED
|
@@ -164,7 +164,7 @@ class Notiformer {
|
|
|
164
164
|
headers: {
|
|
165
165
|
"Content-Type": "application/json",
|
|
166
166
|
Authorization: `Bearer ${this.apiKey}`,
|
|
167
|
-
"X-SDK-Version": "1.0.
|
|
167
|
+
"X-SDK-Version": "1.0.8",
|
|
168
168
|
...((_a = init.headers) !== null && _a !== void 0 ? _a : {}),
|
|
169
169
|
},
|
|
170
170
|
});
|