@proj-airi/server-sdk 0.6.0 → 0.6.1

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/dist/index.d.mts CHANGED
@@ -1,34 +1,36 @@
1
- import { WebSocketEvents, WebSocketBaseEvent, WebSocketEvent } from '@proj-airi/server-shared/types';
1
+ import { WebSocketBaseEvent, WebSocketEvent, WebSocketEvents } from "@proj-airi/server-shared/types";
2
2
 
3
+ //#region src/client.d.ts
3
4
  interface ClientOptions<C = undefined> {
4
- url?: string;
5
- name: string;
6
- possibleEvents?: Array<(keyof WebSocketEvents<C>)>;
7
- token?: string;
8
- onError?: (error: unknown) => void;
9
- onClose?: () => void;
10
- autoConnect?: boolean;
11
- autoReconnect?: boolean;
5
+ url?: string;
6
+ name: string;
7
+ possibleEvents?: Array<(keyof WebSocketEvents<C>)>;
8
+ token?: string;
9
+ onError?: (error: unknown) => void;
10
+ onClose?: () => void;
11
+ autoConnect?: boolean;
12
+ autoReconnect?: boolean;
12
13
  }
13
14
  declare class Client<C = undefined> {
14
- private connected;
15
- private opts;
16
- private websocket;
17
- private eventListeners;
18
- private reconnectAttempts;
19
- private shouldClose;
20
- constructor(options: ClientOptions<C>);
21
- retryWithExponentialBackoff(fn: () => void | Promise<void>, attempts?: number, maxAttempts?: number): Promise<void>;
22
- tryReconnectWithExponentialBackoff(): Promise<void>;
23
- private _connect;
24
- connect(): Promise<void>;
25
- private tryAnnounce;
26
- private tryAuthenticate;
27
- private handleMessage;
28
- onEvent<E extends keyof WebSocketEvents<C>>(event: E, callback: (data: WebSocketBaseEvent<E, WebSocketEvents<C>[E]>) => void | Promise<void>): void;
29
- send(data: WebSocketEvent<C>): void;
30
- sendRaw(data: string | ArrayBufferLike | ArrayBufferView): void;
31
- close(): void;
15
+ private connected;
16
+ private opts;
17
+ private websocket;
18
+ private eventListeners;
19
+ private reconnectAttempts;
20
+ private shouldClose;
21
+ constructor(options: ClientOptions<C>);
22
+ retryWithExponentialBackoff(fn: () => void | Promise<void>, attempts?: number, maxAttempts?: number): Promise<void>;
23
+ tryReconnectWithExponentialBackoff(): Promise<void>;
24
+ private _connect;
25
+ connect(): Promise<void>;
26
+ private tryAnnounce;
27
+ private tryAuthenticate;
28
+ private handleMessage;
29
+ onEvent<E extends keyof WebSocketEvents<C>>(event: E, callback: (data: WebSocketBaseEvent<E, WebSocketEvents<C>[E]>) => void | Promise<void>): void;
30
+ send(data: WebSocketEvent<C>): void;
31
+ sendRaw(data: string | ArrayBufferLike | ArrayBufferView): void;
32
+ close(): void;
32
33
  }
33
-
34
- export { Client, type ClientOptions };
34
+ //#endregion
35
+ export { Client, ClientOptions };
36
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,167 +1,151 @@
1
- import WebSocket from 'crossws/websocket';
2
- import { defu } from 'defu';
1
+ import WebSocket from "crossws/websocket";
2
+ import { defu } from "defu";
3
3
 
4
+ //#region src/utils/concurrency.ts
4
5
  function sleep(ms) {
5
- return new Promise((resolve) => setTimeout(resolve, ms));
6
+ return new Promise((resolve) => setTimeout(resolve, ms));
6
7
  }
7
8
 
