@gravito/ripple 1.0.0-beta.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,7 +21,7 @@ bun add @gravito/ripple
21
21
  ### Server Setup
22
22
 
23
23
  ```typescript
24
- import { PlanetCore } from 'gravito-core'
24
+ import { PlanetCore } from '@gravito/core'
25
25
  import { OrbitRipple, RippleServer } from '@gravito/ripple'
26
26
 
27
27
  const core = new PlanetCore()
package/README.zh-TW.md CHANGED
@@ -11,7 +11,7 @@ bun add @gravito/ripple
11
11
  ## 快速開始
12
12
 
13
13
  ```typescript
14
- import { PlanetCore } from 'gravito-core'
14
+ import { PlanetCore } from '@gravito/core'
15
15
  import { OrbitRipple } from '@gravito/ripple'
16
16
 
17
17
  const core = new PlanetCore()
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @fileoverview OrbitRipple - Gravito module wrapper for Ripple WebSocket
3
+ *
4
+ * Integrates RippleServer with Gravito's PlanetCore.
5
+ *
6
+ * @module @gravito/ripple
7
+ */
8
+ import { RippleServer } from './RippleServer';
9
+ import type { RippleConfig } from './types';
10
+ /**
11
+ * PlanetCore interface for type safety without importing
12
+ */
13
+ interface PlanetCore {
14
+ logger: {
15
+ info: (msg: string) => void;
16
+ };
17
+ adapter: {
18
+ use: (path: string, handler: (ctx: any, next: () => Promise<void>) => Promise<any>) => void;
19
+ };
20
+ hooks: {
21
+ addAction: (hook: string, callback: (args: unknown) => Promise<void>) => void;
22
+ };
23
+ }
24
+ /**
25
+ * OrbitRipple - Gravito module for real-time WebSocket communication
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * import { OrbitRipple } from '@gravito/ripple'
30
+ *
31
+ * const core = new PlanetCore()
32
+ *
33
+ * core.install(new OrbitRipple({
34
+ * path: '/ws',
35
+ * authorizer: async (channel, userId, socketId) => {
36
+ * // Return true for authorized, false for denied
37
+ * // For presence channels, return { id: userId, info: { name: '...' } }
38
+ * return true
39
+ * }
40
+ * }))
41
+ *
42
+ * // The WebSocket is automatically integrated with Bun.serve
43
+ * core.boot()
44
+ * ```
45
+ */
46
+ export declare class OrbitRipple {
47
+ private server;
48
+ private config;
49
+ constructor(config?: RippleConfig);
50
+ /**
51
+ * Install the module into PlanetCore
52
+ */
53
+ install(core: PlanetCore): void;
54
+ /**
55
+ * Get the underlying RippleServer instance
56
+ */
57
+ getServer(): RippleServer;
58
+ /**
59
+ * Get WebSocket handler for Bun.serve integration
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const ripple = new OrbitRipple()
64
+ *
65
+ * Bun.serve({
66
+ * fetch: (req, server) => {
67
+ * // Let Ripple handle WebSocket upgrades
68
+ * if (ripple.getServer().upgrade(req, server)) return
69
+ *
70
+ * // Regular HTTP handling
71
+ * return core.adapter.fetch(req, server)
72
+ * },
73
+ * websocket: ripple.getHandler()
74
+ * })
75
+ * ```
76
+ */
77
+ getHandler(): import("./types").WebSocketHandlerConfig;
78
+ }
79
+ export {};
80
+ //# sourceMappingURL=OrbitRipple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrbitRipple.d.ts","sourceRoot":"","sources":["../src/OrbitRipple.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C;;GAEG;AACH,UAAU,UAAU;IAClB,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAA;IACvC,OAAO,EAAE;QACP,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAA;KAC5F,CAAA;IACD,KAAK,EAAE;QACL,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;KAC9E,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAc;gBAEhB,MAAM,GAAE,YAAiB;IAKrC;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAuB/B;;OAEG;IACH,SAAS,IAAI,YAAY;IAIzB;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU;CAGX"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @fileoverview Ripple WebSocket Server
3
+ *
4
+ * Core WebSocket server implementation using Bun's native WebSocket API.
5
+ *
6
+ * @module @gravito/ripple
7
+ */
8
+ import type { Server } from 'bun';
9
+ import type { ClientData, RippleConfig, RippleWebSocket, WebSocketHandlerConfig } from './types';
10
+ /**
11
+ * Ripple WebSocket Server
12
+ *
13
+ * Provides channel-based real-time communication using Bun's native WebSocket.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const ripple = new RippleServer({
18
+ * path: '/ws',
19
+ * authorizer: async (channel, userId) => {
20
+ * // Custom authorization logic
21
+ * return true
22
+ * }
23
+ * })
24
+ *
25
+ * Bun.serve({
26
+ * fetch: (req, server) => {
27
+ * if (ripple.upgrade(req, server)) return
28
+ * return new Response('Not found', { status: 404 })
29
+ * },
30
+ * websocket: ripple.getHandler()
31
+ * })
32
+ * ```
33
+ */
34
+ export declare class RippleServer {
35
+ private channels;
36
+ private driver;
37
+ private authorizer?;
38
+ private pingInterval?;
39
+ private eventListeners;
40
+ readonly config: Required<Pick<RippleConfig, 'path' | 'authEndpoint' | 'pingInterval'>> & RippleConfig;
41
+ constructor(config?: RippleConfig);
42
+ /**
43
+ * Register an event listener for client messages.
44
+ *
45
+ * @param event - The event name to listen for.
46
+ * @param handler - The callback function.
47
+ */
48
+ on(event: string, handler: (socket: RippleWebSocket, data: any) => void): void;
49
+ /**
50
+ * Fluent API for broadcasting to a channel.
51
+ *
52
+ * @param channel - The channel name.
53
+ */
54
+ to(channel: string): {
55
+ emit: (event: string, data: unknown) => void;
56
+ };
57
+ /**
58
+ * Attempt to upgrade an HTTP request to WebSocket.
59
+ *
60
+ * @param req - The HTTP request.
61
+ * @param server - The Bun server instance.
62
+ * @returns True if the request was upgraded, false otherwise.
63
+ */
64
+ upgrade(req: Request, server: Server<ClientData>): boolean;
65
+ /**
66
+ * Get WebSocket handler configuration for Bun.serve.
67
+ *
68
+ * @returns An object containing the WebSocket event handlers.
69
+ */
70
+ getHandler(): WebSocketHandlerConfig;
71
+ private handleOpen;
72
+ private handleMessage;
73
+ private handleClose;
74
+ private handleDrain;
75
+ private handleSubscribe;
76
+ private handleUnsubscribe;
77
+ private handleWhisper;
78
+ /**
79
+ * Broadcast an event to a channel.
80
+ *
81
+ * @param channel - The channel name.
82
+ * @param event - The event name.
83
+ * @param data - The event data.
84
+ */
85
+ broadcast(channel: string, event: string, data: unknown): void;
86
+ /**
87
+ * Broadcast to specific client IDs.
88
+ *
89
+ * @param clientIds - An array of client IDs.
90
+ * @param event - The event name.
91
+ * @param data - The event data.
92
+ */
93
+ broadcastToClients(clientIds: string[], event: string, data: unknown): void;
94
+ private broadcastToChannel;
95
+ private send;
96
+ /**
97
+ * Get server statistics.
98
+ *
99
+ * @returns An object containing connection and channel statistics.
100
+ */
101
+ getStats(): {
102
+ totalClients: number;
103
+ totalChannels: number;
104
+ channels: {
105
+ name: string;
106
+ subscribers: number;
107
+ }[];
108
+ };
109
+ /**
110
+ * Initialize the server.
111
+ *
112
+ * Initializes the driver and starts the ping interval.
113
+ *
114
+ * @returns A promise that resolves when initialization is complete.
115
+ */
116
+ init(): Promise<void>;
117
+ /**
118
+ * Shutdown the server.
119
+ *
120
+ * Clears the ping interval and shuts down the driver.
121
+ *
122
+ * @returns A promise that resolves when shutdown is complete.
123
+ */
124
+ shutdown(): Promise<void>;
125
+ }
126
+ //# sourceMappingURL=RippleServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RippleServer.d.ts","sourceRoot":"","sources":["../src/RippleServer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAGjC,OAAO,KAAK,EAEV,UAAU,EAEV,YAAY,EAEZ,eAAe,EAEf,sBAAsB,EACvB,MAAM,SAAS,CAAA;AAEhB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,UAAU,CAAC,CAAmB;IACtC,OAAO,CAAC,YAAY,CAAC,CAAgC;IACrD,OAAO,CAAC,cAAc,CAA2E;IAEjG,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,GAAG,cAAc,CAAC,CAAC,GACrF,YAAY,CAAA;gBAEF,MAAM,GAAE,YAAiB;IAarC;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAO9E;;;;OAIG;IACH,EAAE,CAAC,OAAO,EAAE,MAAM;sBAEA,MAAM,QAAQ,OAAO;;IAQvC;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,OAAO;IAiB1D;;;;OAIG;IACH,UAAU,IAAI,sBAAsB;IAapC,OAAO,CAAC,UAAU;YAUJ,aAAa;IA6B3B,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,WAAW;YASL,eAAe;IA2D7B,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,aAAa;IA0BrB;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAI9D;;;;;;OAMG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAc3E,OAAO,CAAC,kBAAkB;IAmC1B,OAAO,CAAC,IAAI;IAQZ;;;;OAIG;IACH,QAAQ;;;;;;;;IAIR;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAMhC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @fileoverview Channel implementations for @gravito/ripple
3
+ * @module @gravito/ripple/channels
4
+ */
5
+ import type { Channel, ChannelType } from '../types';
6
+ export declare const CHANNEL_PREFIXES: {
7
+ readonly private: "private-";
8
+ readonly presence: "presence-";
9
+ };
10
+ /**
11
+ * Abstract base class for channels
12
+ */
13
+ declare abstract class BaseChannel implements Channel {
14
+ readonly name: string;
15
+ abstract readonly type: ChannelType;
16
+ constructor(name: string);
17
+ abstract get fullName(): string;
18
+ /**
19
+ * Parse a full channel name to extract type and base name
20
+ */
21
+ static parse(fullName: string): {
22
+ type: ChannelType;
23
+ name: string;
24
+ };
25
+ /**
26
+ * Check if a channel name requires authentication
27
+ */
28
+ static requiresAuth(fullName: string): boolean;
29
+ }
30
+ /**
31
+ * Public channel - no authentication required
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const channel = new PublicChannel('news')
36
+ * // fullName: 'news'
37
+ * ```
38
+ */
39
+ export declare class PublicChannel extends BaseChannel {
40
+ readonly type: "public";
41
+ get fullName(): string;
42
+ }
43
+ /**
44
+ * Private channel - requires authentication
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const channel = new PrivateChannel('orders.123')
49
+ * // fullName: 'private-orders.123'
50
+ * ```
51
+ */
52
+ export declare class PrivateChannel extends BaseChannel {
53
+ readonly type: "private";
54
+ get fullName(): string;
55
+ }
56
+ /**
57
+ * Presence channel - requires authentication, tracks online users
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const channel = new PresenceChannel('chat.lobby')
62
+ * // fullName: 'presence-chat.lobby'
63
+ * ```
64
+ */
65
+ export declare class PresenceChannel extends BaseChannel {
66
+ readonly type: "presence";
67
+ get fullName(): string;
68
+ }
69
+ /**
70
+ * Create a channel from a full name
71
+ */
72
+ export declare function createChannel(fullName: string): Channel;
73
+ /**
74
+ * Check if channel requires authentication
75
+ */
76
+ export declare const requiresAuth: typeof BaseChannel.requiresAuth;
77
+ export {};
78
+ //# sourceMappingURL=Channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../../src/channels/Channel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAMpD,eAAO,MAAM,gBAAgB;;;CAGnB,CAAA;AAMV;;GAEG;AACH,uBAAe,WAAY,YAAW,OAAO;aAGf,IAAI,EAAE,MAAM;IAFxC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;gBAEP,IAAI,EAAE,MAAM;IAExC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAA;IAE/B;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAgBnE;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAM/C;AAMD;;;;;;;;GAQG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAS;IAEjC,IAAI,QAAQ,IAAI,MAAM,CAErB;CACF;AAMD;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAC7C,QAAQ,CAAC,IAAI,EAAG,SAAS,CAAS;IAElC,IAAI,QAAQ,IAAI,MAAM,CAErB;CACF;AAMD;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAS;IAEnC,IAAI,QAAQ,IAAI,MAAM,CAErB;CACF;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWvD;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,iCAA2B,CAAA"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @fileoverview Channel Manager for @gravito/ripple
3
+ *
4
+ * Manages channel subscriptions and member tracking.
5
+ *
6
+ * @module @gravito/ripple/channels
7
+ */
8
+ import type { PresenceUserInfo, RippleWebSocket } from '../types';
9
+ /**
10
+ * Manages all channel subscriptions and presence tracking
11
+ */
12
+ export declare class ChannelManager {
13
+ /** Map of channel name -> Set of client IDs */
14
+ private subscriptions;
15
+ /** Map of client ID -> WebSocket */
16
+ private clients;
17
+ /** Map of presence channel -> Map of user ID -> user info */
18
+ private presenceMembers;
19
+ /**
20
+ * Register a new client connection
21
+ */
22
+ addClient(ws: RippleWebSocket): void;
23
+ /**
24
+ * Remove a client and all its subscriptions
25
+ */
26
+ removeClient(clientId: string): string[];
27
+ /**
28
+ * Get a client by ID
29
+ */
30
+ getClient(clientId: string): RippleWebSocket | undefined;
31
+ /**
32
+ * Get all connected clients
33
+ */
34
+ getAllClients(): RippleWebSocket[];
35
+ /**
36
+ * Subscribe a client to a channel
37
+ */
38
+ subscribe(clientId: string, channel: string, userInfo?: PresenceUserInfo): boolean;
39
+ /**
40
+ * Unsubscribe a client from a channel
41
+ */
42
+ unsubscribe(clientId: string, channel: string): boolean;
43
+ /**
44
+ * Get all subscribers of a channel
45
+ */
46
+ getSubscribers(channel: string): RippleWebSocket[];
47
+ /**
48
+ * Check if a client is subscribed to a channel
49
+ */
50
+ isSubscribed(clientId: string, channel: string): boolean;
51
+ /**
52
+ * Add a member to a presence channel
53
+ */
54
+ private addPresenceMember;
55
+ /**
56
+ * Remove a member from a presence channel
57
+ */
58
+ private removePresenceMember;
59
+ /**
60
+ * Get all members of a presence channel
61
+ */
62
+ getPresenceMembers(channel: string): PresenceUserInfo[];
63
+ /**
64
+ * Get member count for a channel
65
+ */
66
+ getMemberCount(channel: string): number;
67
+ /**
68
+ * Get channel statistics
69
+ */
70
+ getStats(): {
71
+ totalClients: number;
72
+ totalChannels: number;
73
+ channels: {
74
+ name: string;
75
+ subscribers: number;
76
+ }[];
77
+ };
78
+ }
79
+ //# sourceMappingURL=ChannelManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChannelManager.d.ts","sourceRoot":"","sources":["../../src/channels/ChannelManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAGjE;;GAEG;AACH,qBAAa,cAAc;IACzB,+CAA+C;IAC/C,OAAO,CAAC,aAAa,CAAiC;IAEtD,oCAAoC;IACpC,OAAO,CAAC,OAAO,CAAqC;IAEpD,6DAA6D;IAC7D,OAAO,CAAC,eAAe,CAA4D;IAMnF;;OAEG;IACH,SAAS,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI;IAIpC;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAkBxC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIxD;;OAEG;IACH,aAAa,IAAI,eAAe,EAAE;IAQlC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,gBAAgB,GAAG,OAAO;IAyBlF;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IA0BvD;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,EAAE;IAWlD;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IASxD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAOzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAKvD;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAQvC;;OAEG;IACH,QAAQ,IAAI;QACV,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAClD;CAUF"}
@@ -0,0 +1,3 @@
1
+ export * from './Channel';
2
+ export * from './ChannelManager';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/channels/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,kBAAkB,CAAA"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @fileoverview Local (in-memory) driver for @gravito/ripple
3
+ *
4
+ * Suitable for single-instance deployments. For horizontal scaling,
5
+ * use the Redis driver.
6
+ *
7
+ * @module @gravito/ripple/drivers
8
+ */
9
+ import type { RippleDriver } from '../types';
10
+ /**
11
+ * In-memory driver for single-instance deployments
12
+ *
13
+ * This driver keeps all state in memory and is suitable for:
14
+ * - Development
15
+ * - Single-server deployments
16
+ * - Serverless functions (with caveats)
17
+ *
18
+ * For multi-server deployments, use RedisDriver instead.
19
+ */
20
+ export declare class LocalDriver implements RippleDriver {
21
+ readonly name = "local";
22
+ /** Event callbacks per channel */
23
+ private listeners;
24
+ publish(channel: string, event: string, data: unknown): Promise<void>;
25
+ subscribe(channel: string, callback: (event: string, data: unknown) => void): Promise<void>;
26
+ unsubscribe(channel: string): Promise<void>;
27
+ init(): Promise<void>;
28
+ shutdown(): Promise<void>;
29
+ }
30
+ //# sourceMappingURL=LocalDriver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalDriver.d.ts","sourceRoot":"","sources":["../../src/drivers/LocalDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C;;;;;;;;;GASG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C,QAAQ,CAAC,IAAI,WAAU;IAEvB,kCAAkC;IAClC,OAAO,CAAC,SAAS,CAAiE;IAE5E,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IASrE,SAAS,CACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,GAC/C,OAAO,CAAC,IAAI,CAAC;IAOV,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
@@ -0,0 +1,2 @@
1
+ export * from './LocalDriver';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/drivers/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @fileoverview Broadcast Event base class
3
+ *
4
+ * Events that can be broadcast to WebSocket channels.
5
+ *
6
+ * @module @gravito/ripple/events
7
+ */
8
+ import type { Channel } from '../types';
9
+ /**
10
+ * Abstract base class for broadcast events
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * class OrderShipped extends BroadcastEvent {
15
+ * constructor(public order: Order) {
16
+ * super()
17
+ * }
18
+ *
19
+ * broadcastOn() {
20
+ * return new PrivateChannel(`orders.${this.order.userId}`)
21
+ * }
22
+ *
23
+ * broadcastAs() {
24
+ * return 'OrderShipped'
25
+ * }
26
+ * }
27
+ *
28
+ * // Broadcast
29
+ * broadcast(new OrderShipped(order))
30
+ * ```
31
+ */
32
+ export declare abstract class BroadcastEvent {
33
+ /**
34
+ * The channels to broadcast this event on
35
+ */
36
+ abstract broadcastOn(): Channel | Channel[];
37
+ /**
38
+ * The event name to use when broadcasting
39
+ * Defaults to the class name
40
+ */
41
+ broadcastAs(): string;
42
+ /**
43
+ * Socket IDs to exclude from the broadcast
44
+ */
45
+ broadcastExcept(): string[];
46
+ /**
47
+ * Get the event data payload
48
+ * Override to customize the broadcast payload
49
+ */
50
+ broadcastWith(): Record<string, unknown>;
51
+ }
52
+ //# sourceMappingURL=BroadcastEvent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BroadcastEvent.d.ts","sourceRoot":"","sources":["../../src/events/BroadcastEvent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,8BAAsB,cAAc;IAClC;;OAEG;IACH,QAAQ,CAAC,WAAW,IAAI,OAAO,GAAG,OAAO,EAAE;IAE3C;;;OAGG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,eAAe,IAAI,MAAM,EAAE;IAI3B;;;OAGG;IACH,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQzC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview Broadcaster for sending events to channels
3
+ *
4
+ * @module @gravito/ripple/events
5
+ */
6
+ import type { RippleServer } from '../RippleServer';
7
+ import type { BroadcastEvent } from './BroadcastEvent';
8
+ /**
9
+ * Set the global Ripple server instance
10
+ */
11
+ export declare function setRippleServer(server: RippleServer): void;
12
+ /**
13
+ * Get the global Ripple server instance
14
+ */
15
+ export declare function getRippleServer(): RippleServer | null;
16
+ /**
17
+ * Broadcast an event to its channels
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * class OrderShipped extends BroadcastEvent {
22
+ * constructor(public order: Order) { super() }
23
+ * broadcastOn() { return new PrivateChannel(`orders.${this.order.userId}`) }
24
+ * }
25
+ *
26
+ * broadcast(new OrderShipped(order))
27
+ * ```
28
+ */
29
+ export declare function broadcast(event: BroadcastEvent): void;
30
+ /**
31
+ * Fluent Broadcaster API for more control
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * Broadcaster.to('orders.123')
36
+ * .emit('OrderUpdated', { status: 'shipped' })
37
+ *
38
+ * Broadcaster.toPrivate('orders.123')
39
+ * .except(socketId)
40
+ * .emit('OrderUpdated', { status: 'shipped' })
41
+ * ```
42
+ */
43
+ export declare class Broadcaster {
44
+ private _channel;
45
+ private _except;
46
+ private constructor();
47
+ /**
48
+ * Target a public channel
49
+ */
50
+ static to(channel: string): Broadcaster;
51
+ /**
52
+ * Target a private channel
53
+ */
54
+ static toPrivate(channel: string): Broadcaster;
55
+ /**
56
+ * Target a presence channel
57
+ */
58
+ static toPresence(channel: string): Broadcaster;
59
+ /**
60
+ * Exclude specific socket IDs from broadcast
61
+ */
62
+ except(socketIds: string | string[]): this;
63
+ /**
64
+ * Emit an event to the channel
65
+ */
66
+ emit(event: string, data: unknown): void;
67
+ }
68
+ //# sourceMappingURL=Broadcaster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Broadcaster.d.ts","sourceRoot":"","sources":["../../src/events/Broadcaster.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAOtD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAE1D;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAiBrD;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,OAAO,CAAe;IAE9B,OAAO;IAIP;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;IAIvC;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;IAI9C;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;IAI/C;;OAEG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAM1C;;OAEG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;CAQzC"}
@@ -0,0 +1,3 @@
1
+ export * from './BroadcastEvent';
2
+ export * from './Broadcaster';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,eAAe,CAAA"}
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  "use strict";
2
- module.exports = require("./index.mjs");
2
+ module.exports = require("./index.js");
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @fileoverview @gravito/ripple - Bun-native WebSocket broadcasting
3
+ *
4
+ * Channel-based real-time communication for Gravito applications.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { OrbitRipple, broadcast, PrivateChannel, BroadcastEvent } from '@gravito/ripple'
9
+ *
10
+ * // Install the module
11
+ * core.install(new OrbitRipple({
12
+ * path: '/ws',
13
+ * authorizer: async (channel, userId) => userId !== undefined
14
+ * }))
15
+ *
16
+ * // Define a broadcast event
17
+ * class OrderShipped extends BroadcastEvent {
18
+ * constructor(public order: Order) { super() }
19
+ * broadcastOn() { return new PrivateChannel(`orders.${this.order.userId}`) }
20
+ * }
21
+ *
22
+ * // Broadcast from anywhere
23
+ * broadcast(new OrderShipped(order))
24
+ *
25
+ * // Or use the fluent API
26
+ * import { Broadcaster } from '@gravito/ripple'
27
+ * Broadcaster.toPrivate('orders.123').emit('OrderUpdated', { status: 'shipped' })
28
+ * ```
29
+ *
30
+ * @module @gravito/ripple
31
+ */
32
+ export { CHANNEL_PREFIXES, ChannelManager, createChannel, PresenceChannel, PrivateChannel, PublicChannel, requiresAuth, } from './channels';
33
+ export { LocalDriver } from './drivers';
34
+ export { BroadcastEvent, Broadcaster, broadcast, getRippleServer, setRippleServer } from './events';
35
+ export { OrbitRipple } from './OrbitRipple';
36
+ export { RippleServer } from './RippleServer';
37
+ export type { BroadcastEventInterface, Channel, ChannelAuthorizer, ChannelType, ClientData, ClientMessage, PresenceUserInfo, RippleBunServer, RippleConfig, RippleDriver, RippleWebSocket, ServerMessage, WebSocketHandlerConfig, } from './types';
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAEvC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAEnG,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAG7C,YAAY,EACV,uBAAuB,EACvB,OAAO,EACP,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,aAAa,EACb,sBAAsB,GACvB,MAAM,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -267,6 +267,7 @@ class RippleServer {
267
267
  driver;
268
268
  authorizer;
269
269
  pingInterval;
270
+ eventListeners = new Map;
270
271
  config;
271
272
  constructor(config = {}) {
272
273
  this.config = {
@@ -279,6 +280,17 @@ class RippleServer {
279
280
  this.driver = config.driver === "redis" ? new LocalDriver : new LocalDriver;
280
281
  this.authorizer = config.authorizer;
281
282
  }
283
+ on(event, handler) {
284
+ if (!this.eventListeners.has(event)) {
285
+ this.eventListeners.set(event, []);
286
+ }
287
+ this.eventListeners.get(event).push(handler);
288
+ }
289
+ to(channel) {
290
+ return {
291
+ emit: (event, data) => this.broadcast(channel, event, data)
292
+ };
293
+ }
282
294
  upgrade(req, server) {
283
295
  const url = new URL(req.url);
284
296
  if (url.pathname !== this.config.path) {
@@ -399,6 +411,12 @@ class RippleServer {
399
411
  this.send(ws, { type: "unsubscribed", channel });
400
412
  }
401
413
  handleWhisper(ws, channel, event, data) {
414
+ const listeners = this.eventListeners.get(event);
415
+ if (listeners && listeners.length > 0) {
416
+ listeners.forEach((handler) => {
417
+ handler(ws, data);
418
+ });
419
+ }
402
420
  if (!this.channels.isSubscribed(ws.data.id, channel)) {
403
421
  this.send(ws, {
404
422
  type: "error",
@@ -521,4 +539,4 @@ export {
521
539
  BroadcastEvent
522
540
  };
523
541
 
524
- //# debugId=528A850700D2523E64756E2164756E21
542
+ //# debugId=FDAC75CC384E2A3664756E2164756E21
package/dist/index.js.map CHANGED
@@ -7,10 +7,10 @@
7
7
  "/**\n * @fileoverview Local (in-memory) driver for @gravito/ripple\n *\n * Suitable for single-instance deployments. For horizontal scaling,\n * use the Redis driver.\n *\n * @module @gravito/ripple/drivers\n */\n\nimport type { RippleDriver } from '../types'\n\n/**\n * In-memory driver for single-instance deployments\n *\n * This driver keeps all state in memory and is suitable for:\n * - Development\n * - Single-server deployments\n * - Serverless functions (with caveats)\n *\n * For multi-server deployments, use RedisDriver instead.\n */\nexport class LocalDriver implements RippleDriver {\n readonly name = 'local'\n\n /** Event callbacks per channel */\n private listeners = new Map<string, Set<(event: string, data: unknown) => void>>()\n\n async publish(channel: string, event: string, data: unknown): Promise<void> {\n const callbacks = this.listeners.get(channel)\n if (callbacks) {\n for (const callback of callbacks) {\n callback(event, data)\n }\n }\n }\n\n async subscribe(\n channel: string,\n callback: (event: string, data: unknown) => void\n ): Promise<void> {\n if (!this.listeners.has(channel)) {\n this.listeners.set(channel, new Set())\n }\n this.listeners.get(channel)?.add(callback)\n }\n\n async unsubscribe(channel: string): Promise<void> {\n this.listeners.delete(channel)\n }\n\n async init(): Promise<void> {\n // No-op for local driver\n }\n\n async shutdown(): Promise<void> {\n this.listeners.clear()\n }\n}\n",
8
8
  "/**\n * @fileoverview Broadcast Event base class\n *\n * Events that can be broadcast to WebSocket channels.\n *\n * @module @gravito/ripple/events\n */\n\nimport type { Channel } from '../types'\n\n/**\n * Abstract base class for broadcast events\n *\n * @example\n * ```typescript\n * class OrderShipped extends BroadcastEvent {\n * constructor(public order: Order) {\n * super()\n * }\n *\n * broadcastOn() {\n * return new PrivateChannel(`orders.${this.order.userId}`)\n * }\n *\n * broadcastAs() {\n * return 'OrderShipped'\n * }\n * }\n *\n * // Broadcast\n * broadcast(new OrderShipped(order))\n * ```\n */\nexport abstract class BroadcastEvent {\n /**\n * The channels to broadcast this event on\n */\n abstract broadcastOn(): Channel | Channel[]\n\n /**\n * The event name to use when broadcasting\n * Defaults to the class name\n */\n broadcastAs(): string {\n return this.constructor.name\n }\n\n /**\n * Socket IDs to exclude from the broadcast\n */\n broadcastExcept(): string[] {\n return []\n }\n\n /**\n * Get the event data payload\n * Override to customize the broadcast payload\n */\n broadcastWith(): Record<string, unknown> {\n // By default, return all public properties\n const data: Record<string, unknown> = {}\n for (const key of Object.keys(this)) {\n data[key] = (this as Record<string, unknown>)[key]\n }\n return data\n }\n}\n",
