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 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,24 @@
1
1
  /**
2
- * Notiformer Node.js SDK
2
+ * Notiformer — Real-time alerts and feature gates for your code.
3
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.)
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({ apiKey: 'ntf_live_...' });
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 — user@email.com',
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 to a channel. Triggers notifications based on your
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
- * @returns The created event, or null if the call failed.
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
- * Results are cached locally for `cacheTtl` seconds (default: 30).
45
+ * Cached locally for 30 seconds by default.
48
46
  *
49
- * Returns the fallback value (default: false) if the request fails.
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 handleError;
62
- private fetchWithTimeout;
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
@@ -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;;;;;;;;;;;;;;;;;;;;;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 Node.js SDK
3
+ * Notiformer — Real-time alerts and feature gates for your code.
4
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.)
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({ apiKey: 'ntf_live_...' });
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 — user@email.com',
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
- const PLACEHOLDER_URL = "https://api.notiformer.com";
29
- const DEFAULT_TIMEOUT = 5000;
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
- // ── Validation ──────────────────────────────────────────────
34
- var _a, _b, _c, _d, _e;
35
+ var _a, _b, _c;
35
36
  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");
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
- // ── Init ────────────────────────────────────────────────────
40
+ this.isPlaceholder = config.apiKey === PLACEHOLDER_KEY;
58
41
  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;
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((_e = config.logLevel) !== null && _e !== void 0 ? _e : "warn");
47
+ this.logger = new logger_1.Logger("warn");
65
48
  this.gateCache = new cache_1.GateCache();
66
- this.logger.debug("Notiformer initialized", { baseUrl: this.baseUrl });
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 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.
68
+ * Send an event and optionally trigger a notification.
77
69
  *
78
- * @returns The created event, or null if the call failed.
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
- this.logger.debug("Sending event", payload);
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.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
- }),
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 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);
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
- const data = await res.json();
114
- this.logger.debug("Event sent successfully", data);
115
- return data;
105
+ return (await res.json());
116
106
  }
117
107
  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);
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
- * Results are cached locally for `cacheTtl` seconds (default: 30).
116
+ * Cached locally for 30 seconds by default.
130
117
  *
131
- * Returns the fallback value (default: false) if the request fails.
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.fetchWithTimeout(`/v1/gates/${encodeURIComponent(key)}`);
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 (err) {
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 helpers
153
+ // Private
178
154
  // ─────────────────────────────────────────────────────────────
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;
155
+ async post(path, body) {
156
+ return this.request(path, {
157
+ method: "POST",
158
+ body: JSON.stringify(body),
159
+ });
186
160
  }
187
- async fetchWithTimeout(path, init = {}) {
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.1",
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
- 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.");
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
- 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 })");
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":"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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.2",
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",