8
- class Client {
9
- connected = false;
10
- opts;
11
- websocket;
12
- eventListeners = /* @__PURE__ */ new Map();
13
- reconnectAttempts = 0;
14
- shouldClose = false;
15
- constructor(options) {
16
- this.opts = defu(
17
- options,
18
- {
19
- url: "ws://localhost:6121/ws",
20
- possibleEvents: [],
21
- onError: () => {
22
- },
23
- onClose: () => {
24
- },
25
- autoConnect: true,
26
- autoReconnect: true
27
- }
28
- );
29
- if (this.opts.autoConnect) {
30
- try {
31
- this.connect();
32
- } catch (err) {
33
- console.error(err);
34
- }
35
- }
36
- }
37
- async retryWithExponentialBackoff(fn, attempts = 0, maxAttempts = -1) {
38
- if (maxAttempts !== -1 && attempts >= maxAttempts) {
39
- console.error(`Maximum retry attempts (${maxAttempts}) reached`);
40
- return;
41
- }
42
- try {
43
- await fn();
44
- } catch (err) {
45
- console.error("Encountered an error when retrying", err);
46
- await sleep(2 ** attempts * 1e3);
47
- await this.retryWithExponentialBackoff(fn, attempts++, maxAttempts);
48
- }
49
- }
50
- async tryReconnectWithExponentialBackoff() {
51
- await this.retryWithExponentialBackoff(() => this._connect(), this.reconnectAttempts);
52
- }
53
- _connect() {
54
- return new Promise((resolve, reject) => {
55
- if (this.shouldClose) {
56
- resolve();
57
- return;
58
- }
59
- if (this.connected) {
60
- resolve();
61
- return;
62
- }
63
- this.websocket = new WebSocket(this.opts.url);
64
- this.onEvent("module:authenticated", async (event) => {
65
- const auth = event.data.authenticated;
66
- if (!auth) {
67
- this.retryWithExponentialBackoff(() => this.tryAuthenticate());
68
- } else {
69
- this.tryAnnounce();
70
- }
71
- });
72
- this.websocket.onerror = (event) => {
73
- this.opts.onError?.(event);
74
- if ("error" in event && event.error instanceof Error) {
75
- if (event.error.message === "Received network error or non-101 status code.") {
76
- this.connected = false;
77
- if (!this.opts.autoReconnect) {
78
- this.opts.onError?.(event);
79
- this.opts.onClose?.();
80
- reject(event.error);
81
- return;
82
- }
83
- reject(event.error);
84
- }
85
- }
86
- };
87
- this.websocket.onclose = () => {
88
- this.opts.onClose?.();
89
- this.connected = false;
90
- if (!this.opts.autoReconnect) {
91
- this.opts.onClose?.();
92
- } else {
93
- this.tryReconnectWithExponentialBackoff();
94
- }
95
- };
96
- this.websocket.onmessage = (event) => {
97
- this.handleMessage(event);
98
- };
99
- this.websocket.onopen = () => {
100
- this.reconnectAttempts = 0;
101
- if (this.opts.token) {
102
- this.tryAuthenticate();
103
- } else {
104
- this.tryAnnounce();
105
- }
106
- this.connected = true;
107
- resolve();
108
- };
109
- });
110
- }
111
- async connect() {
112
- await this.tryReconnectWithExponentialBackoff();
113
- }
114
- tryAnnounce() {
115
- this.send({
116
- type: "module:announce",
117
- data: {
118
- name: this.opts.name,
119
- possibleEvents: this.opts.possibleEvents
120
- }
121
- });
122
- }
123
- tryAuthenticate() {
124
- if (this.opts.token) {
125
- this.send({ type: "module:authenticate", data: { token: this.opts.token || "" } });
126
- }
127
- }
128
- async handleMessage(event) {
129
- try {
130
- const data = JSON.parse(event.data);
131
- const listeners = this.eventListeners.get(data.type);
132
- if (!listeners)
133
- return;
134
- for (const listener of listeners)
135
- await listener(data);
136
- } catch (err) {
137
- console.error("Failed to parse message:", err);
138
- this.opts.onError?.(err);
139
- }
140
- }
141
- onEvent(event, callback) {
142
- if (!this.eventListeners.get(event)) {
143
- this.eventListeners.set(event, []);
144
- }
145
- const listeners = this.eventListeners.get(event);
146
- if (!listeners) {
147
- return;
148
- }
149
- listeners.push(callback);
150
- this.eventListeners.set(event, listeners);
151
- }
152
- send(data) {
153
- this.websocket?.send(JSON.stringify(data));
154
- }
155
- sendRaw(data) {
156
- this.websocket?.send(data);
157
- }
158
- close() {
159
- this.shouldClose = true;
160
- if (this.connected && this.websocket) {
161
- this.websocket.close();
162
- this.connected = false;
163
- }
164
- }
165
- }
9
+ //#endregion
10
+ //#region src/client.ts
11
+ var Client = class {
12
+ connected = false;
13
+ opts;
14
+ websocket;
15
+ eventListeners = /* @__PURE__ */ new Map();
16
+ reconnectAttempts = 0;
17
+ shouldClose = false;
18
+ constructor(options) {
19
+ this.opts = defu(options, {
20
+ url: "ws://localhost:6121/ws",
21
+ possibleEvents: [],
22
+ onError: () => {},
23
+ onClose: () => {},
24
+ autoConnect: true,
25
+ autoReconnect: true
26
+ });
27
+ if (this.opts.autoConnect) try {
28
+ this.connect();
29
+ } catch (err) {
30
+ console.error(err);
31
+ }
32
+ }
33
+ async retryWithExponentialBackoff(fn, attempts = 0, maxAttempts = -1) {
34
+ if (maxAttempts !== -1 && attempts >= maxAttempts) {
35
+ console.error(`Maximum retry attempts (${maxAttempts}) reached`);
36
+ return;
37
+ }
38
+ try {
39
+ await fn();
40
+ } catch (err) {
41
+ console.error("Encountered an error when retrying", err);
42
+ await sleep(2 ** attempts * 1e3);
43
+ await this.retryWithExponentialBackoff(fn, attempts++, maxAttempts);
44
+ }
45
+ }
46
+ async tryReconnectWithExponentialBackoff() {
47
+ await this.retryWithExponentialBackoff(() => this._connect(), this.reconnectAttempts);
48
+ }
49
+ _connect() {
50
+ return new Promise((resolve, reject) => {
51
+ if (this.shouldClose) {
52
+ resolve();
53
+ return;
54
+ }
55
+ if (this.connected) {
56
+ resolve();
57
+ return;
58
+ }
59
+ this.websocket = new WebSocket(this.opts.url);
60
+ this.onEvent("module:authenticated", async (event) => {
61
+ const auth = event.data.authenticated;
62
+ if (!auth) this.retryWithExponentialBackoff(() => this.tryAuthenticate());
63
+ else this.tryAnnounce();
64
+ });
65
+ this.websocket.onerror = (event) => {
66
+ this.opts.onError?.(event);
67
+ if ("error" in event && event.error instanceof Error) {
68
+ if (event.error.message === "Received network error or non-101 status code.") {
69
+ this.connected = false;
70
+ if (!this.opts.autoReconnect) {
71
+ this.opts.onError?.(event);
72
+ this.opts.onClose?.();
73
+ reject(event.error);
74
+ return;
75
+ }
76
+ reject(event.error);
77
+ }
78
+ }
79
+ };
80
+ this.websocket.onclose = () => {
81
+ this.opts.onClose?.();
82
+ this.connected = false;
83
+ if (!this.opts.autoReconnect) this.opts.onClose?.();
84
+ else this.tryReconnectWithExponentialBackoff();
85
+ };
86
+ this.websocket.onmessage = (event) => {
87
+ this.handleMessage(event);
88
+ };
89
+ this.websocket.onopen = () => {
90
+ this.reconnectAttempts = 0;
91
+ if (this.opts.token) this.tryAuthenticate();
92
+ else this.tryAnnounce();
93
+ this.connected = true;
94
+ resolve();
95
+ };
96
+ });
97
+ }
98
+ async connect() {
99
+ await this.tryReconnectWithExponentialBackoff();
100
+ }
101
+ tryAnnounce() {
102
+ this.send({
103
+ type: "module:announce",
104
+ data: {
105
+ name: this.opts.name,
106
+ possibleEvents: this.opts.possibleEvents
107
+ }
108
+ });
109
+ }
110
+ tryAuthenticate() {
111
+ if (this.opts.token) this.send({
112
+ type: "module:authenticate",
113
+ data: { token: this.opts.token || "" }
114
+ });
115
+ }
116
+ async handleMessage(event) {
117
+ try {
118
+ const data = JSON.parse(event.data);
119
+ const listeners = this.eventListeners.get(data.type);
120
+ if (!listeners) return;
121
+ for (const listener of listeners) await listener(data);
122
+ } catch (err) {
123
+ console.error("Failed to parse message:", err);
124
+ this.opts.onError?.(err);
125
+ }
126
+ }
127
+ onEvent(event, callback) {
128
+ if (!this.eventListeners.get(event)) this.eventListeners.set(event, []);
129
+ const listeners = this.eventListeners.get(event);
130
+ if (!listeners) return;
131
+ listeners.push(callback);
132
+ this.eventListeners.set(event, listeners);
133
+ }
134
+ send(data) {
135
+ this.websocket?.send(JSON.stringify(data));
136
+ }
137
+ sendRaw(data) {
138
+ this.websocket?.send(data);
139
+ }
140
+ close() {
141
+ this.shouldClose = true;
142
+ if (this.connected && this.websocket) {
143
+ this.websocket.close();
144
+ this.connected = false;
145
+ }
146
+ }
147
+ };
166
148
 
