notiformer 1.0.0

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 ADDED
@@ -0,0 +1,245 @@
1
+ # notiformer
2
+
3
+ Real-time alerts, notifications and feature gates for your backend code.
4
+
5
+ Send events from any point in your Node.js code and get notified instantly via push, email, Slack and more.
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install notiformer
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Quick start
18
+
19
+ ```ts
20
+ import { Notiformer } from 'notiformer';
21
+
22
+ const n = new Notiformer({
23
+ apiKey: 'ntf_live_...', // from app.notiformer.com/projects
24
+ });
25
+
26
+ // Send an event + notification
27
+ await n.event({
28
+ channel: 'payments',
29
+ event: 'payment_success',
30
+ description: `$49.00 — john@example.com`,
31
+ icon: '💳',
32
+ tags: { userId: 'usr_123', plan: 'pro' },
33
+ notify: true,
34
+ });
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Events
40
+
41
+ Use `n.event()` to log an event and optionally trigger notifications.
42
+
43
+ ```ts
44
+ await n.event({
45
+ channel: 'auth', // channel name (auto-created)
46
+ event: 'user_signup', // machine-readable event name
47
+ description: 'New signup via Google',
48
+ icon: '🎉',
49
+
50
+ // Optional metadata
51
+ tags: { method: 'google', plan: 'free' },
52
+ value: '42nd user', // shown in the dashboard feed
53
+
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',
60
+ });
61
+ ```
62
+
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.
66
+
67
+ ---
68
+
69
+ ## Feature Gates
70
+
71
+ Use `n.gate()` to check a boolean toggle you control remotely from the dashboard.
72
+
73
+ ```ts
74
+ const isEnabled = await n.gate('new-checkout-flow');
75
+
76
+ if (isEnabled) {
77
+ // run new checkout
78
+ } else {
79
+ // run legacy checkout
80
+ }
81
+ ```
82
+
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
+ ```
111
+
112
+ ---
113
+
114
+ ## Configuration
115
+
116
+ ```ts
117
+ const n = new Notiformer({
118
+ apiKey: 'ntf_live_...', // Required
119
+
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'
125
+ });
126
+ ```
127
+
128
+ ### Silence in development
129
+
130
+ ```ts
131
+ const n = new Notiformer({
132
+ apiKey: process.env.NOTIFORMER_API_KEY!,
133
+ silent: process.env.NODE_ENV !== 'production',
134
+ });
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Common patterns
140
+
141
+ ### Alert on errors
142
+
143
+ ```ts
144
+ app.use(async (err, req, res, next) => {
145
+ await n.event({
146
+ channel: 'errors',
147
+ event: 'unhandled_error',
148
+ description: err.message,
149
+ icon: '🔴',
150
+ tags: {
151
+ path: req.path,
152
+ method: req.method,
153
+ status: 500,
154
+ },
155
+ notify: true,
156
+ });
157
+ res.status(500).json({ error: 'Internal server error' });
158
+ });
159
+ ```
160
+
161
+ ### Track business milestones
162
+
163
+ ```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
+ }
175
+ ```
176
+
177
+ ### Feature gate a new endpoint
178
+
179
+ ```ts
180
+ app.post('/checkout', async (req, res) => {
181
+ const useNewFlow = await n.gate('new-checkout-flow');
182
+
183
+ if (useNewFlow) {
184
+ return newCheckoutHandler(req, res);
185
+ }
186
+ return legacyCheckoutHandler(req, res);
187
+ });
188
+ ```
189
+
190
+ ### Silent analytics (no notification)
191
+
192
+ ```ts
193
+ // Log for analytics without pushing a notification
194
+ await n.event({
195
+ channel: 'monitoring',
196
+ event: 'page_view',
197
+ description: `/dashboard visited`,
198
+ tags: { userId: req.user.id },
199
+ notify: false, // ← silent
200
+ });
201
+ ```
202
+
203
+ ---
204
+
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
+ ## Requirements
222
+
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
+ ```
238
+
239
+ ---
240
+
241
+ ## Links
242
+
243
+ - Dashboard: [app.notiformer.com](https://app.notiformer.com)
244
+ - Docs: [docs.notiformer.com](https://docs.notiformer.com)
245
+ - Support: support@notiformer.com
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Simple in-memory TTL cache for gate values.
3
+ * Reduces API calls when gate() is called frequently.
4
+ */
5
+ export declare class GateCache {
6
+ private store;
7
+ get(key: string): boolean | null;
8
+ set(key: string, value: boolean, ttlSeconds: number): void;
9
+ delete(key: string): void;
10
+ clear(): void;
11
+ size(): number;
12
+ }
13
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAiC;IAE9C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAUhC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAQ1D,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,MAAM;CAGf"}
package/dist/cache.js ADDED
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GateCache = void 0;
4
+ /**
5
+ * Simple in-memory TTL cache for gate values.
6
+ * Reduces API calls when gate() is called frequently.
7
+ */
8
+ class GateCache {
9
+ constructor() {
10
+ this.store = new Map();
11
+ }
12
+ get(key) {
13
+ const entry = this.store.get(key);
14
+ if (!entry)
15
+ return null;
16
+ if (Date.now() > entry.expiresAt) {
17
+ this.store.delete(key);
18
+ return null;
19
+ }
20
+ return entry.value;
21
+ }
22
+ set(key, value, ttlSeconds) {
23
+ if (ttlSeconds <= 0)
24
+ return;
25
+ this.store.set(key, {
26
+ value,
27
+ expiresAt: Date.now() + ttlSeconds * 1000,
28
+ });
29
+ }
30
+ delete(key) {
31
+ this.store.delete(key);
32
+ }
33
+ clear() {
34
+ this.store.clear();
35
+ }
36
+ size() {
37
+ return this.store.size;
38
+ }
39
+ }
40
+ exports.GateCache = GateCache;
41
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":";;;AAKA;;;GAGG;AACH,MAAa,SAAS;IAAtB;QACU,UAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IA+BhD,CAAC;IA7BC,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAc,EAAE,UAAkB;QACjD,IAAI,UAAU,IAAI,CAAC;YAAE,OAAO;QAC5B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF;AAhCD,8BAgCC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Notiformer Node.js SDK
3
+ *
4
+ * Real-time alerts, notifications and feature gates for your backend code.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { Notiformer } from 'notiformer';
9
+ *
10
+ * const n = new Notiformer({ apiKey: 'ntf_live_...' });
11
+ *
12
+ * // Send a notification event
13
+ * await n.event({
14
+ * channel: 'payments',
15
+ * event: 'payment_success',
16
+ * description: '$49.00 — john@example.com',
17
+ * icon: '💳',
18
+ * notify: true,
19
+ * });
20
+ *
21
+ * // Check a feature gate
22
+ * const isEnabled = await n.gate('new-checkout-flow');
23
+ * if (isEnabled) { ... }
24
+ * ```
25
+ */
26
+ import type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult } from './types';
27
+ export type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult, };
28
+ export declare class Notiformer {
29
+ private readonly apiKey;
30
+ private readonly baseUrl;
31
+ private readonly timeout;
32
+ private readonly silent;
33
+ private readonly logger;
34
+ private readonly gateCache;
35
+ constructor(config: NotiformerConfig);
36
+ /**
37
+ * Send an event to a channel. Triggers notifications based on your
38
+ * dashboard settings.
39
+ *
40
+ * @param payload - The event data
41
+ * @returns The created event ID and timestamp, or null if silent mode
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * await n.event({
46
+ * channel: 'payments',
47
+ * event: 'payment_success',
48
+ * description: `$49.00 — ${user.email}`,
49
+ * icon: '💳',
50
+ * tags: { userId: user.id, plan: 'pro' },
51
+ * notify: true,
52
+ * });
53
+ * ```
54
+ */
55
+ event(payload: EventPayload): Promise<EventResponse | null>;
56
+ /**
57
+ * Check whether a feature gate is enabled. Results are cached locally
58
+ * for `cacheTtl` seconds (default: 30) to minimize API calls.
59
+ *
60
+ * @param key - The gate key as defined in your dashboard
61
+ * @param options - Cache and fallback options
62
+ * @returns `true` if the gate is enabled, `false` otherwise
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const isEnabled = await n.gate('new-checkout-flow');
67
+ * if (isEnabled) {
68
+ * // use new checkout
69
+ * }
70
+ * ```
71
+ */
72
+ gate(key: string, options?: GateOptions): Promise<boolean>;
73
+ /**
74
+ * Like `gate()` but returns the full GateResult object
75
+ * including whether the value was cached.
76
+ */
77
+ gateDetails(key: string, options?: GateOptions): Promise<GateResult>;
78
+ /**
79
+ * Clears the in-memory gate cache.
80
+ * Useful if you need to force a fresh fetch.
81
+ */
82
+ clearGateCache(key?: string): void;
83
+ private fetchWithTimeout;
84
+ }
85
+ export default Notiformer;
86
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;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,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,MAAM,EAAE,gBAAgB;IAsBpC;;;;;;;;;;;;;;;;;;OAkBG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAiDjE;;;;;;;;;;;;;;;OAeG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAyCpE;;;OAGG;IACG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IA+B9E;;;OAGG;IACH,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;YAYpB,gBAAgB;CAoB/B;AAMD,eAAe,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ /**
3
+ * Notiformer Node.js SDK
4
+ *
5
+ * Real-time alerts, notifications and feature gates for your backend code.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Notiformer } from 'notiformer';
10
+ *
11
+ * const n = new Notiformer({ apiKey: 'ntf_live_...' });
12
+ *
13
+ * // Send a notification event
14
+ * await n.event({
15
+ * channel: 'payments',
16
+ * event: 'payment_success',
17
+ * description: '$49.00 — john@example.com',
18
+ * icon: '💳',
19
+ * notify: true,
20
+ * });
21
+ *
22
+ * // Check a feature gate
23
+ * const isEnabled = await n.gate('new-checkout-flow');
24
+ * if (isEnabled) { ... }
25
+ * ```
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.Notiformer = void 0;
29
+ const logger_1 = require("./logger");
30
+ const cache_1 = require("./cache");
31
+ const DEFAULT_BASE_URL = 'https://api.notiformer.com';
32
+ const DEFAULT_TIMEOUT = 5000;
33
+ const DEFAULT_GATE_TTL = 30;
34
+ class Notiformer {
35
+ constructor(config) {
36
+ var _a, _b, _c, _d;
37
+ if (!config.apiKey) {
38
+ throw new Error('[notiformer] apiKey is required.');
39
+ }
40
+ if (!config.apiKey.startsWith('ntf_')) {
41
+ console.warn('[notiformer] API key should start with "ntf_". Make sure you are using a valid key from your dashboard.');
42
+ }
43
+ this.apiKey = config.apiKey;
44
+ this.baseUrl = ((_a = config.baseUrl) !== null && _a !== void 0 ? _a : DEFAULT_BASE_URL).replace(/\/$/, '');
45
+ this.timeout = (_b = config.timeout) !== null && _b !== void 0 ? _b : DEFAULT_TIMEOUT;
46
+ this.silent = (_c = config.silent) !== null && _c !== void 0 ? _c : false;
47
+ this.logger = new logger_1.Logger((_d = config.logLevel) !== null && _d !== void 0 ? _d : 'error');
48
+ this.gateCache = new cache_1.GateCache();
49
+ this.logger.debug('Notiformer initialized', { baseUrl: this.baseUrl });
50
+ }
51
+ // ─────────────────────────────────────────────
52
+ // event() — Send a notification event
53
+ // ─────────────────────────────────────────────
54
+ /**
55
+ * Send an event to a channel. Triggers notifications based on your
56
+ * dashboard settings.
57
+ *
58
+ * @param payload - The event data
59
+ * @returns The created event ID and timestamp, or null if silent mode
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * await n.event({
64
+ * channel: 'payments',
65
+ * event: 'payment_success',
66
+ * description: `$49.00 — ${user.email}`,
67
+ * icon: '💳',
68
+ * tags: { userId: user.id, plan: 'pro' },
69
+ * notify: true,
70
+ * });
71
+ * ```
72
+ */
73
+ async event(payload) {
74
+ var _a;
75
+ if (this.silent) {
76
+ this.logger.info('Silent mode: event suppressed', payload);
77
+ return null;
78
+ }
79
+ if (!payload.channel)
80
+ throw new Error('[notiformer] event.channel is required.');
81
+ if (!payload.event)
82
+ throw new Error('[notiformer] event.event is required.');
83
+ this.logger.debug('Sending event', payload);
84
+ try {
85
+ const body = {
86
+ channel: payload.channel,
87
+ event: payload.event,
88
+ description: payload.description,
89
+ icon: payload.icon,
90
+ tags: payload.tags,
91
+ value: payload.value,
92
+ notify: (_a = payload.notify) !== null && _a !== void 0 ? _a : true,
93
+ groupId: payload.groupId,
94
+ };
95
+ const res = await this.fetchWithTimeout('/v1/events', {
96
+ method: 'POST',
97
+ body: JSON.stringify(body),
98
+ });
99
+ if (!res.ok) {
100
+ const err = await res.json().catch(() => ({ error: 'Unknown', code: String(res.status) }));
101
+ this.logger.error(`Event failed: ${err.error} (${err.code})`);
102
+ return null;
103
+ }
104
+ const data = await res.json();
105
+ this.logger.debug('Event sent', data);
106
+ return data;
107
+ }
108
+ catch (err) {
109
+ const message = err instanceof Error ? err.message : String(err);
110
+ this.logger.error('Event request failed', message);
111
+ // Never throw — a failed notification should not crash your app
112
+ return null;
113
+ }
114
+ }
115
+ // ─────────────────────────────────────────────
116
+ // gate() — Check a feature gate
117
+ // ─────────────────────────────────────────────
118
+ /**
119
+ * Check whether a feature gate is enabled. Results are cached locally
120
+ * for `cacheTtl` seconds (default: 30) to minimize API calls.
121
+ *
122
+ * @param key - The gate key as defined in your dashboard
123
+ * @param options - Cache and fallback options
124
+ * @returns `true` if the gate is enabled, `false` otherwise
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * const isEnabled = await n.gate('new-checkout-flow');
129
+ * if (isEnabled) {
130
+ * // use new checkout
131
+ * }
132
+ * ```
133
+ */
134
+ async gate(key, options = {}) {
135
+ var _a, _b;
136
+ if (!key)
137
+ throw new Error('[notiformer] gate key is required.');
138
+ const fallback = (_a = options.fallback) !== null && _a !== void 0 ? _a : false;
139
+ const ttl = (_b = options.cacheTtl) !== null && _b !== void 0 ? _b : DEFAULT_GATE_TTL;
140
+ if (this.silent) {
141
+ this.logger.info(`Silent mode: gate "${key}" returning fallback (${String(fallback)})`);
142
+ return fallback;
143
+ }
144
+ // Check cache first
145
+ const cached = this.gateCache.get(key);
146
+ if (cached !== null) {
147
+ this.logger.debug(`Gate "${key}" from cache: ${String(cached)}`);
148
+ return cached;
149
+ }
150
+ try {
151
+ const res = await this.fetchWithTimeout(`/v1/gates/${encodeURIComponent(key)}`);
152
+ if (!res.ok) {
153
+ this.logger.warn(`Gate "${key}" fetch failed (${res.status}), using fallback: ${String(fallback)}`);
154
+ return fallback;
155
+ }
156
+ const data = await res.json();
157
+ this.gateCache.set(key, data.enabled, ttl);
158
+ this.logger.debug(`Gate "${key}": ${String(data.enabled)}`);
159
+ return data.enabled;
160
+ }
161
+ catch (err) {
162
+ const message = err instanceof Error ? err.message : String(err);
163
+ this.logger.warn(`Gate "${key}" request failed (${message}), using fallback: ${String(fallback)}`);
164
+ return fallback;
165
+ }
166
+ }
167
+ // ─────────────────────────────────────────────
168
+ // gateDetails() — Get full gate result with metadata
169
+ // ─────────────────────────────────────────────
170
+ /**
171
+ * Like `gate()` but returns the full GateResult object
172
+ * including whether the value was cached.
173
+ */
174
+ async gateDetails(key, options = {}) {
175
+ var _a, _b;
176
+ const fallback = (_a = options.fallback) !== null && _a !== void 0 ? _a : false;
177
+ const ttl = (_b = options.cacheTtl) !== null && _b !== void 0 ? _b : DEFAULT_GATE_TTL;
178
+ const now = new Date().toISOString();
179
+ if (this.silent) {
180
+ return { key, enabled: fallback, cached: false, fetchedAt: now };
181
+ }
182
+ const cachedVal = this.gateCache.get(key);
183
+ if (cachedVal !== null) {
184
+ return { key, enabled: cachedVal, cached: true, fetchedAt: now };
185
+ }
186
+ try {
187
+ const res = await this.fetchWithTimeout(`/v1/gates/${encodeURIComponent(key)}`);
188
+ if (!res.ok) {
189
+ return { key, enabled: fallback, cached: false, fetchedAt: now };
190
+ }
191
+ const data = await res.json();
192
+ this.gateCache.set(key, data.enabled, ttl);
193
+ return data;
194
+ }
195
+ catch (_c) {
196
+ return { key, enabled: fallback, cached: false, fetchedAt: now };
197
+ }
198
+ }
199
+ // ─────────────────────────────────────────────
200
+ // clearGateCache() — Force fresh gate fetch
201
+ // ─────────────────────────────────────────────
202
+ /**
203
+ * Clears the in-memory gate cache.
204
+ * Useful if you need to force a fresh fetch.
205
+ */
206
+ clearGateCache(key) {
207
+ if (key) {
208
+ this.gateCache.delete(key);
209
+ }
210
+ else {
211
+ this.gateCache.clear();
212
+ }
213
+ }
214
+ // ─────────────────────────────────────────────
215
+ // Private helpers
216
+ // ─────────────────────────────────────────────
217
+ async fetchWithTimeout(path, init = {}) {
218
+ const controller = new AbortController();
219
+ const timer = setTimeout(() => controller.abort(), this.timeout);
220
+ try {
221
+ return await fetch(`${this.baseUrl}${path}`, {
222
+ ...init,
223
+ signal: controller.signal,
224
+ headers: {
225
+ 'Content-Type': 'application/json',
226
+ 'Authorization': `Bearer ${this.apiKey}`,
227
+ 'X-SDK-Version': '1.0.0',
228
+ 'X-SDK-Language': 'node',
229
+ ...init.headers,
230
+ },
231
+ });
232
+ }
233
+ finally {
234
+ clearTimeout(timer);
235
+ }
236
+ }
237
+ }
238
+ exports.Notiformer = Notiformer;
239
+ // ─────────────────────────────────────────────
240
+ // Named export for convenience
241
+ // ─────────────────────────────────────────────
242
+ exports.default = Notiformer;
243
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { LogLevel } from './types';
2
+ export declare class Logger {
3
+ private level;
4
+ constructor(level?: LogLevel);
5
+ debug(msg: string, ...args: unknown[]): void;
6
+ info(msg: string, ...args: unknown[]): void;
7
+ warn(msg: string, ...args: unknown[]): void;
8
+ error(msg: string, ...args: unknown[]): void;
9
+ }
10
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAUxC,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,GAAE,QAAkB;IAIrC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI5C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI3C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;IAI3C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI;CAG7C"}
package/dist/logger.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Logger = void 0;
4
+ const LEVELS = {
5
+ debug: 0,
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3,
9
+ none: 4,
10
+ };
11
+ class Logger {
12
+ constructor(level = 'error') {
13
+ this.level = LEVELS[level];
14
+ }
15
+ debug(msg, ...args) {
16
+ if (this.level <= LEVELS.debug)
17
+ console.debug(`[notiformer] ${msg}`, ...args);
18
+ }
19
+ info(msg, ...args) {
20
+ if (this.level <= LEVELS.info)
21
+ console.info(`[notiformer] ${msg}`, ...args);
22
+ }
23
+ warn(msg, ...args) {
24
+ if (this.level <= LEVELS.warn)
25
+ console.warn(`[notiformer] ${msg}`, ...args);
26
+ }
27
+ error(msg, ...args) {
28
+ if (this.level <= LEVELS.error)
29
+ console.error(`[notiformer] ${msg}`, ...args);
30
+ }
31
+ }
32
+ exports.Logger = Logger;
33
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;AAEA,MAAM,MAAM,GAA6B;IACvC,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;CACR,CAAC;AAEF,MAAa,MAAM;IAGjB,YAAY,QAAkB,OAAO;QACnC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,GAAW,EAAE,GAAG,IAAe;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,GAAW,EAAE,GAAG,IAAe;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,CAAC,GAAW,EAAE,GAAG,IAAe;QAClC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,GAAW,EAAE,GAAG,IAAe;QACnC,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,gBAAgB,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;IAChF,CAAC;CACF;AAtBD,wBAsBC"}
@@ -0,0 +1,99 @@
1
+ export interface NotiformerConfig {
2
+ /**
3
+ * Your project API key from the Notiformer dashboard.
4
+ * Get it at: https://app.notiformer.com/projects
5
+ */
6
+ apiKey: string;
7
+ /**
8
+ * Base URL of the Notiformer API.
9
+ * @default 'https://api.notiformer.com'
10
+ */
11
+ baseUrl?: string;
12
+ /**
13
+ * Request timeout in milliseconds.
14
+ * @default 5000
15
+ */
16
+ timeout?: number;
17
+ /**
18
+ * If true, SDK calls are no-ops. Useful for local development.
19
+ * @default false
20
+ */
21
+ silent?: boolean;
22
+ /**
23
+ * Log level for SDK internals.
24
+ * @default 'error'
25
+ */
26
+ logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'none';
27
+ }
28
+ export interface EventPayload {
29
+ /**
30
+ * The channel to send this event to.
31
+ * Channels group related events (e.g. 'payments', 'auth', 'errors').
32
+ * Created automatically on first use.
33
+ */
34
+ channel: string;
35
+ /**
36
+ * Machine-readable event name (e.g. 'payment_success', 'user_signup').
37
+ */
38
+ event: string;
39
+ /**
40
+ * Human-readable description shown in the dashboard feed.
41
+ */
42
+ description?: string;
43
+ /**
44
+ * An emoji icon shown next to the event in the feed.
45
+ * @example '💳' | '🚨' | '✅'
46
+ */
47
+ icon?: string;
48
+ /**
49
+ * Optional key-value tags for filtering and search.
50
+ * @example { userId: 'usr_123', plan: 'pro', amount: 49 }
51
+ */
52
+ tags?: Record<string, string | number | boolean>;
53
+ /**
54
+ * A scalar value to display alongside the event.
55
+ * @example '$49.00' | 200 | '98ms'
56
+ */
57
+ value?: string | number;
58
+ /**
59
+ * If true, triggers configured notification channels (push, email, etc).
60
+ * If false, the event is logged silently (analytics only).
61
+ * @default true
62
+ */
63
+ notify?: boolean;
64
+ /**
65
+ * Used for deduplication. Events with the same groupId within
66
+ * a short window are rate-limited.
67
+ */
68
+ groupId?: string;
69
+ }
70
+ export interface EventResponse {
71
+ id: string;
72
+ createdAt: string;
73
+ }
74
+ export interface GateOptions {
75
+ /**
76
+ * Fallback value returned if the network request fails
77
+ * or times out.
78
+ * @default false
79
+ */
80
+ fallback?: boolean;
81
+ /**
82
+ * Cache TTL in seconds. Set to 0 to disable caching.
83
+ * Recommended: 30 (default) to reduce API calls.
84
+ * @default 30
85
+ */
86
+ cacheTtl?: number;
87
+ }
88
+ export interface GateResult {
89
+ key: string;
90
+ enabled: boolean;
91
+ cached: boolean;
92
+ fetchedAt: string;
93
+ }
94
+ export interface ApiErrorResponse {
95
+ error: string;
96
+ code: string;
97
+ }
98
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
99
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;CACzD;AAMD,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAEjD;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAExB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,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;AAMD,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"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ // ─────────────────────────────────────────────
3
+ // Notiformer Node.js SDK — Types
4
+ // ─────────────────────────────────────────────
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gDAAgD;AAChD,iCAAiC;AACjC,gDAAgD"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "notiformer",
3
+ "version": "1.0.0",
4
+ "description": "Real-time alerts, notifications and feature gates for your backend code",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "notifications",
17
+ "alerts",
18
+ "monitoring",
19
+ "feature-flags",
20
+ "feature-gates",
21
+ "events",
22
+ "saas",
23
+ "developer-tools"
24
+ ],
25
+ "author": "Notiformer",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/notiformer/notiformer-node"
30
+ },
31
+ "homepage": "https://notiformer.com",
32
+ "devDependencies": {
33
+ "typescript": "^5.3.3"
34
+ },
35
+ "engines": {
36
+ "node": ">=16.0.0"
37
+ }
38
+ }