9
9
  "/**\n * @fileoverview Broadcaster for sending events to channels\n *\n * @module @gravito/ripple/events\n */\n\nimport type { RippleServer } from '../RippleServer'\nimport type { BroadcastEvent } from './BroadcastEvent'\n\n/**\n * Global Ripple server instance holder\n */\nlet globalRippleServer: RippleServer | null = null\n\n/**\n * Set the global Ripple server instance\n */\nexport function setRippleServer(server: RippleServer): void {\n globalRippleServer = server\n}\n\n/**\n * Get the global Ripple server instance\n */\nexport function getRippleServer(): RippleServer | null {\n return globalRippleServer\n}\n\n/**\n * Broadcast an event to its channels\n *\n * @example\n * ```typescript\n * class OrderShipped extends BroadcastEvent {\n * constructor(public order: Order) { super() }\n * broadcastOn() { return new PrivateChannel(`orders.${this.order.userId}`) }\n * }\n *\n * broadcast(new OrderShipped(order))\n * ```\n */\nexport function broadcast(event: BroadcastEvent): void {\n if (!globalRippleServer) {\n console.warn('[Ripple] No server configured. Event not broadcast.')\n return\n }\n\n const channels = event.broadcastOn()\n const eventName = event.broadcastAs()\n const data = event.broadcastWith()\n const _except = event.broadcastExcept()\n\n const channelList = Array.isArray(channels) ? channels : [channels]\n\n for (const channel of channelList) {\n // For each subscriber in the channel, excluding specified sockets\n globalRippleServer.broadcast(channel.fullName, eventName, data)\n }\n}\n\n/**\n * Fluent Broadcaster API for more control\n *\n * @example\n * ```typescript\n * Broadcaster.to('orders.123')\n * .emit('OrderUpdated', { status: 'shipped' })\n *\n * Broadcaster.toPrivate('orders.123')\n * .except(socketId)\n * .emit('OrderUpdated', { status: 'shipped' })\n * ```\n */\nexport class Broadcaster {\n private _channel: string\n private _except: string[] = []\n\n private constructor(channel: string) {\n this._channel = channel\n }\n\n /**\n * Target a public channel\n */\n static to(channel: string): Broadcaster {\n return new Broadcaster(channel)\n }\n\n /**\n * Target a private channel\n */\n static toPrivate(channel: string): Broadcaster {\n return new Broadcaster(`private-${channel}`)\n }\n\n /**\n * Target a presence channel\n */\n static toPresence(channel: string): Broadcaster {\n return new Broadcaster(`presence-${channel}`)\n }\n\n /**\n * Exclude specific socket IDs from broadcast\n */\n except(socketIds: string | string[]): this {\n const ids = Array.isArray(socketIds) ? socketIds : [socketIds]\n this._except.push(...ids)\n return this\n }\n\n /**\n * Emit an event to the channel\n */\n emit(event: string, data: unknown): void {\n if (!globalRippleServer) {\n console.warn('[Ripple] No server configured. Event not broadcast.')\n return\n }\n\n globalRippleServer.broadcast(this._channel, event, data)\n }\n}\n",
