notiformer 1.1.0 → 1.1.1
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 +288 -201
- package/dist/index.d.ts +56 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +189 -36
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +66 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# notiformer
|
|
2
2
|
|
|
3
|
-
Real-time push notifications and feature
|
|
3
|
+
Real-time push notifications, approval gates, and feature flags for your code.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Pause your AI agent, ask your phone, and continue — or fire a one-line alert the moment something important happens.
|
|
6
6
|
|
|
7
|
-
> **Works everywhere.**
|
|
7
|
+
> **Works everywhere.** Node.js, Express, Next.js, serverless functions, Python, Go, or any HTTP client.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -25,89 +25,216 @@ const n = new Notiformer({
|
|
|
25
25
|
apiKey: "ntf_live_...", // from app.notiformer.com/projects
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
+
// 🛑 Block and wait for approval
|
|
29
|
+
const { approved } = await n.ask({
|
|
30
|
+
message: `Deploy v2 to production?`,
|
|
31
|
+
context: "Build #442 · 3 services affected",
|
|
32
|
+
timeout: 300,
|
|
33
|
+
});
|
|
34
|
+
if (approved) await deploy();
|
|
35
|
+
|
|
36
|
+
// 🔀 Block and wait for a choice from multiple options
|
|
37
|
+
const { selected } = await n.select({
|
|
38
|
+
message: "How to handle the failed payment?",
|
|
39
|
+
options: [
|
|
40
|
+
{ value: "retry", label: "🔄 Retry in 1 hour" },
|
|
41
|
+
{ value: "notify", label: "📧 Notify the customer" },
|
|
42
|
+
{ value: "cancel", label: "✕ Cancel the order", isDestructive: true },
|
|
43
|
+
],
|
|
44
|
+
fallback: "notify",
|
|
45
|
+
timeout: 300,
|
|
46
|
+
});
|
|
47
|
+
if (selected === "retry") await scheduleRetry();
|
|
48
|
+
|
|
49
|
+
// 🔔 Fire-and-forget alert
|
|
28
50
|
await n.event({
|
|
29
|
-
channel: "payments",
|
|
30
|
-
event: "payment_success",
|
|
31
|
-
description: "$49.00 — john@example.com",
|
|
32
|
-
icon: "💳",
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
notify: true, // true → push notification | false → silent log only
|
|
36
|
-
recipients: ["you@company.com"], // optional — notify specific people only (see below)
|
|
51
|
+
channel: "payments",
|
|
52
|
+
event: "payment_success",
|
|
53
|
+
description: "$49.00 — john@example.com",
|
|
54
|
+
icon: "💳",
|
|
55
|
+
value: "$49.00",
|
|
56
|
+
notify: true,
|
|
37
57
|
});
|
|
58
|
+
|
|
59
|
+
// 🚦 Feature gate check (cached 30s)
|
|
60
|
+
if (await n.gate("new-checkout-flow")) {
|
|
61
|
+
return newCheckout(req);
|
|
62
|
+
}
|
|
38
63
|
```
|
|
39
64
|
|
|
40
|
-
> **Tip:** Use `apiKey: 'ntf_live_test'` to get started without a real key. The SDK
|
|
65
|
+
> **Tip:** Use `apiKey: 'ntf_live_test'` to get started without a real key. The SDK prints setup instructions and skips all API calls.
|
|
41
66
|
|
|
42
67
|
---
|
|
43
68
|
|
|
44
69
|
## Get your API key
|
|
45
70
|
|
|
46
|
-
1. Go to [app.notiformer.com](https://app.notiformer.com) and create
|
|
71
|
+
1. Go to [app.notiformer.com](https://app.notiformer.com) and create a free account
|
|
47
72
|
2. Create a project
|
|
48
73
|
3. Copy the API key from the project overview
|
|
49
|
-
4. Replace `'ntf_live_test'` in your code with your real key
|
|
50
74
|
|
|
51
75
|
---
|
|
52
76
|
|
|
53
|
-
##
|
|
77
|
+
## Configuration
|
|
54
78
|
|
|
55
79
|
```ts
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
80
|
+
const n = new Notiformer({
|
|
81
|
+
apiKey: "ntf_live_...", // required
|
|
82
|
+
silent: false, // optional — true = no API calls (great for local dev)
|
|
83
|
+
throwOnError: false, // optional — true = throws instead of returning null
|
|
84
|
+
onError: (err) => {
|
|
85
|
+
// optional — called on any failure
|
|
86
|
+
Sentry.captureException(err);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
59
89
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
notify: true, // optional — default: true
|
|
65
|
-
recipients: ["alice@company.com"], // optional — see "Targeting specific people"
|
|
90
|
+
// Silence in local development
|
|
91
|
+
const n = new Notiformer({
|
|
92
|
+
apiKey: process.env.NOTIFORMER_API_KEY!,
|
|
93
|
+
silent: process.env.NODE_ENV !== "production",
|
|
66
94
|
});
|
|
67
95
|
```
|
|
68
96
|
|
|
69
|
-
|
|
97
|
+
---
|
|
70
98
|
|
|
71
|
-
|
|
72
|
-
| ---------------- | -------------------------------------------------------------- |
|
|
73
|
-
| `true` (default) | Sends push notification to subscribed members |
|
|
74
|
-
| `false` | Stores the event silently for analytics — no notification sent |
|
|
99
|
+
## `ask()` — Approval gate (binary)
|
|
75
100
|
|
|
76
|
-
|
|
101
|
+
Pause your code and wait for a **human to approve or deny** from the Notiformer app. The `Promise` resolves when you respond, or when the timeout expires.
|
|
102
|
+
|
|
103
|
+
> **This is a blocking call.** Your agent stops at `await n.ask()` and waits.
|
|
77
104
|
|
|
78
105
|
```ts
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
106
|
+
const { approved, timedOut, respondedAt } = await n.ask({
|
|
107
|
+
message: "Send campaign to 3,241 users?", // required — shown as notification title
|
|
108
|
+
context: "Campaign: Black Friday · segment A", // optional — shown in notification body
|
|
109
|
+
details: "Full changelog:\n• Fix auth bug", // optional — shown in app detail screen, supports \n
|
|
110
|
+
timeout: 300, // optional — seconds to wait (default: 300)
|
|
111
|
+
fallback: "deny", // optional — 'deny' | 'approve' on timeout (default: 'deny')
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (approved) {
|
|
115
|
+
await sendEmails();
|
|
116
|
+
} else {
|
|
117
|
+
console.log(timedOut ? "Timed out" : "Denied");
|
|
118
|
+
}
|
|
82
119
|
```
|
|
83
120
|
|
|
84
|
-
|
|
121
|
+
### Return value
|
|
122
|
+
|
|
123
|
+
| Field | Type | Description |
|
|
124
|
+
| ------------- | ---------------- | ----------------------------------------------------- |
|
|
125
|
+
| `approved` | `boolean` | `true` if the user tapped Approve |
|
|
126
|
+
| `timedOut` | `boolean` | `true` if nobody responded before the timeout |
|
|
127
|
+
| `respondedAt` | `string \| null` | ISO timestamp of the response, or `null` if timed out |
|
|
128
|
+
|
|
129
|
+
### Plan limits
|
|
130
|
+
|
|
131
|
+
| Plan | Gates/month | Max timeout |
|
|
132
|
+
| -------- | ----------------- | ----------- |
|
|
133
|
+
| Free | — (not available) | — |
|
|
134
|
+
| Starter | 200 | 5 min |
|
|
135
|
+
| Pro | 2,000 | 15 min |
|
|
136
|
+
| Business | 20,000 | 60 min |
|
|
85
137
|
|
|
86
138
|
---
|
|
87
139
|
|
|
88
|
-
##
|
|
140
|
+
## `select()` — Approval gate (multi-option)
|
|
89
141
|
|
|
90
|
-
|
|
142
|
+
Like `ask()`, but instead of Approve/Deny the user picks from **2–6 custom options**. Returns the `value` string of the chosen option.
|
|
91
143
|
|
|
92
|
-
|
|
144
|
+
Uses the same monthly quota as `ask()`.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
const { selected, timedOut, respondedAt } = await n.select({
|
|
148
|
+
message: "How should the agent handle the error?", // required
|
|
149
|
+
options: [
|
|
150
|
+
// required — min 2, max 6
|
|
151
|
+
{ value: "retry", label: "🔄 Retry the request" },
|
|
152
|
+
{ value: "skip", label: "⏭ Skip and continue" },
|
|
153
|
+
{ value: "stop", label: "🛑 Stop the pipeline", isDestructive: true },
|
|
154
|
+
],
|
|
155
|
+
context: "Step 4/10 failed — HTTP 503 from payments API", // optional
|
|
156
|
+
details: "Error: Connection timeout\nEndpoint: /v2/charge\nRetries: 3",
|
|
157
|
+
timeout: 300, // optional — seconds (default: 300)
|
|
158
|
+
fallback: "skip", // optional — value to return on timeout (must match an option)
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (selected === "retry") await retryStep();
|
|
162
|
+
if (selected === "skip") await nextStep();
|
|
163
|
+
if (selected === "stop") await abort();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Return value
|
|
167
|
+
|
|
168
|
+
| Field | Type | Description |
|
|
169
|
+
| ------------- | ---------------- | ------------------------------------------------------------------------------------------------ |
|
|
170
|
+
| `selected` | `string \| null` | The value of the chosen option, or the fallback on timeout. `null` if timed out with no fallback |
|
|
171
|
+
| `timedOut` | `boolean` | `true` if nobody responded in time |
|
|
172
|
+
| `respondedAt` | `string \| null` | ISO timestamp of the response |
|
|
173
|
+
|
|
174
|
+
### Option shape
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
interface SelectOption {
|
|
178
|
+
value: string; // returned in result.selected — max 50 chars
|
|
179
|
+
label: string; // button text in the app — max 80 chars, supports emoji
|
|
180
|
+
isDestructive?: boolean; // if true, button is styled in red
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Validation rules (enforced at call time)
|
|
185
|
+
|
|
186
|
+
- At least 2 options, maximum 6
|
|
187
|
+
- `fallback` must match one of the option `value` strings exactly
|
|
188
|
+
- Each `value` max 50 chars, each `label` max 80 chars
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## `event()` — Fire-and-forget alert
|
|
193
|
+
|
|
194
|
+
Send an event notification. Never throws by default.
|
|
93
195
|
|
|
94
196
|
```ts
|
|
95
197
|
await n.event({
|
|
96
|
-
channel: "payments",
|
|
97
|
-
event: "
|
|
98
|
-
description: "$
|
|
99
|
-
|
|
100
|
-
|
|
198
|
+
channel: "payments", // required — auto-created on first use
|
|
199
|
+
event: "payment_success", // required — machine-readable event name
|
|
200
|
+
description: "$49.00 — john@co.com", // optional — shown in notification + feed
|
|
201
|
+
icon: "💳", // optional — emoji
|
|
202
|
+
tags: { plan: "pro" }, // optional — metadata shown in feed
|
|
203
|
+
value: "$49.00", // optional — highlighted value in feed
|
|
204
|
+
notify: true, // optional — true = push notification (default)
|
|
205
|
+
recipients: ["you@company.com"], // optional — notify specific people only
|
|
101
206
|
});
|
|
102
207
|
```
|
|
103
208
|
|
|
104
|
-
|
|
209
|
+
### `notify` behaviour
|
|
210
|
+
|
|
211
|
+
| Value | Behaviour |
|
|
212
|
+
| ---------------- | ------------------------------------------- |
|
|
213
|
+
| `true` (default) | Sends push to subscribed members |
|
|
214
|
+
| `false` | Stores the event silently — no notification |
|
|
215
|
+
|
|
216
|
+
### Return value
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
const result = await n.event({ ... });
|
|
220
|
+
// result is null if the call failed (never throws by default)
|
|
221
|
+
// result.id → event ID
|
|
222
|
+
// result.createdAt → ISO timestamp
|
|
223
|
+
// result.rateLimited → true if >60 events/min (event stored, notification skipped)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Recipients
|
|
105
227
|
|
|
106
|
-
|
|
107
|
-
- Email notifications are **coming soon** — recipients will receive emails once this feature launches
|
|
108
|
-
- If you don't specify `recipients`, all project members subscribed to the channel are notified
|
|
228
|
+
By default, all project members subscribed to the channel are notified. Use `recipients` to target specific people:
|
|
109
229
|
|
|
110
|
-
|
|
230
|
+
```ts
|
|
231
|
+
await n.event({
|
|
232
|
+
channel: "sales",
|
|
233
|
+
event: "enterprise_signup",
|
|
234
|
+
notify: true,
|
|
235
|
+
recipients: ["cto@company.com"], // only this person gets the push
|
|
236
|
+
});
|
|
237
|
+
```
|
|
111
238
|
|
|
112
239
|
| Plan | Max recipients per event |
|
|
113
240
|
| -------- | ------------------------ |
|
|
@@ -116,230 +243,189 @@ await n.event({
|
|
|
116
243
|
| Pro | 10 |
|
|
117
244
|
| Business | 30 |
|
|
118
245
|
|
|
119
|
-
|
|
246
|
+
### Monthly event quotas
|
|
247
|
+
|
|
248
|
+
| Plan | Events/month |
|
|
249
|
+
| -------- | ------------ |
|
|
250
|
+
| Free | 500 |
|
|
251
|
+
| Starter | 20,000 |
|
|
252
|
+
| Pro | 75,000 |
|
|
253
|
+
| Business | 300,000 |
|
|
254
|
+
|
|
255
|
+
Rate limit: 60 events/minute per project. If exceeded, the event is stored but no notification is sent (`rateLimited: true` in the response).
|
|
120
256
|
|
|
121
257
|
---
|
|
122
258
|
|
|
123
|
-
## `gate()` — Feature
|
|
259
|
+
## `gate()` — Feature flags
|
|
124
260
|
|
|
125
|
-
Toggle features
|
|
261
|
+
Toggle features remotely from the dashboard — no redeploy needed. Results are **cached locally for 30 seconds** by default.
|
|
262
|
+
|
|
263
|
+
> Available on **Pro and Business** plans only.
|
|
126
264
|
|
|
127
265
|
```ts
|
|
128
266
|
const isEnabled = await n.gate("new-checkout-flow");
|
|
129
267
|
|
|
130
268
|
if (isEnabled) {
|
|
131
|
-
|
|
269
|
+
return newCheckout(req);
|
|
132
270
|
} else {
|
|
133
|
-
|
|
271
|
+
return legacyCheckout(req);
|
|
134
272
|
}
|
|
135
273
|
```
|
|
136
274
|
|
|
137
|
-
Gates are **cached locally for 30 seconds** by default to avoid hammering the API on every request.
|
|
138
|
-
|
|
139
275
|
### Options
|
|
140
276
|
|
|
141
277
|
```ts
|
|
142
278
|
const isEnabled = await n.gate("my-gate", {
|
|
143
|
-
fallback: false, //
|
|
144
|
-
cacheTtl: 60, //
|
|
279
|
+
fallback: false, // returned if the gate can't be fetched (default: false)
|
|
280
|
+
cacheTtl: 60, // local cache in seconds (default: 30)
|
|
145
281
|
});
|
|
146
|
-
```
|
|
147
282
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```ts
|
|
283
|
+
// Full result with metadata
|
|
151
284
|
const result = await n.gateDetails("my-gate");
|
|
152
|
-
// { key: 'my-gate', enabled: true, cached: false, fetchedAt: '
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### Clear the cache
|
|
285
|
+
// { key: 'my-gate', enabled: true, cached: false, fetchedAt: '...' }
|
|
156
286
|
|
|
157
|
-
|
|
158
|
-
n.clearGateCache("my-gate"); // clear
|
|
287
|
+
// Cache management
|
|
288
|
+
n.clearGateCache("my-gate"); // clear one gate
|
|
159
289
|
n.clearGateCache(); // clear all gates
|
|
160
290
|
```
|
|
161
291
|
|
|
292
|
+
| Plan | Gate limit per project |
|
|
293
|
+
| -------- | ---------------------- |
|
|
294
|
+
| Free | Not available |
|
|
295
|
+
| Starter | Not available |
|
|
296
|
+
| Pro | 50 gates |
|
|
297
|
+
| Business | 500 gates |
|
|
298
|
+
|
|
162
299
|
---
|
|
163
300
|
|
|
164
|
-
##
|
|
301
|
+
## When quota is exceeded
|
|
302
|
+
|
|
303
|
+
When you hit your monthly limit, the API returns HTTP 429 with an `upgradeUrl` field pointing to a direct Stripe Checkout for the next plan:
|
|
165
304
|
|
|
166
305
|
```ts
|
|
306
|
+
// The SDK logs this automatically:
|
|
307
|
+
// [notiformer] Plan limit reached. Upgrade your plan to continue:
|
|
308
|
+
// → https://api.notiformer.com/v1/upgrade?plan=pro&uid=...&email=...
|
|
309
|
+
|
|
310
|
+
// You can also handle it yourself:
|
|
167
311
|
const n = new Notiformer({
|
|
168
|
-
apiKey: "ntf_live_...",
|
|
169
|
-
silent: false, // optional — true = no API calls (great for local dev)
|
|
170
|
-
throwOnError: false, // optional — true = throws instead of returning null
|
|
312
|
+
apiKey: "ntf_live_...",
|
|
171
313
|
onError: (err) => {
|
|
172
|
-
|
|
173
|
-
|
|
314
|
+
if (err.message.includes("quota")) {
|
|
315
|
+
notifyAdmin("Notiformer quota exceeded");
|
|
316
|
+
}
|
|
174
317
|
},
|
|
175
318
|
});
|
|
176
319
|
```
|
|
177
320
|
|
|
178
|
-
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## REST API
|
|
324
|
+
|
|
325
|
+
All SDK methods wrap REST endpoints. Use them from any language:
|
|
179
326
|
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
327
|
+
```
|
|
328
|
+
POST https://api.notiformer.com/v1/events — n.event()
|
|
329
|
+
POST https://api.notiformer.com/v1/ask — n.ask() create
|
|
330
|
+
GET https://api.notiformer.com/v1/ask/:id — n.ask() poll
|
|
331
|
+
POST https://api.notiformer.com/v1/select — n.select() create
|
|
332
|
+
GET https://api.notiformer.com/v1/select/:id — n.select() poll
|
|
333
|
+
GET https://api.notiformer.com/v1/gates/:key — n.gate()
|
|
334
|
+
GET https://api.notiformer.com/v1/health — status check
|
|
185
335
|
```
|
|
186
336
|
|
|
187
|
-
|
|
337
|
+
All endpoints require `Authorization: Bearer ntf_live_...`.
|
|
188
338
|
|
|
189
|
-
|
|
339
|
+
### Python example
|
|
190
340
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
| Events per minute (per project) | 60 |
|
|
194
|
-
| Events per month (Free plan) | 100 |
|
|
195
|
-
| Events per month (Starter) | 5,000 |
|
|
196
|
-
| Events per month (Pro) | 75,000 |
|
|
197
|
-
| Events per month (Business) | 300,000 |
|
|
341
|
+
```python
|
|
342
|
+
import requests, time
|
|
198
343
|
|
|
199
|
-
|
|
344
|
+
NF_KEY = "ntf_live_..."
|
|
345
|
+
HEADERS = {"Authorization": f"Bearer {NF_KEY}"}
|
|
200
346
|
|
|
201
|
-
|
|
347
|
+
# Create an approval request
|
|
348
|
+
r = requests.post(
|
|
349
|
+
"https://api.notiformer.com/v1/ask",
|
|
350
|
+
headers=HEADERS,
|
|
351
|
+
json={"message": "Delete 500 rows?", "timeout": 300}
|
|
352
|
+
)
|
|
353
|
+
ask_id = r.json()["id"]
|
|
354
|
+
|
|
355
|
+
# Poll until resolved
|
|
356
|
+
while True:
|
|
357
|
+
poll = requests.get(
|
|
358
|
+
f"https://api.notiformer.com/v1/ask/{ask_id}",
|
|
359
|
+
headers=HEADERS
|
|
360
|
+
).json()
|
|
361
|
+
if poll["status"] != "pending":
|
|
362
|
+
break
|
|
363
|
+
time.sleep(2)
|
|
364
|
+
|
|
365
|
+
if poll["status"] == "approved":
|
|
366
|
+
db.execute(delete_query)
|
|
367
|
+
```
|
|
202
368
|
|
|
203
369
|
---
|
|
204
370
|
|
|
205
371
|
## Common patterns
|
|
206
372
|
|
|
207
|
-
###
|
|
373
|
+
### AI agent guard
|
|
208
374
|
|
|
209
375
|
```ts
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
376
|
+
// Stop the agent before any destructive action
|
|
377
|
+
const { approved } = await n.ask({
|
|
378
|
+
message: `Agent wants to delete ${count} records`,
|
|
379
|
+
context: `Table: ${table} · Environment: production`,
|
|
380
|
+
details: `WHERE clause: ${query}\nEstimated rows: ${count}`,
|
|
381
|
+
timeout: 120,
|
|
382
|
+
fallback: "deny",
|
|
217
383
|
});
|
|
384
|
+
if (!approved) throw new Error("Action denied by human");
|
|
218
385
|
```
|
|
219
386
|
|
|
220
|
-
###
|
|
387
|
+
### Multi-step decision
|
|
221
388
|
|
|
222
389
|
```ts
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
});
|
|
233
|
-
res.status(500).json({ error: "Internal server error" });
|
|
390
|
+
const { selected } = await n.select({
|
|
391
|
+
message: `Build #${build.id} failed at step ${step}`,
|
|
392
|
+
options: [
|
|
393
|
+
{ value: "retry", label: "🔄 Retry from this step" },
|
|
394
|
+
{ value: "restart", label: "↩ Restart from scratch" },
|
|
395
|
+
{ value: "abort", label: "🛑 Abort pipeline", isDestructive: true },
|
|
396
|
+
],
|
|
397
|
+
fallback: "abort",
|
|
398
|
+
timeout: 600,
|
|
234
399
|
});
|
|
235
400
|
```
|
|
236
401
|
|
|
237
|
-
### Silent analytics
|
|
402
|
+
### Silent analytics
|
|
238
403
|
|
|
239
404
|
```ts
|
|
240
405
|
await n.event({
|
|
241
406
|
channel: "analytics",
|
|
242
407
|
event: "page_view",
|
|
243
408
|
tags: { path: req.path, userId: session.userId },
|
|
244
|
-
notify: false, // stored in feed, no push
|
|
409
|
+
notify: false, // stored in feed, no push
|
|
245
410
|
});
|
|
246
411
|
```
|
|
247
412
|
|
|
248
|
-
###
|
|
249
|
-
|
|
250
|
-
```ts
|
|
251
|
-
// Next.js API route
|
|
252
|
-
export async function POST(req: Request) {
|
|
253
|
-
const useNewFlow = await n.gate("new-checkout-flow");
|
|
254
|
-
|
|
255
|
-
if (useNewFlow) {
|
|
256
|
-
return newCheckoutHandler(req);
|
|
257
|
-
}
|
|
258
|
-
return legacyCheckoutHandler(req);
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### Notify a specific person
|
|
413
|
+
### Error alert with context
|
|
263
414
|
|
|
264
415
|
```ts
|
|
265
|
-
|
|
266
|
-
await n.event({
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
416
|
+
app.use(async (err, req, res, next) => {
|
|
417
|
+
await n.event({
|
|
418
|
+
channel: "errors",
|
|
419
|
+
event: "unhandled_error",
|
|
420
|
+
description: err.message,
|
|
421
|
+
icon: "🔴",
|
|
422
|
+
tags: { path: req.path, method: req.method, status: 500 },
|
|
423
|
+
notify: true,
|
|
424
|
+
});
|
|
425
|
+
res.status(500).json({ error: "Internal server error" });
|
|
274
426
|
});
|
|
275
427
|
```
|
|
276
428
|
|
|
277
|
-
### Using with Python (REST API)
|
|
278
|
-
|
|
279
|
-
Notiformer works from any language via the REST API:
|
|
280
|
-
|
|
281
|
-
```python
|
|
282
|
-
import requests
|
|
283
|
-
|
|
284
|
-
requests.post(
|
|
285
|
-
'https://api.notiformer.com/v1/events',
|
|
286
|
-
headers={ 'Authorization': f'Bearer {NF_KEY}' },
|
|
287
|
-
json={
|
|
288
|
-
'channel': 'ai-costs',
|
|
289
|
-
'event': 'cost_spike',
|
|
290
|
-
'description': '🤖 $180 spent in 10 min',
|
|
291
|
-
'notify': True,
|
|
292
|
-
'recipients': ['cto@company.com'], # optional
|
|
293
|
-
}
|
|
294
|
-
)
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
---
|
|
298
|
-
|
|
299
|
-
## Receiving notifications
|
|
300
|
-
|
|
301
|
-
Push notifications are delivered via the **Notiformer app**, available for iOS and Android.
|
|
302
|
-
|
|
303
|
-
1. Download the Notiformer app from the App Store or Google Play
|
|
304
|
-
2. Sign in with your Notiformer account
|
|
305
|
-
3. You'll automatically receive push notifications for projects you own or are a member of
|
|
306
|
-
4. Manage which channels you're subscribed to from the app settings
|
|
307
|
-
|
|
308
|
-
> **Email notifications** are in development and coming soon. Sign up at [notiformer.com](https://notiformer.com) to be notified when they launch.
|
|
309
|
-
|
|
310
|
-
---
|
|
311
|
-
|
|
312
|
-
## REST API
|
|
313
|
-
|
|
314
|
-
The same `event()` call maps to this endpoint:
|
|
315
|
-
|
|
316
|
-
```
|
|
317
|
-
POST https://api.notiformer.com/v1/events
|
|
318
|
-
Authorization: Bearer ntf_live_...
|
|
319
|
-
Content-Type: application/json
|
|
320
|
-
|
|
321
|
-
{
|
|
322
|
-
"channel": "payments",
|
|
323
|
-
"event": "payment_success",
|
|
324
|
-
"description": "$49.00 — john@example.com",
|
|
325
|
-
"icon": "💳",
|
|
326
|
-
"tags": { "plan": "pro" },
|
|
327
|
-
"value": "$49.00",
|
|
328
|
-
"notify": true,
|
|
329
|
-
"recipients": ["you@company.com"]
|
|
330
|
-
}
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
Response:
|
|
334
|
-
|
|
335
|
-
```json
|
|
336
|
-
{
|
|
337
|
-
"id": "evt_abc123",
|
|
338
|
-
"createdAt": "2025-01-15T10:30:00.000Z",
|
|
339
|
-
"rateLimited": false
|
|
340
|
-
}
|
|
341
|
-
```
|
|
342
|
-
|
|
343
429
|
---
|
|
344
430
|
|
|
345
431
|
## Requirements
|
|
@@ -355,3 +441,4 @@ Response:
|
|
|
355
441
|
- **Docs:** [docs.notiformer.com](https://docs.notiformer.com)
|
|
356
442
|
- **Status:** [status.notiformer.com](https://status.notiformer.com)
|
|
357
443
|
- **Pricing:** [notiformer.com/#pricing](https://notiformer.com/#pricing)
|
|
444
|
+
- **npm:** [npmjs.com/package/notiformer](https://www.npmjs.com/package/notiformer)
|
package/dist/index.d.ts
CHANGED
|
@@ -8,19 +8,26 @@
|
|
|
8
8
|
*
|
|
9
9
|
* const n = new Notiformer({ apiKey: 'ntf_live_...' });
|
|
10
10
|
*
|
|
11
|
-
* //
|
|
11
|
+
* // Fire-and-forget alert
|
|
12
12
|
* await n.event({ channel: 'payments', event: 'new_sale', notify: true });
|
|
13
13
|
*
|
|
14
|
-
* //
|
|
15
|
-
* await n.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
14
|
+
* // Block and wait for approval
|
|
15
|
+
* const { approved } = await n.ask({ message: 'Deploy to prod?' });
|
|
16
|
+
*
|
|
17
|
+
* // Block and wait for a choice from multiple options
|
|
18
|
+
* const { selected } = await n.select({
|
|
19
|
+
* message: 'How to handle the failed payment?',
|
|
20
|
+
* options: [
|
|
21
|
+
* { value: 'retry', label: '🔄 Retry in 1 hour' },
|
|
22
|
+
* { value: 'notify', label: '📧 Notify customer' },
|
|
23
|
+
* { value: 'cancel', label: '✕ Cancel order', isDestructive: true },
|
|
24
|
+
* ],
|
|
25
|
+
* fallback: 'notify',
|
|
20
26
|
* });
|
|
21
27
|
*/
|
|
22
|
-
import type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult, AskPayload, AskResult } from "./types";
|
|
23
|
-
export type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult, AskPayload, AskResult, };
|
|
28
|
+
import type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult, AskPayload, AskResult, SelectPayload, SelectResult } from "./types";
|
|
29
|
+
export type { NotiformerConfig, EventPayload, EventResponse, GateOptions, GateResult, AskPayload, AskResult, SelectPayload, SelectResult, };
|
|
30
|
+
export type { SelectOption } from "./types";
|
|
24
31
|
export declare class Notiformer {
|
|
25
32
|
private readonly apiKey;
|
|
26
33
|
private readonly baseUrl;
|
|
@@ -34,49 +41,75 @@ export declare class Notiformer {
|
|
|
34
41
|
constructor(config: NotiformerConfig);
|
|
35
42
|
/**
|
|
36
43
|
* Send an event and optionally notify recipients.
|
|
37
|
-
*
|
|
38
|
-
* - Without `recipients`: notifies the project owner + all members
|
|
39
|
-
* subscribed to the event's channel.
|
|
40
|
-
* - With `recipients`: notifies only the specified email addresses
|
|
41
|
-
* (must be project members). Overrides the default behaviour.
|
|
42
|
-
*
|
|
43
44
|
* Never throws by default — returns null if the call fails.
|
|
44
45
|
*/
|
|
45
46
|
event(payload: EventPayload): Promise<EventResponse | null>;
|
|
46
47
|
/**
|
|
47
48
|
* Check whether a feature gate is enabled.
|
|
48
49
|
* Results are cached locally for 30 seconds by default.
|
|
49
|
-
* Returns false if the call fails.
|
|
50
|
+
* Returns false if the call fails or the plan doesn't support gates.
|
|
50
51
|
*/
|
|
51
52
|
gate(key: string, options?: GateOptions): Promise<boolean>;
|
|
52
53
|
gateDetails(key: string, options?: GateOptions): Promise<GateResult>;
|
|
53
54
|
clearGateCache(key?: string): void;
|
|
54
55
|
/**
|
|
55
|
-
* Pause execution and wait for a human to approve or deny
|
|
56
|
+
* Pause execution and wait for a human to approve or deny.
|
|
56
57
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
58
|
+
* A push notification is sent to the Notiformer app with Approve
|
|
59
|
+
* and Deny buttons. The Promise resolves when you respond or when
|
|
60
|
+
* the timeout expires.
|
|
60
61
|
*
|
|
61
|
-
* Never throws by default
|
|
62
|
+
* Never throws by default.
|
|
62
63
|
*
|
|
63
64
|
* @example
|
|
64
65
|
* const { approved } = await n.ask({
|
|
65
66
|
* message: `Send campaign to ${count} users?`,
|
|
66
67
|
* context: `Campaign: Black Friday · ${count} recipients`,
|
|
67
|
-
* details: `CHANGES\n• Segment: paying users only\n• Template: bf-2026\n\nROLLBACK\nSet campaign.active = false`,
|
|
68
68
|
* timeout: 300,
|
|
69
69
|
* });
|
|
70
70
|
* if (approved) await sendEmails();
|
|
71
71
|
*/
|
|
72
72
|
ask(payload: AskPayload): Promise<AskResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Pause execution and wait for a human to choose from multiple options.
|
|
75
|
+
*
|
|
76
|
+
* Unlike ask() which returns a boolean, select() returns the `value`
|
|
77
|
+
* string of the chosen option. Use it when you need more than two actions.
|
|
78
|
+
*
|
|
79
|
+
* Uses the same monthly quota as ask().
|
|
80
|
+
* Never throws by default.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const { selected } = await n.select({
|
|
84
|
+
* message: 'How should I handle the failed payment?',
|
|
85
|
+
* options: [
|
|
86
|
+
* { value: 'retry', label: '🔄 Retry in 1 hour' },
|
|
87
|
+
* { value: 'notify', label: '📧 Notify the customer' },
|
|
88
|
+
* { value: 'cancel', label: '✕ Cancel the order', isDestructive: true },
|
|
89
|
+
* ],
|
|
90
|
+
* fallback: 'notify', // returned automatically on timeout
|
|
91
|
+
* timeout: 300,
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* if (selected === 'retry') await scheduleRetry();
|
|
95
|
+
* if (selected === 'notify') await sendEmail();
|
|
96
|
+
* if (selected === 'cancel') await cancelOrder();
|
|
97
|
+
*/
|
|
98
|
+
select(payload: SelectPayload): Promise<SelectResult>;
|
|
73
99
|
private pollAsk;
|
|
100
|
+
private pollSelect;
|
|
74
101
|
private sleep;
|
|
102
|
+
/**
|
|
103
|
+
* If the API response includes an upgradeUrl (quota exceeded),
|
|
104
|
+
* print a visible warning in the developer's console.
|
|
105
|
+
*/
|
|
106
|
+
private warnUpgrade;
|
|
75
107
|
private failAsk;
|
|
108
|
+
private failSelect;
|
|
109
|
+
private fail;
|
|
76
110
|
private post;
|
|
77
111
|
private get;
|
|
78
112
|
private request;
|
|
79
|
-
private fail;
|
|
80
113
|
private friendlyNetworkError;
|
|
81
114
|
}
|
|
82
115
|
export default Notiformer;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,YAAY,EACb,MAAM,SAAS,CAAC;AAIjB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,YAAY,GACb,CAAC;AACF,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO5C,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;;;OAGG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAsDjE;;;;OAIG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IAkC9D,WAAW,CACf,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;IAKtB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAQlC;;;;;;;;;;;;;;;;OAgBG;IACG,GAAG,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAoDlD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;YA0E7C,OAAO;YA8CP,UAAU;IAoDxB,OAAO,CAAC,KAAK;IAIb;;;OAGG;IACH,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,IAAI;YAOE,IAAI;YAIJ,GAAG;YAIH,OAAO;IAmBrB,OAAO,CAAC,oBAAoB;CAmB7B;AAED,eAAe,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,15 +9,21 @@
|
|
|
9
9
|
*
|
|
10
10
|
* const n = new Notiformer({ apiKey: 'ntf_live_...' });
|
|
11
11
|
*
|
|
12
|
-
* //
|
|
12
|
+
* // Fire-and-forget alert
|
|
13
13
|
* await n.event({ channel: 'payments', event: 'new_sale', notify: true });
|
|
14
14
|
*
|
|
15
|
-
* //
|
|
16
|
-
* await n.
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* // Block and wait for approval
|
|
16
|
+
* const { approved } = await n.ask({ message: 'Deploy to prod?' });
|
|
17
|
+
*
|
|
18
|
+
* // Block and wait for a choice from multiple options
|
|
19
|
+
* const { selected } = await n.select({
|
|
20
|
+
* message: 'How to handle the failed payment?',
|
|
21
|
+
* options: [
|
|
22
|
+
* { value: 'retry', label: '🔄 Retry in 1 hour' },
|
|
23
|
+
* { value: 'notify', label: '📧 Notify customer' },
|
|
24
|
+
* { value: 'cancel', label: '✕ Cancel order', isDestructive: true },
|
|
25
|
+
* ],
|
|
26
|
+
* fallback: 'notify',
|
|
21
27
|
* });
|
|
22
28
|
*/
|
|
23
29
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -59,14 +65,11 @@ class Notiformer {
|
|
|
59
65
|
"└─────────────────────────────────────────────────────┘\n");
|
|
60
66
|
}
|
|
61
67
|
}
|
|
68
|
+
// ─────────────────────────────────────────────────────────────
|
|
69
|
+
// event()
|
|
70
|
+
// ─────────────────────────────────────────────────────────────
|
|
62
71
|
/**
|
|
63
72
|
* Send an event and optionally notify recipients.
|
|
64
|
-
*
|
|
65
|
-
* - Without `recipients`: notifies the project owner + all members
|
|
66
|
-
* subscribed to the event's channel.
|
|
67
|
-
* - With `recipients`: notifies only the specified email addresses
|
|
68
|
-
* (must be project members). Overrides the default behaviour.
|
|
69
|
-
*
|
|
70
73
|
* Never throws by default — returns null if the call fails.
|
|
71
74
|
*/
|
|
72
75
|
async event(payload) {
|
|
@@ -104,6 +107,7 @@ class Notiformer {
|
|
|
104
107
|
const data = await res
|
|
105
108
|
.json()
|
|
106
109
|
.catch(() => ({ error: `HTTP ${res.status}` }));
|
|
110
|
+
this.warnUpgrade(data);
|
|
107
111
|
return this.fail(new Error(`[notiformer] ${(_b = data.error) !== null && _b !== void 0 ? _b : res.statusText}`));
|
|
108
112
|
}
|
|
109
113
|
return (await res.json());
|
|
@@ -112,10 +116,13 @@ class Notiformer {
|
|
|
112
116
|
return this.fail(this.friendlyNetworkError(err));
|
|
113
117
|
}
|
|
114
118
|
}
|
|
119
|
+
// ─────────────────────────────────────────────────────────────
|
|
120
|
+
// gate()
|
|
121
|
+
// ─────────────────────────────────────────────────────────────
|
|
115
122
|
/**
|
|
116
123
|
* Check whether a feature gate is enabled.
|
|
117
124
|
* Results are cached locally for 30 seconds by default.
|
|
118
|
-
* Returns false if the call fails.
|
|
125
|
+
* Returns false if the call fails or the plan doesn't support gates.
|
|
119
126
|
*/
|
|
120
127
|
async gate(key, options = {}) {
|
|
121
128
|
var _a, _b;
|
|
@@ -130,8 +137,15 @@ class Notiformer {
|
|
|
130
137
|
return cached;
|
|
131
138
|
try {
|
|
132
139
|
const res = await this.get(`/v1/gates/${encodeURIComponent(key)}`);
|
|
133
|
-
if (!res.ok)
|
|
140
|
+
if (!res.ok) {
|
|
141
|
+
// 403 = Feature Gates not available on this plan
|
|
142
|
+
if (res.status === 403) {
|
|
143
|
+
const data = await res.json().catch(() => ({}));
|
|
144
|
+
console.warn(`[notiformer] gate("${key}") — Feature Gates require Pro or Business plan.` +
|
|
145
|
+
(data.upgradeUrl ? `\n→ Upgrade: ${data.upgradeUrl}` : ""));
|
|
146
|
+
}
|
|
134
147
|
return fallback;
|
|
148
|
+
}
|
|
135
149
|
const data = (await res.json());
|
|
136
150
|
this.gateCache.set(key, data.enabled, ttl);
|
|
137
151
|
return data.enabled;
|
|
@@ -147,20 +161,22 @@ class Notiformer {
|
|
|
147
161
|
clearGateCache(key) {
|
|
148
162
|
key ? this.gateCache.delete(key) : this.gateCache.clear();
|
|
149
163
|
}
|
|
164
|
+
// ─────────────────────────────────────────────────────────────
|
|
165
|
+
// ask()
|
|
166
|
+
// ─────────────────────────────────────────────────────────────
|
|
150
167
|
/**
|
|
151
|
-
* Pause execution and wait for a human to approve or deny
|
|
168
|
+
* Pause execution and wait for a human to approve or deny.
|
|
152
169
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
170
|
+
* A push notification is sent to the Notiformer app with Approve
|
|
171
|
+
* and Deny buttons. The Promise resolves when you respond or when
|
|
172
|
+
* the timeout expires.
|
|
156
173
|
*
|
|
157
|
-
* Never throws by default
|
|
174
|
+
* Never throws by default.
|
|
158
175
|
*
|
|
159
176
|
* @example
|
|
160
177
|
* const { approved } = await n.ask({
|
|
161
178
|
* message: `Send campaign to ${count} users?`,
|
|
162
179
|
* context: `Campaign: Black Friday · ${count} recipients`,
|
|
163
|
-
* details: `CHANGES\n• Segment: paying users only\n• Template: bf-2026\n\nROLLBACK\nSet campaign.active = false`,
|
|
164
180
|
* timeout: 300,
|
|
165
181
|
* });
|
|
166
182
|
* if (approved) await sendEmails();
|
|
@@ -196,16 +212,101 @@ class Notiformer {
|
|
|
196
212
|
const data = await createRes
|
|
197
213
|
.json()
|
|
198
214
|
.catch(() => ({ error: `HTTP ${createRes.status}` }));
|
|
215
|
+
this.warnUpgrade(data);
|
|
199
216
|
return this.failAsk(new Error(`[notiformer] ${(_c = data.error) !== null && _c !== void 0 ? _c : createRes.statusText}`));
|
|
200
217
|
}
|
|
201
218
|
const created = (await createRes.json());
|
|
202
219
|
return this.pollAsk(created.id, new Date(created.expiresAt).getTime());
|
|
203
220
|
}
|
|
221
|
+
// ─────────────────────────────────────────────────────────────
|
|
222
|
+
// select()
|
|
223
|
+
// ─────────────────────────────────────────────────────────────
|
|
224
|
+
/**
|
|
225
|
+
* Pause execution and wait for a human to choose from multiple options.
|
|
226
|
+
*
|
|
227
|
+
* Unlike ask() which returns a boolean, select() returns the `value`
|
|
228
|
+
* string of the chosen option. Use it when you need more than two actions.
|
|
229
|
+
*
|
|
230
|
+
* Uses the same monthly quota as ask().
|
|
231
|
+
* Never throws by default.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* const { selected } = await n.select({
|
|
235
|
+
* message: 'How should I handle the failed payment?',
|
|
236
|
+
* options: [
|
|
237
|
+
* { value: 'retry', label: '🔄 Retry in 1 hour' },
|
|
238
|
+
* { value: 'notify', label: '📧 Notify the customer' },
|
|
239
|
+
* { value: 'cancel', label: '✕ Cancel the order', isDestructive: true },
|
|
240
|
+
* ],
|
|
241
|
+
* fallback: 'notify', // returned automatically on timeout
|
|
242
|
+
* timeout: 300,
|
|
243
|
+
* });
|
|
244
|
+
*
|
|
245
|
+
* if (selected === 'retry') await scheduleRetry();
|
|
246
|
+
* if (selected === 'notify') await sendEmail();
|
|
247
|
+
* if (selected === 'cancel') await cancelOrder();
|
|
248
|
+
*/
|
|
249
|
+
async select(payload) {
|
|
250
|
+
var _a, _b;
|
|
251
|
+
if (!payload.message)
|
|
252
|
+
throw new Error("[notiformer] select.message is required.");
|
|
253
|
+
if (!payload.options || payload.options.length < 2) {
|
|
254
|
+
throw new Error("[notiformer] select.options requires at least 2 options.");
|
|
255
|
+
}
|
|
256
|
+
if (payload.options.length > 6) {
|
|
257
|
+
throw new Error("[notiformer] select.options supports a maximum of 6 options.");
|
|
258
|
+
}
|
|
259
|
+
if (this.isPlaceholder) {
|
|
260
|
+
console.warn('[notiformer] select() not sent — using example key "ntf_live_test".\n' +
|
|
261
|
+
"→ Replace it with your real key from https://app.notiformer.com/projects");
|
|
262
|
+
return { selected: null, timedOut: false, respondedAt: null };
|
|
263
|
+
}
|
|
264
|
+
if (this.silent)
|
|
265
|
+
return { selected: null, timedOut: false, respondedAt: null };
|
|
266
|
+
// Local validation: fallback must be a valid option value
|
|
267
|
+
if (payload.fallback !== undefined) {
|
|
268
|
+
const validValues = payload.options.map((o) => o.value);
|
|
269
|
+
if (!validValues.includes(payload.fallback)) {
|
|
270
|
+
throw new Error(`[notiformer] select.fallback "${payload.fallback}" must match one of the option values: ` +
|
|
271
|
+
validValues.join(", "));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const body = {
|
|
275
|
+
message: payload.message,
|
|
276
|
+
options: payload.options,
|
|
277
|
+
timeout: (_a = payload.timeout) !== null && _a !== void 0 ? _a : 300,
|
|
278
|
+
};
|
|
279
|
+
if (payload.context !== undefined)
|
|
280
|
+
body.context = payload.context;
|
|
281
|
+
if (payload.details !== undefined)
|
|
282
|
+
body.details = payload.details;
|
|
283
|
+
if (payload.fallback !== undefined)
|
|
284
|
+
body.fallback = payload.fallback;
|
|
285
|
+
let createRes;
|
|
286
|
+
try {
|
|
287
|
+
createRes = await this.post("/v1/select", body);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
return this.failSelect(this.friendlyNetworkError(err));
|
|
291
|
+
}
|
|
292
|
+
if (!createRes.ok) {
|
|
293
|
+
const data = await createRes
|
|
294
|
+
.json()
|
|
295
|
+
.catch(() => ({ error: `HTTP ${createRes.status}` }));
|
|
296
|
+
this.warnUpgrade(data);
|
|
297
|
+
return this.failSelect(new Error(`[notiformer] ${(_b = data.error) !== null && _b !== void 0 ? _b : createRes.statusText}`));
|
|
298
|
+
}
|
|
299
|
+
const created = (await createRes.json());
|
|
300
|
+
return this.pollSelect(created.id, new Date(created.expiresAt).getTime());
|
|
301
|
+
}
|
|
302
|
+
// ─────────────────────────────────────────────────────────────
|
|
303
|
+
// Private: polling
|
|
304
|
+
// ─────────────────────────────────────────────────────────────
|
|
204
305
|
async pollAsk(askId, expiresAtMs) {
|
|
205
306
|
var _a, _b;
|
|
206
|
-
const
|
|
307
|
+
const POLL_MS = 2000;
|
|
207
308
|
while (true) {
|
|
208
|
-
await this.sleep(
|
|
309
|
+
await this.sleep(POLL_MS);
|
|
209
310
|
if (Date.now() >= expiresAtMs) {
|
|
210
311
|
return { approved: false, timedOut: true, respondedAt: null };
|
|
211
312
|
}
|
|
@@ -218,8 +319,7 @@ class Notiformer {
|
|
|
218
319
|
.catch(() => ({ error: `HTTP ${res.status}` }));
|
|
219
320
|
return this.failAsk(new Error(`[notiformer] ${(_a = data.error) !== null && _a !== void 0 ? _a : res.statusText}`));
|
|
220
321
|
}
|
|
221
|
-
// 5xx —
|
|
222
|
-
continue;
|
|
322
|
+
continue; // 5xx — retry
|
|
223
323
|
}
|
|
224
324
|
const data = (await res.json());
|
|
225
325
|
if (data.status === "pending")
|
|
@@ -231,14 +331,59 @@ class Notiformer {
|
|
|
231
331
|
};
|
|
232
332
|
}
|
|
233
333
|
catch (_c) {
|
|
234
|
-
//
|
|
235
|
-
|
|
334
|
+
continue; // network error — retry
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
async pollSelect(selectId, expiresAtMs) {
|
|
339
|
+
var _a, _b, _c;
|
|
340
|
+
const POLL_MS = 2000;
|
|
341
|
+
while (true) {
|
|
342
|
+
await this.sleep(POLL_MS);
|
|
343
|
+
if (Date.now() >= expiresAtMs) {
|
|
344
|
+
return { selected: null, timedOut: true, respondedAt: null };
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
347
|
+
const res = await this.get(`/v1/select/${encodeURIComponent(selectId)}`);
|
|
348
|
+
if (!res.ok) {
|
|
349
|
+
if (res.status >= 400 && res.status < 500) {
|
|
350
|
+
const data = await res
|
|
351
|
+
.json()
|
|
352
|
+
.catch(() => ({ error: `HTTP ${res.status}` }));
|
|
353
|
+
return this.failSelect(new Error(`[notiformer] ${(_a = data.error) !== null && _a !== void 0 ? _a : res.statusText}`));
|
|
354
|
+
}
|
|
355
|
+
continue; // 5xx — retry
|
|
356
|
+
}
|
|
357
|
+
const data = (await res.json());
|
|
358
|
+
if (data.status === "pending")
|
|
359
|
+
continue;
|
|
360
|
+
return {
|
|
361
|
+
selected: (_b = data.selectedValue) !== null && _b !== void 0 ? _b : null,
|
|
362
|
+
timedOut: data.status === "timed_out",
|
|
363
|
+
respondedAt: (_c = data.respondedAt) !== null && _c !== void 0 ? _c : null,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
catch (_d) {
|
|
367
|
+
continue; // network error — retry
|
|
236
368
|
}
|
|
237
369
|
}
|
|
238
370
|
}
|
|
371
|
+
// ─────────────────────────────────────────────────────────────
|
|
372
|
+
// Private: helpers
|
|
373
|
+
// ─────────────────────────────────────────────────────────────
|
|
239
374
|
sleep(ms) {
|
|
240
375
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
241
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* If the API response includes an upgradeUrl (quota exceeded),
|
|
379
|
+
* print a visible warning in the developer's console.
|
|
380
|
+
*/
|
|
381
|
+
warnUpgrade(data) {
|
|
382
|
+
if (data === null || data === void 0 ? void 0 : data.upgradeUrl) {
|
|
383
|
+
console.warn(`[notiformer] Plan limit reached. Upgrade your plan to continue:\n` +
|
|
384
|
+
`→ ${data.upgradeUrl}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
242
387
|
failAsk(error) {
|
|
243
388
|
var _a;
|
|
244
389
|
this.logger.error(error.message);
|
|
@@ -247,6 +392,22 @@ class Notiformer {
|
|
|
247
392
|
throw error;
|
|
248
393
|
return { approved: false, timedOut: false, respondedAt: null };
|
|
249
394
|
}
|
|
395
|
+
failSelect(error) {
|
|
396
|
+
var _a;
|
|
397
|
+
this.logger.error(error.message);
|
|
398
|
+
(_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
399
|
+
if (this.throwOnError)
|
|
400
|
+
throw error;
|
|
401
|
+
return { selected: null, timedOut: false, respondedAt: null };
|
|
402
|
+
}
|
|
403
|
+
fail(error) {
|
|
404
|
+
var _a;
|
|
405
|
+
this.logger.error(error.message);
|
|
406
|
+
(_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
407
|
+
if (this.throwOnError)
|
|
408
|
+
throw error;
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
250
411
|
async post(path, body) {
|
|
251
412
|
return this.request(path, { method: "POST", body: JSON.stringify(body) });
|
|
252
413
|
}
|
|
@@ -264,7 +425,7 @@ class Notiformer {
|
|
|
264
425
|
headers: {
|
|
265
426
|
"Content-Type": "application/json",
|
|
266
427
|
Authorization: `Bearer ${this.apiKey}`,
|
|
267
|
-
"X-SDK-Version": "1.1.
|
|
428
|
+
"X-SDK-Version": "1.1.1",
|
|
268
429
|
...((_a = init.headers) !== null && _a !== void 0 ? _a : {}),
|
|
269
430
|
},
|
|
270
431
|
});
|
|
@@ -273,14 +434,6 @@ class Notiformer {
|
|
|
273
434
|
clearTimeout(timer);
|
|
274
435
|
}
|
|
275
436
|
}
|
|
276
|
-
fail(error) {
|
|
277
|
-
var _a;
|
|
278
|
-
this.logger.error(error.message);
|
|
279
|
-
(_a = this.onError) === null || _a === void 0 ? void 0 : _a.call(this, error);
|
|
280
|
-
if (this.throwOnError)
|
|
281
|
-
throw error;
|
|
282
|
-
return null;
|
|
283
|
-
}
|
|
284
437
|
friendlyNetworkError(err) {
|
|
285
438
|
const msg = err instanceof Error ? err.message.toLowerCase() : "";
|
|
286
439
|
if (msg.includes("aborted") || msg.includes("timeout")) {
|
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
|
@@ -25,9 +25,6 @@ export interface EventPayload {
|
|
|
25
25
|
* If set, **only** these emails receive notifications — the default
|
|
26
26
|
* (owner + channel subscribers) is ignored.
|
|
27
27
|
*
|
|
28
|
-
* Each email must belong to a member of your project
|
|
29
|
-
* (added from the Notiformer dashboard).
|
|
30
|
-
*
|
|
31
28
|
* Plan limits: Free=1, Starter=3, Pro=10, Business=30.
|
|
32
29
|
*
|
|
33
30
|
* @example
|
|
@@ -57,12 +54,11 @@ export interface AskPayload {
|
|
|
57
54
|
context?: string;
|
|
58
55
|
/**
|
|
59
56
|
* Optional long-form text shown in the approval detail screen of the
|
|
60
|
-
* Notiformer app. Supports newlines — use \n to structure content
|
|
61
|
-
* (changelogs, diffs, SQL queries, affected services, etc.).
|
|
57
|
+
* Notiformer app. Supports newlines — use \n to structure content.
|
|
62
58
|
* Max 10,000 characters.
|
|
63
59
|
*
|
|
64
60
|
* @example
|
|
65
|
-
* details: `CHANGES\n• Fix auth bug\n
|
|
61
|
+
* details: `CHANGES\n• Fix auth bug\n\nROLLBACK\n./rollback.sh v1.0.9`
|
|
66
62
|
*/
|
|
67
63
|
details?: string;
|
|
68
64
|
/**
|
|
@@ -85,5 +81,69 @@ export interface AskResult {
|
|
|
85
81
|
/** ISO timestamp of when the user responded. null if timed out. */
|
|
86
82
|
respondedAt: string | null;
|
|
87
83
|
}
|
|
84
|
+
export interface SelectOption {
|
|
85
|
+
/**
|
|
86
|
+
* The value returned in `result.selected` when this option is chosen.
|
|
87
|
+
* Max 50 chars. Use a short descriptive string.
|
|
88
|
+
*
|
|
89
|
+
* @example 'deploy' | 'rollback' | 'cancel'
|
|
90
|
+
*/
|
|
91
|
+
value: string;
|
|
92
|
+
/**
|
|
93
|
+
* The button label shown in the Notiformer app.
|
|
94
|
+
* Max 80 chars. Supports emoji.
|
|
95
|
+
*
|
|
96
|
+
* @example '🚀 Deploy to production'
|
|
97
|
+
*/
|
|
98
|
+
label: string;
|
|
99
|
+
/**
|
|
100
|
+
* If true, the button is styled destructively (red) in the mobile app.
|
|
101
|
+
* Use for dangerous or irreversible actions.
|
|
102
|
+
*/
|
|
103
|
+
isDestructive?: boolean;
|
|
104
|
+
}
|
|
105
|
+
export interface SelectPayload {
|
|
106
|
+
/**
|
|
107
|
+
* The question shown as the push notification title. Required.
|
|
108
|
+
*/
|
|
109
|
+
message: string;
|
|
110
|
+
/**
|
|
111
|
+
* The options shown as buttons in the Notiformer app.
|
|
112
|
+
* Minimum 2, maximum 6 options.
|
|
113
|
+
*/
|
|
114
|
+
options: SelectOption[];
|
|
115
|
+
/** Optional detail shown in the notification body (max 500 chars). */
|
|
116
|
+
context?: string;
|
|
117
|
+
/**
|
|
118
|
+
* Optional long-form text shown in the approval detail screen.
|
|
119
|
+
* Supports newlines. Max 10,000 chars.
|
|
120
|
+
*/
|
|
121
|
+
details?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Seconds to wait before applying the fallback.
|
|
124
|
+
* Default: 300. Maximum depends on your plan.
|
|
125
|
+
*/
|
|
126
|
+
timeout?: number;
|
|
127
|
+
/**
|
|
128
|
+
* The option value to return automatically if nobody responds.
|
|
129
|
+
* Must match one of the option values exactly.
|
|
130
|
+
* If omitted, `selected` is null on timeout.
|
|
131
|
+
*
|
|
132
|
+
* @example 'cancel' // safe default
|
|
133
|
+
*/
|
|
134
|
+
fallback?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface SelectResult {
|
|
137
|
+
/**
|
|
138
|
+
* The value string of the option the user selected,
|
|
139
|
+
* or the fallback value on timeout.
|
|
140
|
+
* Null if timed out with no fallback set.
|
|
141
|
+
*/
|
|
142
|
+
selected: string | null;
|
|
143
|
+
/** True if nobody responded before the timeout expired. */
|
|
144
|
+
timedOut: boolean;
|
|
145
|
+
/** ISO timestamp of when the user responded. null if timed out. */
|
|
146
|
+
respondedAt: string | null;
|
|
147
|
+
}
|
|
88
148
|
export type LogLevel = "debug" | "info" | "warn" | "error" | "none" | "silent";
|
|
89
149
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,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;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB
|
|
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,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,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;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;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,UAAU;IACzB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,SAAS;IACxB,kFAAkF;IAClF,QAAQ,EAAE,OAAO,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAMD,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2DAA2D;IAC3D,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC"}
|