notiformer 1.0.1 → 1.0.3

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 CHANGED
@@ -1,8 +1,10 @@
1
1
  # notiformer
2
2
 
3
- Real-time alerts, notifications and feature gates for your backend code.
3
+ Real-time alerts and feature gates for your backend code.
4
4
 
5
- Send events from any point in your Node.js code and get notified instantly via push, email, Slack and more.
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: 'ntf_live_...', // from app.notiformer.com/projects
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: `$49.00 — john@example.com`,
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
- ## Events
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
- Use `n.event()` to log an event and optionally trigger notifications.
49
+ ---
50
+
51
+ ## Events
42
52
 
43
53
  ```ts
44
54
  await n.event({
45
- channel: 'auth', // channel name (auto-created)
46
- event: 'user_signup', // machine-readable event name
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
- // Optional metadata
51
- tags: { method: 'google', plan: 'free' },
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
- // notify: true → triggers push/email/Slack per your dashboard settings
55
- // notify: false → silent log only (analytics mode)
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
- ### event() is fire-and-forget safe
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
- Use `n.gate()` to check a boolean toggle you control remotely from the dashboard.
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 checkout
80
+ // run new feature
78
81
  } else {
79
- // run legacy checkout
82
+ // run old feature
80
83
  }
81
84
  ```
82
85
 
83
- Gates are cached locally for 30 seconds by default to minimise API calls.
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_...', // Required
94
+ apiKey: 'ntf_live_...', // required — from app.notiformer.com/projects
119
95
 
120
- // Optional
121
- baseUrl: 'https://api.notiformer.com', // default
122
- timeout: 5000, // ms, default: 5000
123
- silent: false, // true = all calls are no-ops (good for local dev)
124
- logLevel: 'error', // 'debug' | 'info' | 'warn' | 'error' | 'none'
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 business milestones
133
+ ### Track a payment
162
134
 
163
135
  ```ts
164
- async function onPaymentSuccess(charge: Charge) {
165
- await n.event({
166
- channel: 'payments',
167
- event: 'payment_success',
168
- description: `${formatCurrency(charge.amount)} — ${charge.email}`,
169
- icon: '💳',
170
- value: formatCurrency(charge.amount),
171
- tags: { chargeId: charge.id, plan: charge.plan },
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 a new endpoint
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
- if (useNewFlow) {
184
- return newCheckoutHandler(req, res);
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
- description: `/dashboard visited`,
198
- tags: { userId: req.user.id },
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 16+
224
- - Fetch API (native in Node 18+; polyfill needed for Node 16)
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,20 @@
1
1
  /**
2
- * Notiformer Node.js SDK
3
- *
4
- * ⚠️ BACKEND ONLY — Do NOT use this in frontend/browser code.
5
- * Your API key would be exposed publicly. Use server-side code only
6
- * (Node.js, Express, Next.js API routes, Cloud Functions, etc.)
2
+ * Notiformer — Real-time alerts and feature gates for your code.
7
3
  *
8
4
  * @example
9
- * ```ts
10
5
  * import { Notiformer } from 'notiformer';
11
6
  *
12
- * const n = new Notiformer({ apiKey: 'ntf_live_...' });
7
+ * const n = new Notiformer({
8
+ * apiKey: 'ntf_live_xxxxxxxxxxxxxxxx', // from app.notiformer.com/projects
9
+ * });
13
10
  *
14
11
  * await n.event({
15
12
  * channel: 'payments',
16
13
  * event: 'payment_success',
17
- * description: '$49.00 — user@email.com',
14
+ * description: '$49.00 — john@example.com',
18
15
  * icon: '💳',
19
16
  * notify: true,
20
17
  * });
