@pushflodev/sdk 1.0.3 → 1.0.5

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/dist/server.cjs CHANGED
@@ -460,6 +460,117 @@ var RestClient = class {
460
460
  }
461
461
  };
462
462
 
463
+ // src/errors/ValidationError.ts
464
+ var ValidationError = class _ValidationError extends PushFloError {
465
+ /** The field that failed validation */
466
+ field;
467
+ constructor(message, field) {
468
+ super(message, "VALIDATION_ERROR", { retryable: false });
469
+ this.name = "ValidationError";
470
+ this.field = field;
471
+ }
472
+ /**
473
+ * Create an error for an invalid channel slug
474
+ */
475
+ static invalidChannelSlug(slug) {
476
+ return new _ValidationError(
477
+ `Invalid channel slug '${slug}': must be 1-64 characters, lowercase alphanumeric with hyphens, cannot start or end with a hyphen`,
478
+ "slug"
479
+ );
480
+ }
481
+ /**
482
+ * Create an error for a required field
483
+ */
484
+ static required(field) {
485
+ return new _ValidationError(`${field} is required`, field);
486
+ }
487
+ toJSON() {
488
+ return {
489
+ ...super.toJSON(),
490
+ field: this.field
491
+ };
492
+ }
493
+ };
494
+
495
+ // src/utils/validation.ts
496
+ var MAX_SLUG_LENGTH = 64;
497
+ var MIN_SLUG_LENGTH = 1;
498
+ var SLUG_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
499
+ function isValidChannelSlug(slug) {
500
+ if (!slug || typeof slug !== "string") {
501
+ return false;
502
+ }
503
+ if (slug.length < MIN_SLUG_LENGTH || slug.length > MAX_SLUG_LENGTH) {
504
+ return false;
505
+ }
506
+ if (slug.includes("--")) {
507
+ return false;
508
+ }
509
+ return SLUG_REGEX.test(slug);
510
+ }
511
+ function toChannelSlug(str) {
512
+ return str.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-").slice(0, MAX_SLUG_LENGTH);
513
+ }
514
+ function validateChannelSlug(slug) {
515
+ if (!slug || typeof slug !== "string") {
516
+ return {
517
+ valid: false,
518
+ error: "Channel slug is required"
519
+ };
520
+ }
521
+ if (slug.length < MIN_SLUG_LENGTH) {
522
+ return {
523
+ valid: false,
524
+ error: "Channel slug cannot be empty"
525
+ };
526
+ }
527
+ if (slug.length > MAX_SLUG_LENGTH) {
528
+ return {
529
+ valid: false,
530
+ error: `Channel slug cannot exceed ${MAX_SLUG_LENGTH} characters (got ${slug.length})`,
531
+ suggestion: toChannelSlug(slug)
532
+ };
533
+ }
534
+ if (slug !== slug.toLowerCase()) {
535
+ return {
536
+ valid: false,
537
+ error: "Channel slug must be lowercase",
538
+ suggestion: toChannelSlug(slug)
539
+ };
540
+ }
541
+ if (slug.startsWith("-")) {
542
+ return {
543
+ valid: false,
544
+ error: "Channel slug cannot start with a hyphen",
545
+ suggestion: toChannelSlug(slug)
546
+ };
547
+ }
548
+ if (slug.endsWith("-")) {
549
+ return {
550
+ valid: false,
551
+ error: "Channel slug cannot end with a hyphen",
552
+ suggestion: toChannelSlug(slug)
553
+ };
554
+ }
555
+ if (slug.includes("--")) {
556
+ return {
557
+ valid: false,
558
+ error: "Channel slug cannot contain consecutive hyphens",
559
+ suggestion: toChannelSlug(slug)
560
+ };
561
+ }
562
+ const invalidChars = slug.match(/[^a-z0-9-]/g);
563
+ if (invalidChars) {
564
+ const uniqueChars = [...new Set(invalidChars)].join(", ");
565
+ return {
566
+ valid: false,
567
+ error: `Channel slug contains invalid characters: ${uniqueChars}. Only lowercase letters, numbers, and hyphens are allowed.`,
568
+ suggestion: toChannelSlug(slug)
569
+ };
570
+ }
571
+ return { valid: true };
572
+ }
573
+
463
574
  // src/server/PushFloServer.ts