10
- "/**\n * @fileoverview Ripple WebSocket Server\n *\n * Core WebSocket server implementation using Bun's native WebSocket API.\n *\n * @module @gravito/ripple\n */\n\nimport type { Server } from 'bun'\nimport { ChannelManager, requiresAuth } from './channels'\nimport { LocalDriver } from './drivers'\nimport type {\n ChannelAuthorizer,\n ClientData,\n ClientMessage,\n RippleConfig,\n RippleDriver,\n RippleWebSocket,\n ServerMessage,\n WebSocketHandlerConfig,\n} from './types'\n\n/**\n * Ripple WebSocket Server\n *\n * Provides channel-based real-time communication using Bun's native WebSocket.\n *\n * @example\n * ```typescript\n * const ripple = new RippleServer({\n * path: '/ws',\n * authorizer: async (channel, userId) => {\n * // Custom authorization logic\n * return true\n * }\n * })\n *\n * Bun.serve({\n * fetch: (req, server) => {\n * if (ripple.upgrade(req, server)) return\n * return new Response('Not found', { status: 404 })\n * },\n * websocket: ripple.getHandler()\n * })\n * ```\n */\nexport class RippleServer {\n private channels: ChannelManager\n private driver: RippleDriver\n private authorizer?: ChannelAuthorizer\n private pingInterval?: Timer\n\n readonly config: Required<Pick<RippleConfig, 'path' | 'authEndpoint' | 'pingInterval'>> &\n RippleConfig\n\n constructor(config: RippleConfig = {}) {\n this.config = {\n path: '/ws',\n authEndpoint: '/broadcasting/auth',\n pingInterval: 30000,\n ...config,\n }\n\n this.channels = new ChannelManager()\n this.driver = config.driver === 'redis' ? new LocalDriver() : new LocalDriver() // TODO: RedisDriver\n this.authorizer = config.authorizer\n }\n\n // ─────────────────────────────────────────────────────────────\n // Bun.serve Integration\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Attempt to upgrade an HTTP request to WebSocket.\n *\n * @param req - The HTTP request.\n * @param server - The Bun server instance.\n * @returns True if the request was upgraded, false otherwise.\n */\n upgrade(req: Request, server: Server<ClientData>): boolean {\n const url = new URL(req.url)\n\n if (url.pathname !== this.config.path) {\n return false\n }\n\n const success = server.upgrade(req, {\n data: {\n id: crypto.randomUUID(),\n channels: new Set<string>(),\n } satisfies ClientData,\n })\n\n return success\n }\n\n /**\n * Get WebSocket handler configuration for Bun.serve.\n *\n * @returns An object containing the WebSocket event handlers.\n */\n getHandler(): WebSocketHandlerConfig {\n return {\n open: (ws) => this.handleOpen(ws),\n message: (ws, message) => this.handleMessage(ws, message),\n close: (ws, code, reason) => this.handleClose(ws, code, reason),\n drain: (ws) => this.handleDrain(ws),\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // WebSocket Event Handlers\n // ─────────────────────────────────────────────────────────────\n\n private handleOpen(ws: RippleWebSocket): void {\n this.channels.addClient(ws)\n\n // Send connection confirmation with socket ID\n this.send(ws, {\n type: 'connected',\n socketId: ws.data.id,\n })\n }\n\n private async handleMessage(ws: RippleWebSocket, message: string | Buffer): Promise<void> {\n try {\n const data: ClientMessage = JSON.parse(message.toString())\n\n switch (data.type) {\n case 'subscribe':\n await this.handleSubscribe(ws, data.channel, data.auth)\n break\n\n case 'unsubscribe':\n this.handleUnsubscribe(ws, data.channel)\n break\n\n case 'whisper':\n this.handleWhisper(ws, data.channel, data.event, data.data)\n break\n\n case 'ping':\n this.send(ws, { type: 'pong' })\n break\n }\n } catch (error) {\n this.send(ws, {\n type: 'error',\n message: error instanceof Error ? error.message : 'Invalid message',\n })\n }\n }\n\n private handleClose(ws: RippleWebSocket, _code: number, _reason: string): void {\n const leftChannels = this.channels.removeClient(ws.data.id)\n\n // Notify presence channels about user leaving\n for (const channel of leftChannels) {\n if (channel.startsWith('presence-') && ws.data.userId) {\n this.broadcastToChannel(channel, 'presence', {\n event: 'leave',\n data: {\n id: ws.data.userId,\n info: ws.data.userInfo,\n },\n })\n }\n }\n }\n\n private handleDrain(_ws: RippleWebSocket): void {\n // Called when backpressure is relieved\n // Currently no-op, but useful for flow control\n }\n\n // ─────────────────────────────────────────────────────────────\n // Subscription Handlers\n // ─────────────────────────────────────────────────────────────\n\n private async handleSubscribe(\n ws: RippleWebSocket,\n channel: string,\n _auth?: { socketId: string; signature: string }\n ): Promise<void> {\n // Check if channel requires authentication\n if (requiresAuth(channel)) {\n if (!this.authorizer) {\n this.send(ws, {\n type: 'error',\n message: 'No authorizer configured for private channels',\n channel,\n })\n return\n }\n\n const result = await this.authorizer(channel, ws.data.userId, ws.data.id)\n\n if (result === false) {\n this.send(ws, {\n type: 'error',\n message: 'Unauthorized',\n channel,\n })\n return\n }\n\n // For presence channels, result contains user info\n if (typeof result === 'object' && 'id' in result) {\n this.channels.subscribe(ws.data.id, channel, result)\n\n // Notify other members about join\n this.broadcastToChannel(\n channel,\n 'presence',\n {\n event: 'join',\n data: result,\n },\n ws.data.id\n )\n\n // Send current members to new subscriber\n this.send(ws, {\n type: 'presence',\n channel,\n event: 'members',\n data: this.channels.getPresenceMembers(channel),\n })\n } else {\n this.channels.subscribe(ws.data.id, channel)\n }\n } else {\n this.channels.subscribe(ws.data.id, channel)\n }\n\n this.send(ws, { type: 'subscribed', channel })\n }\n\n private handleUnsubscribe(ws: RippleWebSocket, channel: string): void {\n // Notify presence channel before leaving\n if (channel.startsWith('presence-') && ws.data.userId) {\n this.broadcastToChannel(\n channel,\n 'presence',\n {\n event: 'leave',\n data: {\n id: ws.data.userId,\n info: ws.data.userInfo,\n },\n },\n ws.data.id\n )\n }\n\n this.channels.unsubscribe(ws.data.id, channel)\n this.send(ws, { type: 'unsubscribed', channel })\n }\n\n private handleWhisper(ws: RippleWebSocket, channel: string, event: string, data: unknown): void {\n // Whispers are client-to-client messages, excluding sender\n if (!this.channels.isSubscribed(ws.data.id, channel)) {\n this.send(ws, {\n type: 'error',\n message: 'Not subscribed to channel',\n channel,\n })\n return\n }\n\n this.broadcastToChannel(channel, event, data, ws.data.id)\n }\n\n // ─────────────────────────────────────────────────────────────\n // Broadcasting\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Broadcast an event to a channel.\n *\n * @param channel - The channel name.\n * @param event - The event name.\n * @param data - The event data.\n */\n broadcast(channel: string, event: string, data: unknown): void {\n this.broadcastToChannel(channel, event, data)\n }\n\n /**\n * Broadcast to specific client IDs.\n *\n * @param clientIds - An array of client IDs.\n * @param event - The event name.\n * @param data - The event data.\n */\n broadcastToClients(clientIds: string[], event: string, data: unknown): void {\n for (const clientId of clientIds) {\n const ws = this.channels.getClient(clientId)\n if (ws) {\n this.send(ws, {\n type: 'event',\n channel: '',\n event,\n data,\n })\n }\n }\n }\n\n private broadcastToChannel(\n channel: string,\n event: string,\n data: unknown,\n excludeClientId?: string\n ): void {\n const subscribers = this.channels.getSubscribers(channel)\n\n for (const ws of subscribers) {\n if (excludeClientId && ws.data.id === excludeClientId) {\n continue\n }\n\n if (event === 'presence') {\n this.send(ws, {\n type: 'presence',\n channel,\n event: (data as { event: 'join' | 'leave' | 'members' }).event,\n data: (data as { data: unknown }).data,\n })\n } else {\n this.send(ws, {\n type: 'event',\n channel,\n event,\n data,\n })\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // Utilities\n // ─────────────────────────────────────────────────────────────\n\n private send(ws: RippleWebSocket, message: ServerMessage): void {\n try {\n ws.send(JSON.stringify(message))\n } catch {\n // Connection might be closed\n }\n }\n\n /**\n * Get server statistics.\n *\n * @returns An object containing connection and channel statistics.\n */\n getStats() {\n return this.channels.getStats()\n }\n\n /**\n * Initialize the server.\n *\n * Initializes the driver and starts the ping interval.\n *\n * @returns A promise that resolves when initialization is complete.\n */\n async init(): Promise<void> {\n await this.driver.init?.()\n\n // Start ping interval\n if (this.config.pingInterval > 0) {\n this.pingInterval = setInterval(() => {\n for (const ws of this.channels.getAllClients()) {\n this.send(ws, { type: 'pong' })\n }\n }, this.config.pingInterval)\n }\n }\n\n /**\n * Shutdown the server.\n *\n * Clears the ping interval and shuts down the driver.\n *\n * @returns A promise that resolves when shutdown is complete.\n */\n async shutdown(): Promise<void> {\n if (this.pingInterval) {\n clearInterval(this.pingInterval)\n }\n await this.driver.shutdown?.()\n }\n}\n",
11
- "/**\n * @fileoverview OrbitRipple - Gravito module wrapper for Ripple WebSocket\n *\n * Integrates RippleServer with Gravito's PlanetCore.\n *\n * @module @gravito/ripple\n */\n\nimport { setRippleServer } from './events/Broadcaster'\nimport { RippleServer } from './RippleServer'\nimport type { RippleConfig } from './types'\n\n/**\n * PlanetCore interface for type safety without importing\n */\ninterface PlanetCore {\n logger: { info: (msg: string) => void }\n adapter: {\n use: (path: string, handler: (ctx: any, next: () => Promise<void>) => Promise<void>) => void\n }\n hooks: {\n addAction: (hook: string, callback: (args: unknown) => Promise<void>) => void\n }\n}\n\n/**\n * OrbitRipple - Gravito module for real-time WebSocket communication\n *\n * @example\n * ```typescript\n * import { OrbitRipple } from '@gravito/ripple'\n *\n * const core = new PlanetCore()\n *\n * core.install(new OrbitRipple({\n * path: '/ws',\n * authorizer: async (channel, userId, socketId) => {\n * // Return true for authorized, false for denied\n * // For presence channels, return { id: userId, info: { name: '...' } }\n * return true\n * }\n * }))\n *\n * // The WebSocket is automatically integrated with Bun.serve\n * core.boot()\n * ```\n */\nexport class OrbitRipple {\n private server: RippleServer\n private config: RippleConfig\n\n constructor(config: RippleConfig = {}) {\n this.config = config\n this.server = new RippleServer(config)\n }\n\n /**\n * Install the module into PlanetCore\n */\n install(core: PlanetCore): void {\n core.logger.info('🌊 Orbit Ripple installed')\n\n // Store reference globally for broadcast() function\n setRippleServer(this.server)\n\n // Expose Ripple server via context variable\n core.adapter.use('*', async (ctx, next) => {\n ctx.set('ripple' as any, this.server)\n await next()\n })\n\n // Initialize server immediately\n this.server.init().then(() => {\n core.logger.info(`🌊 Ripple WebSocket ready at ${this.config.path || '/ws'}`)\n })\n\n // Register shutdown hook\n core.hooks.addAction('shutdown', async () => {\n await this.server.shutdown()\n })\n }\n\n /**\n * Get the underlying RippleServer instance\n */\n getServer(): RippleServer {\n return this.server\n }\n\n /**\n * Get WebSocket handler for Bun.serve integration\n *\n * @example\n * ```typescript\n * const ripple = new OrbitRipple()\n *\n * Bun.serve({\n * fetch: (req, server) => {\n * // Let Ripple handle WebSocket upgrades\n * if (ripple.getServer().upgrade(req, server)) return\n *\n * // Regular HTTP handling\n * return core.adapter.fetch(req, server)\n * },\n * websocket: ripple.getHandler()\n * })\n * ```\n */\n getHandler() {\n return this.server.getHandler()\n }\n}\n"
10
+ "/**\n * @fileoverview Ripple WebSocket Server\n *\n * Core WebSocket server implementation using Bun's native WebSocket API.\n *\n * @module @gravito/ripple\n */\n\nimport type { Server } from 'bun'\nimport { ChannelManager, requiresAuth } from './channels'\nimport { LocalDriver } from './drivers'\nimport type {\n ChannelAuthorizer,\n ClientData,\n ClientMessage,\n RippleConfig,\n RippleDriver,\n RippleWebSocket,\n ServerMessage,\n WebSocketHandlerConfig,\n} from './types'\n\n/**\n * Ripple WebSocket Server\n *\n * Provides channel-based real-time communication using Bun's native WebSocket.\n *\n * @example\n * ```typescript\n * const ripple = new RippleServer({\n * path: '/ws',\n * authorizer: async (channel, userId) => {\n * // Custom authorization logic\n * return true\n * }\n * })\n *\n * Bun.serve({\n * fetch: (req, server) => {\n * if (ripple.upgrade(req, server)) return\n * return new Response('Not found', { status: 404 })\n * },\n * websocket: ripple.getHandler()\n * })\n * ```\n */\nexport class RippleServer {\n private channels: ChannelManager\n private driver: RippleDriver\n private authorizer?: ChannelAuthorizer\n private pingInterval?: ReturnType<typeof setInterval>\n private eventListeners: Map<string, ((socket: RippleWebSocket, data: any) => void)[]> = new Map()\n\n readonly config: Required<Pick<RippleConfig, 'path' | 'authEndpoint' | 'pingInterval'>> &\n RippleConfig\n\n constructor(config: RippleConfig = {}) {\n this.config = {\n path: '/ws',\n authEndpoint: '/broadcasting/auth',\n pingInterval: 30000,\n ...config,\n }\n\n this.channels = new ChannelManager()\n this.driver = config.driver === 'redis' ? new LocalDriver() : new LocalDriver() // TODO: RedisDriver\n this.authorizer = config.authorizer\n }\n\n /**\n * Register an event listener for client messages.\n *\n * @param event - The event name to listen for.\n * @param handler - The callback function.\n */\n on(event: string, handler: (socket: RippleWebSocket, data: any) => void): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, [])\n }\n this.eventListeners.get(event)!.push(handler)\n }\n\n /**\n * Fluent API for broadcasting to a channel.\n *\n * @param channel - The channel name.\n */\n to(channel: string) {\n return {\n emit: (event: string, data: unknown) => this.broadcast(channel, event, data),\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // Bun.serve Integration\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Attempt to upgrade an HTTP request to WebSocket.\n *\n * @param req - The HTTP request.\n * @param server - The Bun server instance.\n * @returns True if the request was upgraded, false otherwise.\n */\n upgrade(req: Request, server: Server<ClientData>): boolean {\n const url = new URL(req.url)\n\n if (url.pathname !== this.config.path) {\n return false\n }\n\n const success = server.upgrade(req, {\n data: {\n id: crypto.randomUUID(),\n channels: new Set<string>(),\n } satisfies ClientData,\n })\n\n return success\n }\n\n /**\n * Get WebSocket handler configuration for Bun.serve.\n *\n * @returns An object containing the WebSocket event handlers.\n */\n getHandler(): WebSocketHandlerConfig {\n return {\n open: (ws) => this.handleOpen(ws),\n message: (ws, message) => this.handleMessage(ws, message),\n close: (ws, code, reason) => this.handleClose(ws, code, reason),\n drain: (ws) => this.handleDrain(ws),\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // WebSocket Event Handlers\n // ─────────────────────────────────────────────────────────────\n\n private handleOpen(ws: RippleWebSocket): void {\n this.channels.addClient(ws)\n\n // Send connection confirmation with socket ID\n this.send(ws, {\n type: 'connected',\n socketId: ws.data.id,\n })\n }\n\n private async handleMessage(ws: RippleWebSocket, message: string | Buffer): Promise<void> {\n try {\n const data: ClientMessage = JSON.parse(message.toString())\n\n switch (data.type) {\n case 'subscribe':\n await this.handleSubscribe(ws, data.channel, data.auth)\n break\n\n case 'unsubscribe':\n this.handleUnsubscribe(ws, data.channel)\n break\n\n case 'whisper':\n this.handleWhisper(ws, data.channel, data.event, data.data)\n break\n\n case 'ping':\n this.send(ws, { type: 'pong' })\n break\n }\n } catch (error) {\n this.send(ws, {\n type: 'error',\n message: error instanceof Error ? error.message : 'Invalid message',\n })\n }\n }\n\n private handleClose(ws: RippleWebSocket, _code: number, _reason: string): void {\n const leftChannels = this.channels.removeClient(ws.data.id)\n\n // Notify presence channels about user leaving\n for (const channel of leftChannels) {\n if (channel.startsWith('presence-') && ws.data.userId) {\n this.broadcastToChannel(channel, 'presence', {\n event: 'leave',\n data: {\n id: ws.data.userId,\n info: ws.data.userInfo,\n },\n })\n }\n }\n }\n\n private handleDrain(_ws: RippleWebSocket): void {\n // Called when backpressure is relieved\n // Currently no-op, but useful for flow control\n }\n\n // ─────────────────────────────────────────────────────────────\n // Subscription Handlers\n // ─────────────────────────────────────────────────────────────\n\n private async handleSubscribe(\n ws: RippleWebSocket,\n channel: string,\n _auth?: { socketId: string; signature: string }\n ): Promise<void> {\n // Check if channel requires authentication\n if (requiresAuth(channel)) {\n if (!this.authorizer) {\n this.send(ws, {\n type: 'error',\n message: 'No authorizer configured for private channels',\n channel,\n })\n return\n }\n\n const result = await this.authorizer(channel, ws.data.userId, ws.data.id)\n\n if (result === false) {\n this.send(ws, {\n type: 'error',\n message: 'Unauthorized',\n channel,\n })\n return\n }\n\n // For presence channels, result contains user info\n if (typeof result === 'object' && 'id' in result) {\n this.channels.subscribe(ws.data.id, channel, result)\n\n // Notify other members about join\n this.broadcastToChannel(\n channel,\n 'presence',\n {\n event: 'join',\n data: result,\n },\n ws.data.id\n )\n\n // Send current members to new subscriber\n this.send(ws, {\n type: 'presence',\n channel,\n event: 'members',\n data: this.channels.getPresenceMembers(channel),\n })\n } else {\n this.channels.subscribe(ws.data.id, channel)\n }\n } else {\n this.channels.subscribe(ws.data.id, channel)\n }\n\n this.send(ws, { type: 'subscribed', channel })\n }\n\n private handleUnsubscribe(ws: RippleWebSocket, channel: string): void {\n // Notify presence channel before leaving\n if (channel.startsWith('presence-') && ws.data.userId) {\n this.broadcastToChannel(\n channel,\n 'presence',\n {\n event: 'leave',\n data: {\n id: ws.data.userId,\n info: ws.data.userInfo,\n },\n },\n ws.data.id\n )\n }\n\n this.channels.unsubscribe(ws.data.id, channel)\n this.send(ws, { type: 'unsubscribed', channel })\n }\n\n private handleWhisper(ws: RippleWebSocket, channel: string, event: string, data: unknown): void {\n // Trigger server-side listeners\n const listeners = this.eventListeners.get(event)\n if (listeners && listeners.length > 0) {\n listeners.forEach((handler) => {\n handler(ws, data)\n })\n }\n\n // Whispers are client-to-client messages, excluding sender\n if (!this.channels.isSubscribed(ws.data.id, channel)) {\n this.send(ws, {\n type: 'error',\n message: 'Not subscribed to channel',\n channel,\n })\n return\n }\n\n this.broadcastToChannel(channel, event, data, ws.data.id)\n }\n\n // ─────────────────────────────────────────────────────────────\n // Broadcasting\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Broadcast an event to a channel.\n *\n * @param channel - The channel name.\n * @param event - The event name.\n * @param data - The event data.\n */\n broadcast(channel: string, event: string, data: unknown): void {\n this.broadcastToChannel(channel, event, data)\n }\n\n /**\n * Broadcast to specific client IDs.\n *\n * @param clientIds - An array of client IDs.\n * @param event - The event name.\n * @param data - The event data.\n */\n broadcastToClients(clientIds: string[], event: string, data: unknown): void {\n for (const clientId of clientIds) {\n const ws = this.channels.getClient(clientId)\n if (ws) {\n this.send(ws, {\n type: 'event',\n channel: '',\n event,\n data,\n })\n }\n }\n }\n\n private broadcastToChannel(\n channel: string,\n event: string,\n data: unknown,\n excludeClientId?: string\n ): void {\n const subscribers = this.channels.getSubscribers(channel)\n\n for (const ws of subscribers) {\n if (excludeClientId && ws.data.id === excludeClientId) {\n continue\n }\n\n if (event === 'presence') {\n this.send(ws, {\n type: 'presence',\n channel,\n event: (data as { event: 'join' | 'leave' | 'members' }).event,\n data: (data as { data: unknown }).data,\n })\n } else {\n this.send(ws, {\n type: 'event',\n channel,\n event,\n data,\n })\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // Utilities\n // ─────────────────────────────────────────────────────────────\n\n private send(ws: RippleWebSocket, message: ServerMessage): void {\n try {\n ws.send(JSON.stringify(message))\n } catch {\n // Connection might be closed\n }\n }\n\n /**\n * Get server statistics.\n *\n * @returns An object containing connection and channel statistics.\n */\n getStats() {\n return this.channels.getStats()\n }\n\n /**\n * Initialize the server.\n *\n * Initializes the driver and starts the ping interval.\n *\n * @returns A promise that resolves when initialization is complete.\n */\n async init(): Promise<void> {\n await this.driver.init?.()\n\n // Start ping interval\n if (this.config.pingInterval > 0) {\n this.pingInterval = setInterval(() => {\n for (const ws of this.channels.getAllClients()) {\n this.send(ws, { type: 'pong' })\n }\n }, this.config.pingInterval)\n }\n }\n\n /**\n * Shutdown the server.\n *\n * Clears the ping interval and shuts down the driver.\n *\n * @returns A promise that resolves when shutdown is complete.\n */\n async shutdown(): Promise<void> {\n if (this.pingInterval) {\n clearInterval(this.pingInterval)\n }\n await this.driver.shutdown?.()\n }\n}\n",
11
+ "/**\n * @fileoverview OrbitRipple - Gravito module wrapper for Ripple WebSocket\n *\n * Integrates RippleServer with Gravito's PlanetCore.\n *\n * @module @gravito/ripple\n */\n\nimport { setRippleServer } from './events/Broadcaster'\nimport { RippleServer } from './RippleServer'\nimport type { RippleConfig } from './types'\n\n/**\n * PlanetCore interface for type safety without importing\n */\ninterface PlanetCore {\n logger: { info: (msg: string) => void }\n adapter: {\n use: (path: string, handler: (ctx: any, next: () => Promise<void>) => Promise<any>) => void\n }\n hooks: {\n addAction: (hook: string, callback: (args: unknown) => Promise<void>) => void\n }\n}\n\n/**\n * OrbitRipple - Gravito module for real-time WebSocket communication\n *\n * @example\n * ```typescript\n * import { OrbitRipple } from '@gravito/ripple'\n *\n * const core = new PlanetCore()\n *\n * core.install(new OrbitRipple({\n * path: '/ws',\n * authorizer: async (channel, userId, socketId) => {\n * // Return true for authorized, false for denied\n * // For presence channels, return { id: userId, info: { name: '...' } }\n * return true\n * }\n * }))\n *\n * // The WebSocket is automatically integrated with Bun.serve\n * core.boot()\n * ```\n */\nexport class OrbitRipple {\n private server: RippleServer\n private config: RippleConfig\n\n constructor(config: RippleConfig = {}) {\n this.config = config\n this.server = new RippleServer(config)\n }\n\n /**\n * Install the module into PlanetCore\n */\n install(core: PlanetCore): void {\n core.logger.info('🌊 Orbit Ripple installed')\n\n // Store reference globally for broadcast() function\n setRippleServer(this.server)\n\n // Expose Ripple server via context variable\n core.adapter.use('*', async (ctx, next) => {\n ctx.set('ripple' as any, this.server)\n await next()\n })\n\n // Initialize server immediately\n this.server.init().then(() => {\n core.logger.info(`🌊 Ripple WebSocket ready at ${this.config.path || '/ws'}`)\n })\n\n // Register shutdown hook\n core.hooks.addAction('shutdown', async () => {\n await this.server.shutdown()\n })\n }\n\n /**\n * Get the underlying RippleServer instance\n */\n getServer(): RippleServer {\n return this.server\n }\n\n /**\n * Get WebSocket handler for Bun.serve integration\n *\n * @example\n * ```typescript\n * const ripple = new OrbitRipple()\n *\n * Bun.serve({\n * fetch: (req, server) => {\n * // Let Ripple handle WebSocket upgrades\n * if (ripple.getServer().upgrade(req, server)) return\n *\n * // Regular HTTP handling\n * return core.adapter.fetch(req, server)\n * },\n * websocket: ripple.getHandler()\n * })\n * ```\n */\n getHandler() {\n return this.server.getHandler()\n }\n}\n"
12
12
  ],
