@syncar/server 1.0.0-alpha.1 → 1.0.0-alpha.2

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/index.d.ts CHANGED
@@ -215,7 +215,7 @@ interface IClientConnection {
215
215
  * Message types for protocol communication
216
216
  *
217
217
  * @remarks
218
- * Enum defining all message types supported by the Synca protocol.
218
+ * Enum defining all message types supported by the Syncar protocol.
219
219
  *
220
220
  * @example
221
221
  * ```ts
@@ -309,7 +309,7 @@ declare enum ErrorCode {
309
309
  * Base message interface
310
310
  *
311
311
  * @remarks
312
- * All messages in the Synca protocol extend this interface with
312
+ * All messages in the Syncar protocol extend this interface with
313
313
  * common fields like ID, timestamp, and optional channel.
314
314
  *
315
315
  * @property id - Unique message identifier
@@ -549,7 +549,7 @@ type Message<T = unknown> = DataMessage<T> | SignalMessage | ErrorMessage | AckM
549
549
  *
550
550
  * @example
551
551
  * ```ts
552
- * import type { IMiddlewareAction } from '@synca/server'
552
+ * import type { IMiddlewareAction } from '@syncar/server'
553
553
  *
554
554
  * function handleAction(action: IMiddlewareAction) {
555
555
  * switch (action) {
@@ -701,7 +701,7 @@ interface Context<S = Record<string, unknown>> {
701
701
  *
702
702
  * @example
703
703
  * ```ts
704
- * import type { Middleware } from '@synca/server'
704
+ * import type { Middleware } from '@syncar/server'
705
705
  *
706
706
  * const authMiddleware: Middleware = async (context, next) => {
707
707
  * const token = context.req.message?.data?.token
@@ -1628,7 +1628,7 @@ type ServerInstance = WebSocketServer;
1628
1628
  *
1629
1629
  * @remarks
1630
1630
  * Configuration options for the WebSocket transport layer. Extends the
1631
- * standard `ws` library options with Synca-specific settings.
1631
+ * standard `ws` library options with Syncar-specific settings.
1632
1632
  *
1633
1633
  * @example
1634
1634
  * ```ts
@@ -1733,7 +1733,7 @@ interface WebSocketServerTransportConfig extends ServerOptions {
1733
1733
  * @example
1734
1734
  * ### Basic usage
1735
1735
  * ```ts
1736
- * import { WebSocketServerTransport } from '@synca/server'
1736
+ * import { WebSocketServerTransport } from '@syncar/server'
1737
1737
  *
1738
1738
  * const transport = new WebSocketServerTransport({
1739
1739
  * server: httpServer,
@@ -1875,7 +1875,7 @@ declare class WebSocketServerTransport extends EventEmitter {
1875
1875
  *
1876
1876
  * @example
1877
1877
  * ```ts
1878
- * const server = createSyncaServer({ port: 3000 })
1878
+ * const server = createSyncarServer({ port: 3000 })
1879
1879
  * await server.start()
1880
1880
  *
1881
1881
  * const stats = server.getStats()
@@ -1899,15 +1899,15 @@ interface IServerStats {
1899
1899
  * Server configuration options
1900
1900
  *
1901
1901
  * @remarks
1902
- * Complete configuration interface for the Synca server. These options
1902
+ * Complete configuration interface for the Syncar server. These options
1903
1903
  * control the WebSocket transport layer, connection handling, middleware,
1904
1904
  * and performance tuning parameters.
1905
1905
  *
1906
1906
  * @example
1907
1907
  * ```ts
1908
- * import { createSyncaServer } from '@synca/server'
1908
+ * import { createSyncarServer } from '@syncar/server'
1909
1909
  *
1910
- * const server = createSyncaServer({
1910
+ * const server = createSyncarServer({
1911
1911
  * port: 3000,
1912
1912
  * host: '0.0.0.0',
1913
1913
  * path: '/ws',
@@ -1970,7 +1970,7 @@ interface IServerOptions {
1970
1970
  */
1971
1971
  host: string;
1972
1972
  /**
1973
- * WebSocket path (default: '/synca')
1973
+ * WebSocket path (default: '/syncar')
1974
1974
  *
1975
1975
  * @remarks
1976
1976
  * The URL path for WebSocket connections. Clients must connect to
@@ -2045,7 +2045,7 @@ interface IServerOptions {
2045
2045
  broadcastChunkSize: number;
2046
2046
  }
2047
2047
  /**
2048
- * Synca Server - Real-time WebSocket server with pub/sub channels
2048
+ * Syncar Server - Real-time WebSocket server with pub/sub channels
2049
2049
  *
2050
2050
  * @remarks
2051
2051
  * The main server class providing WebSocket communication with broadcast
@@ -2053,9 +2053,9 @@ interface IServerOptions {
2053
2053
  *
2054
2054
  * @example
2055
2055
  * ```ts
2056
- * import { createSyncaServer } from '@synca/server'
2056
+ * import { createSyncarServer } from '@syncar/server'
2057
2057
  *
2058
- * const server = createSyncaServer({ port: 3000 })
2058
+ * const server = createSyncarServer({ port: 3000 })
2059
2059
  * await server.start()
2060
2060
  *
2061
2061
  * // Create channels
@@ -2072,9 +2072,9 @@ interface IServerOptions {
2072
2072
  * chat.publish({ text: 'Welcome!' })
2073
2073
  * ```
2074
2074
  *
2075
- * @see {@link createSyncaServer} for factory function
2075
+ * @see {@link createSyncarServer} for factory function
2076
2076
  */
2077
- declare class SyncaServer {
2077
+ declare class SyncarServer {
2078
2078
  private readonly config;
2079
2079
  private transport;
2080
2080
  readonly registry: ClientRegistry;
@@ -2096,7 +2096,7 @@ declare class SyncaServer {
2096
2096
  *
2097
2097
  * @example
2098
2098
  * ```ts
2099
- * const server = createSyncaServer({ port: 3000 })
2099
+ * const server = createSyncarServer({ port: 3000 })
2100
2100
  * await server.start()
2101
2101
  * console.log('Server is running')
2102
2102
  * ```
@@ -2232,7 +2232,7 @@ declare class SyncaServer {
2232
2232
  *
2233
2233
  * @example
2234
2234
  * ```ts
2235
- * import { createAuthMiddleware } from '@synca/server'
2235
+ * import { createAuthMiddleware } from '@syncar/server'
2236
2236
  *
2237
2237
  * server.use(createAuthMiddleware({
2238
2238
  * verifyToken: async (token) => jwt.verify(token, SECRET)
@@ -2324,31 +2324,31 @@ declare class SyncaServer {
2324
2324
  private setupTransportHandlers;
2325
2325
  }
2326
2326
  /**
2327
- * Create a Synca server with automatic WebSocket transport setup
2327
+ * Create a Syncar server with automatic WebSocket transport setup
2328
2328
  *
2329
2329
  * @remarks
2330
- * Factory function that creates a configured SyncaServer instance.
2330
+ * Factory function that creates a configured SyncarServer instance.
2331
2331
  * Automatically sets up the WebSocket transport layer if not provided,
2332
2332
  * merges user configuration with defaults, and creates the client registry.
2333
2333
  *
2334
2334
  * @param config - Optional partial server configuration. All properties are optional
2335
2335
  * and will be merged with {@link DEFAULT_SERVER_CONFIG}.
2336
2336
  *
2337
- * @returns Configured Synca server instance ready to be started
2337
+ * @returns Configured Syncar server instance ready to be started
2338
2338
  *
2339
2339
  * @example
2340
2340
  * ### Basic usage
2341
2341
  * ```ts
2342
- * import { createSyncaServer } from '@synca/server'
2342
+ * import { createSyncarServer } from '@syncar/server'
2343
2343
  *
2344
- * const server = createSyncaServer({ port: 3000 })
2344
+ * const server = createSyncarServer({ port: 3000 })
2345
2345
  * await server.start()
2346
2346
  * ```
2347
2347
  *
2348
2348
  * @example
2349
2349
  * ### With custom configuration
2350
2350
  * ```ts
2351
- * const server = createSyncaServer({
2351
+ * const server = createSyncarServer({
2352
2352
  * port: 8080,
2353
2353
  * host: 'localhost',
2354
2354
  * path: '/ws',
@@ -2364,14 +2364,14 @@ declare class SyncaServer {
2364
2364
  * ### With existing HTTP server
2365
2365
  * ```ts
2366
2366
  * import { createServer } from 'node:http'
2367
- * import { createSyncaServer } from '@synca/server'
2367
+ * import { createSyncarServer } from '@syncar/server'
2368
2368
  *
2369
2369
  * const httpServer = createServer((req, res) => {
2370
2370
  * res.writeHead(200)
2371
2371
  * res.end('OK')
2372
2372
  * })
2373
2373
  *
2374
- * const server = createSyncaServer({
2374
+ * const server = createSyncarServer({
2375
2375
  * server: httpServer,
2376
2376
  * path: '/ws',
2377
2377
  * })
@@ -2383,12 +2383,12 @@ declare class SyncaServer {
2383
2383
  * ### With Express
2384
2384
  * ```ts
2385
2385
  * import express from 'express'
2386
- * import { createSyncaServer } from '@synca/server'
2386
+ * import { createSyncarServer } from '@syncar/server'
2387
2387
  *
2388
2388
  * const app = express()
2389
2389
  * const httpServer = app.listen(3000)
2390
2390
  *
2391
- * const server = createSyncaServer({
2391
+ * const server = createSyncarServer({
2392
2392
  * server: httpServer,
2393
2393
  * path: '/ws',
2394
2394
  * })
@@ -2399,9 +2399,9 @@ declare class SyncaServer {
2399
2399
  * @example
2400
2400
  * ### With custom logger
2401
2401
  * ```ts
2402
- * import { createSyncaServer } from '@synca/server'
2402
+ * import { createSyncarServer } from '@syncar/server'
2403
2403
  *
2404
- * const server = createSyncaServer({
2404
+ * const server = createSyncarServer({
2405
2405
  * port: 3000,
2406
2406
  * logger: {
2407
2407
  * debug: (msg, ...args) => console.debug('[DEBUG]', msg, ...args),
@@ -2415,9 +2415,9 @@ declare class SyncaServer {
2415
2415
  * @example
2416
2416
  * ### With middleware
2417
2417
  * ```ts
2418
- * import { createSyncaServer, createLoggingMiddleware } from '@synca/server'
2418
+ * import { createSyncarServer, createLoggingMiddleware } from '@syncar/server'
2419
2419
  *
2420
- * const server = createSyncaServer({
2420
+ * const server = createSyncarServer({
2421
2421
  * port: 3000,
2422
2422
  * middleware: [
2423
2423
  * createLoggingMiddleware(),
@@ -2427,10 +2427,10 @@ declare class SyncaServer {
2427
2427
  * await server.start()
2428
2428
  * ```
2429
2429
  *
2430
- * @see {@link SyncaServer} for server class API
2430
+ * @see {@link SyncarServer} for server class API
2431
2431
  * @see {@link DEFAULT_SERVER_CONFIG} for default configuration values
2432
2432
  */
2433
- declare function createSyncaServer(config?: Partial<IServerOptions>): SyncaServer;
2433
+ declare function createSyncarServer(config?: Partial<IServerOptions>): SyncarServer;
2434
2434
 
2435
2435
  /**
2436
2436
  * Middleware Factories
@@ -2496,7 +2496,7 @@ interface AuthMiddlewareOptions {
2496
2496
  *
2497
2497
  * @example
2498
2498
  * ```ts
2499
- * import { createAuthMiddleware } from '@synca/server/middleware'
2499
+ * import { createAuthMiddleware } from '@syncar/server/middleware'
2500
2500
  *
2501
2501
  * const authMiddleware = createAuthMiddleware({
2502
2502
  * verifyToken: async (token) => {
@@ -2568,7 +2568,7 @@ interface LoggingMiddlewareOptions {
2568
2568
  *
2569
2569
  * @example
2570
2570
  * ```ts
2571
- * import { createLoggingMiddleware } from '@synca/server/middleware'
2571
+ * import { createLoggingMiddleware } from '@syncar/server/middleware'
2572
2572
  *
2573
2573
  * const loggingMiddleware = createLoggingMiddleware({
2574
2574
  * logger: console,
@@ -2627,7 +2627,7 @@ interface RateLimitMiddlewareOptions {
2627
2627
  *
2628
2628
  * @example
2629
2629
  * ```ts
2630
- * import { createRateLimitMiddleware } from '@synca/server/middleware'
2630
+ * import { createRateLimitMiddleware } from '@syncar/server/middleware'
2631
2631
  *
2632
2632
  * const rateLimitMiddleware = createRateLimitMiddleware({
2633
2633
  * maxRequests: 100,
@@ -2688,7 +2688,7 @@ interface ChannelWhitelistMiddlewareOptions {
2688
2688
  *
2689
2689
  * @example
2690
2690
  * ```ts
2691
- * import { createChannelWhitelistMiddleware } from '@synca/server/middleware'
2691
+ * import { createChannelWhitelistMiddleware } from '@syncar/server/middleware'
2692
2692
  *
2693
2693
  * const whitelistMiddleware = createChannelWhitelistMiddleware({
2694
2694
  * allowedChannels: ['chat', 'notifications']
@@ -2737,7 +2737,7 @@ interface ContextOptions<S = Record<string, unknown>> {
2737
2737
  initialState?: S;
2738
2738
  }
2739
2739
  /**
2740
- * Create a new Hono-style middleware context
2740
+ * Create onion pattern middleware context
2741
2741
  *
2742
2742
  * @remarks
2743
2743
  * Creates a lightweight middleware context using closures to ensure properties
@@ -2800,7 +2800,7 @@ declare function createContext<S = Record<string, unknown>>(options: ContextOpti
2800
2800
  *
2801
2801
  * @example
2802
2802
  * ```ts
2803
- * import { ContextManager } from '@synca/server'
2803
+ * import { ContextManager } from '@syncar/server'
2804
2804
  *
2805
2805
  * const manager = new ContextManager()
2806
2806
  *
@@ -2814,7 +2814,7 @@ declare function createContext<S = Record<string, unknown>>(options: ContextOpti
2814
2814
  * const context = await manager.executeConnection(client, 'connect')
2815
2815
  * ```
2816
2816
  *
2817
- * @see {@link createSyncaServer} for server-level context management
2817
+ * @see {@link createSyncarServer} for server-level context management
2818
2818
  */
2819
2819
  declare class ContextManager {
2820
2820
  /** Registered middleware functions */
@@ -3120,13 +3120,13 @@ declare class ContextManager {
3120
3120
  * Errors Module
3121
3121
  *
3122
3122
  * @description
3123
- * Custom error classes for the Synca server. All errors extend from
3124
- * {@link SyncaError} and include error codes for programmatic handling.
3123
+ * Custom error classes for the Syncar server. All errors extend from
3124
+ * {@link SyncarError} and include error codes for programmatic handling.
3125
3125
  *
3126
3126
  * @remarks
3127
3127
  * The error hierarchy:
3128
3128
  *
3129
- * - {@link SyncaError} - Base error class
3129
+ * - {@link SyncarError} - Base error class
3130
3130
  * - {@link ConfigError} - Server configuration issues
3131
3131
  * - {@link TransportError} - WebSocket transport issues
3132
3132
  * - {@link ChannelError} - Channel operation failures
@@ -3140,7 +3140,7 @@ declare class ContextManager {
3140
3140
  * @example
3141
3141
  * ### Throwing errors
3142
3142
  * ```ts
3143
- * import { StateError, ValidationError } from '@synca/server'
3143
+ * import { StateError, ValidationError } from '@syncar/server'
3144
3144
  *
3145
3145
  * function createChannel(name: string) {
3146
3146
  * if (!name) {
@@ -3156,10 +3156,10 @@ declare class ContextManager {
3156
3156
  * ### Catching errors
3157
3157
  * ```ts
3158
3158
  * import {
3159
- * SyncaError,
3159
+ * SyncarError,
3160
3160
  * MiddlewareRejectionError,
3161
3161
  * StateError
3162
- * } from '@synca/server'
3162
+ * } from '@syncar/server'
3163
3163
  *
3164
3164
  * try {
3165
3165
  * await server.start()
@@ -3168,7 +3168,7 @@ declare class ContextManager {
3168
3168
  * console.error('Invalid state:', error.message)
3169
3169
  * } else if (error instanceof MiddlewareRejectionError) {
3170
3170
  * console.error(`Action rejected: ${error.reason}`)
3171
- * } else if (error instanceof SyncaError) {
3171
+ * } else if (error instanceof SyncarError) {
3172
3172
  * console.error(`[${error.code}] ${error.message}`)
3173
3173
  * }
3174
3174
  * }
@@ -3178,10 +3178,10 @@ declare class ContextManager {
3178
3178
  */
3179
3179
 
3180
3180
  /**
3181
- * Base Synca error class
3181
+ * Base Syncar error class
3182
3182
  *
3183
3183
  * @remarks
3184
- * All custom errors in the Synca server extend this class. Provides
3184
+ * All custom errors in the Syncar server extend this class. Provides
3185
3185
  * consistent error handling with error codes, context, and serialization.
3186
3186
  *
3187
3187
  * @property code - Error code for programmatic handling
@@ -3189,7 +3189,7 @@ declare class ContextManager {
3189
3189
  *
3190
3190
  * @example
3191
3191
  * ```ts
3192
- * throw new SyncaError('Something went wrong', 'CUSTOM_ERROR', { userId: '123' })
3192
+ * throw new SyncarError('Something went wrong', 'CUSTOM_ERROR', { userId: '123' })
3193
3193
  * ```
3194
3194
  *
3195
3195
  * @example
@@ -3198,7 +3198,7 @@ declare class ContextManager {
3198
3198
  * try {
3199
3199
  * // ...
3200
3200
  * } catch (error) {
3201
- * if (error instanceof SyncaError) {
3201
+ * if (error instanceof SyncarError) {
3202
3202
  * console.log(error.code) // 'CUSTOM_ERROR'
3203
3203
  * console.log(error.message) // 'Something went wrong'
3204
3204
  * console.log(error.context) // { userId: '123' }
@@ -3207,7 +3207,7 @@ declare class ContextManager {
3207
3207
  * }
3208
3208
  * ```
3209
3209
  */
3210
- declare class SyncaError extends Error {
3210
+ declare class SyncarError extends Error {
3211
3211
  /**
3212
3212
  * Error code for programmatic error handling
3213
3213
  *
@@ -3225,7 +3225,7 @@ declare class SyncaError extends Error {
3225
3225
  */
3226
3226
  readonly context?: Record<string, unknown>;
3227
3227
  /**
3228
- * Creates a new SyncaError
3228
+ * Creates a new SyncarError
3229
3229
  *
3230
3230
  * @param message - Human-readable error message
3231
3231
  * @param code - Error code for programmatic handling (default: 'SYNNEL_ERROR')
@@ -3239,10 +3239,10 @@ declare class SyncaError extends Error {
3239
3239
  *
3240
3240
  * @example
3241
3241
  * ```ts
3242
- * const error = new SyncaError('Failed', 'FAIL', { id: 123 })
3242
+ * const error = new SyncarError('Failed', 'FAIL', { id: 123 })
3243
3243
  * console.log(JSON.stringify(error.toJSON(), null, 2))
3244
3244
  * // {
3245
- * // "name": "SyncaError",
3245
+ * // "name": "SyncarError",
3246
3246
  * // "message": "Failed",
3247
3247
  * // "code": "FAIL",
3248
3248
  * // "context": { "id": 123 },
@@ -3264,9 +3264,9 @@ declare class SyncaError extends Error {
3264
3264
  *
3265
3265
  * @example
3266
3266
  * ```ts
3267
- * const error = new SyncaError('Failed', 'FAIL')
3267
+ * const error = new SyncarError('Failed', 'FAIL')
3268
3268
  * console.log(error.toString())
3269
- * // "[SyncaError:FAIL] Failed"
3269
+ * // "[SyncarError:FAIL] Failed"
3270
3270
  * ```
3271
3271
  */
3272
3272
  toString(): string;
@@ -3284,7 +3284,7 @@ declare class SyncaError extends Error {
3284
3284
  * }
3285
3285
  * ```
3286
3286
  */
3287
- declare class ConfigError extends SyncaError {
3287
+ declare class ConfigError extends SyncarError {
3288
3288
  constructor(message: string, context?: Record<string, unknown>);
3289
3289
  }
3290
3290
  /**
@@ -3300,7 +3300,7 @@ declare class ConfigError extends SyncaError {
3300
3300
  * }
3301
3301
  * ```
3302
3302
  */
3303
- declare class TransportError extends SyncaError {
3303
+ declare class TransportError extends SyncarError {
3304
3304
  constructor(message: string, context?: Record<string, unknown>);
3305
3305
  }
3306
3306
  /**
@@ -3316,7 +3316,7 @@ declare class TransportError extends SyncaError {
3316
3316
  * }
3317
3317
  * ```
3318
3318
  */
3319
- declare class ChannelError extends SyncaError {
3319
+ declare class ChannelError extends SyncarError {
3320
3320
  constructor(message: string, context?: Record<string, unknown>);
3321
3321
  }
3322
3322
  /**
@@ -3332,7 +3332,7 @@ declare class ChannelError extends SyncaError {
3332
3332
  * }
3333
3333
  * ```
3334
3334
  */
3335
- declare class ClientError extends SyncaError {
3335
+ declare class ClientError extends SyncarError {
3336
3336
  constructor(message: string, context?: Record<string, unknown>);
3337
3337
  }
3338
3338
  /**
@@ -3348,7 +3348,7 @@ declare class ClientError extends SyncaError {
3348
3348
  * }
3349
3349
  * ```
3350
3350
  */
3351
- declare class MessageError extends SyncaError {
3351
+ declare class MessageError extends SyncarError {
3352
3352
  constructor(message: string, context?: Record<string, unknown>);
3353
3353
  }
3354
3354
  /**
@@ -3364,7 +3364,7 @@ declare class MessageError extends SyncaError {
3364
3364
  * }
3365
3365
  * ```
3366
3366
  */
3367
- declare class ValidationError extends SyncaError {
3367
+ declare class ValidationError extends SyncarError {
3368
3368
  constructor(message: string, context?: Record<string, unknown>);
3369
3369
  }
3370
3370
  /**
@@ -3384,7 +3384,7 @@ declare class ValidationError extends SyncaError {
3384
3384
  * }
3385
3385
  * ```
3386
3386
  */
3387
- declare class StateError extends SyncaError {
3387
+ declare class StateError extends SyncarError {
3388
3388
  constructor(message: string, context?: Record<string, unknown>);
3389
3389
  }
3390
3390
  /**
@@ -3599,4 +3599,4 @@ declare class MiddlewareExecutionError extends Error {
3599
3599
  toString(): string;
3600
3600
  }
3601
3601
 
3602
- export { type AckMessage, BROADCAST_CHANNEL, BroadcastChannel, CLOSE_CODES, ChannelError, type ChannelName, ClientError, type ClientId, ConfigError, type Context, ContextManager, type DataMessage, ERROR_CODES, ErrorCode, type ErrorMessage, type IChannelState, type IClientConnection, type IMessageHandler, type IPublishOptions, type IServerOptions, type IServerStats, type Message, MessageError, type MessageId, MessageType, type Middleware, MiddlewareExecutionError, MiddlewareRejectionError, MulticastChannel, type SignalMessage, SignalType, StateError, type SubscriberId, SyncaServer as Synca, SyncaError, SyncaServer, type Timestamp, TransportError, ValidationError, WebSocketServerTransport, createAuthMiddleware, createChannelWhitelistMiddleware, createContext, createLoggingMiddleware, createRateLimitMiddleware, createSyncaServer };
3602
+ export { type AckMessage, BROADCAST_CHANNEL, BroadcastChannel, CLOSE_CODES, ChannelError, type ChannelName, ClientError, type ClientId, ConfigError, type Context, ContextManager, type DataMessage, ERROR_CODES, ErrorCode, type ErrorMessage, type IChannelState, type IClientConnection, type IMessageHandler, type IPublishOptions, type IServerOptions, type IServerStats, type Message, MessageError, type MessageId, MessageType, type Middleware, MiddlewareExecutionError, MiddlewareRejectionError, MulticastChannel, type SignalMessage, SignalType, StateError, type SubscriberId, SyncarServer as Syncar, SyncarError, SyncarServer, type Timestamp, TransportError, ValidationError, WebSocketServerTransport, createAuthMiddleware, createChannelWhitelistMiddleware, createContext, createLoggingMiddleware, createRateLimitMiddleware, createSyncarServer };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- function V(){return`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}function z(){return`client-${Date.now()}-${Math.random().toString(36).substring(2,9)}`}var K=1,j=128,J="__";function ie(i){return typeof i=="string"&&i.length>=K&&i.length<=j}function L(i){return i.startsWith(J)}function f(i){if(!ie(i))throw new Error(`Invalid channel name: must be between ${K} and ${j} characters`);if(L(i))throw new Error(`Reserved channel name: channel names starting with '${J}' are reserved for system use`)}function P(i){return i.type==="data"}function Y(i,e,t){return{id:t||V(),type:"data",channel:i,data:e,timestamp:Date.now()}}function O(i,e,t,n){return{id:n||V(),type:"signal",channel:i,signal:e,data:t,timestamp:Date.now()}}var oe={info:"INFO",warn:"WARN",error:"ERROR",debug:"DEBUG"};function ae(){return new Date().toISOString()}function X(i="Synca",e={}){let t={debug:!1,info:!0,warn:!0,error:!0,...e},n=(r,s)=>{let o=ae();return`[${i} ${o}] [${oe[r]}] ${s}`};return{debug:(r,...s)=>{t.debug&&console.log(n("debug",r),...s)},info:(r,...s)=>{t.info&&console.log(n("info",r),...s)},warn:(r,...s)=>{t.warn&&console.warn(n("warn",r),...s)},error:(r,...s)=>{t.error&&console.error(n("error",r),...s)}}}var y="__broadcast__",H={NORMAL:1e3,GOING_AWAY:1001,PROTOCOL_ERROR:1002,UNSUPPORTED_DATA:1003,NO_STATUS:1005,ABNORMAL:1006,INVALID_PAYLOAD:1007,POLICY_VIOLATION:1008,MESSAGE_TOO_BIG:1009,MISSING_EXTENSION:1010,INTERNAL_ERROR:1011,SERVICE_RESTART:1012,TRY_AGAIN_LATER:1013,REJECTED:4001,RATE_LIMITED:4002,CHANNEL_NOT_FOUND:4003,UNAUTHORIZED:4005},ce={REJECTED:"REJECTED",MISSING_CHANNEL:"MISSING_CHANNEL",SUBSCRIBE_REJECTED:"SUBSCRIBE_REJECTED",UNSUBSCRIBE_REJECTED:"UNSUBSCRIBE_REJECTED",RATE_LIMITED:"RATE_LIMITED",AUTH_FAILED:"AUTH_FAILED",NOT_AUTHORIZED:"NOT_AUTHORIZED",CHANNEL_NOT_ALLOWED:"CHANNEL_NOT_ALLOWED",INVALID_MESSAGE:"INVALID_MESSAGE",SERVER_ERROR:"SERVER_ERROR"},Z="/synca",D=1048576,U=3e4,B=5e3,le=3e3,de="0.0.0.0",ge="/synca",he=!0,Q={port:le,host:de,path:ge,enablePing:he,pingInterval:U,pingTimeout:B,broadcastChunkSize:500};var k=class{constructor(e,t,n=500){this.name=e;this.registry=t;this.chunkSize=n}publish(e,t){let n=this.getTargetClients(t);n.length>this.chunkSize?this.publishInChunks(e,n,t):this.publishToClients(e,n,t)}async dispatch(e,t,n){}publishToClients(e,t,n){let r=Y(this.name,e);for(let s of t){if(n?.to&&!n.to.includes(s)||n?.exclude&&n.exclude.includes(s))continue;let o=this.registry.connections.get(s);if(o)try{o.socket.send(JSON.stringify(r))}catch(a){this.registry.logger?.error(`[${this.name}] Failed to send to ${s}:`,a)}}}publishInChunks(e,t,n){let r=0,s=()=>{let o=t.slice(r,r+this.chunkSize);o.length!==0&&(this.publishToClients(e,o,n),r+=this.chunkSize,r<t.length&&setImmediate(s))};s()}},w=class extends k{constructor(e,t=500){super(y,e,t)}getTargetClients(e){return Array.from(this.registry.connections.keys())}get subscriberCount(){return this.registry.connections.size}isEmpty(){return this.registry.connections.size===0}getMiddlewares(){return[]}},E=class extends k{constructor(t){f(t.name);super(t.name,t.registry,t.options?.chunkSize);this.middlewares=[];this.messageHandlers=new Set}getTargetClients(t){return Array.from(this.registry.getChannelSubscribers(this.name))}use(t){this.middlewares.push(t)}getMiddlewares(){return[...this.middlewares]}get subscriberCount(){return this.registry.getChannelSubscribers(this.name).size}onMessage(t){return this.messageHandlers.add(t),()=>this.messageHandlers.delete(t)}subscribe(t){return this.registry.subscribe(t,this.name)}unsubscribe(t){return this.registry.unsubscribe(t,this.name)}async dispatch(t,n,r){if(this.messageHandlers.size>0)for(let s of this.messageHandlers)try{await s(t,n,r)}catch(o){this.registry.logger?.error(`[${this.name}] Error in message handler:`,o)}else this.publish(t,{exclude:[n.id]})}hasSubscriber(t){return this.registry.getChannelSubscribers(this.name).has(t)}getSubscribers(){return new Set(this.registry.getChannelSubscribers(this.name))}isEmpty(){return this.registry.getChannelSubscribers(this.name).size===0}};var g=class i extends Error{constructor(e,t="SYNNEL_ERROR",n){super(e),this.name="SyncaError",this.code=t,this.context=n,Error.captureStackTrace&&Error.captureStackTrace(this,i)}toJSON(){return{name:this.name,message:this.message,code:this.code,context:this.context,stack:this.stack}}toString(){return`[${this.name}:${this.code}] ${this.message}`}},G=class extends g{constructor(e,t){super(e,"CONFIG_ERROR",t),this.name="ConfigError"}},$=class extends g{constructor(e,t){super(e,"TRANSPORT_ERROR",t),this.name="TransportError"}},h=class extends g{constructor(e,t){super(e,"CHANNEL_ERROR",t),this.name="ChannelError"}},q=class extends g{constructor(e,t){super(e,"CLIENT_ERROR",t),this.name="ClientError"}},u=class extends g{constructor(e,t){super(e,"MESSAGE_ERROR",t),this.name="MessageError"}},F=class extends g{constructor(e,t){super(e,"VALIDATION_ERROR",t),this.name="ValidationError"}},p=class extends g{constructor(e,t){super(e,"STATE_ERROR",t),this.name="StateError"}},S=class i extends Error{constructor(t,n,r,s){super(`Action '${n}' rejected: ${t}`);this.name="MiddlewareRejectionError";this.reason=t,this.action=n,this.name="MiddlewareRejectionError",this.code=r,this.context=s,Error.captureStackTrace&&Error.captureStackTrace(this,i)}toJSON(){return{name:this.name,reason:this.reason,action:this.action,code:this.code,context:this.context,message:this.message,stack:this.stack}}toString(){return`[${this.name}:${this.action}] ${this.reason}`}},I=class i extends Error{constructor(e,t,n){super(`Middleware execution error in ${t} during ${e}: ${n.message}`),this.name="MiddlewareExecutionError",this.action=e,this.middleware=t,this.cause=n,Error.captureStackTrace&&Error.captureStackTrace(this,i)}getCause(){return this.cause}toString(){return`[${this.name}] ${this.middleware} failed during ${this.action}: ${this.cause.message}`}};var x=class{constructor(e){this.registry=e.registry,this.context=e.context,this.options={requireChannel:e.options?.requireChannel??!1,allowReservedChannels:e.options?.allowReservedChannels??!1,sendAcknowledgments:e.options?.sendAcknowledgments??!0,autoRespondToPing:e.options?.autoRespondToPing??!0}}async handleSignal(e,t){let n;t.signal==="subscribe"?n=this.context.createSubscribeContext(e,t.channel):t.signal==="unsubscribe"?n=this.context.createUnsubscribeContext(e,t.channel):n=this.context.createMessageContext(e,t);let r=async()=>{switch(t.signal){case"subscribe":await this.handleSubscribe(e,t);break;case"unsubscribe":await this.handleUnsubscribe(e,t);break;case"ping":await this.handlePing(e,t);break;case"pong":await this.handlePong(e,t);break;default:throw new u(`Unknown signal type: ${t.signal}`)}},s;t.channel&&t.channel!==y&&(s=this.registry.getChannel(t.channel));let o=this.context.getPipeline(s);await this.context.execute(n,o,r)}async handleSubscribe(e,t){let{channel:n}=t;if(!this.options.allowReservedChannels&&L(n))throw new h(`Cannot subscribe to reserved channel: ${n}`);if(n===y)throw new h("Cannot subscribe to broadcast channel");if(!this.registry.subscribe(e.id,n))throw new h(`Failed to subscribe client ${e.id} to channel ${n}`);if(this.options.sendAcknowledgments){let s=O(n,"subscribed",void 0,t.id);e.socket.send(JSON.stringify(s),()=>{})}}async handleUnsubscribe(e,t){let{channel:n}=t;if(!this.registry.isSubscribed(e.id,n))throw new h(`Client not subscribed to channel: ${n}`);if(this.registry.unsubscribe(e.id,n),this.options.sendAcknowledgments){let r=O(n,"unsubscribed",void 0,t.id);e.socket.send(JSON.stringify(r),()=>{})}}async handlePing(e,t){if(e.lastPingAt=Date.now(),this.options.autoRespondToPing){let n=O(t.channel,"pong",void 0,t.id);e.socket.send(JSON.stringify(n),()=>{})}}async handlePong(e,t){e.lastPingAt=Date.now()}getOptions(){return this.options}};var M=class{constructor(e){this.registry=e.registry,this.context=e.context,this.options={requireChannel:e.options?.requireChannel??!0}}async handleMessage(e,t){if(!P(t))throw new u("Invalid message type: expected DATA message");let n=this.registry.getChannel(t.channel);if(this.options.requireChannel&&!n)throw new h(`Channel not found: ${t.channel}`);let r=this.context.getPipeline(n),s=this.context.createMessageContext(e,t),o=async()=>{n&&await n.dispatch(t.data,e,t)};await this.context.execute(s,r,o)}canProcessMessage(e){return P(e)?this.options.requireChannel?!!this.registry.getChannel(e.channel):!0:!1}getChannelForMessage(e){return this.registry.getChannel(e.channel)}getOptions(){return this.options}};var T=class{constructor(e){this.registry=e.registry,this.options={rejectionCloseCode:e.options?.rejectionCloseCode??H.REJECTED}}async handleConnection(e){return this.registry.register(e)}async handleDisconnection(e,t){this.registry.get(e)&&this.registry.unregister(e)}getOptions(){return this.options}};var ee=i=>(e,t)=>{let n=-1,r=async s=>{if(s<=n)throw new Error("next() called multiple times");n=s;let o,a=i[s];if(a)o=await a(e,async()=>{await r(s+1)});else if(s===i.length&&t)o=await t();else return e;return o!==void 0&&!e.finalized&&(e.res=o,e.finalized=!0),e};return r(0)};function R(i){let{action:e,client:t,message:n,channel:r,initialState:s={}}=i,o=s;return{req:{action:e,client:t,message:n,channel:r},var:o,finalized:!1,get:a=>o[a],set:(a,c)=>{o[a]=c},reject:a=>{throw new S(a,e)}}}var A=class{constructor(){this.middlewares=[]}use(e){this.middlewares.push(e)}remove(e){let t=this.middlewares.indexOf(e);return t!==-1?(this.middlewares.splice(t,1),!0):!1}clear(){this.middlewares.length=0}getMiddlewares(){return[...this.middlewares]}getPipeline(e){let t=this.getMiddlewares(),n=e?.getMiddlewares?.();return n&&n.length>0&&(t=[...t,...n]),t}async executeConnection(e,t){let n=this.createConnectionContext(e,t);return await this.execute(n)}async executeMessage(e,t){let n=this.createMessageContext(e,t);return await this.execute(n)}async executeSubscribe(e,t,n){let r=this.createSubscribeContext(e,t);return await this.execute(r,this.middlewares,n)}async executeUnsubscribe(e,t,n){let r=this.createUnsubscribeContext(e,t);return await this.execute(r,this.middlewares,n)}async execute(e,t=this.middlewares,n){let r=e.req.action||"unknown",s=t.map((o,a)=>async(c,d)=>{try{await o(c,d)}catch(l){if(l instanceof S||l instanceof I)throw l;let m=o.name||`middleware[${a}]`;throw new I(r,m,l instanceof Error?l:new Error(String(l)))}});return await ee(s)(e,n)}createConnectionContext(e,t){return R({client:e,action:t})}createMessageContext(e,t){return R({client:e,message:t,action:"message"})}createSubscribeContext(e,t){return R({client:e,channel:t,action:"subscribe"})}createUnsubscribeContext(e,t){return R({client:e,channel:t,action:"unsubscribe"})}getCount(){return this.middlewares.length}hasMiddleware(){return this.middlewares.length>0}};var _=class{constructor(e){this.connections=new Map;this.subscriptions=new Map;this.channels=new Map;this.channelInstances=new Map;this.logger=e}register(e){return this.connections.set(e.id,e),e}unregister(e){let t=this.get(e);return t?(this.clearSubscriptions(t),this.connections.delete(e)):!1}clearSubscriptions(e){let t=this.subscriptions.get(e.id);if(t){for(let n of t)this.channels.get(n)?.delete(e.id);this.subscriptions.delete(e.id)}}get(e){return this.connections.get(e)}getAll(){return Array.from(this.connections.values())}getCount(){return this.connections.size}registerChannel(e){this.channels.has(e.name)||this.channels.set(e.name,new Set),this.channelInstances.set(e.name,e)}getChannel(e){return this.channelInstances.get(e)}removeChannel(e){let t=this.channels.get(e);if(!t)return!1;for(let n of t){let r=this.subscriptions.get(n);r&&r.delete(e)}return this.channelInstances.delete(e),this.channels.delete(e)}subscribe(e,t){if(f(t),!this.connections.has(e))return!1;this.channels.has(t)||this.channels.set(t,new Set);let n=this.channels.get(t);return n.has(e)||(n.add(e),this.subscriptions.has(e)||this.subscriptions.set(e,new Set),this.subscriptions.get(e).add(t)),!0}unsubscribe(e,t){let n=this.channels.get(t);if(!n||!n.has(e))return!1;n.delete(e);let r=this.subscriptions.get(e);return r&&(r.delete(t),r.size===0&&this.subscriptions.delete(e)),!0}getSubscribers(e){let t=this.channels.get(e);if(!t)return[];let n=[];for(let r of t){let s=this.connections.get(r);s&&n.push(s)}return n}getSubscriberCount(e){return this.channels.get(e)?.size??0}getChannels(){return Array.from(this.channels.keys())}getTotalSubscriptionCount(){let e=0;for(let t of this.channels.values())e+=t.size;return e}isSubscribed(e,t){return this.channels.get(t)?.has(e)??!1}getClientChannels(e){return this.subscriptions.get(e)??new Set}getChannelSubscribers(e){return this.channels.get(e)??new Set}clear(){this.connections.clear(),this.subscriptions.clear(),this.channels.clear(),this.channelInstances.clear()}};import{EventEmitter as pe}from"events";import{WebSocketServer as Ce}from"ws";var v=class extends pe{constructor(e){super(),this.setMaxListeners(100),this.connections=e.connections??new Map,this.config={...e,path:e.path??Z,maxPayload:e.maxPayload??D,enablePing:e.enablePing??!0,pingInterval:e.pingInterval??U,pingTimeout:e.pingTimeout??B,connections:this.connections};let t=e.ServerConstructor??Ce;this.wsServer=new t({server:this.config.server,path:this.config.path,maxPayload:this.config.maxPayload}),this.setupEventHandlers(),this.config.enablePing&&this.startPingTimer()}setAuthenticator(e){this.authenticator=e}setupEventHandlers(){this.wsServer.on("connection",(e,t)=>{this.handleConnection(e,t)}),this.wsServer.on("error",e=>{this.config.logger?.error("WebSocket Server Error:",e),this.emit("error",e)})}async handleConnection(e,t){let n;try{this.authenticator?n=await this.authenticator(t):this.config.generateId?n=await this.config.generateId(t):n=z()}catch(o){try{e.close(4001,o instanceof Error?o.message:"Unauthorized")}catch{}return}let r=Date.now(),s={socket:e,id:n,connectedAt:r,lastPingAt:r};this.connections.set(n,s),e.on("message",o=>{this.handleMessage(n,o)}),e.on("close",(o,a)=>{this.handleDisconnection(n)}),e.on("error",o=>{this.emit("error",o)}),this.config.enablePing&&this.setupPingPong(n,e),this.emit("connection",s)}handleMessage(e,t){try{let n=JSON.parse(t.toString()),r=this.connections.get(e);r&&n.type==="signal"&&n.signal==="pong"&&(r.lastPingAt=Date.now()),this.emit("message",e,n)}catch(n){this.config.logger?.error(`Failed to parse message from ${e}:`,n),this.emit("error",n)}}handleDisconnection(e){this.emit("disconnection",e),this.connections.delete(e)}setupPingPong(e,t){t.on("pong",()=>{let n=this.connections.get(e);n&&(n.lastPingAt=Date.now())})}startPingTimer(){this.pingTimer&&clearInterval(this.pingTimer),this.pingTimer=setInterval(()=>{this.checkConnections()},this.config.pingInterval)}checkConnections(){let e=Date.now(),t=Array.from(this.connections.values());for(let n of t){let r=n.socket,s=n.lastPingAt??n.connectedAt;if(e-s>this.config.pingInterval+this.config.pingTimeout){r.close(1e3,"Ping timeout");continue}r.readyState===1&&r.ping()}}};var N=class{constructor(e){this.status={started:!1,startedAt:void 0};if(this.config=e,this.registry=this.config.registry,this.context=new A,this.config.middleware)for(let t of this.config.middleware)this.context.use(t)}async start(){if(this.status.started)throw new p("Server is already started");this.transport=this.config.transport,this.connectionHandler=new T({registry:this.registry}),this.messageHandler=new M({registry:this.registry,context:this.context}),this.signalHandler=new x({registry:this.registry,context:this.context}),this.setupTransportHandlers(),this.broadcastChannel=new w(this.registry,this.config.broadcastChunkSize),this.registry.registerChannel(this.broadcastChannel),this.status.started=!0,this.status.startedAt=Date.now()}async stop(){!this.status.started||!this.transport||(this.connectionHandler=void 0,this.messageHandler=void 0,this.signalHandler=void 0,this.registry.clear(),this.broadcastChannel=void 0,this.status.started=!1,this.status.startedAt=void 0)}createBroadcast(){if(!this.status.started||!this.broadcastChannel)throw new p("Server must be started before creating channels");return this.broadcastChannel}createMulticast(e){if(f(e),!this.status.started||!this.transport)throw new p("Server must be started before creating channels");let t=this.registry.getChannel(e);if(t)return t;let n=new E({name:e,registry:this.registry,options:{chunkSize:this.config.broadcastChunkSize}});return this.registry.registerChannel(n),n}hasChannel(e){return!!this.registry.getChannel(e)}getChannels(){return this.registry.getChannels()}use(e){this.context.use(e)}authenticate(e){let t=this.transport||this.config.transport;t&&"setAuthenticator"in t?t.setAuthenticator(e):this.config.logger.warn("Current transport does not support setting an authenticator.")}getStats(){return{startedAt:this.status.startedAt,clientCount:this.registry.getCount(),channelCount:this.registry.getChannels().length,subscriptionCount:this.registry.getTotalSubscriptionCount()}}getConfig(){return this.config}getRegistry(){return this.registry}setupTransportHandlers(){let e=this.transport;e.on("connection",async t=>{try{await this.context.executeConnection(t,"connect"),await this.connectionHandler.handleConnection(t)}catch(n){this.config.logger.error("Error handling connection:",n)}}),e.on("disconnection",async t=>{try{let n=this.registry.get(t);n&&(await this.context.executeConnection(n,"disconnect"),await this.connectionHandler.handleDisconnection(t))}catch(n){this.config.logger.error("Error handling disconnection:",n)}}),e.on("message",async(t,n)=>{try{let r=this.registry.get(t);if(!r)return;n.type==="data"?await this.messageHandler.handleMessage(r,n):n.type==="signal"&&await this.signalHandler.handleSignal(r,n)}catch(r){this.config.logger.error("Error handling message:",r)}}),e.on("error",t=>{this.config.logger.error("Transport error:",t)})}};function me(i={}){let e=i.registry??new _,t=i.logger??X(),n={...Q,middleware:[],...i,registry:e,logger:t};return n.transport||(n.server||import("http").then(r=>{let s=r.createServer();s.listen(n.port,n.host),n.server=s}),n.transport=new v({server:n.server,path:n.path,maxPayload:i.maxPayload??D,enablePing:n.enablePing,pingInterval:n.pingInterval,pingTimeout:n.pingTimeout,connections:e.connections,generateId:n.generateId,logger:n.logger})),new N(n)}function te(i){let{verifyToken:e,getToken:t=s=>s.req.message?.data?.token,attachProperty:n="user",actions:r}=i;return async(s,o)=>{if(r&&!r.includes(s.req.action))return o();let a=t(s);a||s.reject("Authentication token required");try{let c=await e(a);s.req.client&&(s.req.client[n]=c),s.set(n,c),await o()}catch{s.reject("Authentication failed: Invalid token")}}}function ne(i={}){let{logger:e=console,logLevel:t="info",includeMessageData:n=!1,format:r,actions:s}=i;return async(o,a)=>{if(s&&!s.includes(o.req.action))return a();let c=Date.now();await a();let d=Date.now()-c,l={action:o.req.action,clientId:o.req.client?.id,channel:o.req.channel,message:n?o.req.message:void 0,duration:d},m=r?r(l):`[${l.action}] Client: ${l.clientId??"unknown"}${l.channel?` Channel: ${l.channel}`:""} (${d}ms)`;e[t](m)}}var C=new Map;function re(i={}){let{maxRequests:e=100,windowMs:t=6e4,getMessageId:n=a=>a.req.client?.id??"",actions:r=["message"]}=i,s=setInterval(()=>{let a=Date.now();for(let[c,d]of C)d.resetTime<a&&C.delete(c)},t*10),o=async(a,c)=>{if(!r.includes(a.req.action))return c();let d=n(a);if(!d)return c();let l=Date.now(),m=C.get(d);m&&m.resetTime<l&&C.delete(d);let b=C.get(d);b||(b={count:0,resetTime:l+t},C.set(d,b)),b.count>=e&&a.reject(`Rate limit exceeded. Max ${e} requests per ${t}ms`),b.count++,await c()};return o.cleanup=()=>{clearInterval(s),C.clear()},o}function se(i={}){let{allowedChannels:e=[],isDynamic:t,restrictUnsubscribe:n=!1}=i;return async(r,s)=>{if(r.req.action!=="subscribe"&&r.req.action!=="unsubscribe"||r.req.action==="unsubscribe"&&!n||!r.req.channel)return s();if(t)return t(r.req.channel,r.req.client)||r.reject(`Channel '${r.req.channel}' is not allowed`),s();e.includes(r.req.channel)||r.reject(`Channel '${r.req.channel}' is not allowed`),await s()}}export{y as BROADCAST_CHANNEL,w as BroadcastChannel,H as CLOSE_CODES,h as ChannelError,q as ClientError,G as ConfigError,A as ContextManager,ce as ERROR_CODES,u as MessageError,I as MiddlewareExecutionError,S as MiddlewareRejectionError,E as MulticastChannel,p as StateError,N as Synca,g as SyncaError,N as SyncaServer,$ as TransportError,F as ValidationError,v as WebSocketServerTransport,te as createAuthMiddleware,se as createChannelWhitelistMiddleware,R as createContext,ne as createLoggingMiddleware,re as createRateLimitMiddleware,me as createSyncaServer};
1
+ function V(){return`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}function z(){return`client-${Date.now()}-${Math.random().toString(36).substring(2,9)}`}var K=1,j=128,J="__";function ie(i){return typeof i=="string"&&i.length>=K&&i.length<=j}function L(i){return i.startsWith(J)}function f(i){if(!ie(i))throw new Error(`Invalid channel name: must be between ${K} and ${j} characters`);if(L(i))throw new Error(`Reserved channel name: channel names starting with '${J}' are reserved for system use`)}function P(i){return i.type==="data"}function Y(i,e,t){return{id:t||V(),type:"data",channel:i,data:e,timestamp:Date.now()}}function O(i,e,t,n){return{id:n||V(),type:"signal",channel:i,signal:e,data:t,timestamp:Date.now()}}var oe={info:"INFO",warn:"WARN",error:"ERROR",debug:"DEBUG"};function ae(){return new Date().toISOString()}function X(i="Syncar",e={}){let t={debug:!1,info:!0,warn:!0,error:!0,...e},n=(r,s)=>{let o=ae();return`[${i} ${o}] [${oe[r]}] ${s}`};return{debug:(r,...s)=>{t.debug&&console.log(n("debug",r),...s)},info:(r,...s)=>{t.info&&console.log(n("info",r),...s)},warn:(r,...s)=>{t.warn&&console.warn(n("warn",r),...s)},error:(r,...s)=>{t.error&&console.error(n("error",r),...s)}}}var y="__broadcast__",H={NORMAL:1e3,GOING_AWAY:1001,PROTOCOL_ERROR:1002,UNSUPPORTED_DATA:1003,NO_STATUS:1005,ABNORMAL:1006,INVALID_PAYLOAD:1007,POLICY_VIOLATION:1008,MESSAGE_TOO_BIG:1009,MISSING_EXTENSION:1010,INTERNAL_ERROR:1011,SERVICE_RESTART:1012,TRY_AGAIN_LATER:1013,REJECTED:4001,RATE_LIMITED:4002,CHANNEL_NOT_FOUND:4003,UNAUTHORIZED:4005},ce={REJECTED:"REJECTED",MISSING_CHANNEL:"MISSING_CHANNEL",SUBSCRIBE_REJECTED:"SUBSCRIBE_REJECTED",UNSUBSCRIBE_REJECTED:"UNSUBSCRIBE_REJECTED",RATE_LIMITED:"RATE_LIMITED",AUTH_FAILED:"AUTH_FAILED",NOT_AUTHORIZED:"NOT_AUTHORIZED",CHANNEL_NOT_ALLOWED:"CHANNEL_NOT_ALLOWED",INVALID_MESSAGE:"INVALID_MESSAGE",SERVER_ERROR:"SERVER_ERROR"},Z="/syncar",D=1048576,U=3e4,B=5e3,le=3e3,de="0.0.0.0",ge="/syncar",he=!0,Q={port:le,host:de,path:ge,enablePing:he,pingInterval:U,pingTimeout:B,broadcastChunkSize:500};var k=class{constructor(e,t,n=500){this.name=e;this.registry=t;this.chunkSize=n}publish(e,t){let n=this.getTargetClients(t);n.length>this.chunkSize?this.publishInChunks(e,n,t):this.publishToClients(e,n,t)}async dispatch(e,t,n){}publishToClients(e,t,n){let r=Y(this.name,e);for(let s of t){if(n?.to&&!n.to.includes(s)||n?.exclude&&n.exclude.includes(s))continue;let o=this.registry.connections.get(s);if(o)try{o.socket.send(JSON.stringify(r))}catch(a){this.registry.logger?.error(`[${this.name}] Failed to send to ${s}:`,a)}}}publishInChunks(e,t,n){let r=0,s=()=>{let o=t.slice(r,r+this.chunkSize);o.length!==0&&(this.publishToClients(e,o,n),r+=this.chunkSize,r<t.length&&setImmediate(s))};s()}},w=class extends k{constructor(e,t=500){super(y,e,t)}getTargetClients(e){return Array.from(this.registry.connections.keys())}get subscriberCount(){return this.registry.connections.size}isEmpty(){return this.registry.connections.size===0}getMiddlewares(){return[]}},E=class extends k{constructor(t){f(t.name);super(t.name,t.registry,t.options?.chunkSize);this.middlewares=[];this.messageHandlers=new Set}getTargetClients(t){return Array.from(this.registry.getChannelSubscribers(this.name))}use(t){this.middlewares.push(t)}getMiddlewares(){return[...this.middlewares]}get subscriberCount(){return this.registry.getChannelSubscribers(this.name).size}onMessage(t){return this.messageHandlers.add(t),()=>this.messageHandlers.delete(t)}subscribe(t){return this.registry.subscribe(t,this.name)}unsubscribe(t){return this.registry.unsubscribe(t,this.name)}async dispatch(t,n,r){if(this.messageHandlers.size>0)for(let s of this.messageHandlers)try{await s(t,n,r)}catch(o){this.registry.logger?.error(`[${this.name}] Error in message handler:`,o)}else this.publish(t,{exclude:[n.id]})}hasSubscriber(t){return this.registry.getChannelSubscribers(this.name).has(t)}getSubscribers(){return new Set(this.registry.getChannelSubscribers(this.name))}isEmpty(){return this.registry.getChannelSubscribers(this.name).size===0}};var g=class i extends Error{constructor(e,t="SYNNEL_ERROR",n){super(e),this.name="SyncarError",this.code=t,this.context=n,Error.captureStackTrace&&Error.captureStackTrace(this,i)}toJSON(){return{name:this.name,message:this.message,code:this.code,context:this.context,stack:this.stack}}toString(){return`[${this.name}:${this.code}] ${this.message}`}},G=class extends g{constructor(e,t){super(e,"CONFIG_ERROR",t),this.name="ConfigError"}},$=class extends g{constructor(e,t){super(e,"TRANSPORT_ERROR",t),this.name="TransportError"}},h=class extends g{constructor(e,t){super(e,"CHANNEL_ERROR",t),this.name="ChannelError"}},q=class extends g{constructor(e,t){super(e,"CLIENT_ERROR",t),this.name="ClientError"}},u=class extends g{constructor(e,t){super(e,"MESSAGE_ERROR",t),this.name="MessageError"}},F=class extends g{constructor(e,t){super(e,"VALIDATION_ERROR",t),this.name="ValidationError"}},p=class extends g{constructor(e,t){super(e,"STATE_ERROR",t),this.name="StateError"}},S=class i extends Error{constructor(t,n,r,s){super(`Action '${n}' rejected: ${t}`);this.name="MiddlewareRejectionError";this.reason=t,this.action=n,this.name="MiddlewareRejectionError",this.code=r,this.context=s,Error.captureStackTrace&&Error.captureStackTrace(this,i)}toJSON(){return{name:this.name,reason:this.reason,action:this.action,code:this.code,context:this.context,message:this.message,stack:this.stack}}toString(){return`[${this.name}:${this.action}] ${this.reason}`}},I=class i extends Error{constructor(e,t,n){super(`Middleware execution error in ${t} during ${e}: ${n.message}`),this.name="MiddlewareExecutionError",this.action=e,this.middleware=t,this.cause=n,Error.captureStackTrace&&Error.captureStackTrace(this,i)}getCause(){return this.cause}toString(){return`[${this.name}] ${this.middleware} failed during ${this.action}: ${this.cause.message}`}};var x=class{constructor(e){this.registry=e.registry,this.context=e.context,this.options={requireChannel:e.options?.requireChannel??!1,allowReservedChannels:e.options?.allowReservedChannels??!1,sendAcknowledgments:e.options?.sendAcknowledgments??!0,autoRespondToPing:e.options?.autoRespondToPing??!0}}async handleSignal(e,t){let n;t.signal==="subscribe"?n=this.context.createSubscribeContext(e,t.channel):t.signal==="unsubscribe"?n=this.context.createUnsubscribeContext(e,t.channel):n=this.context.createMessageContext(e,t);let r=async()=>{switch(t.signal){case"subscribe":await this.handleSubscribe(e,t);break;case"unsubscribe":await this.handleUnsubscribe(e,t);break;case"ping":await this.handlePing(e,t);break;case"pong":await this.handlePong(e,t);break;default:throw new u(`Unknown signal type: ${t.signal}`)}},s;t.channel&&t.channel!==y&&(s=this.registry.getChannel(t.channel));let o=this.context.getPipeline(s);await this.context.execute(n,o,r)}async handleSubscribe(e,t){let{channel:n}=t;if(!this.options.allowReservedChannels&&L(n))throw new h(`Cannot subscribe to reserved channel: ${n}`);if(n===y)throw new h("Cannot subscribe to broadcast channel");if(!this.registry.subscribe(e.id,n))throw new h(`Failed to subscribe client ${e.id} to channel ${n}`);if(this.options.sendAcknowledgments){let s=O(n,"subscribed",void 0,t.id);e.socket.send(JSON.stringify(s),()=>{})}}async handleUnsubscribe(e,t){let{channel:n}=t;if(!this.registry.isSubscribed(e.id,n))throw new h(`Client not subscribed to channel: ${n}`);if(this.registry.unsubscribe(e.id,n),this.options.sendAcknowledgments){let r=O(n,"unsubscribed",void 0,t.id);e.socket.send(JSON.stringify(r),()=>{})}}async handlePing(e,t){if(e.lastPingAt=Date.now(),this.options.autoRespondToPing){let n=O(t.channel,"pong",void 0,t.id);e.socket.send(JSON.stringify(n),()=>{})}}async handlePong(e,t){e.lastPingAt=Date.now()}getOptions(){return this.options}};var M=class{constructor(e){this.registry=e.registry,this.context=e.context,this.options={requireChannel:e.options?.requireChannel??!0}}async handleMessage(e,t){if(!P(t))throw new u("Invalid message type: expected DATA message");let n=this.registry.getChannel(t.channel);if(this.options.requireChannel&&!n)throw new h(`Channel not found: ${t.channel}`);let r=this.context.getPipeline(n),s=this.context.createMessageContext(e,t),o=async()=>{n&&await n.dispatch(t.data,e,t)};await this.context.execute(s,r,o)}canProcessMessage(e){return P(e)?this.options.requireChannel?!!this.registry.getChannel(e.channel):!0:!1}getChannelForMessage(e){return this.registry.getChannel(e.channel)}getOptions(){return this.options}};var T=class{constructor(e){this.registry=e.registry,this.options={rejectionCloseCode:e.options?.rejectionCloseCode??H.REJECTED}}async handleConnection(e){return this.registry.register(e)}async handleDisconnection(e,t){this.registry.get(e)&&this.registry.unregister(e)}getOptions(){return this.options}};var ee=i=>(e,t)=>{let n=-1,r=async s=>{if(s<=n)throw new Error("next() called multiple times");n=s;let o,a=i[s];if(a)o=await a(e,async()=>{await r(s+1)});else if(s===i.length&&t)o=await t();else return e;return o!==void 0&&!e.finalized&&(e.res=o,e.finalized=!0),e};return r(0)};function R(i){let{action:e,client:t,message:n,channel:r,initialState:s={}}=i,o=s;return{req:{action:e,client:t,message:n,channel:r},var:o,finalized:!1,get:a=>o[a],set:(a,c)=>{o[a]=c},reject:a=>{throw new S(a,e)}}}var A=class{constructor(){this.middlewares=[]}use(e){this.middlewares.push(e)}remove(e){let t=this.middlewares.indexOf(e);return t!==-1?(this.middlewares.splice(t,1),!0):!1}clear(){this.middlewares.length=0}getMiddlewares(){return[...this.middlewares]}getPipeline(e){let t=this.getMiddlewares(),n=e?.getMiddlewares?.();return n&&n.length>0&&(t=[...t,...n]),t}async executeConnection(e,t){let n=this.createConnectionContext(e,t);return await this.execute(n)}async executeMessage(e,t){let n=this.createMessageContext(e,t);return await this.execute(n)}async executeSubscribe(e,t,n){let r=this.createSubscribeContext(e,t);return await this.execute(r,this.middlewares,n)}async executeUnsubscribe(e,t,n){let r=this.createUnsubscribeContext(e,t);return await this.execute(r,this.middlewares,n)}async execute(e,t=this.middlewares,n){let r=e.req.action||"unknown",s=t.map((o,a)=>async(c,d)=>{try{await o(c,d)}catch(l){if(l instanceof S||l instanceof I)throw l;let m=o.name||`middleware[${a}]`;throw new I(r,m,l instanceof Error?l:new Error(String(l)))}});return await ee(s)(e,n)}createConnectionContext(e,t){return R({client:e,action:t})}createMessageContext(e,t){return R({client:e,message:t,action:"message"})}createSubscribeContext(e,t){return R({client:e,channel:t,action:"subscribe"})}createUnsubscribeContext(e,t){return R({client:e,channel:t,action:"unsubscribe"})}getCount(){return this.middlewares.length}hasMiddleware(){return this.middlewares.length>0}};var _=class{constructor(e){this.connections=new Map;this.subscriptions=new Map;this.channels=new Map;this.channelInstances=new Map;this.logger=e}register(e){return this.connections.set(e.id,e),e}unregister(e){let t=this.get(e);return t?(this.clearSubscriptions(t),this.connections.delete(e)):!1}clearSubscriptions(e){let t=this.subscriptions.get(e.id);if(t){for(let n of t)this.channels.get(n)?.delete(e.id);this.subscriptions.delete(e.id)}}get(e){return this.connections.get(e)}getAll(){return Array.from(this.connections.values())}getCount(){return this.connections.size}registerChannel(e){this.channels.has(e.name)||this.channels.set(e.name,new Set),this.channelInstances.set(e.name,e)}getChannel(e){return this.channelInstances.get(e)}removeChannel(e){let t=this.channels.get(e);if(!t)return!1;for(let n of t){let r=this.subscriptions.get(n);r&&r.delete(e)}return this.channelInstances.delete(e),this.channels.delete(e)}subscribe(e,t){if(f(t),!this.connections.has(e))return!1;this.channels.has(t)||this.channels.set(t,new Set);let n=this.channels.get(t);return n.has(e)||(n.add(e),this.subscriptions.has(e)||this.subscriptions.set(e,new Set),this.subscriptions.get(e).add(t)),!0}unsubscribe(e,t){let n=this.channels.get(t);if(!n||!n.has(e))return!1;n.delete(e);let r=this.subscriptions.get(e);return r&&(r.delete(t),r.size===0&&this.subscriptions.delete(e)),!0}getSubscribers(e){let t=this.channels.get(e);if(!t)return[];let n=[];for(let r of t){let s=this.connections.get(r);s&&n.push(s)}return n}getSubscriberCount(e){return this.channels.get(e)?.size??0}getChannels(){return Array.from(this.channels.keys())}getTotalSubscriptionCount(){let e=0;for(let t of this.channels.values())e+=t.size;return e}isSubscribed(e,t){return this.channels.get(t)?.has(e)??!1}getClientChannels(e){return this.subscriptions.get(e)??new Set}getChannelSubscribers(e){return this.channels.get(e)??new Set}clear(){this.connections.clear(),this.subscriptions.clear(),this.channels.clear(),this.channelInstances.clear()}};import{EventEmitter as pe}from"events";import{WebSocketServer as Ce}from"ws";var v=class extends pe{constructor(e){super(),this.setMaxListeners(100),this.connections=e.connections??new Map,this.config={...e,path:e.path??Z,maxPayload:e.maxPayload??D,enablePing:e.enablePing??!0,pingInterval:e.pingInterval??U,pingTimeout:e.pingTimeout??B,connections:this.connections};let t=e.ServerConstructor??Ce;this.wsServer=new t({server:this.config.server,path:this.config.path,maxPayload:this.config.maxPayload}),this.setupEventHandlers(),this.config.enablePing&&this.startPingTimer()}setAuthenticator(e){this.authenticator=e}setupEventHandlers(){this.wsServer.on("connection",(e,t)=>{this.handleConnection(e,t)}),this.wsServer.on("error",e=>{this.config.logger?.error("WebSocket Server Error:",e),this.emit("error",e)})}async handleConnection(e,t){let n;try{this.authenticator?n=await this.authenticator(t):this.config.generateId?n=await this.config.generateId(t):n=z()}catch(o){try{e.close(4001,o instanceof Error?o.message:"Unauthorized")}catch{}return}let r=Date.now(),s={socket:e,id:n,connectedAt:r,lastPingAt:r};this.connections.set(n,s),e.on("message",o=>{this.handleMessage(n,o)}),e.on("close",(o,a)=>{this.handleDisconnection(n)}),e.on("error",o=>{this.emit("error",o)}),this.config.enablePing&&this.setupPingPong(n,e),this.emit("connection",s)}handleMessage(e,t){try{let n=JSON.parse(t.toString()),r=this.connections.get(e);r&&n.type==="signal"&&n.signal==="pong"&&(r.lastPingAt=Date.now()),this.emit("message",e,n)}catch(n){this.config.logger?.error(`Failed to parse message from ${e}:`,n),this.emit("error",n)}}handleDisconnection(e){this.emit("disconnection",e),this.connections.delete(e)}setupPingPong(e,t){t.on("pong",()=>{let n=this.connections.get(e);n&&(n.lastPingAt=Date.now())})}startPingTimer(){this.pingTimer&&clearInterval(this.pingTimer),this.pingTimer=setInterval(()=>{this.checkConnections()},this.config.pingInterval)}checkConnections(){let e=Date.now(),t=Array.from(this.connections.values());for(let n of t){let r=n.socket,s=n.lastPingAt??n.connectedAt;if(e-s>this.config.pingInterval+this.config.pingTimeout){r.close(1e3,"Ping timeout");continue}r.readyState===1&&r.ping()}}};var N=class{constructor(e){this.status={started:!1,startedAt:void 0};if(this.config=e,this.registry=this.config.registry,this.context=new A,this.config.middleware)for(let t of this.config.middleware)this.context.use(t)}async start(){if(this.status.started)throw new p("Server is already started");this.transport=this.config.transport,this.connectionHandler=new T({registry:this.registry}),this.messageHandler=new M({registry:this.registry,context:this.context}),this.signalHandler=new x({registry:this.registry,context:this.context}),this.setupTransportHandlers(),this.broadcastChannel=new w(this.registry,this.config.broadcastChunkSize),this.registry.registerChannel(this.broadcastChannel),this.status.started=!0,this.status.startedAt=Date.now()}async stop(){!this.status.started||!this.transport||(this.connectionHandler=void 0,this.messageHandler=void 0,this.signalHandler=void 0,this.registry.clear(),this.broadcastChannel=void 0,this.status.started=!1,this.status.startedAt=void 0)}createBroadcast(){if(!this.status.started||!this.broadcastChannel)throw new p("Server must be started before creating channels");return this.broadcastChannel}createMulticast(e){if(f(e),!this.status.started||!this.transport)throw new p("Server must be started before creating channels");let t=this.registry.getChannel(e);if(t)return t;let n=new E({name:e,registry:this.registry,options:{chunkSize:this.config.broadcastChunkSize}});return this.registry.registerChannel(n),n}hasChannel(e){return!!this.registry.getChannel(e)}getChannels(){return this.registry.getChannels()}use(e){this.context.use(e)}authenticate(e){let t=this.transport||this.config.transport;t&&"setAuthenticator"in t?t.setAuthenticator(e):this.config.logger.warn("Current transport does not support setting an authenticator.")}getStats(){return{startedAt:this.status.startedAt,clientCount:this.registry.getCount(),channelCount:this.registry.getChannels().length,subscriptionCount:this.registry.getTotalSubscriptionCount()}}getConfig(){return this.config}getRegistry(){return this.registry}setupTransportHandlers(){let e=this.transport;e.on("connection",async t=>{try{await this.context.executeConnection(t,"connect"),await this.connectionHandler.handleConnection(t)}catch(n){this.config.logger.error("Error handling connection:",n)}}),e.on("disconnection",async t=>{try{let n=this.registry.get(t);n&&(await this.context.executeConnection(n,"disconnect"),await this.connectionHandler.handleDisconnection(t))}catch(n){this.config.logger.error("Error handling disconnection:",n)}}),e.on("message",async(t,n)=>{try{let r=this.registry.get(t);if(!r)return;n.type==="data"?await this.messageHandler.handleMessage(r,n):n.type==="signal"&&await this.signalHandler.handleSignal(r,n)}catch(r){this.config.logger.error("Error handling message:",r)}}),e.on("error",t=>{this.config.logger.error("Transport error:",t)})}};function me(i={}){let e=i.registry??new _,t=i.logger??X(),n={...Q,middleware:[],...i,registry:e,logger:t};return n.transport||(n.server||import("http").then(r=>{let s=r.createServer();s.listen(n.port,n.host),n.server=s}),n.transport=new v({server:n.server,path:n.path,maxPayload:i.maxPayload??D,enablePing:n.enablePing,pingInterval:n.pingInterval,pingTimeout:n.pingTimeout,connections:e.connections,generateId:n.generateId,logger:n.logger})),new N(n)}function te(i){let{verifyToken:e,getToken:t=s=>s.req.message?.data?.token,attachProperty:n="user",actions:r}=i;return async(s,o)=>{if(r&&!r.includes(s.req.action))return o();let a=t(s);a||s.reject("Authentication token required");try{let c=await e(a);s.req.client&&(s.req.client[n]=c),s.set(n,c),await o()}catch{s.reject("Authentication failed: Invalid token")}}}function ne(i={}){let{logger:e=console,logLevel:t="info",includeMessageData:n=!1,format:r,actions:s}=i;return async(o,a)=>{if(s&&!s.includes(o.req.action))return a();let c=Date.now();await a();let d=Date.now()-c,l={action:o.req.action,clientId:o.req.client?.id,channel:o.req.channel,message:n?o.req.message:void 0,duration:d},m=r?r(l):`[${l.action}] Client: ${l.clientId??"unknown"}${l.channel?` Channel: ${l.channel}`:""} (${d}ms)`;e[t](m)}}var C=new Map;function re(i={}){let{maxRequests:e=100,windowMs:t=6e4,getMessageId:n=a=>a.req.client?.id??"",actions:r=["message"]}=i,s=setInterval(()=>{let a=Date.now();for(let[c,d]of C)d.resetTime<a&&C.delete(c)},t*10),o=async(a,c)=>{if(!r.includes(a.req.action))return c();let d=n(a);if(!d)return c();let l=Date.now(),m=C.get(d);m&&m.resetTime<l&&C.delete(d);let b=C.get(d);b||(b={count:0,resetTime:l+t},C.set(d,b)),b.count>=e&&a.reject(`Rate limit exceeded. Max ${e} requests per ${t}ms`),b.count++,await c()};return o.cleanup=()=>{clearInterval(s),C.clear()},o}function se(i={}){let{allowedChannels:e=[],isDynamic:t,restrictUnsubscribe:n=!1}=i;return async(r,s)=>{if(r.req.action!=="subscribe"&&r.req.action!=="unsubscribe"||r.req.action==="unsubscribe"&&!n||!r.req.channel)return s();if(t)return t(r.req.channel,r.req.client)||r.reject(`Channel '${r.req.channel}' is not allowed`),s();e.includes(r.req.channel)||r.reject(`Channel '${r.req.channel}' is not allowed`),await s()}}export{y as BROADCAST_CHANNEL,w as BroadcastChannel,H as CLOSE_CODES,h as ChannelError,q as ClientError,G as ConfigError,A as ContextManager,ce as ERROR_CODES,u as MessageError,I as MiddlewareExecutionError,S as MiddlewareRejectionError,E as MulticastChannel,p as StateError,N as Syncar,g as SyncarError,N as SyncarServer,$ as TransportError,F as ValidationError,v as WebSocketServerTransport,te as createAuthMiddleware,se as createChannelWhitelistMiddleware,R as createContext,ne as createLoggingMiddleware,re as createRateLimitMiddleware,me as createSyncarServer};
2
2
  //# sourceMappingURL=index.js.map