464
575
  var PushFloServer = class {
465
576
  client;
@@ -501,33 +612,55 @@ var PushFloServer = class {
501
612
  * Get a channel by slug
502
613
  */
503
614
  async getChannel(slug) {
615
+ this.validateSlug(slug);
504
616
  return this.client.get(API_PATHS.CHANNEL(slug));
505
617
  }
506
618
  /**
507
619
  * Create a new channel
620
+ *
621
+ * @throws {ValidationError} If the channel slug is invalid
508
622
  */
509
623
  async createChannel(input) {
624
+ this.validateSlug(input.slug);
510
625
  return this.client.post(API_PATHS.CHANNELS, input);
511
626
  }
512
627
  /**
513
628
  * Update an existing channel
514
629
  */
515
630
  async updateChannel(slug, input) {
631
+ this.validateSlug(slug);
516
632
  return this.client.patch(API_PATHS.CHANNEL(slug), input);
517
633
  }
518
634
  /**
519
635
  * Delete a channel
520
636
  */
521
637
  async deleteChannel(slug) {
638
+ this.validateSlug(slug);
522
639
  await this.client.delete(API_PATHS.CHANNEL(slug));
523
640
  }
641
+ /**
642
+ * Validate a channel slug and throw if invalid
643
+ */
644
+ validateSlug(slug) {
645
+ const result = validateChannelSlug(slug);
646
+ if (!result.valid) {
647
+ const error = ValidationError.invalidChannelSlug(slug);
648
+ if (result.suggestion) {
649
+ error.message += `. Suggested: '${result.suggestion}'`;
650
+ }
651
+ throw error;
652
+ }
653
+ }
524
654
  // ============================================
525
655
  // Message Publishing
526
656
  // ============================================
527
657
  /**
528
658
  * Publish a message to a channel
659
+ *
660
+ * @throws {ValidationError} If the channel slug is invalid
529
661
  */
530
662
  async publish(channel, content, options = {}) {
663
+ this.validateSlug(channel);
531
664
  return this.client.post(API_PATHS.CHANNEL_MESSAGES(channel), {
532
665
  content,
533
666
  eventType: options.eventType ?? "message"
@@ -535,8 +668,11 @@ var PushFloServer = class {
535
668
  }
536
669
  /**
537
670
  * Get message history for a channel
671
+ *
672
+ * @throws {ValidationError} If the channel slug is invalid
538
673
  */
539
674
  async getMessageHistory(channel, options = {}) {
675
+ this.validateSlug(channel);
540
676
  const response = await this.client.get(
541
677
  API_PATHS.CHANNEL_MESSAGES(channel),
542
678
  {
@@ -555,8 +691,14 @@ var PushFloServer = class {
555
691
  };
556
692
 
557
693
  exports.AuthenticationError = AuthenticationError;
694
+ exports.MAX_SLUG_LENGTH = MAX_SLUG_LENGTH;
695
+ exports.MIN_SLUG_LENGTH = MIN_SLUG_LENGTH;
558
696
  exports.NetworkError = NetworkError;
559
697
  exports.PushFloError = PushFloError;
560
698
  exports.PushFloServer = PushFloServer;
699
+ exports.ValidationError = ValidationError;
700
+ exports.isValidChannelSlug = isValidChannelSlug;
701
+ exports.toChannelSlug = toChannelSlug;
702
+ exports.validateChannelSlug = validateChannelSlug;
561
703
  //# sourceMappingURL=server.cjs.map
562
704
  //# sourceMappingURL=server.cjs.map
@@ -1 +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 const json = await response.json();\n // Handle wrapped responses: {success: true, data: ...}\n if (json && typeof json === 'object' && 'success' in json && 'data' in json) {\n return json.data as T;\n }\n return 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 items: 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.items,\n pagination: response.pagination,\n };\n }\n}\n"]}
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/errors/ValidationError.ts","../src/utils/validation.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 const json = await response.json();\n // Handle wrapped responses: {success: true, data: ...}\n if (json && typeof json === 'object' && 'success' in json && 'data' in json) {\n return json.data as T;\n }\n return json as T;\n } catch {\n throw new NetworkError('Failed to parse response', 'PARSE_ERROR', { retryable: false });\n }\n }\n}\n","import { PushFloError } from './PushFloError.js';\n\n/**\n * Error thrown when input validation fails\n */\nexport class ValidationError extends PushFloError {\n /** The field that failed validation */\n readonly field?: string;\n\n constructor(message: string, field?: string) {\n super(message, 'VALIDATION_ERROR', { retryable: false });\n this.name = 'ValidationError';\n this.field = field;\n }\n\n /**\n * Create an error for an invalid channel slug\n */\n static invalidChannelSlug(slug: string): ValidationError {\n return new ValidationError(\n `Invalid channel slug '${slug}': must be 1-64 characters, lowercase alphanumeric with hyphens, cannot start or end with a hyphen`,\n 'slug'\n );\n }\n\n /**\n * Create an error for a required field\n */\n static required(field: string): ValidationError {\n return new ValidationError(`${field} is required`, field);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n ...super.toJSON(),\n field: this.field,\n };\n }\n}\n","/**\n * Channel slug validation utilities\n *\n * Channel slugs must follow these rules:\n * - 1-64 characters long\n * - Lowercase letters (a-z), numbers (0-9), and hyphens (-) only\n * - Cannot start or end with a hyphen\n * - Cannot have consecutive hyphens\n */\n\n/** Maximum length for a channel slug */\nexport const MAX_SLUG_LENGTH = 64;\n\n/** Minimum length for a channel slug */\nexport const MIN_SLUG_LENGTH = 1;\n\n/**\n * Regular expression for validating channel slugs\n * Matches: lowercase alphanumeric, can contain hyphens but not at start/end\n */\nconst SLUG_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;\n\n/**\n * Check if a channel slug is valid\n *\n * @param slug - The channel slug to validate\n * @returns true if the slug is valid, false otherwise\n *\n * @example\n * ```typescript\n * isValidChannelSlug('my-channel') // true\n * isValidChannelSlug('channel-123') // true\n * isValidChannelSlug('a') // true\n * isValidChannelSlug('My-Channel') // false (uppercase)\n * isValidChannelSlug('-channel') // false (starts with hyphen)\n * isValidChannelSlug('channel:name') // false (contains colon)\n * isValidChannelSlug('channel_name') // false (contains underscore)\n * ```\n */\nexport function isValidChannelSlug(slug: string): boolean {\n if (!slug || typeof slug !== 'string') {\n return false;\n }\n\n if (slug.length < MIN_SLUG_LENGTH || slug.length > MAX_SLUG_LENGTH) {\n return false;\n }\n\n // Check for consecutive hyphens\n if (slug.includes('--')) {\n return false;\n }\n\n return SLUG_REGEX.test(slug);\n}\n\n/**\n * Convert a string to a valid channel slug\n *\n * @param str - The string to convert\n * @returns A valid channel slug\n *\n * @example\n * ```typescript\n * toChannelSlug('My Channel') // 'my-channel'\n * toChannelSlug('Hello World!') // 'hello-world'\n * toChannelSlug('user:123:messages') // 'user-123-messages'\n * toChannelSlug('___test___') // 'test'\n * ```\n */\nexport function toChannelSlug(str: string): string {\n return str\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-') // Replace non-alphanumeric with hyphens\n .replace(/^-+|-+$/g, '') // Remove leading/trailing hyphens\n .replace(/-{2,}/g, '-') // Replace consecutive hyphens with single\n .slice(0, MAX_SLUG_LENGTH); // Truncate to max length\n}\n\n/**\n * Validation result with detailed error information\n */\nexport interface SlugValidationResult {\n valid: boolean;\n error?: string;\n suggestion?: string;\n}\n\n/**\n * Validate a channel slug with detailed error messages\n *\n * @param slug - The channel slug to validate\n * @returns Validation result with error details and suggestions\n */\nexport function validateChannelSlug(slug: string): SlugValidationResult {\n if (!slug || typeof slug !== 'string') {\n return {\n valid: false,\n error: 'Channel slug is required',\n };\n }\n\n if (slug.length < MIN_SLUG_LENGTH) {\n return {\n valid: false,\n error: 'Channel slug cannot be empty',\n };\n }\n\n if (slug.length > MAX_SLUG_LENGTH) {\n return {\n valid: false,\n error: `Channel slug cannot exceed ${MAX_SLUG_LENGTH} characters (got ${slug.length})`,\n suggestion: toChannelSlug(slug),\n };\n }\n\n if (slug !== slug.toLowerCase()) {\n return {\n valid: false,\n error: 'Channel slug must be lowercase',\n suggestion: toChannelSlug(slug),\n };\n }\n\n if (slug.startsWith('-')) {\n return {\n valid: false,\n error: 'Channel slug cannot start with a hyphen',\n suggestion: toChannelSlug(slug),\n };\n }\n\n if (slug.endsWith('-')) {\n return {\n valid: false,\n error: 'Channel slug cannot end with a hyphen',\n suggestion: toChannelSlug(slug),\n };\n }\n\n if (slug.includes('--')) {\n return {\n valid: false,\n error: 'Channel slug cannot contain consecutive hyphens',\n suggestion: toChannelSlug(slug),\n };\n }\n\n const invalidChars = slug.match(/[^a-z0-9-]/g);\n if (invalidChars) {\n const uniqueChars = [...new Set(invalidChars)].join(', ');\n return {\n valid: false,\n error: `Channel slug contains invalid characters: ${uniqueChars}. Only lowercase letters, numbers, and hyphens are allowed.`,\n suggestion: toChannelSlug(slug),\n };\n }\n\n return { valid: true };\n}\n","import { RestClient } from './RestClient.js';\nimport { API_PATHS, DEFAULTS } from '../utils/constants.js';\nimport { AuthenticationError } from '../errors/AuthenticationError.js';\nimport { ValidationError } from '../errors/ValidationError.js';\nimport { validateChannelSlug } from '../utils/validation.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 items: 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 this.validateSlug(slug);\n return this.client.get<Channel>(API_PATHS.CHANNEL(slug));\n }\n\n /**\n * Create a new channel\n *\n * @throws {ValidationError} If the channel slug is invalid\n */\n async createChannel(input: ChannelInput): Promise<Channel> {\n this.validateSlug(input.slug);\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 this.validateSlug(slug);\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 this.validateSlug(slug);\n await this.client.delete<void>(API_PATHS.CHANNEL(slug));\n }\n\n /**\n * Validate a channel slug and throw if invalid\n */\n private validateSlug(slug: string): void {\n const result = validateChannelSlug(slug);\n if (!result.valid) {\n const error = ValidationError.invalidChannelSlug(slug);\n if (result.suggestion) {\n error.message += `. Suggested: '${result.suggestion}'`;\n }\n throw error;\n }\n }\n\n // ============================================\n // Message Publishing\n // ============================================\n\n /**\n * Publish a message to a channel\n *\n * @throws {ValidationError} If the channel slug is invalid\n */\n async publish(\n channel: string,\n content: Record<string, unknown>,\n options: PublishOptions = {}\n ): Promise<PublishResult> {\n this.validateSlug(channel);\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 * @throws {ValidationError} If the channel slug is invalid\n */\n async getMessageHistory(\n channel: string,\n options: MessageHistoryOptions = {}\n ): Promise<{ messages: Message[]; pagination: Pagination }> {\n this.validateSlug(channel);\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.items,\n pagination: response.pagination,\n };\n }\n}\n"]}
package/dist/server.d.cts CHANGED
@@ -1,6 +1,6 @@
1
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';
2
+ import { L as ListChannelsOptions, C as Channel, d as Pagination, a as ChannelInput, b as ChannelUpdateInput } from './api-Dgp2k2ZF.cjs';
3
+ export { A as AuthenticationError, M as MAX_SLUG_LENGTH, c as MIN_SLUG_LENGTH, N as NetworkError, P as PushFloError, S as SlugValidationResult, V as ValidationError, i as isValidChannelSlug, t as toChannelSlug, v as validateChannelSlug } from './api-Dgp2k2ZF.cjs';
4
4
 
5
5
  /**
6
6
  * Server-side PushFlo client for publishing messages and managing channels
@@ -21,6 +21,8 @@ declare class PushFloServer {
21
21
  getChannel(slug: string): Promise<Channel>;
22
22
  /**
23
23
  * Create a new channel
24
+ *
25
+ * @throws {ValidationError} If the channel slug is invalid
24
26
  */
25
27
  createChannel(input: ChannelInput): Promise<Channel>;
26
28
  /**
@@ -31,12 +33,20 @@ declare class PushFloServer {
31
33
  * Delete a channel
32
34
  */
33
35
  deleteChannel(slug: string): Promise<void>;
36
+ /**
37
+ * Validate a channel slug and throw if invalid
38
+ */
39
+ private validateSlug;
34
40
  /**
35
41
  * Publish a message to a channel
42
+ *
43
+ * @throws {ValidationError} If the channel slug is invalid
36
44
  */
37
45
  publish(channel: string, content: Record<string, unknown>, options?: PublishOptions): Promise<PublishResult>;
38
46
  /**
39
47
  * Get message history for a channel
48
+ *
49
+ * @throws {ValidationError} If the channel slug is invalid
40
50
  */
41
51
  getMessageHistory(channel: string, options?: MessageHistoryOptions): Promise<{
42
52
  messages: Message[];
package/dist/server.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { f as ServerOptions, P as PublishOptions, d as PublishResult, c as MessageHistoryOptions, M as Message } from './message-CVgilLwz.js';
2
- import { L as ListChannelsOptions, C as Channel, c as Pagination, a as ChannelInput, b as ChannelUpdateInput } from './api-DYrG_5uC.js';
3
- export { A as AuthenticationError, N as NetworkError, P as PushFloError } from './api-DYrG_5uC.js';
2
+ import { L as ListChannelsOptions, C as Channel, d as Pagination, a as ChannelInput, b as ChannelUpdateInput } from './api-Dgp2k2ZF.js';
3
+ export { A as AuthenticationError, M as MAX_SLUG_LENGTH, c as MIN_SLUG_LENGTH, N as NetworkError, P as PushFloError, S as SlugValidationResult, V as ValidationError, i as isValidChannelSlug, t as toChannelSlug, v as validateChannelSlug } from './api-Dgp2k2ZF.js';
4
4
 
5
5
  /**
6
6
  * Server-side PushFlo client for publishing messages and managing channels
@@ -21,6 +21,8 @@ declare class PushFloServer {
21
21
  getChannel(slug: string): Promise<Channel>;
22
22
  /**
23
23
  * Create a new channel
24
+ *
25
+ * @throws {ValidationError} If the channel slug is invalid
24
26
  */
25
27
  createChannel(input: ChannelInput): Promise<Channel>;
26
28
  /**
@@ -31,12 +33,20 @@ declare class PushFloServer {
31
33
  * Delete a channel
32
34
  */
33
35
  deleteChannel(slug: string): Promise<void>;
36
+ /**
37
+ * Validate a channel slug and throw if invalid
38
+ */
39
+ private validateSlug;
34
40
  /**
35
41
  * Publish a message to a channel
42
+ *
43
+ * @throws {ValidationError} If the channel slug is invalid
36
44
  */
37
45
  publish(channel: string, content: Record<string, unknown>, options?: PublishOptions): Promise<PublishResult>;
38
46
  /**
39
47
  * Get message history for a channel
48
+ *
49
+ * @throws {ValidationError} If the channel slug is invalid
40
50
  */
41
51
  getMessageHistory(channel: string, options?: MessageHistoryOptions): Promise<{
42
52
  messages: Message[];