notiformer 1.0.1 → 1.0.2
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 +55 -120
- package/dist/index.d.ts +21 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +105 -139
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +39 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# notiformer
|
|
2
2
|
|
|
3
|
-
Real-time alerts
|
|
3
|
+
Real-time alerts and feature gates for your backend code.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Get notified instantly via push, email and more whenever something important happens in your app.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Server-side only.** Do not use in browser/frontend code — your API key would be exposed publicly. Use in Node.js, Express, Next.js API routes, serverless functions, etc.
|
|
6
8
|
|
|
7
9
|
---
|
|
8
10
|
|
|
@@ -19,95 +21,69 @@ npm install notiformer
|
|
|
19
21
|
```ts
|
|
20
22
|
import { Notiformer } from 'notiformer';
|
|
21
23
|
|
|
24
|
+
// Get your API key at https://app.notiformer.com/projects
|
|
22
25
|
const n = new Notiformer({
|
|
23
|
-
apiKey: '
|
|
26
|
+
apiKey: 'ntf_live_test', // ← replace this with your real key
|
|
24
27
|
});
|
|
25
28
|
|
|
26
|
-
// Send an event + notification
|
|
27
29
|
await n.event({
|
|
28
30
|
channel: 'payments',
|
|
29
31
|
event: 'payment_success',
|
|
30
|
-
description:
|
|
32
|
+
description: '$49.00 — john@example.com',
|
|
31
33
|
icon: '💳',
|
|
32
|
-
tags: { userId: 'usr_123', plan: 'pro' },
|
|
33
34
|
notify: true,
|
|
34
35
|
});
|
|
35
36
|
```
|
|
36
37
|
|
|
38
|
+
> Running with `apiKey: 'ntf_live_test'` will print a setup message in your console explaining how to get your real key. No events will be sent until you replace it.
|
|
39
|
+
|
|
37
40
|
---
|
|
38
41
|
|
|
39
|
-
##
|
|
42
|
+
## Get your API key
|
|
43
|
+
|
|
44
|
+
1. Go to [app.notiformer.com/projects](https://app.notiformer.com/projects)
|
|
45
|
+
2. Create or open a project
|
|
46
|
+
3. Copy the API key
|
|
47
|
+
4. Replace `'ntf_live_test'` in your code
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Events
|
|
42
52
|
|
|
43
53
|
```ts
|
|
44
54
|
await n.event({
|
|
45
|
-
channel: 'auth',
|
|
46
|
-
event: 'user_signup',
|
|
55
|
+
channel: 'auth', // groups related events (auto-created on first use)
|
|
56
|
+
event: 'user_signup', // machine-readable name
|
|
47
57
|
description: 'New signup via Google',
|
|
48
58
|
icon: '🎉',
|
|
49
59
|
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
value: '42nd user', // shown in the dashboard feed
|
|
60
|
+
tags: { method: 'google', plan: 'free' }, // optional metadata
|
|
61
|
+
value: '42nd user', // optional value shown in the feed
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
notify: true,
|
|
57
|
-
|
|
58
|
-
// Rate limiting: events with the same groupId are deduplicated
|
|
59
|
-
groupId: 'signup-batch-today',
|
|
63
|
+
notify: true, // true → triggers push/email notifications
|
|
64
|
+
// false → silent log for analytics only
|
|
60
65
|
});
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
`event()` **never throws**. If the network is down or the API returns an error, it logs a warning and returns `null`. Your app continues running.
|
|
68
|
+
`event()` **never throws** by default. If something goes wrong it logs a warning and returns `null` — a failed notification should never crash your app.
|
|
66
69
|
|
|
67
70
|
---
|
|
68
71
|
|
|
69
72
|
## Feature Gates
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
Toggle features remotely from your Notiformer dashboard without redeploying.
|
|
72
75
|
|
|
73
76
|
```ts
|
|
74
77
|
const isEnabled = await n.gate('new-checkout-flow');
|
|
75
78
|
|
|
76
79
|
if (isEnabled) {
|
|
77
|
-
// run new
|
|
80
|
+
// run new feature
|
|
78
81
|
} else {
|
|
79
|
-
// run
|
|
82
|
+
// run old feature
|
|
80
83
|
}
|
|
81
84
|
```
|
|
82
85
|
|
|
83
|
-
Gates are cached
|
|
84
|
-
|
|
85
|
-
```ts
|
|
86
|
-
// Custom fallback and cache TTL
|
|
87
|
-
const isEnabled = await n.gate('my-feature', {
|
|
88
|
-
fallback: false, // returned if network fails
|
|
89
|
-
cacheTtl: 60, // cache for 60 seconds (0 = disable)
|
|
90
|
-
});
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Full gate details
|
|
94
|
-
|
|
95
|
-
```ts
|
|
96
|
-
const result = await n.gateDetails('my-feature');
|
|
97
|
-
// {
|
|
98
|
-
// key: 'my-feature',
|
|
99
|
-
// enabled: true,
|
|
100
|
-
// cached: false,
|
|
101
|
-
// fetchedAt: '2025-04-20T10:00:00.000Z'
|
|
102
|
-
// }
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Force a fresh fetch
|
|
106
|
-
|
|
107
|
-
```ts
|
|
108
|
-
n.clearGateCache('my-feature'); // clear one gate
|
|
109
|
-
n.clearGateCache(); // clear all
|
|
110
|
-
```
|
|
86
|
+
Gates are cached for 30 seconds by default to minimise API calls.
|
|
111
87
|
|
|
112
88
|
---
|
|
113
89
|
|
|
@@ -115,17 +91,17 @@ n.clearGateCache(); // clear all
|
|
|
115
91
|
|
|
116
92
|
```ts
|
|
117
93
|
const n = new Notiformer({
|
|
118
|
-
apiKey: 'ntf_live_...',
|
|
94
|
+
apiKey: 'ntf_live_...', // required — from app.notiformer.com/projects
|
|
119
95
|
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
96
|
+
silent: false, // true = no calls made (useful for local dev)
|
|
97
|
+
throwOnError: false, // true = throws instead of returning null
|
|
98
|
+
onError: (err) => { // called on any failed call
|
|
99
|
+
console.error(err.message);
|
|
100
|
+
},
|
|
125
101
|
});
|
|
126
102
|
```
|
|
127
103
|
|
|
128
|
-
### Silence in development
|
|
104
|
+
### Silence in local development
|
|
129
105
|
|
|
130
106
|
```ts
|
|
131
107
|
const n = new Notiformer({
|
|
@@ -138,7 +114,7 @@ const n = new Notiformer({
|
|
|
138
114
|
|
|
139
115
|
## Common patterns
|
|
140
116
|
|
|
141
|
-
### Alert on errors
|
|
117
|
+
### Alert on unhandled errors
|
|
142
118
|
|
|
143
119
|
```ts
|
|
144
120
|
app.use(async (err, req, res, next) => {
|
|
@@ -147,94 +123,54 @@ app.use(async (err, req, res, next) => {
|
|
|
147
123
|
event: 'unhandled_error',
|
|
148
124
|
description: err.message,
|
|
149
125
|
icon: '🔴',
|
|
150
|
-
tags: {
|
|
151
|
-
path: req.path,
|
|
152
|
-
method: req.method,
|
|
153
|
-
status: 500,
|
|
154
|
-
},
|
|
126
|
+
tags: { path: req.path, status: 500 },
|
|
155
127
|
notify: true,
|
|
156
128
|
});
|
|
157
129
|
res.status(500).json({ error: 'Internal server error' });
|
|
158
130
|
});
|
|
159
131
|
```
|
|
160
132
|
|
|
161
|
-
### Track
|
|
133
|
+
### Track a payment
|
|
162
134
|
|
|
163
135
|
```ts
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
notify: true,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
136
|
+
await n.event({
|
|
137
|
+
channel: 'payments',
|
|
138
|
+
event: 'payment_success',
|
|
139
|
+
description: `${amount} — ${user.email}`,
|
|
140
|
+
icon: '💳',
|
|
141
|
+
value: amount,
|
|
142
|
+
notify: true,
|
|
143
|
+
});
|
|
175
144
|
```
|
|
176
145
|
|
|
177
|
-
### Feature gate
|
|
146
|
+
### Feature gate
|
|
178
147
|
|
|
179
148
|
```ts
|
|
180
149
|
app.post('/checkout', async (req, res) => {
|
|
181
150
|
const useNewFlow = await n.gate('new-checkout-flow');
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
return legacyCheckoutHandler(req, res);
|
|
151
|
+
return useNewFlow
|
|
152
|
+
? newCheckoutHandler(req, res)
|
|
153
|
+
: legacyCheckoutHandler(req, res);
|
|
187
154
|
});
|
|
188
155
|
```
|
|
189
156
|
|
|
190
157
|
### Silent analytics (no notification)
|
|
191
158
|
|
|
192
159
|
```ts
|
|
193
|
-
// Log for analytics without pushing a notification
|
|
194
160
|
await n.event({
|
|
195
161
|
channel: 'monitoring',
|
|
196
162
|
event: 'page_view',
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
notify: false, // ← silent
|
|
163
|
+
tags: { path: req.path },
|
|
164
|
+
notify: false, // ← no notification, just logged
|
|
200
165
|
});
|
|
201
166
|
```
|
|
202
167
|
|
|
203
168
|
---
|
|
204
169
|
|
|
205
|
-
## TypeScript
|
|
206
|
-
|
|
207
|
-
Full TypeScript support included. All types are exported:
|
|
208
|
-
|
|
209
|
-
```ts
|
|
210
|
-
import type {
|
|
211
|
-
NotiformerConfig,
|
|
212
|
-
EventPayload,
|
|
213
|
-
EventResponse,
|
|
214
|
-
GateOptions,
|
|
215
|
-
GateResult,
|
|
216
|
-
} from 'notiformer';
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
170
|
## Requirements
|
|
222
171
|
|
|
223
|
-
- Node.js
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
### Node 16 fetch polyfill
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
npm install node-fetch
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
```ts
|
|
233
|
-
import fetch from 'node-fetch';
|
|
234
|
-
(global as any).fetch = fetch;
|
|
235
|
-
|
|
236
|
-
import { Notiformer } from 'notiformer';
|
|
237
|
-
```
|
|
172
|
+
- Node.js 18+ (uses native `fetch`)
|
|
173
|
+
- For Node 16: install `node-fetch` and polyfill `global.fetch`
|
|
238
174
|
|
|
239
175
|
---
|
|
240
176
|
|
|
@@ -242,4 +178,3 @@ import { Notiformer } from 'notiformer';
|
|
|
242
178
|
|
|
243
179
|
- Dashboard: [app.notiformer.com](https://app.notiformer.com)
|
|
244
180
|
- Docs: [docs.notiformer.com](https://docs.notiformer.com)
|
|
245
|
-
- Support: support@notiformer.com
|
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Notiformer
|
|
2
|
+
* Notiformer — Real-time alerts and feature gates for your code.
|
|
3
3
|
*
|
|
4
|
-
* ⚠️
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* ⚠️ SERVER-SIDE ONLY. Do not use in browser/frontend code.
|
|
5
|
+
* Your API key would be exposed publicly.
|
|
6
|
+
* Use in: Node.js, Express, Next.js API routes, serverless functions.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
|
-
* ```ts
|
|
10
9
|
* import { Notiformer } from 'notiformer';
|
|
11
10
|
*
|
|
12
|
-
* const n = new Notiformer({
|
|
11
|
+
* const n = new Notiformer({
|
|
12
|
+
* apiKey: 'ntf_live_xxxxxxxxxxxxxxxx', // from app.notiformer.com/projects
|
|
13
|
+
* });
|
|
13
14
|
*
|
|
14
15
|
* await n.event({
|
|
15
16
|
* channel: 'payments',
|
|
16
17
|
* event: 'payment_success',
|
|
17
|
-
* description: '$49.00 —
|
|
18
|
+
* description: '$49.00 — john@example.com',
|
|
18
19
|
* icon: '💳',
|
|
19
20
|
* notify: true,
|
|
20
21
|
* });
|
|
21
|
-
* ```
|
|
22
22
|
*/
|
|
23
23
|
import type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult } from "./types";
|
|
24
24
|
export type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult, };
|
|
@@ -31,35 +31,31 @@ export declare class Notiformer {
|
|
|
31
31
|
private readonly onError?;
|
|
32
32
|
private readonly logger;
|
|
33
33
|
private readonly gateCache;
|
|
34
|
+
private readonly isPlaceholder;
|
|
34
35
|
constructor(config: NotiformerConfig);
|
|
35
36
|
/**
|
|
36
|
-
* Send an event
|
|
37
|
-
* dashboard settings.
|
|
38
|
-
*
|
|
39
|
-
* By default this never throws — a failed notification should never
|
|
40
|
-
* crash your app. Set `throwOnError: true` in config if you need exceptions.
|
|
37
|
+
* Send an event and optionally trigger a notification.
|
|
41
38
|
*
|
|
42
|
-
*
|
|
39
|
+
* Safe to use anywhere in your code — never throws by default.
|
|
40
|
+
* Returns null if the call fails (and calls onError if configured).
|
|
43
41
|
*/
|
|
44
42
|
event(payload: EventPayload): Promise<EventResponse | null>;
|
|
45
43
|
/**
|
|
46
44
|
* Check whether a feature gate is enabled.
|
|
47
|
-
*
|
|
45
|
+
* Cached locally for 30 seconds by default.
|
|
48
46
|
*
|
|
49
|
-
* Returns
|
|
47
|
+
* Returns fallback (false) if the call fails.
|
|
50
48
|
*/
|
|
51
49
|
gate(key: string, options?: GateOptions): Promise<boolean>;
|
|
52
|
-
/**
|
|
53
|
-
* Like gate() but returns the full result object with metadata.
|
|
54
|
-
*/
|
|
50
|
+
/** Full gate result with metadata */
|
|
55
51
|
gateDetails(key: string, options?: GateOptions): Promise<GateResult>;
|
|
56
|
-
/**
|
|
57
|
-
* Clears the in-memory gate cache.
|
|
58
|
-
* Pass a key to clear only that gate, or no args to clear all.
|
|
59
|
-
*/
|
|
52
|
+
/** Clear cached gate values */
|
|
60
53
|
clearGateCache(key?: string): void;
|
|
61
|
-
private
|
|
62
|
-
private
|
|
54
|
+
private post;
|
|
55
|
+
private get;
|
|
56
|
+
private request;
|
|
57
|
+
private fail;
|
|
58
|
+
private friendlyNetworkError;
|
|
63
59
|
}
|
|
64
60
|
export default Notiformer;
|
|
65
61
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;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;AAQF,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;IAwCpC;;;;;OAKG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAkDjE;;;;;OAKG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBpE,qCAAqC;IAC/B,WAAW,CACf,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;IAKtB,+BAA+B;IAC/B,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;YAQpB,IAAI;YAOJ,GAAG;YAIH,OAAO;IAmBrB,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,oBAAoB;CAuB7B;AAED,eAAe,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,124 +1,111 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Notiformer
|
|
3
|
+
* Notiformer — Real-time alerts and feature gates for your code.
|
|
4
4
|
*
|
|
5
|
-
* ⚠️
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* ⚠️ SERVER-SIDE ONLY. Do not use in browser/frontend code.
|
|
6
|
+
* Your API key would be exposed publicly.
|
|
7
|
+
* Use in: Node.js, Express, Next.js API routes, serverless functions.
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
10
|
-
* ```ts
|
|
11
10
|
* import { Notiformer } from 'notiformer';
|
|
12
11
|
*
|
|
13
|
-
* const n = new Notiformer({
|
|
12
|
+
* const n = new Notiformer({
|
|
13
|
+
* apiKey: 'ntf_live_xxxxxxxxxxxxxxxx', // from app.notiformer.com/projects
|
|
14
|
+
* });
|
|
14
15
|
*
|
|
15
16
|
* await n.event({
|
|
16
17
|
* channel: 'payments',
|
|
17
18
|
* event: 'payment_success',
|
|
18
|
-
* description: '$49.00 —
|
|
19
|
+
* description: '$49.00 — john@example.com',
|
|
19
20
|
* icon: '💳',
|
|
20
21
|
* notify: true,
|
|
21
22
|
* });
|
|
22
|
-
* ```
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.Notiformer = void 0;
|
|
26
26
|
const logger_1 = require("./logger");
|
|
27
27
|
const cache_1 = require("./cache");
|
|
28
|
-
|
|
29
|
-
const
|
|
28
|
+
// The placeholder key shown in docs — triggers a friendly setup message
|
|
29
|
+
const PLACEHOLDER_KEY = "ntf_live_test";
|
|
30
|
+
const API_URL = "https://api.notiformer.com";
|
|
31
|
+
const DEFAULT_TIMEOUT = 8000;
|
|
30
32
|
const DEFAULT_GATE_TTL = 30;
|
|
31
33
|
class Notiformer {
|
|
32
34
|
constructor(config) {
|
|
33
|
-
|
|
34
|
-
var _a, _b, _c, _d, _e;
|
|
35
|
+
var _a, _b, _c;
|
|
35
36
|
if (!config.apiKey) {
|
|
36
|
-
throw new Error("[notiformer]
|
|
37
|
-
"Get
|
|
38
|
-
}
|
|
39
|
-
if (!config.apiKey.startsWith("ntf_")) {
|
|
40
|
-
console.warn("[notiformer] ⚠️ Invalid API key format.\n" +
|
|
41
|
-
'Your key should start with "ntf_live_" or "ntf_test_".\n' +
|
|
42
|
-
"Get a valid key at https://app.notiformer.com/projects");
|
|
43
|
-
}
|
|
44
|
-
const resolvedUrl = ((_a = config.baseUrl) !== null && _a !== void 0 ? _a : PLACEHOLDER_URL).replace(/\/$/, "");
|
|
45
|
-
if (resolvedUrl === PLACEHOLDER_URL) {
|
|
46
|
-
console.warn("[notiformer] ⚠️ No baseUrl configured — using placeholder URL.\n" +
|
|
47
|
-
"The SDK will not work until you set your real Cloud Functions URL.\n" +
|
|
48
|
-
"\n" +
|
|
49
|
-
"Fix: pass your URL when initializing:\n" +
|
|
50
|
-
" new Notiformer({\n" +
|
|
51
|
-
' apiKey: "ntf_live_...",\n' +
|
|
52
|
-
' baseUrl: "https://YOUR_REGION-YOUR_PROJECT.cloudfunctions.net",\n' +
|
|
53
|
-
" })\n" +
|
|
54
|
-
"\n" +
|
|
55
|
-
"Find your URL in: Firebase Console → Functions → your function URL");
|
|
37
|
+
throw new Error("[notiformer] apiKey is required.\n" +
|
|
38
|
+
"→ Get yours at https://app.notiformer.com/projects");
|
|
56
39
|
}
|
|
57
|
-
|
|
40
|
+
this.isPlaceholder = config.apiKey === PLACEHOLDER_KEY;
|
|
58
41
|
this.apiKey = config.apiKey;
|
|
59
|
-
this.baseUrl =
|
|
60
|
-
this.timeout =
|
|
61
|
-
this.silent = (
|
|
62
|
-
this.throwOnError = (
|
|
42
|
+
this.baseUrl = ((_a = config._baseUrl) !== null && _a !== void 0 ? _a : API_URL).replace(/\/$/, "");
|
|
43
|
+
this.timeout = DEFAULT_TIMEOUT;
|
|
44
|
+
this.silent = (_b = config.silent) !== null && _b !== void 0 ? _b : false;
|
|
45
|
+
this.throwOnError = (_c = config.throwOnError) !== null && _c !== void 0 ? _c : false;
|
|
63
46
|
this.onError = config.onError;
|
|
64
|
-
this.logger = new logger_1.Logger(
|
|
47
|
+
this.logger = new logger_1.Logger("warn");
|
|
65
48
|
this.gateCache = new cache_1.GateCache();
|
|
66
|
-
this.
|
|
49
|
+
if (this.isPlaceholder) {
|
|
50
|
+
console.warn("\n" +
|
|
51
|
+
"┌─────────────────────────────────────────────────────┐\n" +
|
|
52
|
+
"│ notiformer — setup required │\n" +
|
|
53
|
+
"├─────────────────────────────────────────────────────┤\n" +
|
|
54
|
+
'│ You are using the example API key "ntf_live_test". │\n' +
|
|
55
|
+
"│ Events will not be sent until you use a real key. │\n" +
|
|
56
|
+
"│ │\n" +
|
|
57
|
+
"│ 1. Go to https://app.notiformer.com/projects │\n" +
|
|
58
|
+
"│ 2. Create or open a project │\n" +
|
|
59
|
+
"│ 3. Copy your API key │\n" +
|
|
60
|
+
'│ 4. Replace "ntf_live_test" with your real key │\n' +
|
|
61
|
+
"└─────────────────────────────────────────────────────┘\n");
|
|
62
|
+
}
|
|
67
63
|
}
|
|
68
64
|
// ─────────────────────────────────────────────────────────────
|
|
69
65
|
// event()
|
|
70
66
|
// ─────────────────────────────────────────────────────────────
|
|
71
67
|
/**
|
|
72
|
-
* Send an event
|
|
73
|
-
* dashboard settings.
|
|
74
|
-
*
|
|
75
|
-
* By default this never throws — a failed notification should never
|
|
76
|
-
* crash your app. Set `throwOnError: true` in config if you need exceptions.
|
|
68
|
+
* Send an event and optionally trigger a notification.
|
|
77
69
|
*
|
|
78
|
-
*
|
|
70
|
+
* Safe to use anywhere in your code — never throws by default.
|
|
71
|
+
* Returns null if the call fails (and calls onError if configured).
|
|
79
72
|
*/
|
|
80
73
|
async event(payload) {
|
|
81
|
-
var _a;
|
|
82
|
-
if (this.silent) {
|
|
83
|
-
this.logger.info("Silent mode: event suppressed", payload);
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
74
|
+
var _a, _b;
|
|
86
75
|
if (!payload.channel)
|
|
87
76
|
throw new Error("[notiformer] event.channel is required.");
|
|
88
77
|
if (!payload.event)
|
|
89
78
|
throw new Error("[notiformer] event.event is required.");
|
|
90
|
-
|
|
79
|
+
// Placeholder key — log a clear message, do not attempt the call
|
|
80
|
+
if (this.isPlaceholder) {
|
|
81
|
+
console.warn('[notiformer] Event not sent — you are using the example key "ntf_live_test".\n' +
|
|
82
|
+
"→ Replace it with your real API key from https://app.notiformer.com/projects");
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (this.silent) {
|
|
86
|
+
this.logger.info("Silent mode: event suppressed.");
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
91
89
|
try {
|
|
92
|
-
const res = await this.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
value: payload.value,
|
|
101
|
-
notify: (_a = payload.notify) !== null && _a !== void 0 ? _a : true,
|
|
102
|
-
groupId: payload.groupId,
|
|
103
|
-
}),
|
|
90
|
+
const res = await this.post("/v1/events", {
|
|
91
|
+
channel: payload.channel,
|
|
92
|
+
event: payload.event,
|
|
93
|
+
description: payload.description,
|
|
94
|
+
icon: payload.icon,
|
|
95
|
+
tags: payload.tags,
|
|
96
|
+
value: payload.value,
|
|
97
|
+
notify: (_a = payload.notify) !== null && _a !== void 0 ? _a : true,
|
|
104
98
|
});
|
|
105
99
|
if (!res.ok) {
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}));
|
|
110
|
-
const err = new Error(`[notiformer] Event failed: ${errBody.error} (${errBody.code})`);
|
|
111
|
-
return this.handleError(err, "event", payload);
|
|
100
|
+
const body = await res
|
|
101
|
+
.json()
|
|
102
|
+
.catch(() => ({ error: `HTTP ${res.status}` }));
|
|
103
|
+
return this.fail(new Error(`[notiformer] ${(_b = body.error) !== null && _b !== void 0 ? _b : res.statusText}`));
|
|
112
104
|
}
|
|
113
|
-
|
|
114
|
-
this.logger.debug("Event sent successfully", data);
|
|
115
|
-
return data;
|
|
105
|
+
return (await res.json());
|
|
116
106
|
}
|
|
117
107
|
catch (err) {
|
|
118
|
-
|
|
119
|
-
// Detect the most common misconfigurations and give a clear message
|
|
120
|
-
const friendlyError = enrichError(error, this.baseUrl);
|
|
121
|
-
return this.handleError(friendlyError, "event", payload);
|
|
108
|
+
return this.fail(this.friendlyNetworkError(err));
|
|
122
109
|
}
|
|
123
110
|
}
|
|
124
111
|
// ─────────────────────────────────────────────────────────────
|
|
@@ -126,9 +113,9 @@ class Notiformer {
|
|
|
126
113
|
// ─────────────────────────────────────────────────────────────
|
|
127
114
|
/**
|
|
128
115
|
* Check whether a feature gate is enabled.
|
|
129
|
-
*
|
|
116
|
+
* Cached locally for 30 seconds by default.
|
|
130
117
|
*
|
|
131
|
-
* Returns
|
|
118
|
+
* Returns fallback (false) if the call fails.
|
|
132
119
|
*/
|
|
133
120
|
async gate(key, options = {}) {
|
|
134
121
|
var _a, _b;
|
|
@@ -136,55 +123,45 @@ class Notiformer {
|
|
|
136
123
|
throw new Error("[notiformer] gate key is required.");
|
|
137
124
|
const fallback = (_a = options.fallback) !== null && _a !== void 0 ? _a : false;
|
|
138
125
|
const ttl = (_b = options.cacheTtl) !== null && _b !== void 0 ? _b : DEFAULT_GATE_TTL;
|
|
139
|
-
if (this.silent)
|
|
126
|
+
if (this.isPlaceholder || this.silent)
|
|
140
127
|
return fallback;
|
|
141
128
|
const cached = this.gateCache.get(key);
|
|
142
|
-
if (cached !== null)
|
|
143
|
-
this.logger.debug(`Gate "${key}" from cache: ${cached}`);
|
|
129
|
+
if (cached !== null)
|
|
144
130
|
return cached;
|
|
145
|
-
}
|
|
146
131
|
try {
|
|
147
|
-
const res = await this.
|
|
148
|
-
if (!res.ok)
|
|
149
|
-
this.logger.warn(`Gate "${key}" fetch failed (${res.status}), using fallback: ${fallback}`);
|
|
132
|
+
const res = await this.get(`/v1/gates/${encodeURIComponent(key)}`);
|
|
133
|
+
if (!res.ok)
|
|
150
134
|
return fallback;
|
|
151
|
-
|
|
152
|
-
const data = await res.json();
|
|
135
|
+
const data = (await res.json());
|
|
153
136
|
this.gateCache.set(key, data.enabled, ttl);
|
|
154
137
|
return data.enabled;
|
|
155
138
|
}
|
|
156
|
-
catch (
|
|
157
|
-
const error = enrichError(toError(err), this.baseUrl);
|
|
158
|
-
this.handleError(error, "gate", { key });
|
|
139
|
+
catch (_c) {
|
|
159
140
|
return fallback;
|
|
160
141
|
}
|
|
161
142
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Like gate() but returns the full result object with metadata.
|
|
164
|
-
*/
|
|
143
|
+
/** Full gate result with metadata */
|
|
165
144
|
async gateDetails(key, options = {}) {
|
|
166
145
|
const enabled = await this.gate(key, options);
|
|
167
146
|
return { key, enabled, cached: false, fetchedAt: new Date().toISOString() };
|
|
168
147
|
}
|
|
169
|
-
/**
|
|
170
|
-
* Clears the in-memory gate cache.
|
|
171
|
-
* Pass a key to clear only that gate, or no args to clear all.
|
|
172
|
-
*/
|
|
148
|
+
/** Clear cached gate values */
|
|
173
149
|
clearGateCache(key) {
|
|
174
150
|
key ? this.gateCache.delete(key) : this.gateCache.clear();
|
|
175
151
|
}
|
|
176
152
|
// ─────────────────────────────────────────────────────────────
|
|
177
|
-
// Private
|
|
153
|
+
// Private
|
|
178
154
|
// ─────────────────────────────────────────────────────────────
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
throw error;
|
|
185
|
-
return null;
|
|
155
|
+
async post(path, body) {
|
|
156
|
+
return this.request(path, {
|
|
157
|
+
method: "POST",
|
|
158
|
+
body: JSON.stringify(body),
|
|
159
|
+
});
|
|
186
160
|
}
|
|
187
|
-
async
|
|
161
|
+
async get(path) {
|
|
162
|
+
return this.request(path, { method: "GET" });
|
|
163
|
+
}
|
|
164
|
+
async request(path, init) {
|
|
188
165
|
var _a;
|
|
189
166
|
const controller = new AbortController();
|
|
190
167
|
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
@@ -195,8 +172,7 @@ class Notiformer {
|
|
|
195
172
|
headers: {
|
|
196
173
|
"Content-Type": "application/json",
|
|
197
174
|
Authorization: `Bearer ${this.apiKey}`,
|
|
198
|
-
"X-SDK-Version": "1.0.
|
|
199
|
-
"X-SDK-Language": "node",
|
|
175
|
+
"X-SDK-Version": "1.0.2",
|
|
200
176
|
...((_a = init.headers) !== null && _a !== void 0 ? _a : {}),
|
|
201
177
|
},
|
|
202
178
|
});
|
|
@@ -205,39 +181,29 @@ class Notiformer {
|
|
|
205
181
|
clearTimeout(timer);
|
|
206
182
|
}
|
|
207
183
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Converts generic network errors into actionable messages.
|
|
218
|
-
*/
|
|
219
|
-
function enrichError(error, baseUrl) {
|
|
220
|
-
const msg = error.message.toLowerCase();
|
|
221
|
-
if (msg.includes("failed to fetch") ||
|
|
222
|
-
msg.includes("err_name_not_resolved") ||
|
|
223
|
-
msg.includes("enotfound") ||
|
|
224
|
-
msg.includes("network")) {
|
|
225
|
-
if (baseUrl === PLACEHOLDER_URL) {
|
|
226
|
-
return new Error("[notiformer] Cannot reach the API — you are using the placeholder URL.\n" +
|
|
227
|
-
"Set your real Cloud Functions URL:\n" +
|
|
228
|
-
" new Notiformer({\n" +
|
|
229
|
-
' apiKey: "ntf_live_...",\n' +
|
|
230
|
-
' baseUrl: "https://YOUR_REGION-YOUR_PROJECT.cloudfunctions.net",\n' +
|
|
231
|
-
" })");
|
|
232
|
-
}
|
|
233
|
-
return new Error(`[notiformer] Network error — cannot reach ${baseUrl}\n` +
|
|
234
|
-
"Check that your baseUrl is correct and that the server is running.");
|
|
184
|
+
fail(error) {
|
|
185
|
+
var _a;
|
|
186
|
+
this.logger.error(error.message);
|
|
187
|
+
(_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
188
|
+
if (this.throwOnError)
|
|
189
|
+
throw error;
|
|
190
|
+
return null;
|
|
235
191
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
192
|
+
friendlyNetworkError(err) {
|
|
193
|
+
const msg = err instanceof Error ? err.message.toLowerCase() : "";
|
|
194
|
+
if (msg.includes("aborted") || msg.includes("timeout")) {
|
|
195
|
+
return new Error(`[notiformer] Request timed out after ${this.timeout / 1000}s.\n` +
|
|
196
|
+
"Check your internet connection or try again later.");
|
|
197
|
+
}
|
|
198
|
+
if (msg.includes("failed to fetch") ||
|
|
199
|
+
msg.includes("enotfound") ||
|
|
200
|
+
msg.includes("network")) {
|
|
201
|
+
return new Error("[notiformer] Cannot reach the Notiformer API.\n" +
|
|
202
|
+
"Check your internet connection. If the problem persists, visit https://status.notiformer.com");
|
|
203
|
+
}
|
|
204
|
+
return err instanceof Error ? err : new Error(String(err));
|
|
239
205
|
}
|
|
240
|
-
return error;
|
|
241
206
|
}
|
|
207
|
+
exports.Notiformer = Notiformer;
|
|
242
208
|
exports.default = Notiformer;
|
|
243
209
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,42 +1,67 @@
|
|
|
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
|
+
*/
|
|
2
9
|
apiKey: string;
|
|
3
|
-
|
|
4
|
-
|
|
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
|
+
*/
|
|
5
20
|
silent?: boolean;
|
|
6
|
-
logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'none';
|
|
7
21
|
/**
|
|
8
|
-
* Called
|
|
9
|
-
* Use this to
|
|
22
|
+
* Called when an event() or gate() call fails.
|
|
23
|
+
* Use this to forward errors to your own logging system.
|
|
24
|
+
*
|
|
10
25
|
* @example
|
|
11
|
-
* onError: (err) =>
|
|
26
|
+
* onError: (err) => console.error('[notiformer]', err.message)
|
|
12
27
|
*/
|
|
13
|
-
onError?: (error: Error
|
|
14
|
-
method: string;
|
|
15
|
-
payload?: unknown;
|
|
16
|
-
}) => void;
|
|
28
|
+
onError?: (error: Error) => void;
|
|
17
29
|
/**
|
|
18
|
-
* If true,
|
|
19
|
-
*
|
|
20
|
-
* Default: false (recommended — a failed notification should never crash your app)
|
|
30
|
+
* If true, throws on failure instead of returning null silently.
|
|
31
|
+
* Default: false — a failed notification should never crash your app.
|
|
21
32
|
*/
|
|
22
33
|
throwOnError?: boolean;
|
|
34
|
+
/** @internal — do not use in production */
|
|
35
|
+
_baseUrl?: string;
|
|
23
36
|
}
|
|
24
37
|
export interface EventPayload {
|
|
38
|
+
/** Channel name. Groups related events. Created automatically. e.g. 'payments', 'errors' */
|
|
25
39
|
channel: string;
|
|
40
|
+
/** Event name. e.g. 'user_signed_up', 'payment_failed' */
|
|
26
41
|
event: string;
|
|
42
|
+
/** Human-readable description shown in the dashboard */
|
|
27
43
|
description?: string;
|
|
44
|
+
/** Emoji icon shown in the feed */
|
|
28
45
|
icon?: string;
|
|
46
|
+
/** Optional key/value metadata for filtering */
|
|
29
47
|
tags?: Record<string, string | number | boolean>;
|
|
48
|
+
/** A value to display alongside the event. e.g. '$49.00' */
|
|
30
49
|
value?: string | number;
|
|
50
|
+
/**
|
|
51
|
+
* If true, triggers your configured notifications (push, email…).
|
|
52
|
+
* If false, logs silently for analytics only.
|
|
53
|
+
* @default true
|
|
54
|
+
*/
|
|
31
55
|
notify?: boolean;
|
|
32
|
-
groupId?: string;
|
|
33
56
|
}
|
|
34
57
|
export interface EventResponse {
|
|
35
58
|
id: string;
|
|
36
59
|
createdAt: string;
|
|
37
60
|
}
|
|
38
61
|
export interface GateOptions {
|
|
62
|
+
/** Returned if the request fails. @default false */
|
|
39
63
|
fallback?: boolean;
|
|
64
|
+
/** Cache duration in seconds. 0 to disable. @default 30 */
|
|
40
65
|
cacheTtl?: number;
|
|
41
66
|
}
|
|
42
67
|
export interface GateResult {
|
|
@@ -45,9 +70,5 @@ export interface GateResult {
|
|
|
45
70
|
cached: boolean;
|
|
46
71
|
fetchedAt: string;
|
|
47
72
|
}
|
|
48
|
-
export interface ApiErrorResponse {
|
|
49
|
-
error: string;
|
|
50
|
-
code: string;
|
|
51
|
-
}
|
|
52
73
|
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
|
|
53
74
|
//# 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":"AAIA,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,4FAA4F;IAC5F,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACjD,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,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,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":";AAAA,gDAAgD;AAChD,gCAAgC;AAChC,gDAAgD"}
|