@betterlu/notif 0.0.0-stage → 1.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 betterlu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,222 @@
1
- # Temporary Holding Version
1
+ # @betterlu/notif
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Client SDK for [notif](https://github.com/happyx94/notif) — async Telegram / Messenger / Discord / LINE notifications with aliases, retries, and inbound replies.
4
+
5
+ Requires Node.js >= 18 (uses native `fetch`). Zero runtime dependencies.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @betterlu/notif
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```typescript
16
+ import { NotifClient } from "@betterlu/notif";
17
+
18
+ const client = new NotifClient(); // http://localhost:8778
19
+ // or: new NotifClient({ baseUrl: process.env.NOTIF_URL });
20
+
21
+ const n = await client.send({
22
+ channel: "telegram",
23
+ chatId: "larry",
24
+ message: "Deploy finished",
25
+ });
26
+ console.log(n._id, n.status); // pending — worker delivers async
27
+ ```
28
+
29
+ `baseUrl` is the **origin only** (no `/api`). Defaults to `NOTIF_URL` or `http://localhost:8778`.
30
+
31
+ ```bash
32
+ export NOTIF_URL=http://localhost:8778
33
+ ```
34
+
35
+ ## Send a notification
36
+
37
+ `send()` enqueues a job (HTTP 202). Status starts as `pending`; the worker delivers it.
38
+
39
+ | Field | Type | Notes |
40
+ |-------|------|--------|
41
+ | `channel` | string | Channel name, provider type (`telegram` \| `messenger` \| `discord` \| `line` \| `email` \| `chatlu`), or ObjectId |
42
+ | `message` | string | Required |
43
+ | `chatId` | string | Alias name first, else raw chat id |
44
+ | `user` / `userName` | string | Alias-only (back-compat) |
45
+ | `recipient` | `{ chatId?, psid? }` | Raw recipient |
46
+ | `format` | `plain` \| `markdown` \| `html` | Auto-detected if omitted |
47
+ | `options` | object | Provider extras (see below) |
48
+
49
+ `chatId` looks up an alias first, then treats the value as a raw id. Discord **webhook** channels may omit `chatId`. Discord bot, LINE, Telegram, Messenger, and ChatLu require it.
50
+
51
+ ```typescript
52
+ // Alias
53
+ await client.send({ channel: "telegram", chatId: "larry", message: "Hello" });
54
+
55
+ // Raw chat id
56
+ await client.send({ channel: "default-telegram", chatId: "123456789", message: "Hello" });
57
+
58
+ // HTML
59
+ await client.send({
60
+ channel: "telegram",
61
+ userName: "larry",
62
+ message: "<b>Alert</b> disk is full",
63
+ format: "html",
64
+ });
65
+
66
+ // Discord webhook (chatId optional)
67
+ await client.send({
68
+ channel: "alerts-discord",
69
+ message: "Build passed",
70
+ options: { username: "ci", avatarUrl: "https://example.com/bot.png" },
71
+ });
72
+
73
+ // Shorthand
74
+ await client.notify("Hello", { channel: "telegram", chatId: "larry" });
75
+ ```
76
+
77
+ ### Options
78
+
79
+ | Key | Providers |
80
+ |-----|-----------|
81
+ | `disableNotification` | Telegram, Discord, LINE (silent) |
82
+ | `protectContent` | Telegram |
83
+ | `linkPreview` | Telegram |
84
+ | `threadId` | Telegram, Discord (webhook path), ChatLu (Matrix thread event id) |
85
+ | `replyToMessageId` | Telegram, ChatLu (Matrix event id) |
86
+ | `replyMarkup` | Telegram |
87
+ | `messengerTag` | Messenger (`false` → `RESPONSE`; omit for `MESSAGE_TAG`) |
88
+ | `username` / `avatarUrl` | Discord webhook |
89
+ | `subject` | Email (**required**) |
90
+
91
+ ## Status, retry, delete
92
+
93
+ ```typescript
94
+ const items = await client.listNotifications({ status: "failed", limit: 20 });
95
+ const one = await client.getNotification(id);
96
+ await client.retryNotification(id); // failed → pending
97
+ await client.deleteNotification(id);
98
+ ```
99
+
100
+ `listNotifications` filters: `channel` (name or provider type), `status`, `recipient` (regex on chatId/alias), `limit` (default 20, max 50).
101
+
102
+ ## Channels
103
+
104
+ ```typescript
105
+ const channels = await client.listChannels();
106
+ const ch = await client.createChannel({
107
+ name: "alerts-telegram",
108
+ provider: "telegram",
109
+ isDefault: false,
110
+ config: { botToken: "..." },
111
+ });
112
+ await client.updateChannel(ch._id, { isDefault: true });
113
+ await client.registerWebhook(ch._id, { baseUrl: "https://example.com" }); // telegram only
114
+ await client.deleteChannel(ch._id);
115
+ ```
116
+
117
+ Secrets in responses are masked (`abcd••••wxyz`).
118
+
119
+ ### Channel config by provider
120
+
121
+ | Provider | Required | Optional |
122
+ |----------|----------|----------|
123
+ | `telegram` | `botToken` | `webhookSecretToken` |
124
+ | `messenger` | `pageAccessToken` | `apiVersion`, `verifyToken`, `appSecret` |
125
+ | `discord` | `webhookUrl` and/or `botToken` | `username` |
126
+ | `line` | `channelAccessToken` | `channelSecret` |
127
+ | `email` | `host`, `user`, `pass` | `port` (587), `secure` (false), `from`, `fromName` |
128
+ | `chatlu` | `homeserverUrl`, `accessToken` | — |
129
+
130
+ Name: `^[a-zA-Z0-9_-]+$`, not reserved (`telegram` / `messenger` / `discord` / `line` / `email` / `chatlu`).
131
+
132
+ Email channels send over SMTP and require `options.subject`; `chatId` is the recipient address (alias lookup applies first).
133
+
134
+ ChatLu channels deliver to Matrix rooms via the homeserver's client API; `chatId` is a room ID (`!room:chatlu.lan`) or room alias (`#room:chatlu.lan`). Create the bot with `scripts/chatlu-bot-setup.sh`.
135
+
136
+ ## Aliases
137
+
138
+ Friendly name → per-channel chat ids.
139
+
140
+ ```typescript
141
+ await client.createAlias({
142
+ name: "larry",
143
+ mappings: { "default-telegram": "123456789", "alerts-discord": "987654321" },
144
+ });
145
+ const aliases = await client.listAliases();
146
+ await client.updateAlias(id, { mappings: { "default-telegram": "111" } });
147
+ await client.deleteAlias(id);
148
+ ```
149
+
150
+ ## Inbound replies
151
+
152
+ Telegram / Messenger / LINE webhooks persist inbound events. List omits `rawPayload`; `getInbound` includes it.
153
+
154
+ ```typescript
155
+ const replies = await client.listInbound({ channel: "telegram", matched: true, limit: 20 });
156
+ const full = await client.getInbound(replies[0]._id);
157
+ ```
158
+
159
+ ## Health
160
+
161
+ ```typescript
162
+ const h = await client.health();
163
+ // { ok, workerRunning, notificationCount, aliasCount, channelCount, channels, providers }
164
+ ```
165
+
166
+ ## Errors
167
+
168
+ ```typescript
169
+ import { NotifClient, NotifError } from "@betterlu/notif";
170
+
171
+ try {
172
+ await client.send({ channel: "telegram", message: "" });
173
+ } catch (err) {
174
+ if (err instanceof NotifError) {
175
+ console.error(err.status, err.message); // 400 message is required
176
+ } else {
177
+ throw err;
178
+ }
179
+ }
180
+ ```
181
+
182
+ No auth. Inject `fetch` for tests or custom middleware:
183
+
184
+ ```typescript
185
+ const client = new NotifClient({
186
+ baseUrl: "http://localhost:8778",
187
+ fetch: myFetch,
188
+ });
189
+ ```
190
+
191
+ ## API reference
192
+
193
+ ### `NotifClient`
194
+
195
+ | Method | Returns | Description |
196
+ |--------|---------|-------------|
197
+ | `health()` | `HealthResponse` | Worker + channel list |
198
+ | `send(req)` | `Notification` | Enqueue (202) |
199
+ | `notify(message, opts?)` | `Notification` | Shorthand for `send` |
200
+ | `notifyTelegramHtml(user, html)` | `Notification` | Telegram HTML to an alias (`userName`) |
201
+ | `escapeHtml(value)` | `string` | Escape `& < > " '` for Telegram HTML |
202
+ | `listNotifications(query?)` | `Notification[]` | Filter queue |
203
+ | `getNotification(id)` | `Notification` | One notification |
204
+ | `retryNotification(id)` | `Notification` | Re-queue a failed send |
205
+ | `deleteNotification(id)` | `Notification` | Delete |
206
+ | `listChannels()` | `Channel[]` | All channels |
207
+ | `getChannel(id)` | `Channel` | One channel (secrets masked) |
208
+ | `createChannel(req)` | `Channel` | Create |
209
+ | `updateChannel(id, req)` | `Channel` | Partial update |
210
+ | `deleteChannel(id)` | `Channel` | Delete |
211
+ | `registerWebhook(id, req?)` | `RegisterWebhookResult` | Telegram `setWebhook` |
212
+ | `listAliases(query?)` | `Alias[]` | All aliases |
213
+ | `getAlias(id)` | `Alias` | One alias |
214
+ | `createAlias(req)` | `Alias` | Create |
215
+ | `updateAlias(id, req)` | `Alias` | Update |
216
+ | `deleteAlias(id)` | `Alias` | Delete |
217
+ | `listInbound(query?)` | `InboundResponse[]` | Inbound events (no `rawPayload`) |
218
+ | `getInbound(id)` | `InboundResponse` | One inbound (includes `rawPayload`) |
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,27 @@
1
+ import type { Alias, Channel, ClientOptions, CreateAliasRequest, CreateChannelRequest, HealthResponse, InboundResponse, ListAliasesQuery, ListInboundQuery, ListNotificationsQuery, Notification, RegisterWebhookRequest, RegisterWebhookResult, SendNotificationRequest, UpdateAliasRequest, UpdateChannelRequest } from "./types.js";
2
+ export declare class NotifClient {
3
+ private readonly transport;
4
+ constructor(options?: ClientOptions);
5
+ health(): Promise<HealthResponse>;
6
+ send(request: SendNotificationRequest): Promise<Notification>;
7
+ notify(message: string, opts?: Omit<SendNotificationRequest, "message">): Promise<Notification>;
8
+ notifyTelegramHtml(user: string, html: string): Promise<Notification>;
9
+ listNotifications(query?: ListNotificationsQuery): Promise<Notification[]>;
10
+ getNotification(id: string): Promise<Notification>;
11
+ retryNotification(id: string): Promise<Notification>;
12
+ deleteNotification(id: string): Promise<Notification>;
13
+ listChannels(): Promise<Channel[]>;
14
+ getChannel(id: string): Promise<Channel>;
15
+ createChannel(request: CreateChannelRequest): Promise<Channel>;
16
+ updateChannel(id: string, request: UpdateChannelRequest): Promise<Channel>;
17
+ deleteChannel(id: string): Promise<Channel>;
18
+ registerWebhook(id: string, request?: RegisterWebhookRequest): Promise<RegisterWebhookResult>;
19
+ listAliases(query?: ListAliasesQuery): Promise<Alias[]>;
20
+ getAlias(id: string): Promise<Alias>;
21
+ createAlias(request: CreateAliasRequest): Promise<Alias>;
22
+ updateAlias(id: string, request: UpdateAliasRequest): Promise<Alias>;
23
+ deleteAlias(id: string): Promise<Alias>;
24
+ listInbound(query?: ListInboundQuery): Promise<InboundResponse[]>;
25
+ getInbound(id: string): Promise<InboundResponse>;
26
+ }
27
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,KAAK,EACL,OAAO,EACP,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAQpB,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,OAAO,GAAE,aAAkB;IAQjC,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;IAIjC,IAAI,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,YAAY,CAAC;IAI7D,MAAM,CACV,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,IAAI,CAAC,uBAAuB,EAAE,SAAS,CAAM,GAClD,OAAO,CAAC,YAAY,CAAC;IAIlB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIrE,iBAAiB,CAAC,KAAK,GAAE,sBAA2B,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAI9E,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIlD,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIpD,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAIrD,YAAY,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAIlC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxC,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9D,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1E,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI3C,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAQjG,WAAW,CAAC,KAAK,GAAE,gBAAqB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAI3D,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAIpC,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC;IAIxD,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC;IAIpE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAIvC,WAAW,CAAC,KAAK,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAIrE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;CAGvD"}
package/dist/client.js ADDED
@@ -0,0 +1,80 @@
1
+ import { DEFAULT_BASE_URL, ENV_URL_VAR } from "./types.js";
2
+ import { createTransport } from "./transport.js";
3
+ function resolveBaseUrl(baseUrl) {
4
+ const raw = baseUrl ?? (typeof process !== "undefined" ? process.env[ENV_URL_VAR] : undefined) ?? DEFAULT_BASE_URL;
5
+ return raw.replace(/\/+$/, "");
6
+ }
7
+ export class NotifClient {
8
+ transport;
9
+ constructor(options = {}) {
10
+ this.transport = createTransport({
11
+ baseUrl: resolveBaseUrl(options.baseUrl),
12
+ fetch: options.fetch,
13
+ timeoutMs: options.timeoutMs,
14
+ });
15
+ }
16
+ async health() {
17
+ return this.transport.request("GET", "/api/health");
18
+ }
19
+ async send(request) {
20
+ return this.transport.request("POST", "/api/notifications", request);
21
+ }
22
+ async notify(message, opts = {}) {
23
+ return this.send({ ...opts, message });
24
+ }
25
+ async notifyTelegramHtml(user, html) {
26
+ return this.send({ channel: "telegram", userName: user, message: html, format: "html" });
27
+ }
28
+ async listNotifications(query = {}) {
29
+ return this.transport.request("GET", "/api/notifications", undefined, query);
30
+ }
31
+ async getNotification(id) {
32
+ return this.transport.request("GET", `/api/notifications/${id}`);
33
+ }
34
+ async retryNotification(id) {
35
+ return this.transport.request("POST", `/api/notifications/${id}/retry`);
36
+ }
37
+ async deleteNotification(id) {
38
+ return this.transport.request("DELETE", `/api/notifications/${id}`);
39
+ }
40
+ async listChannels() {
41
+ return this.transport.request("GET", "/api/channels");
42
+ }
43
+ async getChannel(id) {
44
+ return this.transport.request("GET", `/api/channels/${id}`);
45
+ }
46
+ async createChannel(request) {
47
+ return this.transport.request("POST", "/api/channels", request);
48
+ }
49
+ async updateChannel(id, request) {
50
+ return this.transport.request("PUT", `/api/channels/${id}`, request);
51
+ }
52
+ async deleteChannel(id) {
53
+ return this.transport.request("DELETE", `/api/channels/${id}`);
54
+ }
55
+ async registerWebhook(id, request = {}) {
56
+ return this.transport.request("POST", `/api/channels/${id}/register-webhook`, request);
57
+ }
58
+ async listAliases(query = {}) {
59
+ return this.transport.request("GET", "/api/aliases", undefined, query);
60
+ }
61
+ async getAlias(id) {
62
+ return this.transport.request("GET", `/api/aliases/${id}`);
63
+ }
64
+ async createAlias(request) {
65
+ return this.transport.request("POST", "/api/aliases", request);
66
+ }
67
+ async updateAlias(id, request) {
68
+ return this.transport.request("PUT", `/api/aliases/${id}`, request);
69
+ }
70
+ async deleteAlias(id) {
71
+ return this.transport.request("DELETE", `/api/aliases/${id}`);
72
+ }
73
+ async listInbound(query = {}) {
74
+ return this.transport.request("GET", "/api/inbound-responses", undefined, query);
75
+ }
76
+ async getInbound(id) {
77
+ return this.transport.request("GET", `/api/inbound-responses/${id}`);
78
+ }
79
+ }
80
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare class NotifError extends Error {
2
+ readonly status: number;
3
+ constructor(status: number, message: string);
4
+ }
5
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAEnB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C"}
package/dist/errors.js ADDED
@@ -0,0 +1,9 @@
1
+ export class NotifError extends Error {
2
+ status;
3
+ constructor(status, message) {
4
+ super(message);
5
+ this.name = "NotifError";
6
+ this.status = status;
7
+ }
8
+ }
9
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnB,MAAM,CAAS;IAE/B,YAAY,MAAc,EAAE,OAAe;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
package/dist/html.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /** Escape text for Telegram HTML. `&` is handled in the same pass so entities are not double-escaped. */
2
+ export declare function escapeHtml(value: string): string;
3
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAQA,yGAAyG;AACzG,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD"}
package/dist/html.js ADDED
@@ -0,0 +1,12 @@
1
+ const REPLACEMENTS = {
2
+ "&": "&amp;",
3
+ "<": "&lt;",
4
+ ">": "&gt;",
5
+ '"': "&quot;",
6
+ "'": "&#39;",
7
+ };
8
+ /** Escape text for Telegram HTML. `&` is handled in the same pass so entities are not double-escaped. */
9
+ export function escapeHtml(value) {
10
+ return value.replace(/[&<>"']/g, (char) => REPLACEMENTS[char]);
11
+ }
12
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAA2B;IAC3C,GAAG,EAAE,OAAO;IACZ,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,OAAO;CACb,CAAC;AAEF,yGAAyG;AACzG,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAE,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { NotifClient } from "./client.js";
2
+ export { escapeHtml } from "./html.js";
3
+ export { NotifError } from "./errors.js";
4
+ export { ENDPOINTS, DEFAULT_BASE_URL, ENV_URL_VAR } from "./types.js";
5
+ export type { ClientOptions, Provider, Format, NotificationStatus, CorrelationMethod, CorrelationConfidence, NotificationOptions, Recipient, SendNotificationRequest, NotificationError, Notification, ListNotificationsQuery, TelegramChannelConfig, MessengerChannelConfig, DiscordChannelConfig, LineChannelConfig, ChannelConfig, Channel, CreateChannelRequest, UpdateChannelRequest, RegisterWebhookRequest, RegisterWebhookResult, Alias, CreateAliasRequest, UpdateAliasRequest, ListAliasesQuery, InboundResponse, ListInboundQuery, HealthResponse, } from "./types.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACtE,YAAY,EACV,aAAa,EACb,QAAQ,EACR,MAAM,EACN,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,SAAS,EACT,uBAAuB,EACvB,iBAAiB,EACjB,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,OAAO,EACP,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,EACL,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,cAAc,GACf,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { NotifClient } from "./client.js";
2
+ export { escapeHtml } from "./html.js";
3
+ export { NotifError } from "./errors.js";
4
+ export { ENDPOINTS, DEFAULT_BASE_URL, ENV_URL_VAR } from "./types.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface TransportOptions {
2
+ baseUrl: string;
3
+ fetch?: typeof globalThis.fetch;
4
+ timeoutMs?: number;
5
+ }
6
+ type QueryParams = object;
7
+ export declare function createTransport(opts: TransportOptions): {
8
+ request: <T>(method: string, path: string, body?: unknown, query?: QueryParams) => Promise<T>;
9
+ };
10
+ export type Transport = ReturnType<typeof createTransport>;
11
+ export {};
12
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD,KAAK,WAAW,GAAG,MAAM,CAAC;AA8D1B,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB;cAExC,CAAC,UACD,MAAM,QACR,MAAM,SACL,OAAO,UACN,WAAW;EAGxB;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { NotifError } from "./errors.js";
2
+ function toQuery(params) {
3
+ if (!params)
4
+ return "";
5
+ const search = new URLSearchParams();
6
+ for (const [key, value] of Object.entries(params)) {
7
+ if (value === undefined)
8
+ continue;
9
+ search.set(key, String(value));
10
+ }
11
+ const qs = search.toString();
12
+ return qs ? `?${qs}` : "";
13
+ }
14
+ async function request(opts, method, path, body, query) {
15
+ const fetchFn = opts.fetch ?? globalThis.fetch;
16
+ const url = `${opts.baseUrl}${path}${toQuery(query)}`;
17
+ const headers = {};
18
+ let reqBody;
19
+ if (body !== undefined) {
20
+ headers["Content-Type"] = "application/json";
21
+ reqBody = JSON.stringify(body);
22
+ }
23
+ const res = await fetchFn(url, {
24
+ method,
25
+ headers,
26
+ body: reqBody,
27
+ signal: opts.timeoutMs ? AbortSignal.timeout(opts.timeoutMs) : undefined,
28
+ });
29
+ let json;
30
+ try {
31
+ json = (await res.json());
32
+ }
33
+ catch {
34
+ if (!res.ok) {
35
+ throw new NotifError(res.status, `HTTP ${res.status}`);
36
+ }
37
+ throw new NotifError(res.status, "Response is not JSON");
38
+ }
39
+ if (!res.ok) {
40
+ const message = json && typeof json === "object" && "error" in json && typeof json.error === "string"
41
+ ? json.error
42
+ : `HTTP ${res.status}`;
43
+ throw new NotifError(res.status, message);
44
+ }
45
+ if (json && typeof json === "object" && "data" in json && json.ok === true) {
46
+ return json.data;
47
+ }
48
+ return json;
49
+ }
50
+ export function createTransport(opts) {
51
+ return {
52
+ request: (method, path, body, query) => request(opts, method, path, body, query),
53
+ };
54
+ }
55
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,216 @@
1
+ export declare const ENDPOINTS: {
2
+ readonly local: "http://localhost:8778";
3
+ };
4
+ export declare const DEFAULT_BASE_URL: "http://localhost:8778";
5
+ export declare const ENV_URL_VAR = "NOTIF_URL";
6
+ export interface ClientOptions {
7
+ /** Origin only (no `/api`). Defaults to `NOTIF_URL` or `http://localhost:8778`. */
8
+ baseUrl?: string;
9
+ fetch?: typeof globalThis.fetch;
10
+ /** Abort each request after this many milliseconds. */
11
+ timeoutMs?: number;
12
+ }
13
+ export type Provider = "telegram" | "messenger" | "discord" | "line" | "email" | "chatlu";
14
+ export type Format = "plain" | "markdown" | "html";
15
+ export type NotificationStatus = "pending" | "processing" | "sent" | "failed";
16
+ export type CorrelationMethod = "unmatched" | "reply_metadata" | "known_sender" | "sender_recent_sent" | "ambiguous";
17
+ export type CorrelationConfidence = "none" | "medium" | "high";
18
+ export interface NotificationOptions {
19
+ disableNotification?: boolean;
20
+ protectContent?: boolean;
21
+ linkPreview?: boolean;
22
+ threadId?: string | number;
23
+ replyToMessageId?: string | number;
24
+ replyMarkup?: unknown;
25
+ messengerTag?: string | false | null;
26
+ username?: string;
27
+ avatarUrl?: string;
28
+ /** Required for email channels. */
29
+ subject?: string;
30
+ }
31
+ export interface Recipient {
32
+ chatId?: string | null;
33
+ psid?: string | null;
34
+ }
35
+ export interface SendNotificationRequest {
36
+ /** Channel name, provider type (`telegram` | …), or channel ObjectId. */
37
+ channel?: string;
38
+ /** Alternate field for `channel`. */
39
+ channelId?: string;
40
+ message: string;
41
+ /** Alias name first, else raw chat id. */
42
+ chatId?: string;
43
+ /** Alias-only (back-compat). */
44
+ user?: string;
45
+ /** Alias-only (back-compat). */
46
+ userName?: string;
47
+ recipient?: Recipient;
48
+ format?: Format;
49
+ options?: NotificationOptions;
50
+ }
51
+ export interface NotificationError {
52
+ code?: string;
53
+ message?: string;
54
+ retryable?: boolean;
55
+ raw?: unknown;
56
+ at?: string;
57
+ }
58
+ export interface Notification {
59
+ _id: string;
60
+ channel: string;
61
+ channelId: string;
62
+ provider: Provider;
63
+ message: string;
64
+ format: Format;
65
+ recipient: Recipient;
66
+ chatId: string | null;
67
+ alias: string | null;
68
+ userName: string | null;
69
+ options: NotificationOptions | null;
70
+ status: NotificationStatus;
71
+ attempts: number;
72
+ maxAttempts: number;
73
+ nextAttemptAt: string;
74
+ lastAttemptAt: string | null;
75
+ providerMessageId: string | null;
76
+ providerResponse: unknown;
77
+ error: NotificationError | null;
78
+ createdAt: string;
79
+ updatedAt: string;
80
+ }
81
+ export interface ListNotificationsQuery {
82
+ /** Channel name, or provider type (`telegram` filters by provider). */
83
+ channel?: string;
84
+ status?: NotificationStatus;
85
+ recipient?: string;
86
+ /** Default 50, max 50. */
87
+ limit?: number;
88
+ }
89
+ export interface TelegramChannelConfig {
90
+ botToken?: string;
91
+ webhookSecretToken?: string;
92
+ }
93
+ export interface MessengerChannelConfig {
94
+ pageAccessToken?: string;
95
+ apiVersion?: string;
96
+ verifyToken?: string;
97
+ appSecret?: string;
98
+ }
99
+ export interface DiscordChannelConfig {
100
+ webhookUrl?: string;
101
+ botToken?: string;
102
+ username?: string;
103
+ }
104
+ export interface LineChannelConfig {
105
+ channelAccessToken?: string;
106
+ channelSecret?: string;
107
+ }
108
+ export interface EmailChannelConfig {
109
+ host?: string;
110
+ port?: number;
111
+ secure?: boolean;
112
+ user?: string;
113
+ pass?: string;
114
+ from?: string;
115
+ fromName?: string;
116
+ }
117
+ export interface ChatluChannelConfig {
118
+ /** Matrix homeserver base URL, e.g. `http://127.0.0.1:8008`. */
119
+ homeserverUrl?: string;
120
+ /** Bot user access token (sent as `Authorization: Bearer`). */
121
+ accessToken?: string;
122
+ }
123
+ export type ChannelConfig = TelegramChannelConfig | MessengerChannelConfig | DiscordChannelConfig | LineChannelConfig | EmailChannelConfig | ChatluChannelConfig | Record<string, string | undefined>;
124
+ export interface Channel {
125
+ _id: string;
126
+ name: string;
127
+ provider: Provider;
128
+ config: ChannelConfig;
129
+ isDefault: boolean;
130
+ createdAt: string;
131
+ updatedAt: string;
132
+ }
133
+ export interface CreateChannelRequest {
134
+ name: string;
135
+ provider: Provider;
136
+ isDefault?: boolean;
137
+ config: ChannelConfig;
138
+ }
139
+ export interface UpdateChannelRequest {
140
+ name?: string;
141
+ provider?: Provider;
142
+ isDefault?: boolean;
143
+ config?: ChannelConfig;
144
+ }
145
+ export interface RegisterWebhookRequest {
146
+ baseUrl?: string;
147
+ }
148
+ export interface RegisterWebhookResult {
149
+ webhookUrl: string;
150
+ raw: unknown;
151
+ }
152
+ export interface Alias {
153
+ _id: string;
154
+ name: string;
155
+ normalizedName: string;
156
+ mappings: Record<string, string>;
157
+ createdAt: string;
158
+ updatedAt: string;
159
+ }
160
+ export interface CreateAliasRequest {
161
+ name: string;
162
+ mappings: Record<string, string>;
163
+ }
164
+ export interface UpdateAliasRequest {
165
+ name?: string;
166
+ mappings?: Record<string, string>;
167
+ }
168
+ export interface ListAliasesQuery {
169
+ /** Default 500, max 500. */
170
+ limit?: number;
171
+ }
172
+ export interface InboundResponse {
173
+ _id: string;
174
+ channel: string;
175
+ channelId: string | null;
176
+ provider?: Provider;
177
+ providerEventId: string;
178
+ providerMessageId: string | null;
179
+ senderId: string | null;
180
+ recipientId: string | null;
181
+ senderDisplayName: string | null;
182
+ messageText: string | null;
183
+ eventType: string | null;
184
+ rawPayload?: unknown;
185
+ matchedNotificationId: string | null;
186
+ matchedAliasId: string | null;
187
+ matchedUserId: string | null;
188
+ correlationMethod?: CorrelationMethod;
189
+ correlationConfidence?: CorrelationConfidence;
190
+ isMatched: boolean;
191
+ receivedAt: string;
192
+ createdAt: string;
193
+ updatedAt: string;
194
+ }
195
+ export interface ListInboundQuery {
196
+ /** Channel name, or provider type. */
197
+ channel?: string;
198
+ matched?: boolean;
199
+ senderId?: string;
200
+ aliasId?: string;
201
+ userId?: string;
202
+ channelId?: string;
203
+ notificationId?: string;
204
+ /** Default 50, max 100. */
205
+ limit?: number;
206
+ }
207
+ export interface HealthResponse {
208
+ ok: boolean;
209
+ workerRunning: boolean;
210
+ notificationCount: number;
211
+ aliasCount: number;
212
+ channelCount: number;
213
+ channels: Channel[];
214
+ providers: Provider[];
215
+ }
216
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ export const ENDPOINTS = {
2
+ local: "http://localhost:8778",
3
+ };
4
+ export const DEFAULT_BASE_URL = ENDPOINTS.local;
5
+ export const ENV_URL_VAR = "NOTIF_URL";
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,KAAK,EAAE,uBAAuB;CACtB,CAAC;AAEX,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC,KAAK,CAAC;AAEhD,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "@betterlu/notif",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.1.0",
4
+ "description": "Client SDK for notif — async Telegram / Messenger / Discord / LINE / email / ChatLu notifications",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "sideEffects": false,
18
+ "scripts": {
19
+ "build": "rm -rf dist && tsc",
20
+ "typecheck": "tsc --noEmit",
21
+ "prepublishOnly": "npm run build",
22
+ "clean": "rm -rf dist"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "keywords": [
28
+ "notif",
29
+ "notifications",
30
+ "telegram",
31
+ "messenger",
32
+ "discord",
33
+ "line",
34
+ "sdk"
35
+ ],
36
+ "author": "betterlu",
37
+ "license": "MIT",
38
+ "engines": {
39
+ "node": ">=18"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.10.0",
43
+ "typescript": "^5.7.3"
44
+ }
45
+ }