149
+ //#endregion
167
150
  export { Client };
151
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["ms: number","options: ClientOptions<C>","fn: () => void | Promise<void>","event: any","event: E","callback: (data: WebSocketBaseEvent<E, WebSocketEvents<C>[E]>) => void | Promise<void>","data: WebSocketEvent<C>","data: string | ArrayBufferLike | ArrayBufferView"],"sources":["../src/utils/concurrency.ts","../src/client.ts"],"sourcesContent":["export function sleep(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n","import type { WebSocketBaseEvent, WebSocketEvent, WebSocketEvents } from '@proj-airi/server-shared/types'\n\nimport WebSocket from 'crossws/websocket'\nimport { defu } from 'defu'\n\nimport { sleep } from './utils'\n\nexport interface ClientOptions<C = undefined> {\n url?: string\n name: string\n possibleEvents?: Array<(keyof WebSocketEvents<C>)>\n token?: string\n onError?: (error: unknown) => void\n onClose?: () => void\n autoConnect?: boolean\n autoReconnect?: boolean\n}\n\nexport class Client<C = undefined> {\n private connected = false\n private opts: Required<ClientOptions<C>>\n private websocket: WebSocket | undefined\n private eventListeners: Map<keyof WebSocketEvents<C>, Array<(data: WebSocketBaseEvent<any, any>) => void | Promise<void>>> = new Map()\n\n private reconnectAttempts = 0\n private shouldClose = false\n\n constructor(options: ClientOptions<C>) {\n this.opts = defu<Required<ClientOptions<C>>, Required<Omit<ClientOptions<C>, 'name' | 'token'>>[]>(\n options,\n {\n url: 'ws://localhost:6121/ws',\n possibleEvents: [],\n onError: () => { },\n onClose: () => { },\n autoConnect: true,\n autoReconnect: true,\n },\n )\n\n if (this.opts.autoConnect) {\n try {\n this.connect()\n }\n catch (err) {\n console.error(err)\n }\n }\n }\n\n async retryWithExponentialBackoff(fn: () => void | Promise<void>, attempts = 0, maxAttempts = -1) {\n if (maxAttempts !== -1 && attempts >= maxAttempts) {\n console.error(`Maximum retry attempts (${maxAttempts}) reached`)\n return\n }\n\n try {\n await fn()\n }\n catch (err) {\n console.error('Encountered an error when retrying', err)\n await sleep(2 ** attempts * 1000)\n await this.retryWithExponentialBackoff(fn, attempts++, maxAttempts)\n }\n }\n\n async tryReconnectWithExponentialBackoff() {\n await this.retryWithExponentialBackoff(() => this._connect(), this.reconnectAttempts)\n }\n\n private _connect() {\n return new Promise<void>((resolve, reject) => {\n if (this.shouldClose) {\n resolve()\n return\n }\n\n if (this.connected) {\n resolve()\n return\n }\n\n this.websocket = new WebSocket(this.opts.url)\n\n this.onEvent('module:authenticated', async (event) => {\n const auth = event.data.authenticated\n if (!auth) {\n this.retryWithExponentialBackoff(() => this.tryAuthenticate())\n }\n else {\n this.tryAnnounce()\n }\n })\n\n this.websocket.onerror = (event) => {\n this.opts.onError?.(event)\n\n if ('error' in event && event.error instanceof Error) {\n if (event.error.message === 'Received network error or non-101 status code.') {\n this.connected = false\n\n if (!this.opts.autoReconnect) {\n this.opts.onError?.(event)\n this.opts.onClose?.()\n reject(event.error)\n return\n }\n\n reject(event.error)\n }\n }\n }\n\n this.websocket.onclose = () => {\n this.opts.onClose?.()\n this.connected = false\n\n if (!this.opts.autoReconnect) {\n this.opts.onClose?.()\n }\n else {\n this.tryReconnectWithExponentialBackoff()\n }\n }\n\n this.websocket.onmessage = (event) => {\n this.handleMessage(event)\n }\n\n this.websocket.onopen = () => {\n this.reconnectAttempts = 0\n\n if (this.opts.token) {\n this.tryAuthenticate()\n }\n else {\n this.tryAnnounce()\n }\n\n this.connected = true\n\n resolve()\n }\n })\n }\n\n async connect() {\n await this.tryReconnectWithExponentialBackoff()\n }\n\n private tryAnnounce() {\n this.send({\n type: 'module:announce',\n data: {\n name: this.opts.name,\n possibleEvents: this.opts.possibleEvents,\n },\n })\n }\n\n private tryAuthenticate() {\n if (this.opts.token) {\n this.send({ type: 'module:authenticate', data: { token: this.opts.token || '' } })\n }\n }\n\n private async handleMessage(event: any) {\n try {\n const data = JSON.parse(event.data) as WebSocketEvent<C>\n const listeners = this.eventListeners.get(data.type)\n if (!listeners)\n return\n\n for (const listener of listeners)\n await listener(data)\n }\n catch (err) {\n console.error('Failed to parse message:', err)\n this.opts.onError?.(err)\n }\n }\n\n onEvent<E extends keyof WebSocketEvents<C>>(\n event: E,\n callback: (data: WebSocketBaseEvent<E, WebSocketEvents<C>[E]>) => void | Promise<void>,\n ): void {\n if (!this.eventListeners.get(event)) {\n this.eventListeners.set(event, [])\n }\n\n const listeners = this.eventListeners.get(event)\n if (!listeners) {\n return\n }\n\n listeners.push(callback as unknown as (data: WebSocketBaseEvent<E, WebSocketEvents<C>[E]>) => void | Promise<void>)\n this.eventListeners.set(event, listeners)\n }\n\n send(data: WebSocketEvent<C>): void {\n this.websocket?.send(JSON.stringify(data))\n }\n\n sendRaw(data: string | ArrayBufferLike | ArrayBufferView): void {\n this.websocket?.send(data)\n }\n\n close(): void {\n this.shouldClose = true\n\n if (this.connected && this.websocket) {\n this.websocket.close()\n this.connected = false\n }\n }\n}\n"],"mappings":";;;;AAAA,SAAgB,MAAMA,IAAY;AAChC,QAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAG;AACtD;;;;ACgBD,IAAa,SAAb,MAAmC;CACjC,AAAQ,YAAY;CACpB,AAAQ;CACR,AAAQ;CACR,AAAQ,iCAAqH,IAAI;CAEjI,AAAQ,oBAAoB;CAC5B,AAAQ,cAAc;CAEtB,YAAYC,SAA2B;AACrC,OAAK,OAAO,KACV,SACA;GACE,KAAK;GACL,gBAAgB,CAAE;GAClB,SAAS,MAAM,CAAG;GAClB,SAAS,MAAM,CAAG;GAClB,aAAa;GACb,eAAe;EAChB,EACF;AAED,MAAI,KAAK,KAAK,YACZ,KAAI;AACF,QAAK,SAAS;EACf,SACM,KAAK;AACV,WAAQ,MAAM,IAAI;EACnB;CAEJ;CAED,MAAM,4BAA4BC,IAAgC,WAAW,GAAG,cAAc,IAAI;AAChG,MAAI,gBAAgB,MAAM,YAAY,aAAa;AACjD,WAAQ,OAAO,0BAA0B,YAAY,WAAW;AAChE;EACD;AAED,MAAI;AACF,SAAM,IAAI;EACX,SACM,KAAK;AACV,WAAQ,MAAM,sCAAsC,IAAI;AACxD,SAAM,MAAM,KAAK,WAAW,IAAK;AACjC,SAAM,KAAK,4BAA4B,IAAI,YAAY,YAAY;EACpE;CACF;CAED,MAAM,qCAAqC;AACzC,QAAM,KAAK,4BAA4B,MAAM,KAAK,UAAU,EAAE,KAAK,kBAAkB;CACtF;CAED,AAAQ,WAAW;AACjB,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,OAAI,KAAK,aAAa;AACpB,aAAS;AACT;GACD;AAED,OAAI,KAAK,WAAW;AAClB,aAAS;AACT;GACD;AAED,QAAK,YAAY,IAAI,UAAU,KAAK,KAAK;AAEzC,QAAK,QAAQ,wBAAwB,OAAO,UAAU;IACpD,MAAM,OAAO,MAAM,KAAK;AACxB,SAAK,KACH,MAAK,4BAA4B,MAAM,KAAK,iBAAiB,CAAC;QAG9D,MAAK,aAAa;GAErB,EAAC;AAEF,QAAK,UAAU,UAAU,CAAC,UAAU;AAClC,SAAK,KAAK,UAAU,MAAM;AAE1B,QAAI,WAAW,SAAS,MAAM,iBAAiB,OAC7C;SAAI,MAAM,MAAM,YAAY,kDAAkD;AAC5E,WAAK,YAAY;AAEjB,WAAK,KAAK,KAAK,eAAe;AAC5B,YAAK,KAAK,UAAU,MAAM;AAC1B,YAAK,KAAK,WAAW;AACrB,cAAO,MAAM,MAAM;AACnB;MACD;AAED,aAAO,MAAM,MAAM;KACpB;;GAEJ;AAED,QAAK,UAAU,UAAU,MAAM;AAC7B,SAAK,KAAK,WAAW;AACrB,SAAK,YAAY;AAEjB,SAAK,KAAK,KAAK,cACb,MAAK,KAAK,WAAW;QAGrB,MAAK,oCAAoC;GAE5C;AAED,QAAK,UAAU,YAAY,CAAC,UAAU;AACpC,SAAK,cAAc,MAAM;GAC1B;AAED,QAAK,UAAU,SAAS,MAAM;AAC5B,SAAK,oBAAoB;AAEzB,QAAI,KAAK,KAAK,MACZ,MAAK,iBAAiB;QAGtB,MAAK,aAAa;AAGpB,SAAK,YAAY;AAEjB,aAAS;GACV;EACF;CACF;CAED,MAAM,UAAU;AACd,QAAM,KAAK,oCAAoC;CAChD;CAED,AAAQ,cAAc;AACpB,OAAK,KAAK;GACR,MAAM;GACN,MAAM;IACJ,MAAM,KAAK,KAAK;IAChB,gBAAgB,KAAK,KAAK;GAC3B;EACF,EAAC;CACH;CAED,AAAQ,kBAAkB;AACxB,MAAI,KAAK,KAAK,MACZ,MAAK,KAAK;GAAE,MAAM;GAAuB,MAAM,EAAE,OAAO,KAAK,KAAK,SAAS,GAAI;EAAE,EAAC;CAErF;CAED,MAAc,cAAcC,OAAY;AACtC,MAAI;GACF,MAAM,OAAO,KAAK,MAAM,MAAM,KAAK;GACnC,MAAM,YAAY,KAAK,eAAe,IAAI,KAAK,KAAK;AACpD,QAAK,UACH;AAEF,QAAK,MAAM,YAAY,UACrB,OAAM,SAAS,KAAK;EACvB,SACM,KAAK;AACV,WAAQ,MAAM,4BAA4B,IAAI;AAC9C,QAAK,KAAK,UAAU,IAAI;EACzB;CACF;CAED,QACEC,OACAC,UACM;AACN,OAAK,KAAK,eAAe,IAAI,MAAM,CACjC,MAAK,eAAe,IAAI,OAAO,CAAE,EAAC;EAGpC,MAAM,YAAY,KAAK,eAAe,IAAI,MAAM;AAChD,OAAK,UACH;AAGF,YAAU,KAAK,SAAoG;AACnH,OAAK,eAAe,IAAI,OAAO,UAAU;CAC1C;CAED,KAAKC,MAA+B;AAClC,OAAK,WAAW,KAAK,KAAK,UAAU,KAAK,CAAC;CAC3C;CAED,QAAQC,MAAwD;AAC9D,OAAK,WAAW,KAAK,KAAK;CAC3B;CAED,QAAc;AACZ,OAAK,cAAc;AAEnB,MAAI,KAAK,aAAa,KAAK,WAAW;AACpC,QAAK,UAAU,OAAO;AACtB,QAAK,YAAY;EAClB;CACF;AACF"}
@@ -1,3 +1,5 @@
1
+ //#region src/utils/node/process.d.ts
1
2
  declare function runUntilSignal(): void;
