Skip to content

Commit ee26d45

Browse files
author
Anatoly Ostrovsky
committed
Websocket provider and sse/ws injectables
1 parent e5dd019 commit ee26d45

File tree

16 files changed

+243
-50
lines changed

16 files changed

+243
-50
lines changed

@types/core/di/ng-module/ng-module.d.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,28 @@ export class NgModule {
199199
entityClass: ng.EntityClass<T>,
200200
options?: any | undefined,
201201
): NgModule;
202+
/**
203+
* Register a pre-configured SSE connection during module configuration.
204+
*
205+
* @param {string} name - Injectable name
206+
* @param {string} url - SSE endpoint
207+
* @param {ng.SseConfig} [options] - Optional SSE config
208+
* @returns {NgModule}
209+
*/
210+
sse(name: string, url: string, options?: ng.SseConfig): NgModule;
211+
/**
212+
* Register a pre-configured WebSocket connection during module configuration.
213+
*
214+
* @param {string} name - Injectable name
215+
* @param {string} url - WebSocket endpoint
216+
* @param {string[]} [protocols] - Optional subprotocols
217+
* @param {ng.WebSocketConfig} [options] - Optional WebSocket configuration
218+
* @returns {NgModule}
219+
*/
220+
websocket(
221+
name: string,
222+
url: string,
223+
protocols?: string[],
224+
options?: ng.WebSocketConfig,
225+
): NgModule;
202226
}

