@liphium/neoroute-ts 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 (145) hide show
  1. package/.prettierignore +5 -0
  2. package/.prettierrc +8 -0
  3. package/.zed/settings.json +3 -0
  4. package/dist/client.d.ts +8 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +15 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/config.d.ts +5 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +2 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/examples/http_client/src/main.d.ts +2 -0
  13. package/dist/examples/http_client/src/main.d.ts.map +1 -0
  14. package/dist/examples/http_client/src/main.js +51 -0
  15. package/dist/examples/http_client/src/main.js.map +1 -0
  16. package/dist/examples/http_client/src/messages.d.ts +9 -0
  17. package/dist/examples/http_client/src/messages.d.ts.map +1 -0
  18. package/dist/examples/http_client/src/messages.js +2 -0
  19. package/dist/examples/http_client/src/messages.js.map +1 -0
  20. package/dist/examples/http_client/src/requests.d.ts +5 -0
  21. package/dist/examples/http_client/src/requests.d.ts.map +1 -0
  22. package/dist/examples/http_client/src/requests.js +56 -0
  23. package/dist/examples/http_client/src/requests.js.map +1 -0
  24. package/dist/examples/web_socket_client/src/main.d.ts +2 -0
  25. package/dist/examples/web_socket_client/src/main.d.ts.map +1 -0
  26. package/dist/examples/web_socket_client/src/main.js +59 -0
  27. package/dist/examples/web_socket_client/src/main.js.map +1 -0
  28. package/dist/examples/web_socket_client/src/messages.d.ts +14 -0
  29. package/dist/examples/web_socket_client/src/messages.d.ts.map +1 -0
  30. package/dist/examples/web_socket_client/src/messages.js +3 -0
  31. package/dist/examples/web_socket_client/src/messages.js.map +1 -0
  32. package/dist/examples/web_socket_client/src/receiver.d.ts +3 -0
  33. package/dist/examples/web_socket_client/src/receiver.d.ts.map +1 -0
  34. package/dist/examples/web_socket_client/src/receiver.js +8 -0
  35. package/dist/examples/web_socket_client/src/receiver.js.map +1 -0
  36. package/dist/examples/web_socket_client/src/requests.d.ts +4 -0
  37. package/dist/examples/web_socket_client/src/requests.d.ts.map +1 -0
  38. package/dist/examples/web_socket_client/src/requests.js +32 -0
  39. package/dist/examples/web_socket_client/src/requests.js.map +1 -0
  40. package/dist/index.d.ts +11 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +11 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/interfaces.d.ts +24 -0
  45. package/dist/interfaces.d.ts.map +1 -0
  46. package/dist/interfaces.js +7 -0
  47. package/dist/interfaces.js.map +1 -0
  48. package/dist/logger.d.ts +9 -0
  49. package/dist/logger.d.ts.map +1 -0
  50. package/dist/logger.js +11 -0
  51. package/dist/logger.js.map +1 -0
  52. package/dist/receiver.d.ts +12 -0
  53. package/dist/receiver.d.ts.map +1 -0
  54. package/dist/receiver.js +49 -0
  55. package/dist/receiver.js.map +1 -0
  56. package/dist/sender.d.ts +26 -0
  57. package/dist/sender.d.ts.map +1 -0
  58. package/dist/sender.js +135 -0
  59. package/dist/sender.js.map +1 -0
  60. package/dist/src/client.d.ts +8 -0
  61. package/dist/src/client.d.ts.map +1 -0
  62. package/dist/src/client.js +15 -0
  63. package/dist/src/client.js.map +1 -0
  64. package/dist/src/config.d.ts +5 -0
  65. package/dist/src/config.d.ts.map +1 -0
  66. package/dist/src/config.js +2 -0
  67. package/dist/src/config.js.map +1 -0
  68. package/dist/src/index.d.ts +11 -0
  69. package/dist/src/index.d.ts.map +1 -0
  70. package/dist/src/index.js +11 -0
  71. package/dist/src/index.js.map +1 -0
  72. package/dist/src/interfaces.d.ts +24 -0
  73. package/dist/src/interfaces.d.ts.map +1 -0
  74. package/dist/src/interfaces.js +7 -0
  75. package/dist/src/interfaces.js.map +1 -0
  76. package/dist/src/logger.d.ts +9 -0
  77. package/dist/src/logger.d.ts.map +1 -0
  78. package/dist/src/logger.js +11 -0
  79. package/dist/src/logger.js.map +1 -0
  80. package/dist/src/receiver.d.ts +12 -0
  81. package/dist/src/receiver.d.ts.map +1 -0
  82. package/dist/src/receiver.js +49 -0
  83. package/dist/src/receiver.js.map +1 -0
  84. package/dist/src/sender.d.ts +26 -0
  85. package/dist/src/sender.d.ts.map +1 -0
  86. package/dist/src/sender.js +135 -0
  87. package/dist/src/sender.js.map +1 -0
  88. package/dist/src/transporter/transporter_http.d.ts +6 -0
  89. package/dist/src/transporter/transporter_http.d.ts.map +1 -0
  90. package/dist/src/transporter/transporter_http.js +30 -0
  91. package/dist/src/transporter/transporter_http.js.map +1 -0
  92. package/dist/src/transporter/transporter_websocket.d.ts +17 -0
  93. package/dist/src/transporter/transporter_websocket.d.ts.map +1 -0
  94. package/dist/src/transporter/transporter_websocket.js +93 -0
  95. package/dist/src/transporter/transporter_websocket.js.map +1 -0
  96. package/dist/src/user_error.d.ts +4 -0
  97. package/dist/src/user_error.d.ts.map +1 -0
  98. package/dist/src/user_error.js +11 -0
  99. package/dist/src/user_error.js.map +1 -0
  100. package/dist/src/util.d.ts +9 -0
  101. package/dist/src/util.d.ts.map +1 -0
  102. package/dist/src/util.js +42 -0
  103. package/dist/src/util.js.map +1 -0
  104. package/dist/transporter/transporter_http.d.ts +6 -0
  105. package/dist/transporter/transporter_http.d.ts.map +1 -0
  106. package/dist/transporter/transporter_http.js +30 -0
  107. package/dist/transporter/transporter_http.js.map +1 -0
  108. package/dist/transporter/transporter_websocket.d.ts +17 -0
  109. package/dist/transporter/transporter_websocket.d.ts.map +1 -0
  110. package/dist/transporter/transporter_websocket.js +93 -0
  111. package/dist/transporter/transporter_websocket.js.map +1 -0
  112. package/dist/user_error.d.ts +4 -0
  113. package/dist/user_error.d.ts.map +1 -0
  114. package/dist/user_error.js +11 -0
  115. package/dist/user_error.js.map +1 -0
  116. package/dist/util.d.ts +9 -0
  117. package/dist/util.d.ts.map +1 -0
  118. package/dist/util.js +42 -0
  119. package/dist/util.js.map +1 -0
  120. package/examples/http_client/package.json +20 -0
  121. package/examples/http_client/src/main.ts +59 -0
  122. package/examples/http_client/src/messages.ts +9 -0
  123. package/examples/http_client/src/requests.ts +64 -0
  124. package/examples/http_client/tsconfig.json +44 -0
  125. package/examples/web_socket_client/package.json +20 -0
  126. package/examples/web_socket_client/src/main.ts +72 -0
  127. package/examples/web_socket_client/src/messages.ts +22 -0
  128. package/examples/web_socket_client/src/receiver.ts +8 -0
  129. package/examples/web_socket_client/src/requests.ts +51 -0
  130. package/examples/web_socket_client/tsconfig.json +44 -0
  131. package/package.json +36 -0
  132. package/pnpm-workspace.yaml +5 -0
  133. package/readme.md +49 -0
  134. package/src/client.ts +17 -0
  135. package/src/config.ts +4 -0
  136. package/src/index.ts +13 -0
  137. package/src/interfaces.ts +31 -0
  138. package/src/logger.ts +18 -0
  139. package/src/receiver.ts +56 -0
  140. package/src/sender.ts +203 -0
  141. package/src/transporter/transporter_http.ts +37 -0
  142. package/src/transporter/transporter_websocket.ts +115 -0
  143. package/src/user_error.ts +21 -0
  144. package/src/util.ts +58 -0
  145. package/tsconfig.json +44 -0
