notiformer 1.0.5 → 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.
Files changed (3) hide show
  1. package/README.md +80 -77
  2. package/dist/index.js +1 -1
  3. package/package.json +6 -3
package/README.md CHANGED
@@ -19,21 +19,21 @@ npm install notiformer
19
19
  ## Quick start
20
20
 
21
21
  ```ts
22
- import { Notiformer } from 'notiformer';
22
+ import { Notiformer } from "notiformer";
23
23
 
24
24
  const n = new Notiformer({
25
- apiKey: 'ntf_live_...', // from app.notiformer.com/projects
25
+ apiKey: "ntf_live_...", // from app.notiformer.com/projects
26
26
  });
27
27
 
28
28
  await n.event({
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)
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: '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"
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 | Behaviour |
72
- |---|---|
73
- | `true` (default) | Sends push notification to subscribed members |
74
- | `false` | Stores the event silently for analytics — no notification sent |
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: '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
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 | Max recipients per event |
112
- |---|---|
113
- | Free | 1 |
114
- | Starter | 3 |
115
- | Pro | 10 |
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('new-checkout-flow');
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('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)
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('my-gate');
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('my-gate'); // clear a specific gate
158
- n.clearGateCache(); // clear all gates
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: '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
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 !== 'production', // no calls in dev/test
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 | 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 |
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: 'payments',
210
- event: 'payment_success',
211
+ channel: "payments",
212
+ event: "payment_success",
211
213
  description: `${amount} — ${user.email}`,
212
- icon: '💳',
213
- value: amount,
214
- notify: true,
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: 'errors',
225
- event: 'unhandled_error',
226
+ channel: "errors",
227
+ event: "unhandled_error",
226
228
  description: err.message,
227
- icon: '🔴',
228
- tags: { path: req.path, method: req.method },
229
- notify: true,
229
+ icon: "🔴",
230
+ tags: { path: req.path, method: req.method },
231
+ notify: true,
230
232
  });
231
- res.status(500).json({ error: 'Internal server 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: 'analytics',
240
- event: 'page_view',
241
- tags: { path: req.path, userId: session.userId },
242
- notify: false, // stored in feed, no push notification sent
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('new-checkout-flow');
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: 'sales',
266
- event: 'enterprise_signup',
267
+ channel: "sales",
268
+ event: "enterprise_signup",
267
269
  description: `${company} — ${mrr}/mo`,
268
- icon: '🏢',
269
- value: mrr,
270
- notify: true,
271
- recipients: ['cto@yourcompany.com'], // only they get the push
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": "evt_abc123",
335
- "createdAt": "2025-01-15T10:30:00.000Z",
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.5",
167
+ "X-SDK-Version": "1.0.8",
168
168
  ...((_a = init.headers) !== null && _a !== void 0 ? _a : {}),
169
169
  },
170
170
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "notiformer",
3
- "version": "1.0.5",
3
+ "version": "1.0.8",
4
4
  "description": "Real-time alerts, notifications and feature gates for your backend code",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,9 +26,12 @@
26
26
  "license": "MIT",
27
27
  "repository": {
28
28
  "type": "git",
29
- "url": "https://github.com/notiformer/notiformer-node"
29
+ "url": "https://github.com/notiformer/notiformer"
30
+ },
31
+ "homepage": "https://docs.notiformer.com",
32
+ "bugs": {
33
+ "url": "https://github.com/notiformer/notiformer/issues"
30
34
  },
31
- "homepage": "https://notiformer.com",
32
35
  "devDependencies": {
33
36
  "typescript": "^5.3.3"
34
37
  },