@smarthivelabs-devs/hive-socket-node 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 +365 -0
- package/dist/index.cjs +147 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +72 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
# @smarthivelabs-devs/hive-socket-node
|
|
2
|
+
|
|
3
|
+
Node.js SDK for Hive-Socket — push real-time notifications and events to connected clients from any backend service.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @smarthivelabs-devs/hive-socket-node
|
|
9
|
+
# or
|
|
10
|
+
yarn add @smarthivelabs-devs/hive-socket-node
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @smarthivelabs-devs/hive-socket-node
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Requirements:** Node 18+ (uses native `fetch`). No peer dependencies.
|
|
16
|
+
|
|
17
|
+
Supports both ESM and CommonJS:
|
|
18
|
+
```typescript
|
|
19
|
+
// ESM
|
|
20
|
+
import { createHiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';
|
|
21
|
+
|
|
22
|
+
// CommonJS
|
|
23
|
+
const { createHiveSocketClient } = require('@smarthivelabs-devs/hive-socket-node');
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Environment variables
|
|
29
|
+
|
|
30
|
+
Add to your backend `.env`:
|
|
31
|
+
|
|
32
|
+
```env
|
|
33
|
+
HIVE_SOCKET_URL=https://socket.smarthivelabs.dev
|
|
34
|
+
HIVE_SOCKET_API_KEY=shai_hivesocket_<your-key>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Get the API key from the Hive-Socket server's `.env` (`INTERNAL_API_KEY`).
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { createHiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';
|
|
45
|
+
|
|
46
|
+
const hive = createHiveSocketClient({
|
|
47
|
+
baseUrl: process.env.HIVE_SOCKET_URL!,
|
|
48
|
+
apiKey: process.env.HIVE_SOCKET_API_KEY!,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Push a notification to a user
|
|
52
|
+
await hive.notify.user('user-id-123', {
|
|
53
|
+
projectId: 'your-project-id',
|
|
54
|
+
title: 'New message',
|
|
55
|
+
body: 'Alice sent you a message',
|
|
56
|
+
type: 'message',
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## API
|
|
63
|
+
|
|
64
|
+
### `createHiveSocketClient(config)`
|
|
65
|
+
|
|
66
|
+
Creates a client instance. Create once and reuse across your application.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const hive = createHiveSocketClient({
|
|
70
|
+
baseUrl: 'https://socket.smarthivelabs.dev', // Hive-Socket server URL
|
|
71
|
+
apiKey: 'shai_hivesocket_...', // Internal API key
|
|
72
|
+
timeout: 10_000, // Optional. Request timeout in ms. Default: 10000
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### `hive.notify.user(userId, payload)`
|
|
79
|
+
|
|
80
|
+
Push a notification to a specific user. Delivered instantly to all their connected devices. If the user is offline, the notification is persisted and delivered on their next login.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
await hive.notify.user(userId, {
|
|
84
|
+
projectId: string, // Your SmartHive project ID
|
|
85
|
+
title: string, // Notification title
|
|
86
|
+
body: string, // Notification body
|
|
87
|
+
type: NotificationType, // 'info' | 'success' | 'warning' | 'error' | 'message'
|
|
88
|
+
metadata?: Record<string, unknown>, // Optional — any JSON data
|
|
89
|
+
sourceService?: string, // Optional — identifies the sending service
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Example — payment confirmed:**
|
|
94
|
+
```typescript
|
|
95
|
+
await hive.notify.user(userId, {
|
|
96
|
+
projectId: 'workspace-project-id',
|
|
97
|
+
title: 'Payment confirmed',
|
|
98
|
+
body: `₦${amount.toLocaleString()} received`,
|
|
99
|
+
type: 'success',
|
|
100
|
+
metadata: { paymentId, amount },
|
|
101
|
+
sourceService: 'payment-backend',
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Example — new comment:**
|
|
106
|
+
```typescript
|
|
107
|
+
await hive.notify.user(comment.authorId, {
|
|
108
|
+
projectId: workspace.projectId,
|
|
109
|
+
title: 'New reply',
|
|
110
|
+
body: `${commenter.name} replied to your comment`,
|
|
111
|
+
type: 'message',
|
|
112
|
+
metadata: { commentId: comment.id, threadId: comment.threadId },
|
|
113
|
+
sourceService: 'workspace-backend',
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
### `hive.notify.room(roomId, payload)`
|
|
120
|
+
|
|
121
|
+
Broadcast a notification to all users currently in a room. Room notifications are ephemeral — not persisted to the database.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
await hive.notify.room(roomId, {
|
|
125
|
+
projectId: string,
|
|
126
|
+
title: string,
|
|
127
|
+
body: string,
|
|
128
|
+
type: NotificationType,
|
|
129
|
+
metadata?: Record<string, unknown>,
|
|
130
|
+
sourceService?: string,
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Example — quiz started:**
|
|
135
|
+
```typescript
|
|
136
|
+
await hive.notify.room(`course:${courseId}`, {
|
|
137
|
+
projectId: 'hivedemia-project-id',
|
|
138
|
+
title: 'Quiz started',
|
|
139
|
+
body: 'Chapter 3 quiz is now live',
|
|
140
|
+
type: 'info',
|
|
141
|
+
sourceService: 'hivedemia-backend',
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Example — live vote update:**
|
|
146
|
+
```typescript
|
|
147
|
+
await hive.notify.room(`event:${eventId}`, {
|
|
148
|
+
projectId: 'votyhive-project-id',
|
|
149
|
+
title: 'Results updated',
|
|
150
|
+
body: 'New votes have been counted',
|
|
151
|
+
type: 'info',
|
|
152
|
+
metadata: { candidateId, totalVotes },
|
|
153
|
+
sourceService: 'votyhive-backend',
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### `hive.health()`
|
|
160
|
+
|
|
161
|
+
Check server health and current connection count.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const { status, connections, uptime } = await hive.health();
|
|
165
|
+
// { status: 'ok', connections: 42, uptime: 3600 }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Error handling
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import {
|
|
174
|
+
HiveSocketAuthError,
|
|
175
|
+
HiveSocketNetworkError,
|
|
176
|
+
HiveSocketError,
|
|
177
|
+
} from '@smarthivelabs-devs/hive-socket-node';
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
await hive.notify.user(userId, payload);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
if (err instanceof HiveSocketAuthError) {
|
|
183
|
+
// HTTP 401 — wrong API key
|
|
184
|
+
// Check HIVE_SOCKET_API_KEY matches INTERNAL_API_KEY on the server
|
|
185
|
+
} else if (err instanceof HiveSocketNetworkError) {
|
|
186
|
+
// Network failure or request timed out
|
|
187
|
+
// Safe to retry with exponential backoff
|
|
188
|
+
} else if (err instanceof HiveSocketError) {
|
|
189
|
+
// Other server error
|
|
190
|
+
console.error(err.message, err.statusCode);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## NestJS integration
|
|
198
|
+
|
|
199
|
+
### Create a shared module
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// hive-socket.module.ts
|
|
203
|
+
import { Module, Global } from '@nestjs/common';
|
|
204
|
+
import { ConfigService } from '@nestjs/config';
|
|
205
|
+
import { createHiveSocketClient, HiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';
|
|
206
|
+
|
|
207
|
+
export const HIVE_SOCKET = Symbol('HIVE_SOCKET');
|
|
208
|
+
|
|
209
|
+
@Global()
|
|
210
|
+
@Module({
|
|
211
|
+
providers: [
|
|
212
|
+
{
|
|
213
|
+
provide: HIVE_SOCKET,
|
|
214
|
+
inject: [ConfigService],
|
|
215
|
+
useFactory: (config: ConfigService) =>
|
|
216
|
+
createHiveSocketClient({
|
|
217
|
+
baseUrl: config.getOrThrow('HIVE_SOCKET_URL'),
|
|
218
|
+
apiKey: config.getOrThrow('HIVE_SOCKET_API_KEY'),
|
|
219
|
+
}),
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
exports: [HIVE_SOCKET],
|
|
223
|
+
})
|
|
224
|
+
export class HiveSocketModule {}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Inject into any service
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// notifications.service.ts
|
|
231
|
+
import { Injectable, Inject } from '@nestjs/common';
|
|
232
|
+
import { HiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';
|
|
233
|
+
import { HIVE_SOCKET } from './hive-socket.module';
|
|
234
|
+
|
|
235
|
+
@Injectable()
|
|
236
|
+
export class NotificationsService {
|
|
237
|
+
constructor(
|
|
238
|
+
@Inject(HIVE_SOCKET) private readonly hive: HiveSocketClient,
|
|
239
|
+
) {}
|
|
240
|
+
|
|
241
|
+
async sendPaymentNotification(userId: string, projectId: string, amount: number) {
|
|
242
|
+
await this.hive.notify.user(userId, {
|
|
243
|
+
projectId,
|
|
244
|
+
title: 'Payment received',
|
|
245
|
+
body: `Your payment of ₦${amount.toLocaleString()} was confirmed`,
|
|
246
|
+
type: 'success',
|
|
247
|
+
metadata: { amount },
|
|
248
|
+
sourceService: 'payment-service',
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async announceToRoom(roomId: string, projectId: string, message: string) {
|
|
253
|
+
await this.hive.notify.room(roomId, {
|
|
254
|
+
projectId,
|
|
255
|
+
title: 'Announcement',
|
|
256
|
+
body: message,
|
|
257
|
+
type: 'info',
|
|
258
|
+
sourceService: 'admin-service',
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Express / Next.js API route
|
|
267
|
+
|
|
268
|
+
### Express
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// routes/messages.ts
|
|
272
|
+
import { Router } from 'express';
|
|
273
|
+
import { hive } from '../lib/hive-socket'; // your singleton
|
|
274
|
+
|
|
275
|
+
const router = Router();
|
|
276
|
+
|
|
277
|
+
router.post('/messages', async (req, res) => {
|
|
278
|
+
const { userId, projectId, text } = req.body;
|
|
279
|
+
|
|
280
|
+
// ... save message to your DB ...
|
|
281
|
+
|
|
282
|
+
await hive.notify.user(userId, {
|
|
283
|
+
projectId,
|
|
284
|
+
title: 'New message',
|
|
285
|
+
body: text.slice(0, 100),
|
|
286
|
+
type: 'message',
|
|
287
|
+
sourceService: 'workspace-api',
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
res.json({ ok: true });
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Next.js App Router
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// app/api/notify/route.ts
|
|
298
|
+
import { createHiveSocketClient } from '@smarthivelabs-devs/hive-socket-node';
|
|
299
|
+
|
|
300
|
+
const hive = createHiveSocketClient({
|
|
301
|
+
baseUrl: process.env.HIVE_SOCKET_URL!,
|
|
302
|
+
apiKey: process.env.HIVE_SOCKET_API_KEY!,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
export async function POST(req: Request) {
|
|
306
|
+
const { userId, projectId, title, body } = await req.json();
|
|
307
|
+
|
|
308
|
+
await hive.notify.user(userId, {
|
|
309
|
+
projectId,
|
|
310
|
+
title,
|
|
311
|
+
body,
|
|
312
|
+
type: 'info',
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
return Response.json({ ok: true });
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Notification types
|
|
322
|
+
|
|
323
|
+
| Type | When to use |
|
|
324
|
+
|------|-------------|
|
|
325
|
+
| `'message'` | New chat message or direct message |
|
|
326
|
+
| `'info'` | General information (quiz started, event begins) |
|
|
327
|
+
| `'success'` | Positive outcome (payment confirmed, grade posted) |
|
|
328
|
+
| `'warning'` | Requires attention (deadline approaching, low balance) |
|
|
329
|
+
| `'error'` | Something failed (payment declined, submission error) |
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Types
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
import type {
|
|
337
|
+
HiveSocketConfig,
|
|
338
|
+
HiveNotifyPayload,
|
|
339
|
+
HiveHealthResponse,
|
|
340
|
+
NotificationType,
|
|
341
|
+
} from '@smarthivelabs-devs/hive-socket-node';
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
interface HiveSocketConfig {
|
|
346
|
+
baseUrl: string;
|
|
347
|
+
apiKey: string;
|
|
348
|
+
timeout?: number; // ms, default 10000
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
interface HiveNotifyPayload {
|
|
352
|
+
projectId: string;
|
|
353
|
+
title: string;
|
|
354
|
+
body: string;
|
|
355
|
+
type: 'info' | 'success' | 'warning' | 'error' | 'message';
|
|
356
|
+
metadata?: Record<string, unknown>;
|
|
357
|
+
sourceService?: string;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
interface HiveHealthResponse {
|
|
361
|
+
status: 'ok';
|
|
362
|
+
connections: number;
|
|
363
|
+
uptime: number;
|
|
364
|
+
}
|
|
365
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
HiveSocketAuthError: () => HiveSocketAuthError,
|
|
24
|
+
HiveSocketClient: () => HiveSocketClient,
|
|
25
|
+
HiveSocketError: () => HiveSocketError,
|
|
26
|
+
HiveSocketNetworkError: () => HiveSocketNetworkError,
|
|
27
|
+
NotifyResource: () => NotifyResource,
|
|
28
|
+
createHiveSocketClient: () => createHiveSocketClient
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// src/errors.ts
|
|
33
|
+
var HiveSocketError = class extends Error {
|
|
34
|
+
statusCode;
|
|
35
|
+
constructor(message, statusCode) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "HiveSocketError";
|
|
38
|
+
this.statusCode = statusCode;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var HiveSocketAuthError = class extends HiveSocketError {
|
|
42
|
+
constructor(message = "Invalid API key") {
|
|
43
|
+
super(message, 401);
|
|
44
|
+
this.name = "HiveSocketAuthError";
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var HiveSocketNetworkError = class extends HiveSocketError {
|
|
48
|
+
constructor(message) {
|
|
49
|
+
super(message, 0);
|
|
50
|
+
this.name = "HiveSocketNetworkError";
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/resources/notify.ts
|
|
55
|
+
var NotifyResource = class {
|
|
56
|
+
constructor(baseUrl, apiKey, timeout) {
|
|
57
|
+
this.baseUrl = baseUrl;
|
|
58
|
+
this.apiKey = apiKey;
|
|
59
|
+
this.timeout = timeout;
|
|
60
|
+
}
|
|
61
|
+
baseUrl;
|
|
62
|
+
apiKey;
|
|
63
|
+
timeout;
|
|
64
|
+
/** Push a notification to a specific user's connected sockets. */
|
|
65
|
+
async user(userId, payload) {
|
|
66
|
+
await this.post(`/internal/notify/user/${encodeURIComponent(userId)}`, payload);
|
|
67
|
+
}
|
|
68
|
+
/** Broadcast a notification to all sockets in a room. */
|
|
69
|
+
async room(roomId, payload) {
|
|
70
|
+
await this.post(`/internal/notify/room/${encodeURIComponent(roomId)}`, payload);
|
|
71
|
+
}
|
|
72
|
+
async post(path, body) {
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
75
|
+
try {
|
|
76
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: {
|
|
79
|
+
"content-type": "application/json",
|
|
80
|
+
"x-internal-api-key": this.apiKey
|
|
81
|
+
},
|
|
82
|
+
body: JSON.stringify(body),
|
|
83
|
+
signal: controller.signal
|
|
84
|
+
});
|
|
85
|
+
if (res.status === 401) throw new HiveSocketAuthError();
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
const text = await res.text().catch(() => res.statusText);
|
|
88
|
+
throw new HiveSocketError(`Hive-Socket request failed: ${text}`, res.status);
|
|
89
|
+
}
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (err instanceof HiveSocketError) throw err;
|
|
92
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
93
|
+
throw new HiveSocketNetworkError(
|
|
94
|
+
controller.signal.aborted ? `Request timed out after ${this.timeout}ms` : msg
|
|
95
|
+
);
|
|
96
|
+
} finally {
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/client.ts
|
|
103
|
+
var HiveSocketClient = class {
|
|
104
|
+
notify;
|
|
105
|
+
baseUrl;
|
|
106
|
+
apiKey;
|
|
107
|
+
timeout;
|
|
108
|
+
constructor(config) {
|
|
109
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
110
|
+
this.apiKey = config.apiKey;
|
|
111
|
+
this.timeout = config.timeout ?? 1e4;
|
|
112
|
+
this.notify = new NotifyResource(this.baseUrl, this.apiKey, this.timeout);
|
|
113
|
+
}
|
|
114
|
+
/** Check the Hive-Socket server health and current connection count. */
|
|
115
|
+
async health() {
|
|
116
|
+
const controller = new AbortController();
|
|
117
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
118
|
+
try {
|
|
119
|
+
const res = await fetch(`${this.baseUrl}/health`, {
|
|
120
|
+
signal: controller.signal
|
|
121
|
+
});
|
|
122
|
+
if (!res.ok) throw new HiveSocketNetworkError(`Health check failed: ${res.statusText}`);
|
|
123
|
+
return res.json();
|
|
124
|
+
} catch (err) {
|
|
125
|
+
if (err instanceof HiveSocketNetworkError) throw err;
|
|
126
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
127
|
+
throw new HiveSocketNetworkError(
|
|
128
|
+
controller.signal.aborted ? `Health check timed out after ${this.timeout}ms` : msg
|
|
129
|
+
);
|
|
130
|
+
} finally {
|
|
131
|
+
clearTimeout(timer);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function createHiveSocketClient(config) {
|
|
136
|
+
return new HiveSocketClient(config);
|
|
137
|
+
}
|
|
138
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
139
|
+
0 && (module.exports = {
|
|
140
|
+
HiveSocketAuthError,
|
|
141
|
+
HiveSocketClient,
|
|
142
|
+
HiveSocketError,
|
|
143
|
+
HiveSocketNetworkError,
|
|
144
|
+
NotifyResource,
|
|
145
|
+
createHiveSocketClient
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/resources/notify.ts","../src/client.ts"],"sourcesContent":["export { HiveSocketClient, createHiveSocketClient } from './client.js';\nexport { NotifyResource } from './resources/notify.js';\nexport { HiveSocketError, HiveSocketAuthError, HiveSocketNetworkError } from './errors.js';\nexport type {\n HiveSocketConfig,\n HiveNotifyPayload,\n HiveHealthResponse,\n NotificationType,\n} from './types.js';\n","export class HiveSocketError extends Error {\n readonly statusCode: number;\n\n constructor(message: string, statusCode: number) {\n super(message);\n this.name = 'HiveSocketError';\n this.statusCode = statusCode;\n }\n}\n\n/** Thrown when the API key is wrong (HTTP 401) */\nexport class HiveSocketAuthError extends HiveSocketError {\n constructor(message = 'Invalid API key') {\n super(message, 401);\n this.name = 'HiveSocketAuthError';\n }\n}\n\n/** Thrown when the fetch fails entirely (network down, timeout) */\nexport class HiveSocketNetworkError extends HiveSocketError {\n constructor(message: string) {\n super(message, 0);\n this.name = 'HiveSocketNetworkError';\n }\n}\n","import { HiveSocketAuthError, HiveSocketError, HiveSocketNetworkError } from '../errors.js';\nimport type { HiveNotifyPayload } from '../types.js';\n\nexport class NotifyResource {\n constructor(\n private readonly baseUrl: string,\n private readonly apiKey: string,\n private readonly timeout: number,\n ) {}\n\n /** Push a notification to a specific user's connected sockets. */\n async user(userId: string, payload: HiveNotifyPayload): Promise<void> {\n await this.post(`/internal/notify/user/${encodeURIComponent(userId)}`, payload);\n }\n\n /** Broadcast a notification to all sockets in a room. */\n async room(roomId: string, payload: HiveNotifyPayload): Promise<void> {\n await this.post(`/internal/notify/room/${encodeURIComponent(roomId)}`, payload);\n }\n\n private async post(path: string, body: unknown): Promise<void> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-internal-api-key': this.apiKey,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (res.status === 401) throw new HiveSocketAuthError();\n if (!res.ok) {\n const text = await res.text().catch(() => res.statusText);\n throw new HiveSocketError(`Hive-Socket request failed: ${text}`, res.status);\n }\n } catch (err) {\n if (err instanceof HiveSocketError) throw err;\n const msg = err instanceof Error ? err.message : String(err);\n throw new HiveSocketNetworkError(\n controller.signal.aborted ? `Request timed out after ${this.timeout}ms` : msg,\n );\n } finally {\n clearTimeout(timer);\n }\n }\n}\n","import { NotifyResource } from './resources/notify.js';\nimport { HiveSocketNetworkError } from './errors.js';\nimport type { HiveSocketConfig, HiveHealthResponse } from './types.js';\n\nexport class HiveSocketClient {\n readonly notify: NotifyResource;\n\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n\n constructor(config: HiveSocketConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.timeout = config.timeout ?? 10_000;\n this.notify = new NotifyResource(this.baseUrl, this.apiKey, this.timeout);\n }\n\n /** Check the Hive-Socket server health and current connection count. */\n async health(): Promise<HiveHealthResponse> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const res = await fetch(`${this.baseUrl}/health`, {\n signal: controller.signal,\n });\n if (!res.ok) throw new HiveSocketNetworkError(`Health check failed: ${res.statusText}`);\n return res.json() as Promise<HiveHealthResponse>;\n } catch (err) {\n if (err instanceof HiveSocketNetworkError) throw err;\n const msg = err instanceof Error ? err.message : String(err);\n throw new HiveSocketNetworkError(\n controller.signal.aborted ? `Health check timed out after ${this.timeout}ms` : msg,\n );\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n/**\n * Create a Hive-Socket server-side client.\n *\n * @example\n * const hive = createHiveSocketClient({\n * baseUrl: process.env.HIVE_SOCKET_URL!,\n * apiKey: process.env.HIVE_SOCKET_API_KEY!,\n * });\n * await hive.notify.user(userId, { projectId, title: 'Hey', body: 'Msg', type: 'message' });\n */\nexport function createHiveSocketClient(config: HiveSocketConfig): HiveSocketClient {\n return new HiveSocketClient(config);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
type NotificationType = 'info' | 'success' | 'warning' | 'error' | 'message';
|
|
2
|
+
/** Payload sent to POST /internal/notify/user/:userId or /internal/notify/room/:roomId */
|
|
3
|
+
interface HiveNotifyPayload {
|
|
4
|
+
projectId: string;
|
|
5
|
+
title: string;
|
|
6
|
+
body: string;
|
|
7
|
+
type: NotificationType;
|
|
8
|
+
metadata?: Record<string, unknown>;
|
|
9
|
+
sourceService?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Response from GET /health */
|
|
12
|
+
interface HiveHealthResponse {
|
|
13
|
+
status: 'ok';
|
|
14
|
+
connections: number;
|
|
15
|
+
uptime: number;
|
|
16
|
+
}
|
|
17
|
+
interface HiveSocketConfig {
|
|
18
|
+
/** Base URL of the Hive-Socket server, e.g. https://socket.smarthivelabs.dev */
|
|
19
|
+
baseUrl: string;
|
|
20
|
+
/** Internal API key (shai_* format) */
|
|
21
|
+
apiKey: string;
|
|
22
|
+
/** Request timeout in ms. Default: 10000 */
|
|
23
|
+
timeout?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare class NotifyResource {
|
|
27
|
+
private readonly baseUrl;
|
|
28
|
+
private readonly apiKey;
|
|
29
|
+
private readonly timeout;
|
|
30
|
+
constructor(baseUrl: string, apiKey: string, timeout: number);
|
|
31
|
+
/** Push a notification to a specific user's connected sockets. */
|
|
32
|
+
user(userId: string, payload: HiveNotifyPayload): Promise<void>;
|
|
33
|
+
/** Broadcast a notification to all sockets in a room. */
|
|
34
|
+
room(roomId: string, payload: HiveNotifyPayload): Promise<void>;
|
|
35
|
+
private post;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare class HiveSocketClient {
|
|
39
|
+
readonly notify: NotifyResource;
|
|
40
|
+
private readonly baseUrl;
|
|
41
|
+
private readonly apiKey;
|
|
42
|
+
private readonly timeout;
|
|
43
|
+
constructor(config: HiveSocketConfig);
|
|
44
|
+
/** Check the Hive-Socket server health and current connection count. */
|
|
45
|
+
health(): Promise<HiveHealthResponse>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a Hive-Socket server-side client.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const hive = createHiveSocketClient({
|
|
52
|
+
* baseUrl: process.env.HIVE_SOCKET_URL!,
|
|
53
|
+
* apiKey: process.env.HIVE_SOCKET_API_KEY!,
|
|
54
|
+
* });
|
|
55
|
+
* await hive.notify.user(userId, { projectId, title: 'Hey', body: 'Msg', type: 'message' });
|
|
56
|
+
*/
|
|
57
|
+
declare function createHiveSocketClient(config: HiveSocketConfig): HiveSocketClient;
|
|
58
|
+
|
|
59
|
+
declare class HiveSocketError extends Error {
|
|
60
|
+
readonly statusCode: number;
|
|
61
|
+
constructor(message: string, statusCode: number);
|
|
62
|
+
}
|
|
63
|
+
/** Thrown when the API key is wrong (HTTP 401) */
|
|
64
|
+
declare class HiveSocketAuthError extends HiveSocketError {
|
|
65
|
+
constructor(message?: string);
|
|
66
|
+
}
|
|
67
|
+
/** Thrown when the fetch fails entirely (network down, timeout) */
|
|
68
|
+
declare class HiveSocketNetworkError extends HiveSocketError {
|
|
69
|
+
constructor(message: string);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { type HiveHealthResponse, type HiveNotifyPayload, HiveSocketAuthError, HiveSocketClient, type HiveSocketConfig, HiveSocketError, HiveSocketNetworkError, type NotificationType, NotifyResource, createHiveSocketClient };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
type NotificationType = 'info' | 'success' | 'warning' | 'error' | 'message';
|
|
2
|
+
/** Payload sent to POST /internal/notify/user/:userId or /internal/notify/room/:roomId */
|
|
3
|
+
interface HiveNotifyPayload {
|
|
4
|
+
projectId: string;
|
|
5
|
+
title: string;
|
|
6
|
+
body: string;
|
|
7
|
+
type: NotificationType;
|
|
8
|
+
metadata?: Record<string, unknown>;
|
|
9
|
+
sourceService?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Response from GET /health */
|
|
12
|
+
interface HiveHealthResponse {
|
|
13
|
+
status: 'ok';
|
|
14
|
+
connections: number;
|
|
15
|
+
uptime: number;
|
|
16
|
+
}
|
|
17
|
+
interface HiveSocketConfig {
|
|
18
|
+
/** Base URL of the Hive-Socket server, e.g. https://socket.smarthivelabs.dev */
|
|
19
|
+
baseUrl: string;
|
|
20
|
+
/** Internal API key (shai_* format) */
|
|
21
|
+
apiKey: string;
|
|
22
|
+
/** Request timeout in ms. Default: 10000 */
|
|
23
|
+
timeout?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare class NotifyResource {
|
|
27
|
+
private readonly baseUrl;
|
|
28
|
+
private readonly apiKey;
|
|
29
|
+
private readonly timeout;
|
|
30
|
+
constructor(baseUrl: string, apiKey: string, timeout: number);
|
|
31
|
+
/** Push a notification to a specific user's connected sockets. */
|
|
32
|
+
user(userId: string, payload: HiveNotifyPayload): Promise<void>;
|
|
33
|
+
/** Broadcast a notification to all sockets in a room. */
|
|
34
|
+
room(roomId: string, payload: HiveNotifyPayload): Promise<void>;
|
|
35
|
+
private post;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare class HiveSocketClient {
|
|
39
|
+
readonly notify: NotifyResource;
|
|
40
|
+
private readonly baseUrl;
|
|
41
|
+
private readonly apiKey;
|
|
42
|
+
private readonly timeout;
|
|
43
|
+
constructor(config: HiveSocketConfig);
|
|
44
|
+
/** Check the Hive-Socket server health and current connection count. */
|
|
45
|
+
health(): Promise<HiveHealthResponse>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a Hive-Socket server-side client.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const hive = createHiveSocketClient({
|
|
52
|
+
* baseUrl: process.env.HIVE_SOCKET_URL!,
|
|
53
|
+
* apiKey: process.env.HIVE_SOCKET_API_KEY!,
|
|
54
|
+
* });
|
|
55
|
+
* await hive.notify.user(userId, { projectId, title: 'Hey', body: 'Msg', type: 'message' });
|
|
56
|
+
*/
|
|
57
|
+
declare function createHiveSocketClient(config: HiveSocketConfig): HiveSocketClient;
|
|
58
|
+
|
|
59
|
+
declare class HiveSocketError extends Error {
|
|
60
|
+
readonly statusCode: number;
|
|
61
|
+
constructor(message: string, statusCode: number);
|
|
62
|
+
}
|
|
63
|
+
/** Thrown when the API key is wrong (HTTP 401) */
|
|
64
|
+
declare class HiveSocketAuthError extends HiveSocketError {
|
|
65
|
+
constructor(message?: string);
|
|
66
|
+
}
|
|
67
|
+
/** Thrown when the fetch fails entirely (network down, timeout) */
|
|
68
|
+
declare class HiveSocketNetworkError extends HiveSocketError {
|
|
69
|
+
constructor(message: string);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { type HiveHealthResponse, type HiveNotifyPayload, HiveSocketAuthError, HiveSocketClient, type HiveSocketConfig, HiveSocketError, HiveSocketNetworkError, type NotificationType, NotifyResource, createHiveSocketClient };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var HiveSocketError = class extends Error {
|
|
3
|
+
statusCode;
|
|
4
|
+
constructor(message, statusCode) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "HiveSocketError";
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var HiveSocketAuthError = class extends HiveSocketError {
|
|
11
|
+
constructor(message = "Invalid API key") {
|
|
12
|
+
super(message, 401);
|
|
13
|
+
this.name = "HiveSocketAuthError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var HiveSocketNetworkError = class extends HiveSocketError {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message, 0);
|
|
19
|
+
this.name = "HiveSocketNetworkError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// src/resources/notify.ts
|
|
24
|
+
var NotifyResource = class {
|
|
25
|
+
constructor(baseUrl, apiKey, timeout) {
|
|
26
|
+
this.baseUrl = baseUrl;
|
|
27
|
+
this.apiKey = apiKey;
|
|
28
|
+
this.timeout = timeout;
|
|
29
|
+
}
|
|
30
|
+
baseUrl;
|
|
31
|
+
apiKey;
|
|
32
|
+
timeout;
|
|
33
|
+
/** Push a notification to a specific user's connected sockets. */
|
|
34
|
+
async user(userId, payload) {
|
|
35
|
+
await this.post(`/internal/notify/user/${encodeURIComponent(userId)}`, payload);
|
|
36
|
+
}
|
|
37
|
+
/** Broadcast a notification to all sockets in a room. */
|
|
38
|
+
async room(roomId, payload) {
|
|
39
|
+
await this.post(`/internal/notify/room/${encodeURIComponent(roomId)}`, payload);
|
|
40
|
+
}
|
|
41
|
+
async post(path, body) {
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
44
|
+
try {
|
|
45
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"content-type": "application/json",
|
|
49
|
+
"x-internal-api-key": this.apiKey
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(body),
|
|
52
|
+
signal: controller.signal
|
|
53
|
+
});
|
|
54
|
+
if (res.status === 401) throw new HiveSocketAuthError();
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
const text = await res.text().catch(() => res.statusText);
|
|
57
|
+
throw new HiveSocketError(`Hive-Socket request failed: ${text}`, res.status);
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (err instanceof HiveSocketError) throw err;
|
|
61
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
62
|
+
throw new HiveSocketNetworkError(
|
|
63
|
+
controller.signal.aborted ? `Request timed out after ${this.timeout}ms` : msg
|
|
64
|
+
);
|
|
65
|
+
} finally {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/client.ts
|
|
72
|
+
var HiveSocketClient = class {
|
|
73
|
+
notify;
|
|
74
|
+
baseUrl;
|
|
75
|
+
apiKey;
|
|
76
|
+
timeout;
|
|
77
|
+
constructor(config) {
|
|
78
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
79
|
+
this.apiKey = config.apiKey;
|
|
80
|
+
this.timeout = config.timeout ?? 1e4;
|
|
81
|
+
this.notify = new NotifyResource(this.baseUrl, this.apiKey, this.timeout);
|
|
82
|
+
}
|
|
83
|
+
/** Check the Hive-Socket server health and current connection count. */
|
|
84
|
+
async health() {
|
|
85
|
+
const controller = new AbortController();
|
|
86
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch(`${this.baseUrl}/health`, {
|
|
89
|
+
signal: controller.signal
|
|
90
|
+
});
|
|
91
|
+
if (!res.ok) throw new HiveSocketNetworkError(`Health check failed: ${res.statusText}`);
|
|
92
|
+
return res.json();
|
|
93
|
+
} catch (err) {
|
|
94
|
+
if (err instanceof HiveSocketNetworkError) throw err;
|
|
95
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
96
|
+
throw new HiveSocketNetworkError(
|
|
97
|
+
controller.signal.aborted ? `Health check timed out after ${this.timeout}ms` : msg
|
|
98
|
+
);
|
|
99
|
+
} finally {
|
|
100
|
+
clearTimeout(timer);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
function createHiveSocketClient(config) {
|
|
105
|
+
return new HiveSocketClient(config);
|
|
106
|
+
}
|
|
107
|
+
export {
|
|
108
|
+
HiveSocketAuthError,
|
|
109
|
+
HiveSocketClient,
|
|
110
|
+
HiveSocketError,
|
|
111
|
+
HiveSocketNetworkError,
|
|
112
|
+
NotifyResource,
|
|
113
|
+
createHiveSocketClient
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/resources/notify.ts","../src/client.ts"],"sourcesContent":["export class HiveSocketError extends Error {\n readonly statusCode: number;\n\n constructor(message: string, statusCode: number) {\n super(message);\n this.name = 'HiveSocketError';\n this.statusCode = statusCode;\n }\n}\n\n/** Thrown when the API key is wrong (HTTP 401) */\nexport class HiveSocketAuthError extends HiveSocketError {\n constructor(message = 'Invalid API key') {\n super(message, 401);\n this.name = 'HiveSocketAuthError';\n }\n}\n\n/** Thrown when the fetch fails entirely (network down, timeout) */\nexport class HiveSocketNetworkError extends HiveSocketError {\n constructor(message: string) {\n super(message, 0);\n this.name = 'HiveSocketNetworkError';\n }\n}\n","import { HiveSocketAuthError, HiveSocketError, HiveSocketNetworkError } from '../errors.js';\nimport type { HiveNotifyPayload } from '../types.js';\n\nexport class NotifyResource {\n constructor(\n private readonly baseUrl: string,\n private readonly apiKey: string,\n private readonly timeout: number,\n ) {}\n\n /** Push a notification to a specific user's connected sockets. */\n async user(userId: string, payload: HiveNotifyPayload): Promise<void> {\n await this.post(`/internal/notify/user/${encodeURIComponent(userId)}`, payload);\n }\n\n /** Broadcast a notification to all sockets in a room. */\n async room(roomId: string, payload: HiveNotifyPayload): Promise<void> {\n await this.post(`/internal/notify/room/${encodeURIComponent(roomId)}`, payload);\n }\n\n private async post(path: string, body: unknown): Promise<void> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const res = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'x-internal-api-key': this.apiKey,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (res.status === 401) throw new HiveSocketAuthError();\n if (!res.ok) {\n const text = await res.text().catch(() => res.statusText);\n throw new HiveSocketError(`Hive-Socket request failed: ${text}`, res.status);\n }\n } catch (err) {\n if (err instanceof HiveSocketError) throw err;\n const msg = err instanceof Error ? err.message : String(err);\n throw new HiveSocketNetworkError(\n controller.signal.aborted ? `Request timed out after ${this.timeout}ms` : msg,\n );\n } finally {\n clearTimeout(timer);\n }\n }\n}\n","import { NotifyResource } from './resources/notify.js';\nimport { HiveSocketNetworkError } from './errors.js';\nimport type { HiveSocketConfig, HiveHealthResponse } from './types.js';\n\nexport class HiveSocketClient {\n readonly notify: NotifyResource;\n\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n\n constructor(config: HiveSocketConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\n this.apiKey = config.apiKey;\n this.timeout = config.timeout ?? 10_000;\n this.notify = new NotifyResource(this.baseUrl, this.apiKey, this.timeout);\n }\n\n /** Check the Hive-Socket server health and current connection count. */\n async health(): Promise<HiveHealthResponse> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const res = await fetch(`${this.baseUrl}/health`, {\n signal: controller.signal,\n });\n if (!res.ok) throw new HiveSocketNetworkError(`Health check failed: ${res.statusText}`);\n return res.json() as Promise<HiveHealthResponse>;\n } catch (err) {\n if (err instanceof HiveSocketNetworkError) throw err;\n const msg = err instanceof Error ? err.message : String(err);\n throw new HiveSocketNetworkError(\n controller.signal.aborted ? `Health check timed out after ${this.timeout}ms` : msg,\n );\n } finally {\n clearTimeout(timer);\n }\n }\n}\n\n/**\n * Create a Hive-Socket server-side client.\n *\n * @example\n * const hive = createHiveSocketClient({\n * baseUrl: process.env.HIVE_SOCKET_URL!,\n * apiKey: process.env.HIVE_SOCKET_API_KEY!,\n * });\n * await hive.notify.user(userId, { projectId, title: 'Hey', body: 'Msg', type: 'message' });\n */\nexport function createHiveSocketClient(config: HiveSocketConfig): HiveSocketClient {\n return new HiveSocketClient(config);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@smarthivelabs-devs/hive-socket-node",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Node.js SDK for Hive-Socket — push notifications and events to connected clients",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"files": ["dist", "README.md"],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"prepublishOnly": "pnpm run build && pnpm run typecheck"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"tsup": "^8.0.0",
|
|
25
|
+
"typescript": "^5.0.0"
|
|
26
|
+
},
|
|
27
|
+
"engines": { "node": ">=18.0.0" },
|
|
28
|
+
"publishConfig": { "access": "public" }
|
|
29
|
+
}
|