2
-
3
+ //#endregion
3
4
  export { runUntilSignal };
5
+ //# sourceMappingURL=index.d.mts.map
@@ -1,24 +1,26 @@
1
- import process from 'node:process';
1
+ import process from "node:process";
2
2
 
3
+ //#region src/utils/node/process.ts
3
4
  let running = true;
4
5
  function killProcess() {
5
- running = false;
6
+ running = false;
6
7
  }
7
8
  process.on("SIGTERM", () => {
8
- killProcess();
9
+ killProcess();
9
10
  });
10
11
  process.on("SIGINT", () => {
11
- killProcess();
12
+ killProcess();
12
13
  });
13
14
  process.on("uncaughtException", (e) => {
14
- console.error(e);
15
- killProcess();
15
+ console.error(e);
16
+ killProcess();
16
17
  });
17
18
  function runUntilSignal() {
18
- setTimeout(() => {
19
- if (running)
20
- runUntilSignal();
21
- }, 10);
19
+ setTimeout(() => {
20
+ if (running) runUntilSignal();
21
+ }, 10);
22
22
  }
23
23
 
24
+ //#endregion
24
25
  export { runUntilSignal };
26
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/utils/node/process.ts"],"sourcesContent":["import process from 'node:process'\n\nlet running = true\n\nfunction killProcess() {\n running = false\n}\n\nprocess.on('SIGTERM', () => {\n killProcess()\n})\nprocess.on('SIGINT', () => {\n killProcess()\n})\nprocess.on('uncaughtException', (e) => {\n console.error(e)\n killProcess()\n})\n\nexport function runUntilSignal() {\n setTimeout(() => {\n if (running)\n runUntilSignal()\n }, 10)\n}\n"],"mappings":";;;AAEA,IAAI,UAAU;AAEd,SAAS,cAAc;AACrB,WAAU;AACX;AAED,QAAQ,GAAG,WAAW,MAAM;AAC1B,cAAa;AACd,EAAC;AACF,QAAQ,GAAG,UAAU,MAAM;AACzB,cAAa;AACd,EAAC;AACF,QAAQ,GAAG,qBAAqB,CAAC,MAAM;AACrC,SAAQ,MAAM,EAAE;AAChB,cAAa;AACd,EAAC;AAEF,SAAgB,iBAAiB;AAC/B,YAAW,MAAM;AACf,MAAI,QACF,iBAAgB;CACnB,GAAE,GAAG;AACP"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@proj-airi/server-sdk",
3
3
  "type": "module",