@@ -0,0 +1,37 @@
1
+ import type { Sender } from '../sender.js';
2
+
3
+ export class HTTPTransporter {
4
+ private sender: Sender;
5
+
6
+ constructor(s: Sender, method: string, url: string) {
7
+ this.sender = s;
8
+
9
+ this.sender.setSendFunc(async (data: Uint8Array): Promise<void> => {
10
+ const controller = new AbortController();
11
+ const timeout = setTimeout(() => controller.abort(), 20000);
12
+
13
+ try {
14
+ const response = await fetch(url, {
15
+ method: method,
16
+ body: data as unknown as BodyInit,
17
+ signal: controller.signal,
18
+ headers: {
19
+ 'Content-Type': 'application/octet-stream',
20
+ },
21
+ });
22
+
23
+ // Check for transporter errors
24
+ if (!response.ok) {
25
+ throw new Error(
26
+ `received non ok status ${response.status} ${response.statusText}`,
27
+ );
28
+ }
29
+
30
+ // Let sender handle the response routing
31
+ this.sender.handle(await response.bytes());
32
+ } finally {
33
+ clearTimeout(timeout);
34
+ }
35
+ });
36
+ }
37
+ }
@@ -0,0 +1,115 @@
1
+ import { logger } from '../logger.js';
2
+ import type { Receiver } from '../receiver.js';
3
+
4
+ export interface WebSocketOptions {
5
+ // Timeout for the initial connection attempt, default is 20 seconds.
6
+ connectionTimeout?: number;
7
+
8
+ // When the connection actually opens.
9
+ onOpen?: () => void;
10
+ }
11
+
12
+ export class WebSocketTransporter {
13
+ private conn: WebSocket | null = null;
14
+ private receiver: Receiver;
15
+ private options: WebSocketOptions;
16
+ private connected: boolean = false;
17
+ private queue: Uint8Array[] = [];
18
+
19
+ constructor(receiver: Receiver, options: WebSocketOptions) {
20
+ this.receiver = receiver;
21
+ this.options = options;
22
+ }
23
+
24
+ /// Will start a connection to the server. Will not block until the connection is open.
25
+ ///
26
+ /// All things sent before the connection is open are queued, so feel free to send already after calling connect.
27
+ public connect(url: string) {
28
+ if (this.connected || this.conn) {
29
+ return;
30
+ }
31
+
32
+ // Queue outgoing messages until connection is open
33
+ this.receiver.setSendFunc(async (data: Uint8Array): Promise<void> => {
34
+ if (this.connected && this.conn?.readyState === WebSocket.OPEN) {
35
+ this.conn.send(data as any); // TODO: Find out if this is actually fine xd
36
+ } else {
37
+ this.queue.push(data);
38
+ }
39
+ });
40
+
41
+ // Add a timeout to make sure the connection actually happens
42
+ const timeout = setTimeout(() => {
43
+ if (this.conn?.readyState !== WebSocket.OPEN) {
44
+ this.close('connection timeout');
45
+ }
46
+ }, this.options.connectionTimeout ?? 20000);
47
+
48
+ // Init WebSocket to open the actual connection
49
+ this.conn = new WebSocket(url);
50
+ this.conn.binaryType = 'arraybuffer';
51
+
52
+ this.conn.onopen = () => {
53
+ if (!this.conn) return;
54
+
55
+ clearTimeout(timeout);
56
+ this.connected = true;
57
+
58
+ // Call onOpen callback
59
+ this.options.onOpen?.();
60
+
61
+ // Flush queue
62
+ while (this.queue.length > 0) {
63
+ const data = this.queue.shift();
64
+ if (data) {
65
+ this.conn.send(data as any);
66
+ }
67
+ }
68
+ };
69
+
70
+ // When there is an error, we immediately disconnect
71
+ this.conn.onerror = () => {
72
+ if (this.conn) {
73
+ this.close('websocket error');
74
+ }
75
+ };
76
+
77
+ // Even on a close, we want to quickly close the thingy to notify the event handler for onError and update internal state
78
+ this.conn.onclose = (event) => {
79
+ if (this.conn) {
80
+ this.close(
81
+ `websocket connection closed: ${event.code} ${event.reason}`,
82
+ );
83
+ }
84
+ };
85
+
86
+ // Forward messages to the receiver
87
+ this.conn.onmessage = (event) => {
88
+ if (event.data instanceof ArrayBuffer) {
89
+ this.receiver.handle(new Uint8Array(event.data));
90
+ } else {
91
+ // If we get this, the browser is doing something weird
92
+ logger.error('wrong message type received:', typeof event.data);
93
+ this.close('wrong kind of message received');
94
+ }
95
+ };
96
+ }
97
+
98
+ /// Closes the connection to the server. Will not throw if the connection is already closed.
99
+ public close(reason: string = 'Connection closed'): void {
100
+ const wasConnected = this.connected || !!this.conn;
101
+ this.connected = false;
102
+ if (this.conn) {
103
+ const c = this.conn;
104
+ this.conn = null;
105
+ c.close(1000, reason);
106
+ }
107
+ if (wasConnected) {
108
+ this.receiver.getConfig().errorHandler(new Error(reason));
109
+ }
110
+ }
111
+
112
+ public isConnected(): boolean {
113
+ return this.connected;
114
+ }
115
+ }
@@ -0,0 +1,21 @@
1
+ export class UserError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+
5
+ this.name = 'UserError';
6
+
7
+ if (
8
+ typeof (Error as ErrorConstructor & { captureStackTrace?: unknown })
9
+ .captureStackTrace === 'function'
10
+ ) {
11
+ (
12
+ Error as ErrorConstructor & {
13
+ captureStackTrace: (
14
+ targetObject: object,
15
+ constructorOpt?: Function,
16
+ ) => void;
17
+ }
18
+ ).captureStackTrace(this, UserError);
19
+ }
20
+ }
21
+ }
package/src/util.ts ADDED
@@ -0,0 +1,58 @@
1
+ import { decode, encode } from '@msgpack/msgpack';
2
+
3
+ // Creates a promise that can be resolved or rejected externally. This is useful for creating a promise that can be resolved or rejected at a later time, such as when waiting for an event to occur.
4
+ export function newPromiseWithResolver<T>(): {
5
+ resolve: (value: T | PromiseLike<T>) => void;
6
+ reject: (reason?: any) => void;
7
+ promise: Promise<T>;
8
+ } {
9
+ let resolve!: (value: T | PromiseLike<T>) => void;
10
+ let reject!: (reason?: any) => void;
11
+
12
+ const promise = new Promise<T>((res, rej) => {
13
+ resolve = res;
14
+ reject = rej;
15
+ });
16
+
17
+ return { resolve, reject, promise };
18
+ }
19
+
20
+ // Helper to create a timeout promise
21
+ export function withTimeout<T>(
22
+ promise: Promise<T>,
23
+ timeoutMs: number,
24
+ onTimeout?: () => void,
25
+ ): Promise<T> {
26
+ let timeoutId: ReturnType<typeof setTimeout>;
27
+ const timeoutPromise = new Promise<T>((_, reject) => {
28
+ timeoutId = setTimeout(() => {
29
+ onTimeout?.();
30
+ reject(
31
+ new Error(
32
+ `waiting for response timed out after ${timeoutMs}ms`,
33
+ ),
34
+ );
35
+ }, timeoutMs);
36
+ });
37
+
38
+ return Promise.race([
39
+ promise.finally(() => clearTimeout(timeoutId)),
40
+ timeoutPromise,
41
+ ]);
42
+ }
43
+
44
+ export function marshalRequestData<RQ>(req: RQ): Uint8Array {
45
+ try {
46
+ return encode(req);
47
+ } catch (error) {
48
+ throw new Error(`failed to marshal request data: ${error}`);
49
+ }
50
+ }
51
+
52
+ export function unmarshalResponseData<RS>(respBytes: Uint8Array): RS {
53
+ try {
54
+ return decode(respBytes) as RS;
55
+ } catch (error) {
56
+ throw new Error(`failed to unmarshal response data: ${error}`);
57
+ }
58
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ // Visit https://aka.ms/tsconfig to read more about this file
3
+ "compilerOptions": {
4
+ // File Layout
5
+ "rootDir": ".",
6
+ "outDir": "./dist",
7
+
8
+ // Environment Settings
9
+ // See also https://aka.ms/tsconfig/module
10
+ "module": "nodenext",
11
+ "target": "esnext",
12
+ "types": ["node"],
13
+ // For nodejs:
14
+ // "lib": ["esnext"],
15
+ // "types": ["node"],
16
+ // and npm install -D @types/node
17
+
18
+ // Other Outputs
19
+ "sourceMap": true,
20
+ "declaration": true,
21
+ "declarationMap": true,
22
+
23
+ // Stricter Typechecking Options
24
+ "noUncheckedIndexedAccess": true,
25
+ "exactOptionalPropertyTypes": true,
26
+
27
+ // Style Options
28
+ // "noImplicitReturns": true,
29
+ // "noImplicitOverride": true,
30
+ // "noUnusedLocals": true,
31
+ // "noUnusedParameters": true,
32
+ // "noFallthroughCasesInSwitch": true,
33
+ // "noPropertyAccessFromIndexSignature": true,
34
+
35
+ // Recommended Options
36
+ "strict": true,
37
+ "jsx": "react-jsx",
38
+ "verbatimModuleSyntax": true,
39
+ "isolatedModules": true,
40
+ "noUncheckedSideEffectImports": true,
41
+ "moduleDetection": "force",
42
+ "skipLibCheck": true,
43
+ },
44
+ }