21
- * ```
22
18
  */
23
19
  import type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult } from "./types";
24
20
  export type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult, };
@@ -31,35 +27,31 @@ export declare class Notiformer {
31
27
  private readonly onError?;
32
28
  private readonly logger;
33
29
  private readonly gateCache;
30
+ private readonly isPlaceholder;
34
31
  constructor(config: NotiformerConfig);
35
32
  /**
36
- * Send an event to a channel. Triggers notifications based on your
37
- * dashboard settings.
33
+ * Send an event and optionally trigger a notification.
38
34
  *
39
- * By default this never throwsa failed notification should never
40
- * crash your app. Set `throwOnError: true` in config if you need exceptions.
41
- *
42
- * @returns The created event, or null if the call failed.
35
+ * Safe to use anywhere in your code never throws by default.
36
+ * Returns null if the call fails (and calls onError if configured).
43
37
  */
44
38
  event(payload: EventPayload): Promise<EventResponse | null>;
45
39
  /**
46
40
  * Check whether a feature gate is enabled.
47
- * Results are cached locally for `cacheTtl` seconds (default: 30).
41
+ * Cached locally for 30 seconds by default.
48
42
  *
49
- * Returns the fallback value (default: false) if the request fails.
43
+ * Returns fallback (false) if the call fails.
50
44
  */
51
45
  gate(key: string, options?: GateOptions): Promise<boolean>;
52
- /**
53
- * Like gate() but returns the full result object with metadata.
54
- */
46
+ /** Full gate result with metadata */
55
47
  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
- */
48
+ /** Clear cached gate values */
60
49
  clearGateCache(key?: string): void;
61
- private handleError;
62
- private fetchWithTimeout;
50
+ private post;
51
+ private get;
52
+ private request;
53
+ private fail;
54
+ private friendlyNetworkError;
63
55
  }
64
56
  export default Notiformer;
65
57
  //# sourceMappingURL=index.d.ts.map
@@ -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,EAEX,MAAM,SAAS,CAAC;AAIjB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,GACX,CAAC;AAMF,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;gBAE1B,MAAM,EAAE,gBAAgB;IAqDpC;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAuDjE;;;;;OAKG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAkCpE;;OAEG;IACG,WAAW,CACf,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;IAKtB;;;OAGG;IACH,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAQlC,OAAO,CAAC,WAAW;YAOL,gBAAgB;CAuB/B;AAgDD,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;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,107 @@
1
1
  "use strict";
2
2
  /**
3
- * Notiformer Node.js SDK
4
- *
5
- * ⚠️ BACKEND ONLY — Do NOT use this in frontend/browser code.
6
- * Your API key would be exposed publicly. Use server-side code only
7
- * (Node.js, Express, Next.js API routes, Cloud Functions, etc.)
3
+ * Notiformer — Real-time alerts and feature gates for your code.
8
4
  *
9
5
  * @example
10
- * ```ts
11
6
  * import { Notiformer } from 'notiformer';
12
7
  *
13
- * const n = new Notiformer({ apiKey: 'ntf_live_...' });
8
+ * const n = new Notiformer({
9
+ * apiKey: 'ntf_live_xxxxxxxxxxxxxxxx', // from app.notiformer.com/projects
10
+ * });
14
11
  *
15
12
  * await n.event({
16
13
  * channel: 'payments',
17
14
  * event: 'payment_success',
18
- * description: '$49.00 — user@email.com',
15
+ * description: '$49.00 — john@example.com',
19
16
  * icon: '💳',
20
17
  * notify: true,
21
18
  * });
