@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.
Files changed (56) hide show
  1. package/README.md +106 -0
  2. package/dist/client/index.d.ts +6 -0
  3. package/dist/client/index.d.ts.map +1 -0
  4. package/dist/client/index.js +5 -0
  5. package/dist/client/proxy.d.ts +72 -0
  6. package/dist/client/proxy.d.ts.map +1 -0
  7. package/dist/client/proxy.js +446 -0
  8. package/dist/client/rpc.d.ts +62 -0
  9. package/dist/client/rpc.d.ts.map +1 -0
  10. package/dist/client/rpc.js +138 -0
  11. package/dist/host/index.d.ts +5 -0
  12. package/dist/host/index.d.ts.map +1 -0
  13. package/dist/host/index.js +4 -0
  14. package/dist/host/message-bridge.d.ts +146 -0
  15. package/dist/host/message-bridge.d.ts.map +1 -0
  16. package/dist/host/message-bridge.js +360 -0
  17. package/dist/index.d.ts +14 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +17 -0
  20. package/dist/messages.d.ts +197 -0
  21. package/dist/messages.d.ts.map +1 -0
  22. package/dist/messages.js +141 -0
  23. package/dist/transport/http/client-polling.d.ts +32 -0
  24. package/dist/transport/http/client-polling.d.ts.map +1 -0
  25. package/dist/transport/http/client-polling.js +181 -0
  26. package/dist/transport/http/client-sse.d.ts +30 -0
  27. package/dist/transport/http/client-sse.d.ts.map +1 -0
  28. package/dist/transport/http/client-sse.js +155 -0
  29. package/dist/transport/http/host-manager.d.ts +63 -0
  30. package/dist/transport/http/host-manager.d.ts.map +1 -0
  31. package/dist/transport/http/host-manager.js +74 -0
  32. package/dist/transport/http/host-polling.d.ts +65 -0
  33. package/dist/transport/http/host-polling.d.ts.map +1 -0
  34. package/dist/transport/http/host-polling.js +143 -0
  35. package/dist/transport/http/host-sse.d.ts +56 -0
  36. package/dist/transport/http/host-sse.d.ts.map +1 -0
  37. package/dist/transport/http/host-sse.js +149 -0
  38. package/dist/transport/http/index.d.ts +13 -0
  39. package/dist/transport/http/index.d.ts.map +1 -0
  40. package/dist/transport/http/index.js +12 -0
  41. package/dist/transport/http/types.d.ts +73 -0
  42. package/dist/transport/http/types.d.ts.map +1 -0
  43. package/dist/transport/http/types.js +8 -0
  44. package/dist/transport/index.d.ts +33 -0
  45. package/dist/transport/index.d.ts.map +1 -0
  46. package/dist/transport/index.js +37 -0
  47. package/dist/transport/postMessage.d.ts +70 -0
  48. package/dist/transport/postMessage.d.ts.map +1 -0
  49. package/dist/transport/postMessage.js +94 -0
  50. package/dist/transport/relay.d.ts +118 -0
  51. package/dist/transport/relay.d.ts.map +1 -0
  52. package/dist/transport/relay.js +216 -0
  53. package/dist/transport/types.d.ts +30 -0
  54. package/dist/transport/types.d.ts.map +1 -0
  55. package/dist/transport/types.js +6 -0
  56. 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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Transport layer types for AppStrata Digital Signage SDK
3
+ *
4
+ * The transport layer abstracts the underlying message delivery mechanism.
5
+ */
6
+ export {};
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
+ }