@appstrata/protocol 0.1.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 +106 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/proxy.d.ts +72 -0
- package/dist/client/proxy.d.ts.map +1 -0
- package/dist/client/proxy.js +446 -0
- package/dist/client/rpc.d.ts +62 -0
- package/dist/client/rpc.d.ts.map +1 -0
- package/dist/client/rpc.js +138 -0
- package/dist/host/index.d.ts +5 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +4 -0
- package/dist/host/message-bridge.d.ts +146 -0
- package/dist/host/message-bridge.d.ts.map +1 -0
- package/dist/host/message-bridge.js +360 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/messages.d.ts +197 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +141 -0
- package/dist/transport/http/client-polling.d.ts +32 -0
- package/dist/transport/http/client-polling.d.ts.map +1 -0
- package/dist/transport/http/client-polling.js +181 -0
- package/dist/transport/http/client-sse.d.ts +30 -0
- package/dist/transport/http/client-sse.d.ts.map +1 -0
- package/dist/transport/http/client-sse.js +155 -0
- package/dist/transport/http/host-manager.d.ts +63 -0
- package/dist/transport/http/host-manager.d.ts.map +1 -0
- package/dist/transport/http/host-manager.js +74 -0
- package/dist/transport/http/host-polling.d.ts +65 -0
- package/dist/transport/http/host-polling.d.ts.map +1 -0
- package/dist/transport/http/host-polling.js +143 -0
- package/dist/transport/http/host-sse.d.ts +56 -0
- package/dist/transport/http/host-sse.d.ts.map +1 -0
- package/dist/transport/http/host-sse.js +149 -0
- package/dist/transport/http/index.d.ts +13 -0
- package/dist/transport/http/index.d.ts.map +1 -0
- package/dist/transport/http/index.js +12 -0
- package/dist/transport/http/types.d.ts +73 -0
- package/dist/transport/http/types.d.ts.map +1 -0
- package/dist/transport/http/types.js +8 -0
- package/dist/transport/index.d.ts +33 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +37 -0
- package/dist/transport/postMessage.d.ts +70 -0
- package/dist/transport/postMessage.d.ts.map +1 -0
- package/dist/transport/postMessage.js +94 -0
- package/dist/transport/relay.d.ts +118 -0
- package/dist/transport/relay.d.ts.map +1 -0
- package/dist/transport/relay.js +216 -0
- package/dist/transport/types.d.ts +30 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +6 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postMessage.d.ts","sourceRoot":"","sources":["../../src/transport/postMessage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;;;OAUG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,SAAS,CA4DX"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostMessage transport implementation.
|
|
3
|
+
*
|
|
4
|
+
* Unified transport for both host and app sides.
|
|
5
|
+
* Works for iframe and same-window scenarios.
|
|
6
|
+
*/
|
|
7
|
+
import { isProtocolMessage } from "../messages.js";
|
|
8
|
+
/**
|
|
9
|
+
* Create a postMessage transport.
|
|
10
|
+
*
|
|
11
|
+
* Sends messages to the target window, receives messages from it.
|
|
12
|
+
* Automatically determines sensible origin defaults based on whether
|
|
13
|
+
* the target is the same window or a different window.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Transport configuration
|
|
16
|
+
* @returns Transport instance
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // Host-side: iframe app
|
|
21
|
+
* const iframe = document.getElementById("app-frame") as HTMLIFrameElement;
|
|
22
|
+
* const transport = createPostMessageTransport({
|
|
23
|
+
* targetWindow: iframe.contentWindow!,
|
|
24
|
+
* targetOrigin: "https://app.example.com"
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // Host-side: same-window app
|
|
28
|
+
* const transport = createPostMessageTransport({
|
|
29
|
+
* targetWindow: window,
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // App-side: in iframe
|
|
33
|
+
* const transport = createPostMessageTransport({
|
|
34
|
+
* targetWindow: window.parent,
|
|
35
|
+
* targetOrigin: "https://player.example.com"
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* // App-side: same-window
|
|
39
|
+
* const transport = createPostMessageTransport({
|
|
40
|
+
* targetWindow: window,
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function createPostMessageTransport(options) {
|
|
45
|
+
const { targetWindow, targetOrigin } = options;
|
|
46
|
+
const origin = targetOrigin ?? "*";
|
|
47
|
+
const handlers = new Set();
|
|
48
|
+
/**
|
|
49
|
+
* Handle incoming postMessage events.
|
|
50
|
+
*/
|
|
51
|
+
const handleMessage = (event) => {
|
|
52
|
+
// Validate source (should be the target window)
|
|
53
|
+
if (event.source !== targetWindow) {
|
|
54
|
+
return; // Ignore messages not from target
|
|
55
|
+
}
|
|
56
|
+
// Validate origin if specified
|
|
57
|
+
if (origin !== "*" && event.origin !== origin) {
|
|
58
|
+
return; // Ignore messages from unexpected origins
|
|
59
|
+
}
|
|
60
|
+
// Validate message structure
|
|
61
|
+
const message = event.data;
|
|
62
|
+
if (!isProtocolMessage(message)) {
|
|
63
|
+
return; // Ignore non-protocol messages
|
|
64
|
+
}
|
|
65
|
+
// Dispatch to all handlers
|
|
66
|
+
// Snapshot the handler set to prevent handlers added during iteration from being called.
|
|
67
|
+
handlers.forEach((handler) => {
|
|
68
|
+
try {
|
|
69
|
+
handler(message);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error("[AppStrata] Error in message handler:", error);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
// Install listener
|
|
77
|
+
window.addEventListener("message", handleMessage);
|
|
78
|
+
return {
|
|
79
|
+
send(message) {
|
|
80
|
+
targetWindow.postMessage(message, origin);
|
|
81
|
+
},
|
|
82
|
+
onMessage(handler) {
|
|
83
|
+
handlers.add(handler);
|
|
84
|
+
// Return unsubscribe function
|
|
85
|
+
return () => {
|
|
86
|
+
handlers.delete(handler);
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
close() {
|
|
90
|
+
window.removeEventListener("message", handleMessage);
|
|
91
|
+
handlers.clear();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relay transport implementation.
|
|
3
|
+
*
|
|
4
|
+
* Bridges two transports together, forwarding messages between them.
|
|
5
|
+
* Commonly used to relay between a postMessage transport (app-side) and an HTTP transport (host-side).
|
|
6
|
+
*
|
|
7
|
+
* **Architecture:**
|
|
8
|
+
* ```
|
|
9
|
+
* [App] <--postMessage--> [RelayTransport] <--HTTP--> [Remote Host]
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* **Use Cases:**
|
|
13
|
+
* - Relaying app messages to a server-side or native Player (written in any language)
|
|
14
|
+
* - Service worker proxying messages between local app and cloud host
|
|
15
|
+
* - Development/debugging proxy for inspecting protocol messages
|
|
16
|
+
*/
|
|
17
|
+
import type { Transport } from "./types.js";
|
|
18
|
+
import type { ProtocolMessage } from "../messages.js";
|
|
19
|
+
/**
|
|
20
|
+
* Options for creating a relay transport.
|
|
21
|
+
*/
|
|
22
|
+
export interface RelayTransportOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Transport for communicating with the app (typically postMessage).
|
|
25
|
+
* Messages from the app will be forwarded to the host transport.
|
|
26
|
+
*/
|
|
27
|
+
appTransport: Transport;
|
|
28
|
+
/**
|
|
29
|
+
* Transport for communicating with the host (typically HTTP).
|
|
30
|
+
* Messages from the host will be forwarded to the app transport.
|
|
31
|
+
*/
|
|
32
|
+
hostTransport: Transport;
|
|
33
|
+
/**
|
|
34
|
+
* Optional message interceptor for debugging or transformation.
|
|
35
|
+
* Called for every message passing through the relay.
|
|
36
|
+
*
|
|
37
|
+
* @param message - The protocol message
|
|
38
|
+
* @param direction - Direction of the message flow
|
|
39
|
+
* @returns The message to forward (can be modified), or null to drop the message
|
|
40
|
+
*/
|
|
41
|
+
onMessage?: (message: ProtocolMessage, direction: "app-to-host" | "host-to-app") => ProtocolMessage | null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extended Transport interface for relay transport.
|
|
45
|
+
*
|
|
46
|
+
* Provides additional methods for managing the relay lifecycle.
|
|
47
|
+
*/
|
|
48
|
+
export interface RelayTransport extends Transport {
|
|
49
|
+
/**
|
|
50
|
+
* Check if the relay is currently active.
|
|
51
|
+
*/
|
|
52
|
+
isActive(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Get statistics about messages relayed.
|
|
55
|
+
*/
|
|
56
|
+
getStats(): {
|
|
57
|
+
appToHost: number;
|
|
58
|
+
hostToApp: number;
|
|
59
|
+
dropped: number;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a relay transport that bridges two transports together.
|
|
64
|
+
*
|
|
65
|
+
* The relay automatically starts forwarding messages between the two transports.
|
|
66
|
+
* Messages from the app transport are forwarded to the host transport, and vice versa.
|
|
67
|
+
*
|
|
68
|
+
* @param options - Relay configuration options
|
|
69
|
+
* @returns RelayTransport instance
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* // Relay between iframe app and remote HTTP host
|
|
74
|
+
* const appTransport = createPostMessageTransport({
|
|
75
|
+
* targetWindow: iframe.contentWindow!,
|
|
76
|
+
* targetOrigin: "https://app.example.com"
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* const hostTransport = createHttpSseTransport({
|
|
80
|
+
* sendUrl: "https://player.example.com/api/send",
|
|
81
|
+
* receiveUrl: "https://player.example.com/api/receive",
|
|
82
|
+
* sessionId: "abc-123",
|
|
83
|
+
* authToken: "secret-token"
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* const relay = createRelayTransport({
|
|
87
|
+
* appTransport,
|
|
88
|
+
* hostTransport,
|
|
89
|
+
* debug: true
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // Relay automatically forwards messages in both directions
|
|
93
|
+
* // Close when done
|
|
94
|
+
* relay.close();
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* // With message interceptor for debugging
|
|
100
|
+
* const relay = createRelayTransport({
|
|
101
|
+
* appTransport,
|
|
102
|
+
* hostTransport,
|
|
103
|
+
* onMessage: (msg, direction) => {
|
|
104
|
+
* console.log(`[Relay ${direction}]`, msg.type, msg);
|
|
105
|
+
*
|
|
106
|
+
* // Transform or filter messages if needed
|
|
107
|
+
* if (msg.type === "HELLO") {
|
|
108
|
+
* // Augment HELLO message with relay info
|
|
109
|
+
* return { ...msg, relayVersion: "1.0" };
|
|
110
|
+
* }
|
|
111
|
+
*
|
|
112
|
+
* return msg; // Forward as-is
|
|
113
|
+
* }
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare function createRelayTransport(options: RelayTransportOptions): RelayTransport;
|
|
118
|
+
//# sourceMappingURL=relay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../src/transport/relay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,YAAY,EAAE,SAAS,CAAC;IAExB;;;OAGG;IACH,aAAa,EAAE,SAAS,CAAC;IAEzB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CACV,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,aAAa,GAAG,aAAa,KACrC,eAAe,GAAG,IAAI,CAAC;CAE7B;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C;;OAEG;IACH,QAAQ,IAAI,OAAO,CAAC;IAEpB;;OAEG;IACH,QAAQ,IAAI;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CAmKnF"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relay transport implementation.
|
|
3
|
+
*
|
|
4
|
+
* Bridges two transports together, forwarding messages between them.
|
|
5
|
+
* Commonly used to relay between a postMessage transport (app-side) and an HTTP transport (host-side).
|
|
6
|
+
*
|
|
7
|
+
* **Architecture:**
|
|
8
|
+
* ```
|
|
9
|
+
* [App] <--postMessage--> [RelayTransport] <--HTTP--> [Remote Host]
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* **Use Cases:**
|
|
13
|
+
* - Relaying app messages to a server-side or native Player (written in any language)
|
|
14
|
+
* - Service worker proxying messages between local app and cloud host
|
|
15
|
+
* - Development/debugging proxy for inspecting protocol messages
|
|
16
|
+
*/
|
|
17
|
+
import { createLogger } from "@appstrata/core";
|
|
18
|
+
/**
|
|
19
|
+
* Create a relay transport that bridges two transports together.
|
|
20
|
+
*
|
|
21
|
+
* The relay automatically starts forwarding messages between the two transports.
|
|
22
|
+
* Messages from the app transport are forwarded to the host transport, and vice versa.
|
|
23
|
+
*
|
|
24
|
+
* @param options - Relay configuration options
|
|
25
|
+
* @returns RelayTransport instance
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* // Relay between iframe app and remote HTTP host
|
|
30
|
+
* const appTransport = createPostMessageTransport({
|
|
31
|
+
* targetWindow: iframe.contentWindow!,
|
|
32
|
+
* targetOrigin: "https://app.example.com"
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* const hostTransport = createHttpSseTransport({
|
|
36
|
+
* sendUrl: "https://player.example.com/api/send",
|
|
37
|
+
* receiveUrl: "https://player.example.com/api/receive",
|
|
38
|
+
* sessionId: "abc-123",
|
|
39
|
+
* authToken: "secret-token"
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* const relay = createRelayTransport({
|
|
43
|
+
* appTransport,
|
|
44
|
+
* hostTransport,
|
|
45
|
+
* debug: true
|
|
46
|
+
* });
|
|
47
|
+
*
|
|
48
|
+
* // Relay automatically forwards messages in both directions
|
|
49
|
+
* // Close when done
|
|
50
|
+
* relay.close();
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // With message interceptor for debugging
|
|
56
|
+
* const relay = createRelayTransport({
|
|
57
|
+
* appTransport,
|
|
58
|
+
* hostTransport,
|
|
59
|
+
* onMessage: (msg, direction) => {
|
|
60
|
+
* console.log(`[Relay ${direction}]`, msg.type, msg);
|
|
61
|
+
*
|
|
62
|
+
* // Transform or filter messages if needed
|
|
63
|
+
* if (msg.type === "HELLO") {
|
|
64
|
+
* // Augment HELLO message with relay info
|
|
65
|
+
* return { ...msg, relayVersion: "1.0" };
|
|
66
|
+
* }
|
|
67
|
+
*
|
|
68
|
+
* return msg; // Forward as-is
|
|
69
|
+
* }
|
|
70
|
+
* });
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function createRelayTransport(options) {
|
|
74
|
+
const { appTransport, hostTransport, onMessage: messageInterceptor, } = options;
|
|
75
|
+
const logger = createLogger("Relay");
|
|
76
|
+
let closed = false;
|
|
77
|
+
const stats = {
|
|
78
|
+
appToHost: 0,
|
|
79
|
+
hostToApp: 0,
|
|
80
|
+
dropped: 0
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Handle message from app, forward to host.
|
|
84
|
+
*/
|
|
85
|
+
function handleAppMessage(message) {
|
|
86
|
+
if (closed)
|
|
87
|
+
return;
|
|
88
|
+
logger.debug(`App → Host: ${message.type}`, message);
|
|
89
|
+
// Apply interceptor if provided
|
|
90
|
+
let messageToSend = message;
|
|
91
|
+
if (messageInterceptor) {
|
|
92
|
+
try {
|
|
93
|
+
const result = messageInterceptor(message, "app-to-host");
|
|
94
|
+
if (result === null) {
|
|
95
|
+
logger.debug("Message dropped by interceptor");
|
|
96
|
+
stats.dropped++;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
messageToSend = result;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
logger.error("Error in message interceptor", error);
|
|
103
|
+
// Forward original message on error
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Forward to host
|
|
107
|
+
try {
|
|
108
|
+
hostTransport.send(messageToSend);
|
|
109
|
+
stats.appToHost++;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logger.error("Error forwarding to host", error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Handle message from host, forward to app.
|
|
117
|
+
*/
|
|
118
|
+
function handleHostMessage(message) {
|
|
119
|
+
if (closed)
|
|
120
|
+
return;
|
|
121
|
+
logger.debug(`Host → App: ${message.type}`, message);
|
|
122
|
+
// Apply interceptor if provided
|
|
123
|
+
let messageToSend = message;
|
|
124
|
+
if (messageInterceptor) {
|
|
125
|
+
try {
|
|
126
|
+
const result = messageInterceptor(message, "host-to-app");
|
|
127
|
+
if (result === null) {
|
|
128
|
+
logger.debug("Message dropped by interceptor");
|
|
129
|
+
stats.dropped++;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
messageToSend = result;
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
logger.error("Error in message interceptor", error);
|
|
136
|
+
// Forward original message on error
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Forward to app
|
|
140
|
+
try {
|
|
141
|
+
appTransport.send(messageToSend);
|
|
142
|
+
stats.hostToApp++;
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
logger.error("Error forwarding to app", error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Set up bidirectional forwarding
|
|
149
|
+
const unsubscribeApp = appTransport.onMessage(handleAppMessage);
|
|
150
|
+
const unsubscribeHost = hostTransport.onMessage(handleHostMessage);
|
|
151
|
+
logger.debug("Relay started");
|
|
152
|
+
return {
|
|
153
|
+
// Standard Transport interface
|
|
154
|
+
// Note: The relay itself doesn't have direct handlers, it just forwards
|
|
155
|
+
// If you need to intercept messages, use the messageInterceptor option
|
|
156
|
+
send(message) {
|
|
157
|
+
// When someone calls send() on the relay directly, we need to decide where to send it.
|
|
158
|
+
// By convention, we send to the host (assuming the caller is the app).
|
|
159
|
+
if (closed) {
|
|
160
|
+
logger.warn("Cannot send: relay is closed");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
logger.debug(`Direct send → Host: ${message.type}`, message);
|
|
164
|
+
try {
|
|
165
|
+
hostTransport.send(message);
|
|
166
|
+
stats.appToHost++;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
logger.error("Error sending to host", error);
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
onMessage(handler) {
|
|
173
|
+
// For the relay to act as a transport itself, we need to support onMessage.
|
|
174
|
+
// We'll register handlers on BOTH transports and call the handler for all messages.
|
|
175
|
+
if (closed) {
|
|
176
|
+
return () => { }; // No-op if already closed
|
|
177
|
+
}
|
|
178
|
+
const unsubApp = appTransport.onMessage(handler);
|
|
179
|
+
const unsubHost = hostTransport.onMessage(handler);
|
|
180
|
+
return () => {
|
|
181
|
+
unsubApp();
|
|
182
|
+
unsubHost();
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
close() {
|
|
186
|
+
if (closed)
|
|
187
|
+
return;
|
|
188
|
+
logger.debug("Relay closing");
|
|
189
|
+
closed = true;
|
|
190
|
+
// Unsubscribe from both transports
|
|
191
|
+
unsubscribeApp();
|
|
192
|
+
unsubscribeHost();
|
|
193
|
+
// Close both underlying transports
|
|
194
|
+
try {
|
|
195
|
+
appTransport.close();
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
logger.error("Error closing app transport", error);
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
hostTransport.close();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
logger.error("Error closing host transport", error);
|
|
205
|
+
}
|
|
206
|
+
logger.debug("Relay closed", stats);
|
|
207
|
+
},
|
|
208
|
+
// Relay-specific extensions
|
|
209
|
+
isActive() {
|
|
210
|
+
return !closed;
|
|
211
|
+
},
|
|
212
|
+
getStats() {
|
|
213
|
+
return { ...stats };
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport layer types for AppStrata Digital Signage SDK
|
|
3
|
+
*
|
|
4
|
+
* The transport layer abstracts the underlying message delivery mechanism.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProtocolMessage } from "../messages.js";
|
|
7
|
+
/**
|
|
8
|
+
* Transport interface - abstracts message delivery mechanism.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
export interface Transport {
|
|
12
|
+
/**
|
|
13
|
+
* Send a protocol message to the host.
|
|
14
|
+
*
|
|
15
|
+
* @param message - Protocol message to send
|
|
16
|
+
*/
|
|
17
|
+
send(message: ProtocolMessage): void;
|
|
18
|
+
/**
|
|
19
|
+
* Register a message handler.
|
|
20
|
+
*
|
|
21
|
+
* @param handler - Function to call when a message is received
|
|
22
|
+
* @returns Unsubscribe function
|
|
23
|
+
*/
|
|
24
|
+
onMessage(handler: (message: ProtocolMessage) => void): () => void;
|
|
25
|
+
/**
|
|
26
|
+
* Close the transport and clean up resources.
|
|
27
|
+
*/
|
|
28
|
+
close(): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/transport/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAErC;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAEnE;;OAEG;IACH,KAAK,IAAI,IAAI,CAAC;CACf"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appstrata/protocol",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AppStrata protocol implementation - messages, transport, client and host",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./messages": {
|
|
14
|
+
"types": "./dist/messages.d.ts",
|
|
15
|
+
"import": "./dist/messages.js"
|
|
16
|
+
},
|
|
17
|
+
"./transport": {
|
|
18
|
+
"types": "./dist/transport/index.d.ts",
|
|
19
|
+
"import": "./dist/transport/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./client": {
|
|
22
|
+
"types": "./dist/client/index.d.ts",
|
|
23
|
+
"import": "./dist/client/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./host": {
|
|
26
|
+
"types": "./dist/host/index.d.ts",
|
|
27
|
+
"import": "./dist/host/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"digital-signage",
|
|
32
|
+
"appstrata",
|
|
33
|
+
"protocol"
|
|
34
|
+
],
|
|
35
|
+
"author": "AppStrata",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "restricted"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@appstrata/core": "0.1.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@jest/globals": "^29.7.0",
|
|
48
|
+
"jest": "^29.7.0",
|
|
49
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
50
|
+
"ts-jest": "^29.1.1",
|
|
51
|
+
"typescript": "^5.3.3"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc --build tsconfig.build.json",
|
|
55
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
56
|
+
"dev": "tsc --build --watch",
|
|
57
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
58
|
+
"test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch"
|
|
59
|
+
}
|
|
60
|
+
}
|