13
- "mappings": "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",
14
- "debugId": "528A850700D2523E64756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "FDAC75CC384E2A3664756E2164756E21",
15
15
  "names": []
16
16
  }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * @fileoverview Core types for @gravito/ripple WebSocket module
3
+ * @module @gravito/ripple
4
+ */
5
+ import type { Server, ServerWebSocket } from 'bun';
6
+ /**
7
+ * Data attached to each WebSocket connection
8
+ */
9
+ export interface ClientData {
10
+ /** Unique client identifier */
11
+ id: string;
12
+ /** User ID if authenticated */
13
+ userId?: string | number;
14
+ /** Channels this client has joined */
15
+ channels: Set<string>;
16
+ /** Additional user info for presence channels */
17
+ userInfo?: Record<string, unknown>;
18
+ }
19
+ export type ChannelType = 'public' | 'private' | 'presence';
20
+ /**
21
+ * Base channel interface
22
+ */
23
+ export interface Channel {
24
+ /** Channel name (without prefix) */
25
+ readonly name: string;
26
+ /** Channel type */
27
+ readonly type: ChannelType;
28
+ /** Full channel name with prefix */
29
+ readonly fullName: string;
30
+ }
31
+ /**
32
+ * Channel authorization callback
33
+ */
34
+ export type ChannelAuthorizer = (channelName: string, userId: string | number | undefined, socketId: string) => boolean | Promise<boolean> | PresenceUserInfo | Promise<PresenceUserInfo | false>;
35
+ /**
36
+ * User info returned for presence channels
37
+ */
38
+ export interface PresenceUserInfo {
39
+ id: string | number;
40
+ info: Record<string, unknown>;
41
+ }
42
+ /**
43
+ * Broadcast event interface
44
+ */
45
+ export interface BroadcastEventInterface {
46
+ /** Channels to broadcast to */
47
+ broadcastOn(): Channel | Channel[];
48
+ /** Event name (defaults to class name) */
49
+ broadcastAs?(): string;
50
+ /** Exclude specific socket IDs */
51
+ broadcastExcept?(): string[];
52
+ }
53
+ /**
54
+ * Client-to-server message types
55
+ */
56
+ export type ClientMessage = {
57
+ type: 'subscribe';
58
+ channel: string;
59
+ auth?: {
60
+ socketId: string;
61
+ signature: string;
62
+ };
63
+ } | {
64
+ type: 'unsubscribe';
65
+ channel: string;
66
+ } | {
67
+ type: 'whisper';
68
+ channel: string;
69
+ event: string;
70
+ data: unknown;
71
+ } | {
72
+ type: 'ping';
73
+ };
74
+ /**
75
+ * Server-to-client message types
76
+ */
77
+ export type ServerMessage = {
78
+ type: 'subscribed';
79
+ channel: string;
80
+ } | {
81
+ type: 'unsubscribed';
82
+ channel: string;
83
+ } | {
84
+ type: 'error';
85
+ message: string;
86
+ channel?: string;
87
+ } | {
88
+ type: 'event';
89
+ channel: string;
90
+ event: string;
91
+ data: unknown;
92
+ } | {
93
+ type: 'presence';
94
+ channel: string;
95
+ event: 'join' | 'leave' | 'members';
96
+ data: unknown;
97
+ } | {
98
+ type: 'pong';
99
+ } | {
100
+ type: 'connected';
101
+ socketId: string;
102
+ };
103
+ /**
104
+ * Driver interface for pub/sub backends
105
+ */
106
+ export interface RippleDriver {
107
+ /** Driver name */
108
+ readonly name: string;
109
+ /**
110
+ * Publish a message to a channel
111
+ */
112
+ publish(channel: string, event: string, data: unknown): Promise<void>;
113
+ /**
114
+ * Subscribe to channel messages (for Redis driver)
115
+ */
116
+ subscribe?(channel: string, callback: (event: string, data: unknown) => void): Promise<void>;
117
+ /**
118
+ * Unsubscribe from a channel
119
+ */
120
+ unsubscribe?(channel: string): Promise<void>;
121
+ /**
122
+ * Initialize the driver
123
+ */
124
+ init?(): Promise<void>;
125
+ /**
126
+ * Shutdown the driver
127
+ */
128
+ shutdown?(): Promise<void>;
129
+ }
130
+ /**
131
+ * Ripple server configuration
132
+ */
133
+ export interface RippleConfig {
134
+ /** WebSocket endpoint path (default: '/ws') */
135
+ path?: string;
136
+ /** Authentication endpoint for private/presence channels */
137
+ authEndpoint?: string;
138
+ /** Driver to use ('local' | 'redis') */
139
+ driver?: 'local' | 'redis';
140
+ /** Redis configuration (if using redis driver) */
141
+ redis?: {
142
+ host?: string;
143
+ port?: number;
144
+ password?: string;
145
+ db?: number;
146
+ };
147
+ /** Channel authorizer function */
148
+ authorizer?: ChannelAuthorizer;
149
+ /** Ping interval in milliseconds (default: 30000) */
150
+ pingInterval?: number;
151
+ }
152
+ export type RippleWebSocket = ServerWebSocket<ClientData>;
153
+ export type RippleBunServer = Server<ClientData>;
154
+ /**
155
+ * WebSocket handler configuration for Bun.serve
156
+ */
157
+ export interface WebSocketHandlerConfig {
158
+ open: (ws: RippleWebSocket) => void | Promise<void>;
159
+ message: (ws: RippleWebSocket, message: string | Buffer) => void | Promise<void>;
160
+ close: (ws: RippleWebSocket, code: number, reason: string) => void | Promise<void>;
161
+ drain?: (ws: RippleWebSocket) => void;
162
+ }
163
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@gravito/ripple",
3
- "version": "1.0.0-beta.1",
3
+ "version": "2.0.0",
4
4
  "description": "Bun-native WebSocket broadcasting for Gravito. Channel-based real-time communication.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