22
- * ```
23
19
  */
24
20
  Object.defineProperty(exports, "__esModule", { value: true });
25
21
  exports.Notiformer = void 0;
26
22
  const logger_1 = require("./logger");
27
23
  const cache_1 = require("./cache");
28
- const PLACEHOLDER_URL = "https://api.notiformer.com";
29
- const DEFAULT_TIMEOUT = 5000;
24
+ // The placeholder key shown in docs — triggers a friendly setup message
25
+ const PLACEHOLDER_KEY = "ntf_live_test";
26
+ const API_URL = "https://api.notiformer.com";
27
+ const DEFAULT_TIMEOUT = 8000;
30
28
  const DEFAULT_GATE_TTL = 30;
31
29
  class Notiformer {
32
30
  constructor(config) {
33
- // ── Validation ──────────────────────────────────────────────
34
- var _a, _b, _c, _d, _e;
31
+ var _a, _b, _c;
35
32
  if (!config.apiKey) {
36
- throw new Error("[notiformer] Missing apiKey.\n" +
37
- "Get your API key at https://app.notiformer.com/projects");
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");
33
+ throw new Error("[notiformer] apiKey is required.\n" +
34
+ "Get yours at https://app.notiformer.com/projects");
43
35
  }
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");
56
- }
57
- // ── Init ────────────────────────────────────────────────────
36
+ this.isPlaceholder = config.apiKey === PLACEHOLDER_KEY;
58
37
  this.apiKey = config.apiKey;
59
- this.baseUrl = resolvedUrl;
60
- this.timeout = (_b = config.timeout) !== null && _b !== void 0 ? _b : DEFAULT_TIMEOUT;
61
- this.silent = (_c = config.silent) !== null && _c !== void 0 ? _c : false;
62
- this.throwOnError = (_d = config.throwOnError) !== null && _d !== void 0 ? _d : false;
38
+ this.baseUrl = ((_a = config._baseUrl) !== null && _a !== void 0 ? _a : API_URL).replace(/\/$/, "");
39
+ this.timeout = DEFAULT_TIMEOUT;
40
+ this.silent = (_b = config.silent) !== null && _b !== void 0 ? _b : false;
41
+ this.throwOnError = (_c = config.throwOnError) !== null && _c !== void 0 ? _c : false;
63
42
  this.onError = config.onError;
64
- this.logger = new logger_1.Logger((_e = config.logLevel) !== null && _e !== void 0 ? _e : "warn");
43
+ this.logger = new logger_1.Logger("warn");
65
44
  this.gateCache = new cache_1.GateCache();
66
- this.logger.debug("Notiformer initialized", { baseUrl: this.baseUrl });
45
+ if (this.isPlaceholder) {
46
+ console.warn("\n" +
47
+ "┌─────────────────────────────────────────────────────┐\n" +
48
+ "│ notiformer — setup required │\n" +
49
+ "├─────────────────────────────────────────────────────┤\n" +
50
+ '│ You are using the example API key "ntf_live_test". │\n' +
51
+ "│ Events will not be sent until you use a real key. │\n" +
52
+ "│ │\n" +
53
+ "│ 1. Go to https://app.notiformer.com/projects │\n" +
54
+ "│ 2. Create or open a project │\n" +
55
+ "│ 3. Copy your API key │\n" +
56
+ '│ 4. Replace "ntf_live_test" with your real key │\n' +
57
+ "└─────────────────────────────────────────────────────┘\n");
58
+ }
67
59
  }
68
60
  // ─────────────────────────────────────────────────────────────
69
61
  // event()
70
62
  // ─────────────────────────────────────────────────────────────
71
63
  /**
72
- * Send an event to a channel. Triggers notifications based on your
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.
64
+ * Send an event and optionally trigger a notification.
77
65
  *
78
- * @returns The created event, or null if the call failed.
66
+ * Safe to use anywhere in your code never throws by default.
67
+ * Returns null if the call fails (and calls onError if configured).
79
68
  */
80
69
  async event(payload) {
81
- var _a;
82
- if (this.silent) {
83
- this.logger.info("Silent mode: event suppressed", payload);
84
- return null;
85
- }
70
+ var _a, _b;
86
71
  if (!payload.channel)
87
72
  throw new Error("[notiformer] event.channel is required.");
88
73
  if (!payload.event)
89
74
  throw new Error("[notiformer] event.event is required.");
90
- this.logger.debug("Sending event", payload);
75
+ // Placeholder key — log a clear message, do not attempt the call
76
+ if (this.isPlaceholder) {
77
+ console.warn('[notiformer] Event not sent — you are using the example key "ntf_live_test".\n' +
78
+ "→ Replace it with your real API key from https://app.notiformer.com/projects");
79
+ return null;
80
+ }
81
+ if (this.silent) {
82
+ this.logger.info("Silent mode: event suppressed.");
83
+ return null;
84
+ }
91
85
  try {
92
- const res = await this.fetchWithTimeout("/v1/events", {
93
- method: "POST",
94
- body: JSON.stringify({
95
- channel: payload.channel,
96
- event: payload.event,
97
- description: payload.description,
98
- icon: payload.icon,
99
- tags: payload.tags,
100
- value: payload.value,
101
- notify: (_a = payload.notify) !== null && _a !== void 0 ? _a : true,
102
- groupId: payload.groupId,
103
- }),
86
+ const res = await this.post("/v1/events", {
87
+ channel: payload.channel,
88
+ event: payload.event,
89
+ description: payload.description,
90
+ icon: payload.icon,
91
+ tags: payload.tags,
92
+ value: payload.value,
93
+ notify: (_a = payload.notify) !== null && _a !== void 0 ? _a : true,
104
94
  });
105
95
  if (!res.ok) {
106
- const errBody = await res.json().catch(() => ({
107
- error: `HTTP ${res.status}`,
108
- code: String(res.status),
109
- }));
110
- const err = new Error(`[notiformer] Event failed: ${errBody.error} (${errBody.code})`);
111
- return this.handleError(err, "event", payload);
96
+ const body = await res
97
+ .json()
98
+ .catch(() => ({ error: `HTTP ${res.status}` }));
99
+ return this.fail(new Error(`[notiformer] ${(_b = body.error) !== null && _b !== void 0 ? _b : res.statusText}`));
112
100
  }
113
- const data = await res.json();
114
- this.logger.debug("Event sent successfully", data);
115
- return data;
101
+ return (await res.json());
116
102
  }
117
103
  catch (err) {
118
- const error = toError(err);
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);
104
+ return this.fail(this.friendlyNetworkError(err));
122
105
  }
123
106
  }
124
107
  // ─────────────────────────────────────────────────────────────
@@ -126,9 +109,9 @@ class Notiformer {
126
109
  // ─────────────────────────────────────────────────────────────
127
110
  /**
128
111
  * Check whether a feature gate is enabled.
129
- * Results are cached locally for `cacheTtl` seconds (default: 30).
112
+ * Cached locally for 30 seconds by default.
130
113
  *
131
- * Returns the fallback value (default: false) if the request fails.
114
+ * Returns fallback (false) if the call fails.
132
115
  */
133
116
  async gate(key, options = {}) {
134
117
  var _a, _b;
@@ -136,55 +119,45 @@ class Notiformer {
136
119
  throw new Error("[notiformer] gate key is required.");
137
120
  const fallback = (_a = options.fallback) !== null && _a !== void 0 ? _a : false;
138
121
  const ttl = (_b = options.cacheTtl) !== null && _b !== void 0 ? _b : DEFAULT_GATE_TTL;
139
- if (this.silent)
122
+ if (this.isPlaceholder || this.silent)
140
123
  return fallback;
141
124
  const cached = this.gateCache.get(key);
142
- if (cached !== null) {
143
- this.logger.debug(`Gate "${key}" from cache: ${cached}`);
125
+ if (cached !== null)
144
126
  return cached;
145
- }
146
127
  try {
147
- const res = await this.fetchWithTimeout(`/v1/gates/${encodeURIComponent(key)}`);
148
- if (!res.ok) {
149
- this.logger.warn(`Gate "${key}" fetch failed (${res.status}), using fallback: ${fallback}`);
128
+ const res = await this.get(`/v1/gates/${encodeURIComponent(key)}`);
129
+ if (!res.ok)
150
130
  return fallback;
151
- }
152
- const data = await res.json();
131
+ const data = (await res.json());
153
132
  this.gateCache.set(key, data.enabled, ttl);
154
133
  return data.enabled;
155
134
  }
156
- catch (err) {
157
- const error = enrichError(toError(err), this.baseUrl);
158
- this.handleError(error, "gate", { key });
135
+ catch (_c) {
159
136
  return fallback;
160
137
  }
161
138
  }
162
- /**
163
- * Like gate() but returns the full result object with metadata.
164
- */
139
+ /** Full gate result with metadata */
165
140
  async gateDetails(key, options = {}) {
166
141
  const enabled = await this.gate(key, options);
167
142
  return { key, enabled, cached: false, fetchedAt: new Date().toISOString() };
168
143
  }
169
- /**
170
- * Clears the in-memory gate cache.
171
- * Pass a key to clear only that gate, or no args to clear all.
172
- */
144
+ /** Clear cached gate values */
173
145
  clearGateCache(key) {
174
146
  key ? this.gateCache.delete(key) : this.gateCache.clear();
175
147
  }
176
148
  // ─────────────────────────────────────────────────────────────
177
- // Private helpers
149
+ // Private
178
150
  // ─────────────────────────────────────────────────────────────
179
- handleError(error, method, payload) {
180
- var _a;
181
- this.logger.error(error.message);
182
- (_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, error, { method, payload });
183
- if (this.throwOnError)
184
- throw error;
185
- return null;
151
+ async post(path, body) {
152
+ return this.request(path, {
153
+ method: "POST",
154
+ body: JSON.stringify(body),
155
+ });
156
+ }
157
+ async get(path) {
158
+ return this.request(path, { method: "GET" });
186
159
  }
187
- async fetchWithTimeout(path, init = {}) {
160
+ async request(path, init) {
188
161
  var _a;
189
162
  const controller = new AbortController();
190
163
  const timer = setTimeout(() => controller.abort(), this.timeout);
@@ -195,8 +168,7 @@ class Notiformer {
195
168
  headers: {
196
169
  "Content-Type": "application/json",
197
170
  Authorization: `Bearer ${this.apiKey}`,
198
- "X-SDK-Version": "1.0.1",
199
- "X-SDK-Language": "node",
171
+ "X-SDK-Version": "1.0.3",
200
172
  ...((_a = init.headers) !== null && _a !== void 0 ? _a : {}),
201
173
  },
202
174
  });
@@ -205,39 +177,29 @@ class Notiformer {
205
177
  clearTimeout(timer);
206
178
  }
207
179
  }
208
- }
209
- exports.Notiformer = Notiformer;
210
- // ─────────────────────────────────────────────────────────────
211
- // Helpers
212
- // ─────────────────────────────────────────────────────────────
213
- function toError(err) {
214
- return err instanceof Error ? err : new Error(String(err));
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.");
180
+ fail(error) {
181
+ var _a;
182
+ this.logger.error(error.message);
183
+ (_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, error);
184
+ if (this.throwOnError)
185
+ throw error;
186
+ return null;
235
187
  }
236
- if (msg.includes("aborted") || msg.includes("timeout")) {
237
- return new Error(`[notiformer] Request timed out after ${DEFAULT_TIMEOUT}ms.\n` +
238
- "Increase timeout: new Notiformer({ ..., timeout: 10000 })");
188
+ friendlyNetworkError(err) {
189
+ const msg = err instanceof Error ? err.message.toLowerCase() : "";
190
+ if (msg.includes("aborted") || msg.includes("timeout")) {
191
+ return new Error(`[notiformer] Request timed out after ${this.timeout / 1000}s.\n` +
192
+ "Check your internet connection or try again later.");
193
+ }
194
+ if (msg.includes("failed to fetch") ||
195
+ msg.includes("enotfound") ||
196
+ msg.includes("network")) {
197
+ return new Error("[notiformer] Cannot reach the Notiformer API.\n" +
198
+ "Check your internet connection. If the problem persists, visit https://status.notiformer.com");
199
+ }
200
+ return err instanceof Error ? err : new Error(String(err));
239
201
  }
240
- return error;
241
202
  }
203
+ exports.Notiformer = Notiformer;
242
204
  exports.default = Notiformer;
243
205
  //# 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":"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"}
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
- baseUrl?: string;
4
- timeout?: number;
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 whenever an event() or gate() call fails silently.
9
- * Use this to log errors to your own monitoring system.
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) => Sentry.captureException(err)
26
+ * onError: (err) => console.error('[notiformer]', err.message)
12
27
  */
13
- onError?: (error: Error, context: {
14
- method: string;
15
- payload?: unknown;
16
- }) => void;
28
+ onError?: (error: Error) => void;
17
29
  /**
18
- * If true, event() and gate() will throw on failure instead of returning null/fallback.
19
- * Only use this if you want to handle errors yourself with try/catch.
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
@@ -1 +1 @@
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,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACxD;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACjF;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,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,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;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,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC"}
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
@@ -1,3 +1,6 @@
1
1
  "use strict";
2
+ // ─────────────────────────────────────────────
3
+ // Notiformer SDK — Public Types
4
+ // ─────────────────────────────────────────────
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  //# sourceMappingURL=types.js.map
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "notiformer",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
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",