4
- "version": "0.6.0",
4
+ "version": "0.6.1",
5
5
  "description": "Client-side SDK implementation for connecting to AIRI server components and runtimes",
6
6
  "author": {
7
7
  "name": "Moeru AI Project AIRI Team",
@@ -16,19 +16,19 @@
16
16
  },
17
17
  "exports": {
18
18
  ".": {
19
- "types": "./dist/index.d.ts",
19
+ "types": "./dist/index.d.mts",
20
20
  "import": "./dist/index.mjs",
21
- "require": "./dist/index.cjs"
21
+ "require": "./dist/index.mjs"
22
22
  },
23
23
  "./utils/node": {
24
- "types": "./dist/utils/node/index.d.ts",
24
+ "types": "./dist/utils/node/index.d.mts",
25
25
  "import": "./dist/utils/node/index.mjs",
26
- "require": "./dist/utils/node/index.cjs"
26
+ "require": "./dist/utils/node/index.mjs"
27
27
  }
28
28
  },
29
- "main": "./dist/index.cjs",
29
+ "main": "./dist/index.mjs",
30
30
  "module": "./dist/index.mjs",
31
- "types": "./dist/index.d.ts",
31
+ "types": "./dist/index.d.mts",
32
32
  "files": [
33
33
  "README.md",
34
34
  "dist",
@@ -37,12 +37,12 @@
37
37
  "dependencies": {
38
38
  "crossws": "^0.4.1",
39
39
  "defu": "^6.1.4",
40
- "@proj-airi/server-shared": "^0.6.0"
40
+ "@proj-airi/server-shared": "^0.6.1"
41
41
  },
42
42
  "scripts": {
43
- "dev": "pnpm run stub",
44
- "stub": "unbuild --stub",
45
- "build": "unbuild",
43
+ "dev": "pnpm run build",
44
+ "stub": "pnpm run build",
45
+ "build": "tsdown",
46
46
  "typecheck": "tsc --noEmit"
47
47
  }
48
48
  }