@types/namespace.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ import {
121121
SCEService as TSCEService,
122122
SCEDelegateService as TSCEDelegateService,
123123
} from "./services/sce/interface.ts";
124+
import {
125+
WebSocketConfig as TWebSocketConfig,
126+
WebSocketService as TWebSocketService,
127+
} from "./services/websocket/interface.ts";
124128
declare global {
125129
interface Function {
126130
$inject?: readonly string[] | undefined;
@@ -229,5 +233,7 @@ declare global {
229233
type RequestShortcutConfig = TRequestShortcutConfig;
230234
type HttpProviderDefaults = THttpProviderDefaults;
231235
type ProviderCache = TProviderCache;
236+
type WebSocketConfig = TWebSocketConfig;
237+
type WebSocketService = TWebSocketService;
232238
}
233239
}

@types/services/sse/interface.d.ts

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
1+
import { StreamConnectionConfig } from "../stream/interface.ts";
12
/**
2-
* Configuration object for SSE
3+
* SSE-specific configuration
34
*/
4-
export interface SseConfig {
5+
export interface SseConfig extends StreamConnectionConfig {
56
/** Include cookies/credentials when connecting */
67
withCredentials?: boolean;
7-
/** Custom headers (Note: EventSource doesn't natively support headers; handled at app level if needed) */
8-
headers?: Record<string, string>;
9-
/** Called when the connection is successfully opened */
10-
onOpen?: (event: Event) => void;
11-
/** Called when a message event is received */
12-
onMessage?: (data: any, event: MessageEvent) => void;
13-
/** Called on connection error */
14-
onError?: (err: Event) => void;
15-
/** Transform raw SSE message data (default: JSON.parse if possible) */
16-
transformMessage?: (data: string) => any;
178
/** Optional query parameters appended to the URL */
189
params?: Record<string, any>;
19-
/** Called when the connection is being re-established */
20-
onReconnect?: (attempt: number) => void;
21-
/** Delay in milliseconds before attempting to reconnect (default: 1000ms) */
22-
retryDelay?: number;
23-
/** Maximum number of reconnect attempts (default: Infinity) */
24-
maxRetries?: number;
25-
/** Heartbeat timeout in milliseconds; reconnect if no message within this time */
26-
heartbeatTimeout?: number;
10+
/** Custom headers (EventSource doesn't natively support headers) */
11+
headers?: Record<string, string>;
2712
}
2813
/**
2914
* Managed SSE connection object returned by $sse.

@types/services/stream/interface.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ export interface StreamConnectionConfig {
1515
heartbeatTimeout?: number;
1616
/** Function to transform incoming messages */
1717
transformMessage?: (data: any) => any;
18+
[key: string]: any;
1819
}

@types/services/stream/stream.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class StreamConnection {
2323
retryDelay: number;
2424
maxRetries: number;
2525
heartbeatTimeout: number;
26-
transformMessage: (data: string) => any;
26+
transformMessage: (data: any) => any;
2727
};
2828
_log: import("../log/interface.ts").LogService;
2929
_retryCount: number;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { StreamConnectionConfig } from "../stream/interface.ts";
2+
import { StreamConnection } from "../stream/stream.js";
3+
/**
4+
* WebSocket-specific configuration
5+
*/
6+
export interface WebSocketConfig extends StreamConnectionConfig {
7+
/** Optional WebSocket subprotocols */
8+
protocols?: string[];
9+
/** Called when the WebSocket connection closes */
10+
onClose?: (event: CloseEvent) => void;
11+
}
12+
/**
13+
* Type of the injectable WebSocket service returned by the provider.
14+
* Acts as a factory for pre-configured WebSocket connections.
15+
*/
16+
export type WebSocketService = (
17+
/** The WebSocket URL (already pre-configured if passed at module registration) */
18+
url?: string,
19+
/** Optional WebSocket subprotocols */
20+
protocols?: string[],
21+
/** Optional configuration (merges with defaults) */
22+
config?: WebSocketConfig,
23+
) => StreamConnection;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* WebSocketProvider
3+
* Provides a pre-configured WebSocket connection as an injectable.
4+
*/
5+
export class WebSocketProvider {
6+
/** @type {ng.WebSocketConfig} */
7+
defaults: ng.WebSocketConfig;
8+
$get: (
9+
| string
10+
| ((
11+
log: ng.LogService,
12+
) => (
13+
url: string,
14+
protocols?: string[],
15+
config?: import("./interface.ts").WebSocketConfig,
16+
) => StreamConnection)
17+
)[];
18+
_$log: import("../log/interface.ts").LogService;
19+
}
20+
import { StreamConnection } from "../stream/stream.js";

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ AngularTS builds on that foundation and adds:
1717
- built-in enterprise-level router (`ui-router` ported as `ng-router`)
1818
- built-in animations (`animate`)
1919
- new directives, inspired by `HTMX`
20-
- new injectables for REST resources, persistent stores, Web Workers and WASM modules
20+
- new injectables for REST resources, persistent stores, Web Workers, EventSources, WebSockets and WASM modules
2121

2222
The result is a high-performance, buildless, multi-paradigm and battle-tested JS framework that stays as close to Web standards as possible.
2323

src/core/di/ng-module/ng-module.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,60 @@ export class NgModule {
372372

373373
return this;
374374
}
375+
376+
/**
377+
* Register a pre-configured SSE connection during module configuration.
378+
*
379+
* @param {string} name - Injectable name
380+
* @param {string} url - SSE endpoint
381+
* @param {ng.SseConfig} [options] - Optional SSE config
382+
* @returns {NgModule}
383+
*/
384+
sse(name, url, options = {}) {
385+
validate(isString, name, "name");
386+
validate(isString, url, "url");
387+
388+
this._invokeQueue.push([
389+
$t._provide,
390+
"factory",
391+
[
392+
name,
393+
[
394+
$t._sse,
395+
/** @param {ng.SseService} $sse */ ($sse) => $sse(url, options),
396+
],
397+
],
398+
]);
399+
400+
return this;
401+
}
402+
403+
/**
404+
* Register a pre-configured WebSocket connection during module configuration.
405+
*
406+
* @param {string} name - Injectable name
407+
* @param {string} url - WebSocket endpoint
408+
* @param {string[]} [protocols] - Optional subprotocols
409+
* @param {ng.WebSocketConfig} [options] - Optional WebSocket configuration
410+
* @returns {NgModule}
411+
*/
412+
websocket(name, url, protocols = [], options = {}) {
413+
validate(isString, name, "name");
414+
validate(isString, url, "url");
415+
416+
this._invokeQueue.push([
417+
$t._provide,
418+
"factory",
419+
[
420+
name,
421+
[
422+
$t._websocket,
423+
/** @param {ng.WebSocketService} $ws */ ($ws) =>
424+
$ws(url, protocols, options),
425+
],
426+
],
427+
]);
428+
429+
return this;
430+
}
375431
}

src/injection-tokens.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export const $injectTokens = {
6666
_url: "$url",
6767
_view: "$view",
6868
_window: "$window",
69+
_ws: "$ws",
70+
6971
// provide literals
7072
_provide: "$provide",
7173
_injector: "$injector",

0 commit comments

Comments
 (0)