- "module": "./dist/index.mjs",
7
+ "module": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
- "import": "./dist/index.mjs",
12
+ "import": "./dist/index.js",
13
13
  "require": "./dist/index.cjs"
14
14
  }
15
15
  },
@@ -20,7 +20,9 @@
20
20
  "scripts": {
21
21
  "build": "bun run build.ts",
22
22
  "test": "bun test",
23
- "typecheck": "tsc --noEmit"
23
+ "typecheck": "bun tsc -p tsconfig.json --noEmit --skipLibCheck",
24
+ "test:coverage": "bun test --coverage --coverage-threshold=80",
25
+ "test:ci": "bun test --coverage --coverage-threshold=80"
24
26
  },
25
27
  "keywords": [
26
28
  "gravito",
@@ -39,7 +41,7 @@
39
41
  },
40
42
  "homepage": "https://github.com/gravito-framework/gravito#readme",
41
43
  "peerDependencies": {
42
- "gravito-core": "1.0.0-beta.6"
44
+ "@gravito/core": "workspace:*"
43
45
  },
44
46
  "devDependencies": {
45
47
  "bun-types": "latest",
@@ -48,4 +50,4 @@
48
50
  "publishConfig": {
49
51
  "access": "public"
50
52
  }
51
- }
53
+ }