package/dist/index.cjs DELETED
@@ -1,173 +0,0 @@
1
- 'use strict';
2
-
3
- const WebSocket = require('crossws/websocket');
4
- const defu = require('defu');
5
-
6
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
7
-
8
- const WebSocket__default = /*#__PURE__*/_interopDefaultCompat(WebSocket);
9
-
10
- function sleep(ms) {
11
- return new Promise((resolve) => setTimeout(resolve, ms));
12
- }
13
-
14
- class Client {
15
- connected = false;
16
- opts;
17
- websocket;
18
- eventListeners = /* @__PURE__ */ new Map();
19
- reconnectAttempts = 0;
20
- shouldClose = false;
21
- constructor(options) {
22
- this.opts = defu.defu(
23
- options,
24
- {
25
- url: "ws://localhost:6121/ws",
26
- possibleEvents: [],
27
- onError: () => {
28
- },
29
- onClose: () => {
30
- },
31
- autoConnect: true,
32
- autoReconnect: true
33
- }
34
- );
35
- if (this.opts.autoConnect) {
36
- try {
37
- this.connect();
38
- } catch (err) {
39
- console.error(err);
40
- }
41
- }
42
- }
43
- async retryWithExponentialBackoff(fn, attempts = 0, maxAttempts = -1) {
44
- if (maxAttempts !== -1 && attempts >= maxAttempts) {
45
- console.error(`Maximum retry attempts (${maxAttempts}) reached`);
46
- return;
47
- }
48
- try {
49
- await fn();
50
- } catch (err) {
51
- console.error("Encountered an error when retrying", err);
52
- await sleep(2 ** attempts * 1e3);
53
- await this.retryWithExponentialBackoff(fn, attempts++, maxAttempts);
54
- }
55
- }
56
- async tryReconnectWithExponentialBackoff() {
57
- await this.retryWithExponentialBackoff(() => this._connect(), this.reconnectAttempts);
58
- }
59
- _connect() {
60
- return new Promise((resolve, reject) => {
61
- if (this.shouldClose) {
62
- resolve();
63
- return;
64
- }
65
- if (this.connected) {
66
- resolve();
67
- return;
68
- }
69
- this.websocket = new WebSocket__default(this.opts.url);
70
- this.onEvent("module:authenticated", async (event) => {
71
- const auth = event.data.authenticated;
72
- if (!auth) {
73
- this.retryWithExponentialBackoff(() => this.tryAuthenticate());
74
- } else {
75
- this.tryAnnounce();
76
- }
77
- });
78
- this.websocket.onerror = (event) => {
79
- this.opts.onError?.(event);
80
- if ("error" in event && event.error instanceof Error) {
81
- if (event.error.message === "Received network error or non-101 status code.") {
82
- this.connected = false;
83
- if (!this.opts.autoReconnect) {
84
- this.opts.onError?.(event);
85
- this.opts.onClose?.();
86
- reject(event.error);
87
- return;
88
- }
89
- reject(event.error);
90
- }
91
- }
92
- };
93
- this.websocket.onclose = () => {
94
- this.opts.onClose?.();
95
- this.connected = false;
96
- if (!this.opts.autoReconnect) {
97
- this.opts.onClose?.();
98
- } else {
99
- this.tryReconnectWithExponentialBackoff();
100
- }
101
- };
102
- this.websocket.onmessage = (event) => {
103
- this.handleMessage(event);
104
- };
105
- this.websocket.onopen = () => {
106
- this.reconnectAttempts = 0;
107
- if (this.opts.token) {
108
- this.tryAuthenticate();
109
- } else {
110
- this.tryAnnounce();
111
- }
112
- this.connected = true;
113
- resolve();
114
- };
115
- });
116
- }
117
- async connect() {
118
- await this.tryReconnectWithExponentialBackoff();
119
- }
120
- tryAnnounce() {
121
- this.send({
122
- type: "module:announce",
123
- data: {
124
- name: this.opts.name,
125
- possibleEvents: this.opts.possibleEvents
126
- }
127
- });
128
- }
129
- tryAuthenticate() {
130
- if (this.opts.token) {
131
- this.send({ type: "module:authenticate", data: { token: this.opts.token || "" } });
132
- }
133
- }
134
- async handleMessage(event) {
135
- try {
136
- const data = JSON.parse(event.data);
137
- const listeners = this.eventListeners.get(data.type);
138
- if (!listeners)
139
- return;
140
- for (const listener of listeners)
141
- await listener(data);
142
- } catch (err) {
143
- console.error("Failed to parse message:", err);
144
- this.opts.onError?.(err);
145
- }
146
- }
147
- onEvent(event, callback) {
148
- if (!this.eventListeners.get(event)) {
149
- this.eventListeners.set(event, []);
150
- }
151
- const listeners = this.eventListeners.get(event);
152
- if (!listeners) {
153
- return;
154
- }
155
- listeners.push(callback);
156
- this.eventListeners.set(event, listeners);
157
- }
158
- send(data) {
159
- this.websocket?.send(JSON.stringify(data));
160
- }
161
- sendRaw(data) {
162
- this.websocket?.send(data);
163
- }
164
- close() {
165
- this.shouldClose = true;
166
- if (this.connected && this.websocket) {
167
- this.websocket.close();
168
- this.connected = false;
169
- }
170
- }
171
- }
172
-
173
- exports.Client = Client;
package/dist/index.d.cts DELETED
@@ -1,34 +0,0 @@
1
- import { WebSocketEvents, WebSocketBaseEvent, WebSocketEvent } from '@proj-airi/server-shared/types';
2
-
3
- interface ClientOptions<C = undefined> {
4
- url?: string;
5
- name: string;
6
- possibleEvents?: Array<(keyof WebSocketEvents<C>)>;
7
- token?: string;
8
- onError?: (error: unknown) => void;
9
- onClose?: () => void;
10
- autoConnect?: boolean;
11
- autoReconnect?: boolean;
12
- }
13
- declare class Client<C = undefined> {
14
- private connected;
15
- private opts;
16
- private websocket;
17
- private eventListeners;
18
- private reconnectAttempts;
19
- private shouldClose;
20
- constructor(options: ClientOptions<C>);
21
- retryWithExponentialBackoff(fn: () => void | Promise<void>, attempts?: number, maxAttempts?: number): Promise<void>;
22
- tryReconnectWithExponentialBackoff(): Promise<void>;
23
- private _connect;
24
- connect(): Promise<void>;
25
- private tryAnnounce;
26
- private tryAuthenticate;
27
- private handleMessage;
28
- onEvent<E extends keyof WebSocketEvents<C>>(event: E, callback: (data: WebSocketBaseEvent<E, WebSocketEvents<C>[E]>) => void | Promise<void>): void;
29
- send(data: WebSocketEvent<C>): void;
30
- sendRaw(data: string | ArrayBufferLike | ArrayBufferView): void;
31
- close(): void;
32
- }
33
-
34
- export { Client, type ClientOptions };
package/dist/index.d.ts DELETED
@@ -1,34 +0,0 @@
1
- import { WebSocketEvents, WebSocketBaseEvent, WebSocketEvent } from '@proj-airi/server-shared/types';
2
-
3
- interface ClientOptions<C = undefined> {
4
- url?: string;
5
- name: string;
6
- possibleEvents?: Array<(keyof WebSocketEvents<C>)>;
7
- token?: string;
8
- onError?: (error: unknown) => void;
9
- onClose?: () => void;
10
- autoConnect?: boolean;
11
- autoReconnect?: boolean;
12
- }
13
- declare class Client<C = undefined> {
14
- private connected;
15
- private opts;
16
- private websocket;
17
- private eventListeners;
18
- private reconnectAttempts;
19
- private shouldClose;
20
- constructor(options: ClientOptions<C>);
21
- retryWithExponentialBackoff(fn: () => void | Promise<void>, attempts?: number, maxAttempts?: number): Promise<void>;
22
- tryReconnectWithExponentialBackoff(): Promise<void>;
23
- private _connect;
24
- connect(): Promise<void>;
25
- private tryAnnounce;
26
- private tryAuthenticate;
27
- private handleMessage;
28
- onEvent<E extends keyof WebSocketEvents<C>>(event: E, callback: (data: WebSocketBaseEvent<E, WebSocketEvents<C>[E]>) => void | Promise<void>): void;
29
- send(data: WebSocketEvent<C>): void;
30
- sendRaw(data: string | ArrayBufferLike | ArrayBufferView): void;
31
- close(): void;
32
- }
33
-
34
- export { Client, type ClientOptions };
@@ -1,30 +0,0 @@
1
- 'use strict';
2
-
3
- const process = require('node:process');
4
-
5
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
6
-
7
- const process__default = /*#__PURE__*/_interopDefaultCompat(process);
8
-
9
- let running = true;
10
- function killProcess() {
11
- running = false;
12
- }
13
- process__default.on("SIGTERM", () => {
14
- killProcess();
15
- });
16
- process__default.on("SIGINT", () => {
17
- killProcess();
18
- });
19
- process__default.on("uncaughtException", (e) => {
20
- console.error(e);
21
- killProcess();
22
- });
23
- function runUntilSignal() {
24
- setTimeout(() => {
25
- if (running)
26
- runUntilSignal();
27
- }, 10);
28
- }
29
-
30
- exports.runUntilSignal = runUntilSignal;
@@ -1,3 +0,0 @@
1
- declare function runUntilSignal(): void;
2
-
3
- export { runUntilSignal };
@@ -1,3 +0,0 @@
1
- declare function runUntilSignal(): void;
2
-
3
- export { runUntilSignal };