@pushflodev/sdk 1.0.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/LICENSE +21 -0
- package/README.md +500 -0
- package/dist/PushFloClient-JPowShqE.d.cts +102 -0
- package/dist/PushFloClient-ny0iyTYJ.d.ts +102 -0
- package/dist/api-DYrG_5uC.d.cts +149 -0
- package/dist/api-DYrG_5uC.d.ts +149 -0
- package/dist/index.cjs +1210 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +1204 -0
- package/dist/index.js.map +1 -0
- package/dist/message-CVgilLwz.d.cts +130 -0
- package/dist/message-CVgilLwz.d.ts +130 -0
- package/dist/react.cjs +1300 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +116 -0
- package/dist/react.d.ts +116 -0
- package/dist/react.js +1295 -0
- package/dist/react.js.map +1 -0
- package/dist/server.cjs +558 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +47 -0
- package/dist/server.d.ts +47 -0
- package/dist/server.js +553 -0
- package/dist/server.js.map +1 -0
- package/package.json +103 -0
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* @pushflo/sdk - https://pushflo.dev */
|
|
4
|
+
|
|
5
|
+
// src/utils/constants.ts
|
|
6
|
+
var DEFAULTS = {
|
|
7
|
+
/** Default PushFlo API base URL */
|
|
8
|
+
BASE_URL: "https://api.pushflo.dev",
|
|
9
|
+
/** API version prefix */
|
|
10
|
+
API_VERSION: "/api/v1",
|
|
11
|
+
/** Connection timeout in milliseconds */
|
|
12
|
+
CONNECTION_TIMEOUT: 3e4,
|
|
13
|
+
/** Initial reconnection delay in milliseconds */
|
|
14
|
+
RECONNECT_DELAY: 1e3,
|
|
15
|
+
/** Maximum reconnection delay in milliseconds */
|
|
16
|
+
MAX_RECONNECT_DELAY: 3e4,
|
|
17
|
+
/** Reconnection delay multiplier for exponential backoff */
|
|
18
|
+
RECONNECT_MULTIPLIER: 1.5,
|
|
19
|
+
/** Default page size for list operations */
|
|
20
|
+
PAGE_SIZE: 25
|
|
21
|
+
};
|
|
22
|
+
var API_PATHS = {
|
|
23
|
+
AUTH_TOKEN: "/auth/token",
|
|
24
|
+
CHANNELS: "/channels",
|
|
25
|
+
CHANNEL: (slug) => `/channels/${encodeURIComponent(slug)}`,
|
|
26
|
+
CHANNEL_MESSAGES: (slug) => `/channels/${encodeURIComponent(slug)}/messages`
|
|
27
|
+
};
|
|
28
|
+
var ERROR_CODES = {
|
|
29
|
+
// Authentication errors
|
|
30
|
+
INVALID_API_KEY: "INVALID_API_KEY",
|
|
31
|
+
UNAUTHORIZED: "UNAUTHORIZED",
|
|
32
|
+
FORBIDDEN: "FORBIDDEN",
|
|
33
|
+
// Network errors
|
|
34
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
35
|
+
REQUEST_TIMEOUT: "REQUEST_TIMEOUT",
|
|
36
|
+
// API errors
|
|
37
|
+
NOT_FOUND: "NOT_FOUND",
|
|
38
|
+
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
39
|
+
RATE_LIMITED: "RATE_LIMITED",
|
|
40
|
+
SERVER_ERROR: "SERVER_ERROR"};
|
|
41
|
+
|
|
42
|
+
// src/utils/retry.ts
|
|
43
|
+
function calculateBackoff(attempt, options = {}) {
|
|
44
|
+
const {
|
|
45
|
+
initialDelay = DEFAULTS.RECONNECT_DELAY,
|
|
46
|
+
maxDelay = DEFAULTS.MAX_RECONNECT_DELAY,
|
|
47
|
+
multiplier = DEFAULTS.RECONNECT_MULTIPLIER
|
|
48
|
+
} = options;
|
|
49
|
+
const exponentialDelay = initialDelay * Math.pow(multiplier, attempt);
|
|
50
|
+
const cappedDelay = Math.min(exponentialDelay, maxDelay);
|
|
51
|
+
const jitter = cappedDelay * 0.25 * (Math.random() * 2 - 1);
|
|
52
|
+
return Math.floor(cappedDelay + jitter);
|
|
53
|
+
}
|
|
54
|
+
function sleep(ms, signal) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
if (signal?.aborted) {
|
|
57
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const timeoutId = setTimeout(resolve, ms);
|
|
61
|
+
signal?.addEventListener(
|
|
62
|
+
"abort",
|
|
63
|
+
() => {
|
|
64
|
+
clearTimeout(timeoutId);
|
|
65
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
66
|
+
},
|
|
67
|
+
{ once: true }
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async function retry(fn, options = {}) {
|
|
72
|
+
const {
|
|
73
|
+
maxAttempts = 3,
|
|
74
|
+
initialDelay = DEFAULTS.RECONNECT_DELAY,
|
|
75
|
+
maxDelay = DEFAULTS.MAX_RECONNECT_DELAY,
|
|
76
|
+
multiplier = DEFAULTS.RECONNECT_MULTIPLIER,
|
|
77
|
+
isRetryable = () => true,
|
|
78
|
+
onRetry,
|
|
79
|
+
signal
|
|
80
|
+
} = options;
|
|
81
|
+
let lastError;
|
|
82
|
+
let attempt = 0;
|
|
83
|
+
while (maxAttempts === 0 || attempt < maxAttempts) {
|
|
84
|
+
try {
|
|
85
|
+
if (signal?.aborted) {
|
|
86
|
+
throw new DOMException("Aborted", "AbortError");
|
|
87
|
+
}
|
|
88
|
+
return await fn();
|
|
89
|
+
} catch (error) {
|
|
90
|
+
lastError = error;
|
|
91
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
if (!isRetryable(error)) {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
if (maxAttempts !== 0 && attempt >= maxAttempts - 1) {
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
const delay = calculateBackoff(attempt, { initialDelay, maxDelay, multiplier });
|
|
101
|
+
onRetry?.(attempt + 1, delay, error);
|
|
102
|
+
await sleep(delay, signal);
|
|
103
|
+
attempt++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
throw lastError;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/utils/logger.ts
|
|
110
|
+
var LOG_LEVELS = {
|
|
111
|
+
debug: 0,
|
|
112
|
+
info: 1,
|
|
113
|
+
warn: 2,
|
|
114
|
+
error: 3
|
|
115
|
+
};
|
|
116
|
+
var Logger = class {
|
|
117
|
+
enabled;
|
|
118
|
+
prefix;
|
|
119
|
+
minLevel;
|
|
120
|
+
constructor(options = {}) {
|
|
121
|
+
this.enabled = options.debug ?? false;
|
|
122
|
+
this.prefix = options.prefix ?? "[PushFlo]";
|
|
123
|
+
this.minLevel = LOG_LEVELS[options.level ?? "debug"];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Enable or disable logging
|
|
127
|
+
*/
|
|
128
|
+
setEnabled(enabled) {
|
|
129
|
+
this.enabled = enabled;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Set minimum log level
|
|
133
|
+
*/
|
|
134
|
+
setLevel(level) {
|
|
135
|
+
this.minLevel = LOG_LEVELS[level];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Log a debug message
|
|
139
|
+
*/
|
|
140
|
+
debug(message, ...args) {
|
|
141
|
+
this.log("debug", message, ...args);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Log an info message
|
|
145
|
+
*/
|
|
146
|
+
info(message, ...args) {
|
|
147
|
+
this.log("info", message, ...args);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Log a warning message
|
|
151
|
+
*/
|
|
152
|
+
warn(message, ...args) {
|
|
153
|
+
this.log("warn", message, ...args);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Log an error message
|
|
157
|
+
*/
|
|
158
|
+
error(message, ...args) {
|
|
159
|
+
this.log("error", message, ...args);
|
|
160
|
+
}
|
|
161
|
+
log(level, message, ...args) {
|
|
162
|
+
if (!this.enabled && level !== "error") {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (LOG_LEVELS[level] < this.minLevel) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
169
|
+
const formattedMessage = `${this.prefix} ${timestamp} [${level.toUpperCase()}] ${message}`;
|
|
170
|
+
switch (level) {
|
|
171
|
+
case "debug":
|
|
172
|
+
console.debug(formattedMessage, ...args);
|
|
173
|
+
break;
|
|
174
|
+
case "info":
|
|
175
|
+
console.info(formattedMessage, ...args);
|
|
176
|
+
break;
|
|
177
|
+
case "warn":
|
|
178
|
+
console.warn(formattedMessage, ...args);
|
|
179
|
+
break;
|
|
180
|
+
case "error":
|
|
181
|
+
console.error(formattedMessage, ...args);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
function createLogger(options = {}) {
|
|
187
|
+
return new Logger(options);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/errors/PushFloError.ts
|
|
191
|
+
var PushFloError = class extends Error {
|
|
192
|
+
/** Error code for programmatic handling */
|
|
193
|
+
code;
|
|
194
|
+
/** Whether this error is potentially recoverable through retry */
|
|
195
|
+
retryable;
|
|
196
|
+
/** Original error that caused this error, if any */
|
|
197
|
+
cause;
|
|
198
|
+
constructor(message, code, options = {}) {
|
|
199
|
+
super(message);
|
|
200
|
+
this.name = "PushFloError";
|
|
201
|
+
this.code = code;
|
|
202
|
+
this.retryable = options.retryable ?? false;
|
|
203
|
+
this.cause = options.cause;
|
|
204
|
+
if (Error.captureStackTrace) {
|
|
205
|
+
Error.captureStackTrace(this, this.constructor);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Convert error to JSON-serializable object
|
|
210
|
+
*/
|
|
211
|
+
toJSON() {
|
|
212
|
+
return {
|
|
213
|
+
name: this.name,
|
|
214
|
+
message: this.message,
|
|
215
|
+
code: this.code,
|
|
216
|
+
retryable: this.retryable,
|
|
217
|
+
stack: this.stack,
|
|
218
|
+
cause: this.cause?.message
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Create a string representation
|
|
223
|
+
*/
|
|
224
|
+
toString() {
|
|
225
|
+
return `${this.name} [${this.code}]: ${this.message}`;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// src/errors/AuthenticationError.ts
|
|
230
|
+
var AuthenticationError = class _AuthenticationError extends PushFloError {
|
|
231
|
+
constructor(message, code = ERROR_CODES.UNAUTHORIZED, options = {}) {
|
|
232
|
+
super(message, code, { retryable: false, ...options });
|
|
233
|
+
this.name = "AuthenticationError";
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Create an invalid API key error
|
|
237
|
+
*/
|
|
238
|
+
static invalidKey(keyType) {
|
|
239
|
+
const message = keyType ? `Invalid ${keyType} API key` : "Invalid API key";
|
|
240
|
+
return new _AuthenticationError(message, ERROR_CODES.INVALID_API_KEY);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Create an unauthorized error
|
|
244
|
+
*/
|
|
245
|
+
static unauthorized(reason) {
|
|
246
|
+
return new _AuthenticationError(
|
|
247
|
+
reason ?? "Unauthorized - check your API key",
|
|
248
|
+
ERROR_CODES.UNAUTHORIZED
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Create a forbidden error
|
|
253
|
+
*/
|
|
254
|
+
static forbidden(action) {
|
|
255
|
+
const message = action ? `Access forbidden: insufficient permissions for ${action}` : "Access forbidden: insufficient permissions";
|
|
256
|
+
return new _AuthenticationError(message, ERROR_CODES.FORBIDDEN);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// src/errors/NetworkError.ts
|
|
261
|
+
var NetworkError = class _NetworkError extends PushFloError {
|
|
262
|
+
/** HTTP status code, if applicable */
|
|
263
|
+
statusCode;
|
|
264
|
+
constructor(message, code = ERROR_CODES.NETWORK_ERROR, options = {}) {
|
|
265
|
+
super(message, code, { retryable: true, ...options });
|
|
266
|
+
this.name = "NetworkError";
|
|
267
|
+
this.statusCode = options.statusCode;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Create a network error from fetch failure
|
|
271
|
+
*/
|
|
272
|
+
static fromFetch(cause) {
|
|
273
|
+
return new _NetworkError(
|
|
274
|
+
`Network request failed: ${cause.message}`,
|
|
275
|
+
ERROR_CODES.NETWORK_ERROR,
|
|
276
|
+
{ retryable: true, cause }
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Create a request timeout error
|
|
281
|
+
*/
|
|
282
|
+
static timeout(timeoutMs) {
|
|
283
|
+
return new _NetworkError(
|
|
284
|
+
`Request timed out after ${timeoutMs}ms`,
|
|
285
|
+
ERROR_CODES.REQUEST_TIMEOUT,
|
|
286
|
+
{ retryable: true }
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Create an error from HTTP status code
|
|
291
|
+
*/
|
|
292
|
+
static fromStatus(statusCode, message) {
|
|
293
|
+
const defaultMessage = _NetworkError.getStatusMessage(statusCode);
|
|
294
|
+
const retryable = statusCode >= 500 || statusCode === 429;
|
|
295
|
+
let code = ERROR_CODES.SERVER_ERROR;
|
|
296
|
+
if (statusCode === 404) {
|
|
297
|
+
code = ERROR_CODES.NOT_FOUND;
|
|
298
|
+
} else if (statusCode === 422 || statusCode === 400) {
|
|
299
|
+
code = ERROR_CODES.VALIDATION_ERROR;
|
|
300
|
+
} else if (statusCode === 429) {
|
|
301
|
+
code = ERROR_CODES.RATE_LIMITED;
|
|
302
|
+
}
|
|
303
|
+
return new _NetworkError(
|
|
304
|
+
message ?? defaultMessage,
|
|
305
|
+
code,
|
|
306
|
+
{ retryable, statusCode }
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
static getStatusMessage(statusCode) {
|
|
310
|
+
const messages = {
|
|
311
|
+
400: "Bad request",
|
|
312
|
+
404: "Resource not found",
|
|
313
|
+
422: "Validation error",
|
|
314
|
+
429: "Rate limit exceeded",
|
|
315
|
+
500: "Internal server error",
|
|
316
|
+
502: "Bad gateway",
|
|
317
|
+
503: "Service unavailable",
|
|
318
|
+
504: "Gateway timeout"
|
|
319
|
+
};
|
|
320
|
+
return messages[statusCode] ?? `HTTP error ${statusCode}`;
|
|
321
|
+
}
|
|
322
|
+
toJSON() {
|
|
323
|
+
return {
|
|
324
|
+
...super.toJSON(),
|
|
325
|
+
statusCode: this.statusCode
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// src/server/RestClient.ts
|
|
331
|
+
var RestClient = class {
|
|
332
|
+
apiKey;
|
|
333
|
+
baseUrl;
|
|
334
|
+
timeout;
|
|
335
|
+
retryAttempts;
|
|
336
|
+
logger;
|
|
337
|
+
constructor(options) {
|
|
338
|
+
this.apiKey = options.apiKey;
|
|
339
|
+
this.baseUrl = (options.baseUrl ?? DEFAULTS.BASE_URL).replace(/\/$/, "");
|
|
340
|
+
this.timeout = options.timeout ?? DEFAULTS.CONNECTION_TIMEOUT;
|
|
341
|
+
this.retryAttempts = options.retryAttempts ?? 3;
|
|
342
|
+
this.logger = createLogger({ debug: options.debug, prefix: "[PushFlo REST]" });
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Make an HTTP request to the API
|
|
346
|
+
*/
|
|
347
|
+
async request(method, path, options = {}) {
|
|
348
|
+
const url = this.buildUrl(path, options.query);
|
|
349
|
+
this.logger.debug(`${method} ${url}`);
|
|
350
|
+
const retryOpts = {
|
|
351
|
+
maxAttempts: this.retryAttempts,
|
|
352
|
+
isRetryable: (error) => {
|
|
353
|
+
if (error instanceof NetworkError) {
|
|
354
|
+
return error.retryable;
|
|
355
|
+
}
|
|
356
|
+
return false;
|
|
357
|
+
},
|
|
358
|
+
onRetry: (attempt, delay, error) => {
|
|
359
|
+
this.logger.warn(`Request failed, retrying (${attempt}/${this.retryAttempts}) in ${delay}ms`, error);
|
|
360
|
+
},
|
|
361
|
+
...options.retryOptions
|
|
362
|
+
};
|
|
363
|
+
return retry(async () => {
|
|
364
|
+
const controller = new AbortController();
|
|
365
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
366
|
+
try {
|
|
367
|
+
const response = await fetch(url, {
|
|
368
|
+
method,
|
|
369
|
+
headers: this.getHeaders(),
|
|
370
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
371
|
+
signal: controller.signal
|
|
372
|
+
});
|
|
373
|
+
return await this.handleResponse(response);
|
|
374
|
+
} catch (error) {
|
|
375
|
+
if (error instanceof AuthenticationError || error instanceof NetworkError) {
|
|
376
|
+
throw error;
|
|
377
|
+
}
|
|
378
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
379
|
+
throw NetworkError.timeout(this.timeout);
|
|
380
|
+
}
|
|
381
|
+
if (error instanceof TypeError) {
|
|
382
|
+
throw NetworkError.fromFetch(error);
|
|
383
|
+
}
|
|
384
|
+
throw error;
|
|
385
|
+
} finally {
|
|
386
|
+
clearTimeout(timeoutId);
|
|
387
|
+
}
|
|
388
|
+
}, retryOpts);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Make a GET request
|
|
392
|
+
*/
|
|
393
|
+
get(path, query) {
|
|
394
|
+
return this.request("GET", path, { query });
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Make a POST request
|
|
398
|
+
*/
|
|
399
|
+
post(path, body) {
|
|
400
|
+
return this.request("POST", path, { body });
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Make a PATCH request
|
|
404
|
+
*/
|
|
405
|
+
patch(path, body) {
|
|
406
|
+
return this.request("PATCH", path, { body });
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Make a DELETE request
|
|
410
|
+
*/
|
|
411
|
+
delete(path) {
|
|
412
|
+
return this.request("DELETE", path);
|
|
413
|
+
}
|
|
414
|
+
buildUrl(path, query) {
|
|
415
|
+
const fullPath = `${DEFAULTS.API_VERSION}${path}`;
|
|
416
|
+
const url = new URL(fullPath, this.baseUrl);
|
|
417
|
+
if (query) {
|
|
418
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
419
|
+
if (value !== void 0) {
|
|
420
|
+
url.searchParams.set(key, String(value));
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return url.toString();
|
|
425
|
+
}
|
|
426
|
+
getHeaders() {
|
|
427
|
+
return {
|
|
428
|
+
"Content-Type": "application/json",
|
|
429
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
async handleResponse(response) {
|
|
433
|
+
if (response.status === 401) {
|
|
434
|
+
throw AuthenticationError.unauthorized();
|
|
435
|
+
}
|
|
436
|
+
if (response.status === 403) {
|
|
437
|
+
throw AuthenticationError.forbidden();
|
|
438
|
+
}
|
|
439
|
+
if (!response.ok) {
|
|
440
|
+
let errorMessage;
|
|
441
|
+
try {
|
|
442
|
+
const errorBody = await response.json();
|
|
443
|
+
errorMessage = errorBody.error;
|
|
444
|
+
} catch {
|
|
445
|
+
}
|
|
446
|
+
throw NetworkError.fromStatus(response.status, errorMessage);
|
|
447
|
+
}
|
|
448
|
+
if (response.status === 204) {
|
|
449
|
+
return void 0;
|
|
450
|
+
}
|
|
451
|
+
try {
|
|
452
|
+
return await response.json();
|
|
453
|
+
} catch {
|
|
454
|
+
throw new NetworkError("Failed to parse response", "PARSE_ERROR", { retryable: false });
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// src/server/PushFloServer.ts
|
|
460
|
+
var PushFloServer = class {
|
|
461
|
+
client;
|
|
462
|
+
constructor(options) {
|
|
463
|
+
if (!options.secretKey) {
|
|
464
|
+
throw new AuthenticationError(
|
|
465
|
+
"Secret key is required",
|
|
466
|
+
"MISSING_SECRET_KEY"
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
if (!options.secretKey.startsWith("sec_") && !options.secretKey.startsWith("mgmt_")) {
|
|
470
|
+
throw AuthenticationError.invalidKey("secret");
|
|
471
|
+
}
|
|
472
|
+
this.client = new RestClient({
|
|
473
|
+
apiKey: options.secretKey,
|
|
474
|
+
baseUrl: options.baseUrl,
|
|
475
|
+
timeout: options.timeout,
|
|
476
|
+
retryAttempts: options.retryAttempts,
|
|
477
|
+
debug: options.debug
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
// ============================================
|
|
481
|
+
// Channel Management
|
|
482
|
+
// ============================================
|
|
483
|
+
/**
|
|
484
|
+
* List all channels
|
|
485
|
+
*/
|
|
486
|
+
async listChannels(options = {}) {
|
|
487
|
+
const response = await this.client.get(API_PATHS.CHANNELS, {
|
|
488
|
+
page: options.page,
|
|
489
|
+
pageSize: options.pageSize ?? DEFAULTS.PAGE_SIZE
|
|
490
|
+
});
|
|
491
|
+
return {
|
|
492
|
+
channels: response.channels,
|
|
493
|
+
pagination: response.pagination
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get a channel by slug
|
|
498
|
+
*/
|
|
499
|
+
async getChannel(slug) {
|
|
500
|
+
return this.client.get(API_PATHS.CHANNEL(slug));
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Create a new channel
|
|
504
|
+
*/
|
|
505
|
+
async createChannel(input) {
|
|
506
|
+
return this.client.post(API_PATHS.CHANNELS, input);
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Update an existing channel
|
|
510
|
+
*/
|
|
511
|
+
async updateChannel(slug, input) {
|
|
512
|
+
return this.client.patch(API_PATHS.CHANNEL(slug), input);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Delete a channel
|
|
516
|
+
*/
|
|
517
|
+
async deleteChannel(slug) {
|
|
518
|
+
await this.client.delete(API_PATHS.CHANNEL(slug));
|
|
519
|
+
}
|
|
520
|
+
// ============================================
|
|
521
|
+
// Message Publishing
|
|
522
|
+
// ============================================
|
|
523
|
+
/**
|
|
524
|
+
* Publish a message to a channel
|
|
525
|
+
*/
|
|
526
|
+
async publish(channel, content, options = {}) {
|
|
527
|
+
return this.client.post(API_PATHS.CHANNEL_MESSAGES(channel), {
|
|
528
|
+
content,
|
|
529
|
+
eventType: options.eventType ?? "message"
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Get message history for a channel
|
|
534
|
+
*/
|
|
535
|
+
async getMessageHistory(channel, options = {}) {
|
|
536
|
+
const response = await this.client.get(
|
|
537
|
+
API_PATHS.CHANNEL_MESSAGES(channel),
|
|
538
|
+
{
|
|
539
|
+
page: options.page,
|
|
540
|
+
pageSize: options.pageSize ?? DEFAULTS.PAGE_SIZE,
|
|
541
|
+
eventType: options.eventType,
|
|
542
|
+
after: options.after,
|
|
543
|
+
before: options.before
|
|
544
|
+
}
|
|
545
|
+
);
|
|
546
|
+
return {
|
|
547
|
+
messages: response.messages,
|
|
548
|
+
pagination: response.pagination
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
exports.AuthenticationError = AuthenticationError;
|
|
554
|
+
exports.NetworkError = NetworkError;
|
|
555
|
+
exports.PushFloError = PushFloError;
|
|
556
|
+
exports.PushFloServer = PushFloServer;
|
|
557
|
+
//# sourceMappingURL=server.cjs.map
|
|
558
|
+
//# sourceMappingURL=server.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/constants.ts","../src/utils/retry.ts","../src/utils/logger.ts","../src/errors/PushFloError.ts","../src/errors/AuthenticationError.ts","../src/errors/NetworkError.ts","../src/server/RestClient.ts","../src/server/PushFloServer.ts"],"names":[],"mappings":"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","file":"server.cjs","sourcesContent":["/**\n * Default configuration values\n */\nexport const DEFAULTS = {\n /** Default PushFlo API base URL */\n BASE_URL: 'https://api.pushflo.dev',\n\n /** WebSocket endpoint path */\n WS_PATH: '/ws',\n\n /** API version prefix */\n API_VERSION: '/api/v1',\n\n /** Connection timeout in milliseconds */\n CONNECTION_TIMEOUT: 30000,\n\n /** Heartbeat interval in milliseconds */\n HEARTBEAT_INTERVAL: 25000,\n\n /** Initial reconnection delay in milliseconds */\n RECONNECT_DELAY: 1000,\n\n /** Maximum reconnection delay in milliseconds */\n MAX_RECONNECT_DELAY: 30000,\n\n /** Reconnection delay multiplier for exponential backoff */\n RECONNECT_MULTIPLIER: 1.5,\n\n /** Maximum number of reconnection attempts (0 = infinite) */\n MAX_RECONNECT_ATTEMPTS: 0,\n\n /** Default page size for list operations */\n PAGE_SIZE: 25,\n} as const;\n\n/**\n * API endpoint paths\n */\nexport const API_PATHS = {\n AUTH_TOKEN: '/auth/token',\n CHANNELS: '/channels',\n CHANNEL: (slug: string) => `/channels/${encodeURIComponent(slug)}`,\n CHANNEL_MESSAGES: (slug: string) => `/channels/${encodeURIComponent(slug)}/messages`,\n} as const;\n\n/**\n * WebSocket message types (client -> server)\n */\nexport const WS_CLIENT_MESSAGES = {\n SUBSCRIBE: 'subscribe',\n UNSUBSCRIBE: 'unsubscribe',\n PING: 'ping',\n ACK: 'ack',\n} as const;\n\n/**\n * WebSocket message types (server -> client)\n */\nexport const WS_SERVER_MESSAGES = {\n CONNECTED: 'connected',\n SUBSCRIBED: 'subscribed',\n UNSUBSCRIBED: 'unsubscribed',\n MESSAGE: 'message',\n ERROR: 'error',\n PONG: 'pong',\n} as const;\n\n/**\n * Error codes\n */\nexport const ERROR_CODES = {\n // Connection errors\n CONNECTION_FAILED: 'CONNECTION_FAILED',\n CONNECTION_TIMEOUT: 'CONNECTION_TIMEOUT',\n CONNECTION_CLOSED: 'CONNECTION_CLOSED',\n\n // Authentication errors\n INVALID_API_KEY: 'INVALID_API_KEY',\n UNAUTHORIZED: 'UNAUTHORIZED',\n FORBIDDEN: 'FORBIDDEN',\n\n // Network errors\n NETWORK_ERROR: 'NETWORK_ERROR',\n REQUEST_TIMEOUT: 'REQUEST_TIMEOUT',\n\n // API errors\n NOT_FOUND: 'NOT_FOUND',\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n RATE_LIMITED: 'RATE_LIMITED',\n SERVER_ERROR: 'SERVER_ERROR',\n\n // Client errors\n INVALID_STATE: 'INVALID_STATE',\n ALREADY_CONNECTED: 'ALREADY_CONNECTED',\n NOT_CONNECTED: 'NOT_CONNECTED',\n CHANNEL_NOT_FOUND: 'CHANNEL_NOT_FOUND',\n} as const;\n","import { DEFAULTS } from './constants.js';\n\nexport interface RetryOptions {\n /** Maximum number of retry attempts (0 = infinite) */\n maxAttempts?: number;\n /** Initial delay in milliseconds */\n initialDelay?: number;\n /** Maximum delay in milliseconds */\n maxDelay?: number;\n /** Delay multiplier for exponential backoff */\n multiplier?: number;\n /** Function to determine if error is retryable */\n isRetryable?: (error: unknown) => boolean;\n /** Callback for each retry attempt */\n onRetry?: (attempt: number, delay: number, error: unknown) => void;\n /** Abort signal for cancellation */\n signal?: AbortSignal;\n}\n\n/**\n * Calculate delay with exponential backoff and jitter\n */\nexport function calculateBackoff(\n attempt: number,\n options: {\n initialDelay?: number;\n maxDelay?: number;\n multiplier?: number;\n } = {}\n): number {\n const {\n initialDelay = DEFAULTS.RECONNECT_DELAY,\n maxDelay = DEFAULTS.MAX_RECONNECT_DELAY,\n multiplier = DEFAULTS.RECONNECT_MULTIPLIER,\n } = options;\n\n // Exponential backoff\n const exponentialDelay = initialDelay * Math.pow(multiplier, attempt);\n\n // Cap at max delay\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n\n // Add jitter (±25%)\n const jitter = cappedDelay * 0.25 * (Math.random() * 2 - 1);\n\n return Math.floor(cappedDelay + jitter);\n}\n\n/**\n * Sleep for a given duration (cancellable)\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const timeoutId = setTimeout(resolve, ms);\n\n signal?.addEventListener(\n 'abort',\n () => {\n clearTimeout(timeoutId);\n reject(new DOMException('Aborted', 'AbortError'));\n },\n { once: true }\n );\n });\n}\n\n/**\n * Retry a function with exponential backoff\n */\nexport async function retry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n maxAttempts = 3,\n initialDelay = DEFAULTS.RECONNECT_DELAY,\n maxDelay = DEFAULTS.MAX_RECONNECT_DELAY,\n multiplier = DEFAULTS.RECONNECT_MULTIPLIER,\n isRetryable = () => true,\n onRetry,\n signal,\n } = options;\n\n let lastError: unknown;\n let attempt = 0;\n\n while (maxAttempts === 0 || attempt < maxAttempts) {\n try {\n if (signal?.aborted) {\n throw new DOMException('Aborted', 'AbortError');\n }\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Don't retry abort errors\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw error;\n }\n\n // Check if we should retry\n if (!isRetryable(error)) {\n throw error;\n }\n\n // Check if we've exhausted attempts\n if (maxAttempts !== 0 && attempt >= maxAttempts - 1) {\n throw error;\n }\n\n // Calculate delay\n const delay = calculateBackoff(attempt, { initialDelay, maxDelay, multiplier });\n\n // Notify retry callback\n onRetry?.(attempt + 1, delay, error);\n\n // Wait before next attempt\n await sleep(delay, signal);\n\n attempt++;\n }\n }\n\n throw lastError;\n}\n\n/**\n * Create a retry function with preset options\n */\nexport function createRetry(defaultOptions: RetryOptions) {\n return <T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T> => {\n return retry(fn, { ...defaultOptions, ...options });\n };\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface LoggerOptions {\n /** Enable debug logging */\n debug?: boolean;\n /** Custom log prefix */\n prefix?: string;\n /** Minimum log level */\n level?: LogLevel;\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * Simple logger with debug mode support\n */\nexport class Logger {\n private enabled: boolean;\n private prefix: string;\n private minLevel: number;\n\n constructor(options: LoggerOptions = {}) {\n this.enabled = options.debug ?? false;\n this.prefix = options.prefix ?? '[PushFlo]';\n this.minLevel = LOG_LEVELS[options.level ?? 'debug'];\n }\n\n /**\n * Enable or disable logging\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /**\n * Set minimum log level\n */\n setLevel(level: LogLevel): void {\n this.minLevel = LOG_LEVELS[level];\n }\n\n /**\n * Log a debug message\n */\n debug(message: string, ...args: unknown[]): void {\n this.log('debug', message, ...args);\n }\n\n /**\n * Log an info message\n */\n info(message: string, ...args: unknown[]): void {\n this.log('info', message, ...args);\n }\n\n /**\n * Log a warning message\n */\n warn(message: string, ...args: unknown[]): void {\n this.log('warn', message, ...args);\n }\n\n /**\n * Log an error message\n */\n error(message: string, ...args: unknown[]): void {\n this.log('error', message, ...args);\n }\n\n private log(level: LogLevel, message: string, ...args: unknown[]): void {\n if (!this.enabled && level !== 'error') {\n return;\n }\n\n if (LOG_LEVELS[level] < this.minLevel) {\n return;\n }\n\n const timestamp = new Date().toISOString();\n const formattedMessage = `${this.prefix} ${timestamp} [${level.toUpperCase()}] ${message}`;\n\n switch (level) {\n case 'debug':\n console.debug(formattedMessage, ...args);\n break;\n case 'info':\n console.info(formattedMessage, ...args);\n break;\n case 'warn':\n console.warn(formattedMessage, ...args);\n break;\n case 'error':\n console.error(formattedMessage, ...args);\n break;\n }\n }\n}\n\n/**\n * Create a child logger with a custom prefix\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n return new Logger(options);\n}\n","/**\n * Base error class for all PushFlo SDK errors\n */\nexport class PushFloError extends Error {\n /** Error code for programmatic handling */\n readonly code: string;\n\n /** Whether this error is potentially recoverable through retry */\n readonly retryable: boolean;\n\n /** Original error that caused this error, if any */\n readonly cause?: Error;\n\n constructor(\n message: string,\n code: string,\n options: { retryable?: boolean; cause?: Error } = {}\n ) {\n super(message);\n this.name = 'PushFloError';\n this.code = code;\n this.retryable = options.retryable ?? false;\n this.cause = options.cause;\n\n // Maintain proper stack trace in V8 environments\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n }\n }\n\n /**\n * Convert error to JSON-serializable object\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n retryable: this.retryable,\n stack: this.stack,\n cause: this.cause?.message,\n };\n }\n\n /**\n * Create a string representation\n */\n toString(): string {\n return `${this.name} [${this.code}]: ${this.message}`;\n }\n}\n","import { PushFloError } from './PushFloError.js';\nimport { ERROR_CODES } from '../utils/constants.js';\n\n/**\n * Error thrown when authentication fails\n */\nexport class AuthenticationError extends PushFloError {\n constructor(\n message: string,\n code: string = ERROR_CODES.UNAUTHORIZED,\n options: { retryable?: boolean; cause?: Error } = {}\n ) {\n // Authentication errors are generally not retryable\n super(message, code, { retryable: false, ...options });\n this.name = 'AuthenticationError';\n }\n\n /**\n * Create an invalid API key error\n */\n static invalidKey(keyType?: string): AuthenticationError {\n const message = keyType\n ? `Invalid ${keyType} API key`\n : 'Invalid API key';\n return new AuthenticationError(message, ERROR_CODES.INVALID_API_KEY);\n }\n\n /**\n * Create an unauthorized error\n */\n static unauthorized(reason?: string): AuthenticationError {\n return new AuthenticationError(\n reason ?? 'Unauthorized - check your API key',\n ERROR_CODES.UNAUTHORIZED\n );\n }\n\n /**\n * Create a forbidden error\n */\n static forbidden(action?: string): AuthenticationError {\n const message = action\n ? `Access forbidden: insufficient permissions for ${action}`\n : 'Access forbidden: insufficient permissions';\n return new AuthenticationError(message, ERROR_CODES.FORBIDDEN);\n }\n}\n","import { PushFloError } from './PushFloError.js';\nimport { ERROR_CODES } from '../utils/constants.js';\n\n/**\n * Error thrown for network-related failures\n */\nexport class NetworkError extends PushFloError {\n /** HTTP status code, if applicable */\n readonly statusCode?: number;\n\n constructor(\n message: string,\n code: string = ERROR_CODES.NETWORK_ERROR,\n options: { retryable?: boolean; cause?: Error; statusCode?: number } = {}\n ) {\n super(message, code, { retryable: true, ...options });\n this.name = 'NetworkError';\n this.statusCode = options.statusCode;\n }\n\n /**\n * Create a network error from fetch failure\n */\n static fromFetch(cause: Error): NetworkError {\n return new NetworkError(\n `Network request failed: ${cause.message}`,\n ERROR_CODES.NETWORK_ERROR,\n { retryable: true, cause }\n );\n }\n\n /**\n * Create a request timeout error\n */\n static timeout(timeoutMs: number): NetworkError {\n return new NetworkError(\n `Request timed out after ${timeoutMs}ms`,\n ERROR_CODES.REQUEST_TIMEOUT,\n { retryable: true }\n );\n }\n\n /**\n * Create an error from HTTP status code\n */\n static fromStatus(statusCode: number, message?: string): NetworkError {\n const defaultMessage = NetworkError.getStatusMessage(statusCode);\n\n // Determine if retryable based on status\n const retryable = statusCode >= 500 || statusCode === 429;\n\n // Map status to error code\n let code: string = ERROR_CODES.SERVER_ERROR;\n if (statusCode === 404) {\n code = ERROR_CODES.NOT_FOUND;\n } else if (statusCode === 422 || statusCode === 400) {\n code = ERROR_CODES.VALIDATION_ERROR;\n } else if (statusCode === 429) {\n code = ERROR_CODES.RATE_LIMITED;\n }\n\n return new NetworkError(\n message ?? defaultMessage,\n code,\n { retryable, statusCode }\n );\n }\n\n private static getStatusMessage(statusCode: number): string {\n const messages: Record<number, string> = {\n 400: 'Bad request',\n 404: 'Resource not found',\n 422: 'Validation error',\n 429: 'Rate limit exceeded',\n 500: 'Internal server error',\n 502: 'Bad gateway',\n 503: 'Service unavailable',\n 504: 'Gateway timeout',\n };\n return messages[statusCode] ?? `HTTP error ${statusCode}`;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n ...super.toJSON(),\n statusCode: this.statusCode,\n };\n }\n}\n","import { DEFAULTS } from '../utils/constants.js';\nimport { retry, type RetryOptions } from '../utils/retry.js';\nimport { createLogger, type Logger } from '../utils/logger.js';\nimport { AuthenticationError } from '../errors/AuthenticationError.js';\nimport { NetworkError } from '../errors/NetworkError.js';\nimport type { ApiErrorResponse } from '../types/api.js';\n\nexport interface RestClientOptions {\n /** API key (secret or management key) */\n apiKey: string;\n\n /** Base URL for the API */\n baseUrl?: string;\n\n /** Request timeout in milliseconds */\n timeout?: number;\n\n /** Number of retry attempts */\n retryAttempts?: number;\n\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * HTTP client for PushFlo REST API\n */\nexport class RestClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly retryAttempts: number;\n private readonly logger: Logger;\n\n constructor(options: RestClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULTS.BASE_URL).replace(/\\/$/, '');\n this.timeout = options.timeout ?? DEFAULTS.CONNECTION_TIMEOUT;\n this.retryAttempts = options.retryAttempts ?? 3;\n this.logger = createLogger({ debug: options.debug, prefix: '[PushFlo REST]' });\n }\n\n /**\n * Make an HTTP request to the API\n */\n async request<T>(\n method: string,\n path: string,\n options: {\n body?: unknown;\n query?: Record<string, string | number | undefined>;\n retryOptions?: Partial<RetryOptions>;\n } = {}\n ): Promise<T> {\n const url = this.buildUrl(path, options.query);\n\n this.logger.debug(`${method} ${url}`);\n\n const retryOpts: RetryOptions = {\n maxAttempts: this.retryAttempts,\n isRetryable: (error) => {\n if (error instanceof NetworkError) {\n return error.retryable;\n }\n return false;\n },\n onRetry: (attempt, delay, error) => {\n this.logger.warn(`Request failed, retrying (${attempt}/${this.retryAttempts}) in ${delay}ms`, error);\n },\n ...options.retryOptions,\n };\n\n return retry(async () => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: this.getHeaders(),\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n return await this.handleResponse<T>(response);\n } catch (error) {\n if (error instanceof AuthenticationError || error instanceof NetworkError) {\n throw error;\n }\n\n if (error instanceof DOMException && error.name === 'AbortError') {\n throw NetworkError.timeout(this.timeout);\n }\n\n if (error instanceof TypeError) {\n throw NetworkError.fromFetch(error);\n }\n\n throw error;\n } finally {\n clearTimeout(timeoutId);\n }\n }, retryOpts);\n }\n\n /**\n * Make a GET request\n */\n get<T>(path: string, query?: Record<string, string | number | undefined>): Promise<T> {\n return this.request<T>('GET', path, { query });\n }\n\n /**\n * Make a POST request\n */\n post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('POST', path, { body });\n }\n\n /**\n * Make a PATCH request\n */\n patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>('PATCH', path, { body });\n }\n\n /**\n * Make a DELETE request\n */\n delete<T>(path: string): Promise<T> {\n return this.request<T>('DELETE', path);\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | undefined>): string {\n const fullPath = `${DEFAULTS.API_VERSION}${path}`;\n const url = new URL(fullPath, this.baseUrl);\n\n if (query) {\n Object.entries(query).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n });\n }\n\n return url.toString();\n }\n\n private getHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n };\n }\n\n private async handleResponse<T>(response: Response): Promise<T> {\n // Handle authentication errors\n if (response.status === 401) {\n throw AuthenticationError.unauthorized();\n }\n\n if (response.status === 403) {\n throw AuthenticationError.forbidden();\n }\n\n // Handle other errors\n if (!response.ok) {\n let errorMessage: string | undefined;\n\n try {\n const errorBody = (await response.json()) as ApiErrorResponse;\n errorMessage = errorBody.error;\n } catch {\n // Ignore JSON parse errors\n }\n\n throw NetworkError.fromStatus(response.status, errorMessage);\n }\n\n // Handle empty responses\n if (response.status === 204) {\n return undefined as T;\n }\n\n // Parse JSON response\n try {\n return (await response.json()) as T;\n } catch {\n throw new NetworkError('Failed to parse response', 'PARSE_ERROR', { retryable: false });\n }\n }\n}\n","import { RestClient } from './RestClient.js';\nimport { API_PATHS, DEFAULTS } from '../utils/constants.js';\nimport { AuthenticationError } from '../errors/AuthenticationError.js';\nimport type { ServerOptions } from '../types/connection.js';\nimport type {\n Channel,\n ChannelInput,\n ChannelUpdateInput,\n ListChannelsOptions,\n} from '../types/channel.js';\nimport type {\n Message,\n PublishOptions,\n PublishResult,\n MessageHistoryOptions,\n} from '../types/message.js';\nimport type { Pagination } from '../types/api.js';\n\ninterface ChannelsResponse {\n channels: Channel[];\n pagination: Pagination;\n}\n\ninterface MessagesResponse {\n messages: Message[];\n pagination: Pagination;\n}\n\n/**\n * Server-side PushFlo client for publishing messages and managing channels\n */\nexport class PushFloServer {\n private readonly client: RestClient;\n\n constructor(options: ServerOptions) {\n if (!options.secretKey) {\n throw new AuthenticationError(\n 'Secret key is required',\n 'MISSING_SECRET_KEY'\n );\n }\n\n if (!options.secretKey.startsWith('sec_') && !options.secretKey.startsWith('mgmt_')) {\n throw AuthenticationError.invalidKey('secret');\n }\n\n this.client = new RestClient({\n apiKey: options.secretKey,\n baseUrl: options.baseUrl,\n timeout: options.timeout,\n retryAttempts: options.retryAttempts,\n debug: options.debug,\n });\n }\n\n // ============================================\n // Channel Management\n // ============================================\n\n /**\n * List all channels\n */\n async listChannels(\n options: ListChannelsOptions = {}\n ): Promise<{ channels: Channel[]; pagination: Pagination }> {\n const response = await this.client.get<ChannelsResponse>(API_PATHS.CHANNELS, {\n page: options.page,\n pageSize: options.pageSize ?? DEFAULTS.PAGE_SIZE,\n });\n\n return {\n channels: response.channels,\n pagination: response.pagination,\n };\n }\n\n /**\n * Get a channel by slug\n */\n async getChannel(slug: string): Promise<Channel> {\n return this.client.get<Channel>(API_PATHS.CHANNEL(slug));\n }\n\n /**\n * Create a new channel\n */\n async createChannel(input: ChannelInput): Promise<Channel> {\n return this.client.post<Channel>(API_PATHS.CHANNELS, input);\n }\n\n /**\n * Update an existing channel\n */\n async updateChannel(slug: string, input: ChannelUpdateInput): Promise<Channel> {\n return this.client.patch<Channel>(API_PATHS.CHANNEL(slug), input);\n }\n\n /**\n * Delete a channel\n */\n async deleteChannel(slug: string): Promise<void> {\n await this.client.delete<void>(API_PATHS.CHANNEL(slug));\n }\n\n // ============================================\n // Message Publishing\n // ============================================\n\n /**\n * Publish a message to a channel\n */\n async publish(\n channel: string,\n content: Record<string, unknown>,\n options: PublishOptions = {}\n ): Promise<PublishResult> {\n return this.client.post<PublishResult>(API_PATHS.CHANNEL_MESSAGES(channel), {\n content,\n eventType: options.eventType ?? 'message',\n });\n }\n\n /**\n * Get message history for a channel\n */\n async getMessageHistory(\n channel: string,\n options: MessageHistoryOptions = {}\n ): Promise<{ messages: Message[]; pagination: Pagination }> {\n const response = await this.client.get<MessagesResponse>(\n API_PATHS.CHANNEL_MESSAGES(channel),\n {\n page: options.page,\n pageSize: options.pageSize ?? DEFAULTS.PAGE_SIZE,\n eventType: options.eventType,\n after: options.after,\n before: options.before,\n }\n );\n\n return {\n messages: response.messages,\n pagination: response.pagination,\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { f as ServerOptions, P as PublishOptions, d as PublishResult, c as MessageHistoryOptions, M as Message } from './message-CVgilLwz.cjs';
|
|
2
|
+
import { L as ListChannelsOptions, C as Channel, c as Pagination, a as ChannelInput, b as ChannelUpdateInput } from './api-DYrG_5uC.cjs';
|
|
3
|
+
export { A as AuthenticationError, N as NetworkError, P as PushFloError } from './api-DYrG_5uC.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Server-side PushFlo client for publishing messages and managing channels
|
|
7
|
+
*/
|
|
8
|
+
declare class PushFloServer {
|
|
9
|
+
private readonly client;
|
|
10
|
+
constructor(options: ServerOptions);
|
|
11
|
+
/**
|
|
12
|
+
* List all channels
|
|
13
|
+
*/
|
|
14
|
+
listChannels(options?: ListChannelsOptions): Promise<{
|
|
15
|
+
channels: Channel[];
|
|
16
|
+
pagination: Pagination;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Get a channel by slug
|
|
20
|
+
*/
|
|
21
|
+
getChannel(slug: string): Promise<Channel>;
|
|
22
|
+
/**
|
|
23
|
+
* Create a new channel
|
|
24
|
+
*/
|
|
25
|
+
createChannel(input: ChannelInput): Promise<Channel>;
|
|
26
|
+
/**
|
|
27
|
+
* Update an existing channel
|
|
28
|
+
*/
|
|
29
|
+
updateChannel(slug: string, input: ChannelUpdateInput): Promise<Channel>;
|
|
30
|
+
/**
|
|
31
|
+
* Delete a channel
|
|
32
|
+
*/
|
|
33
|
+
deleteChannel(slug: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Publish a message to a channel
|
|
36
|
+
*/
|
|
37
|
+
publish(channel: string, content: Record<string, unknown>, options?: PublishOptions): Promise<PublishResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Get message history for a channel
|
|
40
|
+
*/
|
|
41
|
+
getMessageHistory(channel: string, options?: MessageHistoryOptions): Promise<{
|
|
42
|
+
messages: Message[];
|
|
43
|
+
pagination: Pagination;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { Channel, ChannelInput, ChannelUpdateInput, ListChannelsOptions, Message, MessageHistoryOptions, Pagination, PublishOptions, PublishResult, PushFloServer, ServerOptions };
|