airdcpp-apisocket 3.0.0-beta.1 → 3.0.0-beta.11

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 (47) hide show
  1. package/dist-es/PublicHelpers.d.ts +1 -1
  2. package/dist-es/PublicHelpers.js +24 -7
  3. package/dist-es/PublicHelpers.js.map +1 -1
  4. package/dist-es/SocketBase.js +13 -11
  5. package/dist-es/SocketBase.js.map +1 -1
  6. package/dist-es/SocketRequestHandler.js +3 -5
  7. package/dist-es/SocketRequestHandler.js.map +1 -1
  8. package/dist-es/SocketSubscriptionHandler.js +9 -5
  9. package/dist-es/SocketSubscriptionHandler.js.map +1 -1
  10. package/dist-es/tests/mocks/index.d.ts +3 -0
  11. package/dist-es/tests/mocks/index.js +4 -0
  12. package/dist-es/tests/mocks/index.js.map +1 -0
  13. package/dist-es/tests/mocks/mock-data.d.ts +54 -0
  14. package/dist-es/tests/mocks/mock-data.js +34 -0
  15. package/dist-es/tests/mocks/mock-data.js.map +1 -0
  16. package/dist-es/tests/mocks/mock-server.d.ts +43 -0
  17. package/dist-es/tests/mocks/mock-server.js +163 -0
  18. package/dist-es/tests/mocks/mock-server.js.map +1 -0
  19. package/dist-es/tests/mocks/mock-socket.d.ts +24 -0
  20. package/dist-es/tests/mocks/mock-socket.js +35 -0
  21. package/dist-es/tests/mocks/mock-socket.js.map +1 -0
  22. package/dist-es/tests/test-utils.d.ts +8 -0
  23. package/dist-es/tests/test-utils.js +28 -0
  24. package/dist-es/tests/test-utils.js.map +1 -0
  25. package/dist-es/types/public_helpers.d.ts +12 -3
  26. package/dist-es/types/public_helpers_internal.d.ts +4 -4
  27. package/dist-es/types/socket.d.ts +1 -0
  28. package/dist-es/types/subscriptions.d.ts +1 -1
  29. package/package.json +10 -7
  30. package/src/PublicHelpers.ts +25 -7
  31. package/src/SocketBase.ts +15 -12
  32. package/src/SocketRequestHandler.ts +3 -5
  33. package/src/SocketSubscriptionHandler.ts +7 -6
  34. package/src/tests/Socket.test.ts +129 -111
  35. package/src/tests/mocks/index.ts +3 -0
  36. package/src/tests/mocks/mock-data.ts +36 -0
  37. package/src/tests/mocks/mock-server.ts +276 -0
  38. package/src/tests/mocks/mock-socket.ts +72 -0
  39. package/src/tests/public_helpers.test.ts +64 -63
  40. package/src/tests/test-utils.ts +31 -0
  41. package/src/types/api_internal.ts +0 -1
  42. package/src/types/public_helpers.ts +11 -11
  43. package/src/types/public_helpers_internal.ts +4 -4
  44. package/src/types/socket.ts +1 -0
  45. package/src/types/subscriptions.ts +1 -1
  46. package/tsconfig.json +1 -1
  47. package/src/tests/helpers.ts +0 -195
@@ -0,0 +1,163 @@
1
+ import { Server } from 'mock-socket';
2
+ import { EventEmitter } from 'events';
3
+ import { MOCK_SERVER_URL } from './mock-data.js';
4
+ ;
5
+ const toEmitId = (path, method) => {
6
+ return `${path}_${method}`;
7
+ };
8
+ const getDefaultMockCreatorF = () => ({
9
+ fn: () => { },
10
+ });
11
+ const DEFAULT_MOCK_SERVER_OPTIONS = {
12
+ url: MOCK_SERVER_URL,
13
+ reportMissingListeners: true,
14
+ mockF: getDefaultMockCreatorF(),
15
+ };
16
+ const getMockServer = (initialOptions = {}) => {
17
+ const { url, reportMissingListeners, mockF } = {
18
+ ...DEFAULT_MOCK_SERVER_OPTIONS,
19
+ ...initialOptions,
20
+ };
21
+ const mockServer = new Server(url);
22
+ let socket;
23
+ const emitter = new EventEmitter();
24
+ emitter.setMaxListeners(1);
25
+ const send = (data) => {
26
+ socket.send(JSON.stringify(data));
27
+ };
28
+ const handlers = new Map();
29
+ const addServerHandler = (method, path, responseData, subscriptionCallback) => {
30
+ const requestHandler = (request, s) => {
31
+ if (subscriptionCallback) {
32
+ subscriptionCallback(request);
33
+ }
34
+ const data = typeof responseData === 'function' ? responseData(request, s) : responseData;
35
+ if (!data || !data.code) {
36
+ throw new Error(`Mock server: response handler for path ${path} must return a status code`);
37
+ }
38
+ const response = {
39
+ callback_id: request.callback_id,
40
+ ...data,
41
+ };
42
+ s.send(JSON.stringify(response));
43
+ };
44
+ // Don't add duplicates
45
+ const emitId = toEmitId(path, method);
46
+ const removeExisting = handlers.get(emitId);
47
+ if (removeExisting) {
48
+ removeExisting();
49
+ handlers.delete(emitId);
50
+ }
51
+ // Add new
52
+ emitter.addListener(emitId, requestHandler);
53
+ // Prepare for removal
54
+ const removeListener = () => emitter.removeListener(emitId, requestHandler);
55
+ handlers.set(emitId, removeListener);
56
+ return removeListener;
57
+ };
58
+ const addDummyDataHandler = (method, path) => {
59
+ const handler = (request, s) => {
60
+ // Do nothing
61
+ };
62
+ const emitId = toEmitId(path, method);
63
+ emitter.addListener(emitId, handler);
64
+ emitter.setMaxListeners(1);
65
+ return () => emitter.removeListener(emitId, handler);
66
+ };
67
+ const addRequestHandler = (method, path, data, subscriptionCallback) => {
68
+ const handlerData = typeof data === 'function' ? data : {
69
+ data,
70
+ code: data ? 200 : 204,
71
+ };
72
+ return addServerHandler(method, path, handlerData, subscriptionCallback);
73
+ };
74
+ const addErrorHandler = (method, path, errorStr, errorCode, subscriptionCallback) => {
75
+ return addServerHandler(method, path, {
76
+ error: !errorStr ? null : {
77
+ message: errorStr,
78
+ },
79
+ code: errorCode,
80
+ }, subscriptionCallback);
81
+ };
82
+ const addSubscriptionHandlerImpl = (moduleName, type, listenerName, entityId) => {
83
+ const subscribeFn = mockF.fn();
84
+ const unsubscribeFn = mockF.fn();
85
+ const path = entityId ? `${moduleName}/${entityId}/${type}/${listenerName}` : `${moduleName}/${type}/${listenerName}`;
86
+ const subscribeRemove = addRequestHandler('POST', path, undefined, subscribeFn);
87
+ const unsubscribeRemove = addRequestHandler('DELETE', path, undefined, unsubscribeFn);
88
+ const fire = (data, entityId) => {
89
+ send({
90
+ event: listenerName,
91
+ data,
92
+ id: entityId,
93
+ });
94
+ };
95
+ const remove = () => {
96
+ subscribeRemove();
97
+ unsubscribeRemove();
98
+ };
99
+ return {
100
+ fire,
101
+ remove,
102
+ subscribeFn,
103
+ unsubscribeFn,
104
+ path,
105
+ };
106
+ };
107
+ const addSubscriptionHandler = (moduleName, listenerName, entityId) => {
108
+ return addSubscriptionHandlerImpl(moduleName, 'listeners', listenerName, entityId);
109
+ };
110
+ const addHookHandler = (moduleName, listenerName) => {
111
+ const subscriber = addSubscriptionHandlerImpl(moduleName, 'hooks', listenerName);
112
+ const addResolver = (completionId) => {
113
+ const resolveFn = mockF.fn();
114
+ const rejectFn = mockF.fn();
115
+ const resolveRemove = addRequestHandler('POST', `${subscriber.path}/${completionId}/resolve`, undefined, resolveFn);
116
+ const rejectRemove = addRequestHandler('POST', `${subscriber.path}/${completionId}/reject`, undefined, rejectFn);
117
+ const remove = () => {
118
+ resolveRemove();
119
+ rejectRemove();
120
+ };
121
+ const fire = (data) => {
122
+ send({
123
+ event: listenerName,
124
+ data,
125
+ completion_id: completionId,
126
+ });
127
+ };
128
+ return { fire, remove, resolveFn, rejectFn };
129
+ };
130
+ return {
131
+ addResolver,
132
+ ...subscriber,
133
+ };
134
+ };
135
+ mockServer.on('connection', s => {
136
+ socket = s;
137
+ socket.on('message', (messageObj) => {
138
+ const request = JSON.parse(messageObj);
139
+ const emitId = toEmitId(request.path, request.method);
140
+ const processed = emitter.emit(emitId, request, s);
141
+ if (reportMissingListeners && !processed) {
142
+ console.warn(`Mock server: no listeners for event ${request.method} ${request.path}`);
143
+ }
144
+ });
145
+ });
146
+ return {
147
+ addRequestHandler,
148
+ addErrorHandler,
149
+ addSubscriptionHandler,
150
+ addHookHandler,
151
+ ignoreMissingHandler: addDummyDataHandler,
152
+ stop: () => {
153
+ mockServer.stop(() => {
154
+ emitter.removeAllListeners();
155
+ handlers.clear();
156
+ });
157
+ },
158
+ send,
159
+ url,
160
+ };
161
+ };
162
+ export { getMockServer };
163
+ //# sourceMappingURL=mock-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-server.js","sourceRoot":"","sources":["../../../src/tests/mocks/mock-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import * as Options from '../../types/options.js';
2
+ import { getMockServer } from './mock-server.js';
3
+ export type MockSocketConnectOptions = Omit<Options.APISocketOptions, 'username' | 'password' | 'url'> & {
4
+ username?: string;
5
+ password?: string;
6
+ url?: string;
7
+ };
8
+ type RequestCallback = (requestData: object) => void;
9
+ interface MockSocketOptions {
10
+ console: Options.LogOutput;
11
+ socketOptions?: MockSocketConnectOptions;
12
+ }
13
+ export interface MockConnectedSocketOptions extends MockSocketOptions {
14
+ authCallback?: RequestCallback;
15
+ authResponse: object;
16
+ }
17
+ export declare const getSocket: (socketOptions?: MockSocketConnectOptions) => {
18
+ socket: import("../../NodeSocket.js").APISocket;
19
+ };
20
+ export declare const getConnectedSocket: (server: ReturnType<typeof getMockServer>, userOptions?: Partial<MockConnectedSocketOptions>) => Promise<{
21
+ socket: import("../../NodeSocket.js").APISocket;
22
+ removeAuthHandler: () => import("events")<[never]>;
23
+ }>;
24
+ export {};
@@ -0,0 +1,35 @@
1
+ import { Socket } from '../../NodeSocket.js';
2
+ import { WebSocket } from 'mock-socket';
3
+ import ApiConstants from '../../ApiConstants.js';
4
+ import { DEFAULT_AUTH_RESPONSE, DEFAULT_CONNECT_CREDENTIALS, MOCK_SERVER_URL } from './mock-data.js';
5
+ const getDefaultSocketOptions = () => ({
6
+ url: MOCK_SERVER_URL,
7
+ logOutput: console,
8
+ logLevel: 'warn',
9
+ });
10
+ export const getSocket = (socketOptions = {}) => {
11
+ const socket = Socket({
12
+ ...getDefaultSocketOptions(),
13
+ ...socketOptions
14
+ }, WebSocket);
15
+ return { socket };
16
+ };
17
+ const getDefaultConnectOptions = () => ({
18
+ console,
19
+ authResponse: DEFAULT_AUTH_RESPONSE,
20
+ });
21
+ export const getConnectedSocket = async (server, userOptions) => {
22
+ const options = {
23
+ ...getDefaultConnectOptions(),
24
+ ...userOptions,
25
+ };
26
+ const removeAuthHandler = server.addRequestHandler('POST', ApiConstants.LOGIN_URL, options.authResponse, options.authCallback);
27
+ const { socket } = getSocket({
28
+ ...DEFAULT_CONNECT_CREDENTIALS,
29
+ ...getDefaultSocketOptions(),
30
+ ...options.socketOptions
31
+ });
32
+ await socket.connect();
33
+ return { socket, removeAuthHandler };
34
+ };
35
+ //# sourceMappingURL=mock-socket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-socket.js","sourceRoot":"","sources":["../../../src/tests/mocks/mock-socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,OAAO,YAAY,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAErG,MAAM,uBAAuB,GAAG,GAA6B,EAAE,CAAC,CAAC;IAC/D,GAAG,EAAE,eAAe;IACpB,SAAS,EAAE,OAAO;IAClB,QAAQ,EAAE,MAAM;CACjB,CAAC,CAAC;AAsBH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,gBAA0C,EAAE,EAAE,EAAE;IACxE,MAAM,MAAM,GAAG,MAAM,CACnB;QACE,GAAG,uBAAuB,EAAE;QAC5B,GAAG,aAAa;KACjB,EACD,SAAgB,CACjB,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,GAAG,EAAE,CAAC,CAAC;IACtC,OAAO;IACP,YAAY,EAAE,qBAAqB;CACpC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACrC,MAAwC,EACxC,WAAiD,EACjD,EAAE;IACF,MAAM,OAAO,GAA+B;QAC1C,GAAG,wBAAwB,EAAE;QAC7B,GAAG,WAAW;KACf,CAAC;IAEF,MAAM,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAE/H,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,GAAG,2BAA2B;QAC9B,GAAG,uBAAuB,EAAE;QAC5B,GAAG,OAAO,CAAC,aAAa;KACzB,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IAEvB,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;AACvC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const waitForExpect: (func: () => void | Promise<void>) => Promise<{}>;
2
+ export declare const defusedPromise: (promise: Promise<any>) => Promise<any>;
3
+ export declare const getMockConsole: (verbose?: boolean) => {
4
+ log: jest.Mock<void, [a1: any, a2: any, a3: any, a4: any], any>;
5
+ info: jest.Mock<void, [a1: any, a2: any, a3: any, a4: any], any>;
6
+ warn: jest.Mock<void, [a1: any, a2: any, a3: any, a4: any], any>;
7
+ error: jest.Mock<void, [a1: any, a2: any, a3: any, a4: any], any>;
8
+ };
@@ -0,0 +1,28 @@
1
+ import waitForExpectOriginal from 'wait-for-expect';
2
+ const EXCEPT_TIMEOUT = 1000;
3
+ //@ts-ignore
4
+ export const waitForExpect = (func) => waitForExpectOriginal.default(func, EXCEPT_TIMEOUT);
5
+ // This is a helper function that will suppress the error of a promise.
6
+ export const defusedPromise = (promise) => {
7
+ promise.catch(() => { });
8
+ return promise;
9
+ };
10
+ export const getMockConsole = (verbose = false) => ({
11
+ log: jest.fn((a1, a2, a3, a4) => {
12
+ if (verbose) {
13
+ console.log(a1, a2, a3, a4);
14
+ }
15
+ }),
16
+ info: jest.fn((a1, a2, a3, a4) => {
17
+ if (verbose) {
18
+ console.info(a1, a2, a3, a4);
19
+ }
20
+ }),
21
+ warn: jest.fn((a1, a2, a3, a4) => {
22
+ console.warn(a1, a2, a3, a4);
23
+ }),
24
+ error: jest.fn((a1, a2, a3, a4) => {
25
+ console.error(a1, a2, a3, a4);
26
+ }),
27
+ });
28
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/tests/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,MAAM,iBAAiB,CAAC;AAEpD,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,YAAY;AACZ,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAgC,EAAE,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AAGvH,uEAAuE;AACvE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAqB,EAAE,EAAE;IACtD,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAO,GAAG,KAAK,EAAE,EAAE,CAAC,CAAC;IAClD,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IACF,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QACnD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;IACF,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QACnD,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC;IACF,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QACpD,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC;CACH,CAAC,CAAC"}
@@ -1,17 +1,26 @@
1
1
  import { HookSubscriberInfo } from './subscriptions.js';
2
- type AsyncCallbackProperty<IdT, EntityIdT, ReturnT> = (selectedIds: IdT[], entityId: EntityIdT | null, permissions: string[], supports: string[]) => ReturnT | Promise<ReturnT>;
2
+ export interface MenuCallbackProperties<IdT, EntityIdT> {
3
+ selectedIds: IdT[];
4
+ entityId: EntityIdT;
5
+ permissions: string[];
6
+ supports: string[];
7
+ }
8
+ export interface MenuClickHandlerProperties<IdT, EntityIdT, FormValueT extends object = object> extends MenuCallbackProperties<IdT, EntityIdT> {
9
+ formValues: FormValueT;
10
+ }
11
+ type AsyncCallbackProperty<IdT, EntityIdT, ReturnT> = (props: MenuCallbackProperties<IdT, EntityIdT>) => ReturnT | Promise<ReturnT>;
3
12
  export type ContextMenuIcon = {
4
13
  [key in string]: string;
5
14
  };
6
15
  export interface ContextMenu extends HookSubscriberInfo {
7
16
  icon?: ContextMenuIcon;
8
17
  }
9
- export interface ContextMenuItem<IdT, EntityIdT> {
18
+ export interface ContextMenuItem<IdT, EntityIdT, FormValueT extends object = object> {
10
19
  id: string;
11
20
  title: string;
12
21
  icon?: ContextMenuIcon;
13
22
  urls?: string[] | AsyncCallbackProperty<IdT, EntityIdT, string[] | undefined>;
14
- onClick?: (selectedIds: IdT[], entityId: EntityIdT | null, permissions: string[], supports: string[], formValues: object) => void;
23
+ onClick?: (props: MenuClickHandlerProperties<IdT, EntityIdT, FormValueT>) => void;
15
24
  filter?: AsyncCallbackProperty<IdT, EntityIdT, boolean>;
16
25
  access?: string;
17
26
  formDefinitions?: object[] | AsyncCallbackProperty<IdT, EntityIdT, object[]>;
@@ -4,20 +4,20 @@ export interface SelectedMenuItemListenerData<IdT, EntityIdT> {
4
4
  menu_id: string;
5
5
  menuitem_id: string;
6
6
  selected_ids: IdT[];
7
- entity_id: EntityIdT | null;
7
+ entity_id: EntityIdT;
8
8
  permissions: string[];
9
9
  supports: string[];
10
10
  form_values: object;
11
11
  }
12
12
  export interface MenuItemListHookData<IdT, EntityIdT> {
13
13
  selected_ids: IdT[];
14
- entity_id: EntityIdT | null;
14
+ entity_id: EntityIdT;
15
15
  permissions: string[];
16
16
  supports: string[];
17
17
  }
18
18
  export interface ResponseMenuItemCallbackFields {
19
- urls?: string[] | undefined;
20
- form_definitions?: object[] | undefined;
19
+ urls?: string[];
20
+ form_definitions?: object[];
21
21
  }
22
22
  export type ResponseMenuItem<IdT, EntityIdT> = Omit<ContextMenuItem<IdT, EntityIdT>, 'onClick' | 'filter' | 'urls' | 'form_definitions'> & ResponseMenuItemCallbackFields;
23
23
  export interface MenuItemListHookAcceptData<IdT, EntityIdT> {
@@ -20,4 +20,5 @@ export interface APISocket extends SocketRequestMethods, SocketSubscriptions {
20
20
  onSessionReset: SessionResetCallback | null;
21
21
  onDisconnected: DisconnectedCallback | null;
22
22
  readonly nativeSocket: WebSocket | null;
23
+ readonly url: string;
23
24
  }
@@ -1,5 +1,5 @@
1
1
  import * as API from './api.js';
2
- export type SubscriptionRemoveHandler = (sendApi?: boolean) => void;
2
+ export type SubscriptionRemoveHandler = (sendApi?: boolean) => Promise<void>;
3
3
  export type SubscriptionCallback<DataT extends object | void = object, EntityIdT = API.EntityId | undefined> = (data: DataT, entityId: EntityIdT) => void;
4
4
  export interface HookSubscriberInfo {
5
5
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "airdcpp-apisocket",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.11",
4
4
  "description": "Javascript connector for AirDC++ Web API",
5
5
  "license": "MIT",
6
6
  "authors": [
@@ -41,14 +41,14 @@
41
41
  "devDependencies": {
42
42
  "@babel/preset-env": "^7.20.2",
43
43
  "@types/invariant": "^2.2.35",
44
- "@types/jest": "^29.5.12",
45
- "@types/node": "^20.14.9",
46
- "jest": "^29.7.0",
47
- "jest-cli": "^29.7.0",
44
+ "@types/jest": "^30.0.0",
45
+ "@types/node": "^24.1.0",
46
+ "jest": "^30.0.5",
47
+ "jest-cli": "^30.0.5",
48
48
  "jest-environment-node-debug": "^2.0.0",
49
49
  "mock-socket": "^9.1.5",
50
50
  "pre-commit": "^1.2.2",
51
- "rimraf": "^4.1.2",
51
+ "rimraf": "^6.0.1",
52
52
  "ts-jest": "^29.1.5",
53
53
  "ts-node": "^10.9.1",
54
54
  "tslint": "^6.1.3",
@@ -57,6 +57,9 @@
57
57
  "websocket": "^1.0.34"
58
58
  },
59
59
  "main": "./dist/NodeSocket.js",
60
- "exports": "./dist-es/NodeSocket.js",
60
+ "exports": {
61
+ ".": "./dist-es/NodeSocket.js",
62
+ "./tests": "./dist-es/tests/mocks/index.js"
63
+ },
61
64
  "type": "module"
62
65
  }
@@ -30,7 +30,12 @@ const validateItem = async <IdT, EntityIdT>(
30
30
  return false;
31
31
  }
32
32
 
33
- if (!!menuItem.filter && !(await menuItem.filter(selected_ids, entity_id, permissions, supports))) {
33
+ if (!!menuItem.filter && !(await menuItem.filter({
34
+ selectedIds: selected_ids,
35
+ entityId: entity_id,
36
+ permissions,
37
+ supports
38
+ }))) {
34
39
  return false;
35
40
  }
36
41
 
@@ -42,10 +47,17 @@ const parseCallbackData = async <IdT, EntityIdT extends EntityId | undefined = u
42
47
  data: MenuItemListHookData<IdT, EntityIdT>
43
48
  ): Promise<ResponseMenuItemCallbackFields> => {
44
49
  const { selected_ids, entity_id, permissions, supports } = data;
50
+ const callbackProps = {
51
+ selectedIds: selected_ids,
52
+ entityId: entity_id,
53
+ permissions,
54
+ supports
55
+ }
56
+
45
57
  if (!!item.urls && !!item.urls.length) {
46
58
  let urls: string[] | undefined;
47
59
  if (typeof item.urls === 'function') {
48
- urls = await item.urls(selected_ids, entity_id, permissions, supports);
60
+ urls = await item.urls(callbackProps);
49
61
  } else {
50
62
  urls = item.urls;
51
63
  }
@@ -56,7 +68,7 @@ const parseCallbackData = async <IdT, EntityIdT extends EntityId | undefined = u
56
68
  } else if (!!item.formDefinitions && hasSupport(FORM_SUPPORT, supports)) {
57
69
  let formDefinitions: object[] | undefined;
58
70
  if (typeof item.formDefinitions === 'function') {
59
- formDefinitions = await item.formDefinitions(selected_ids, entity_id, permissions, supports);
71
+ formDefinitions = await item.formDefinitions(callbackProps);
60
72
  } else {
61
73
  formDefinitions = item.formDefinitions;
62
74
  }
@@ -85,7 +97,13 @@ export const addContextMenuItems = async <IdT, EntityIdT extends EntityId | unde
85
97
  const isValid = await validateItem(menuItem, data);
86
98
  if (isValid && !!menuItem.onClick) {
87
99
  const { selected_ids, entity_id, permissions, supports, form_values } = data;
88
- menuItem.onClick(selected_ids, entity_id, permissions, supports, form_values);
100
+ menuItem.onClick({
101
+ selectedIds: selected_ids,
102
+ entityId: entity_id,
103
+ permissions,
104
+ supports,
105
+ formValues: form_values
106
+ });
89
107
  }
90
108
  }
91
109
  }
@@ -125,8 +143,8 @@ export const addContextMenuItems = async <IdT, EntityIdT extends EntityId | unde
125
143
  menu
126
144
  );
127
145
 
128
- return () => {
129
- removeHook();
130
- removeListener();
146
+ return async () => {
147
+ await removeHook();
148
+ await removeListener();
131
149
  };
132
150
  };
package/src/SocketBase.ts CHANGED
@@ -125,11 +125,11 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
125
125
  // Connect handler for creation of new session
126
126
  const handlePasswordLogin = (username = options.username, password = options.password) => {
127
127
  if (!username) {
128
- throw '"username" option was not supplied for authentication';
128
+ throw new Error('"username" option was not supplied for authentication');
129
129
  }
130
130
 
131
131
  if (!password) {
132
- throw '"password" option was not supplied for authentication';
132
+ throw new Error('"password" option was not supplied for authentication');
133
133
  }
134
134
 
135
135
  const data: API.CredentialsAuthenticationData = {
@@ -146,7 +146,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
146
146
 
147
147
  const handleRefreshTokenLogin = (refreshToken: string) => {
148
148
  if (!refreshToken) {
149
- throw '"refreshToken" option was not supplied for authentication';
149
+ throw new Error('"refreshToken" option was not supplied for authentication');
150
150
  }
151
151
 
152
152
  const data: API.RefreshTokenAuthenticationData = {
@@ -268,7 +268,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
268
268
  };
269
269
 
270
270
  ws!.onerror = (event) => {
271
- logger.error('Connecting socket failed');
271
+ logger.error('Connecting socket failed (network/system error, most likely the server is unreachable)');
272
272
  scheduleReconnect();
273
273
  };
274
274
  };
@@ -281,7 +281,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
281
281
  forceNoAutoConnect = false;
282
282
  return new Promise(
283
283
  (resolve, reject) => {
284
- logger.info('Starting socket connect');
284
+ logger.info(`Starting socket connect to ${userOptions.url}`);
285
285
  connectInternal(resolve, reject, authenticationHandler, reconnectOnFailure);
286
286
  }
287
287
  );
@@ -317,7 +317,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
317
317
  if (isActive()) {
318
318
  if (attempts >= maxAttempts) {
319
319
  logger.error(`Socket disconnect timed out after ${timeoutMs} ms`);
320
- reject('Socket disconnect timed out');
320
+ reject(new Error('Socket disconnect timed out'));
321
321
  } else {
322
322
  setTimeout(wait, checkInterval);
323
323
  attempts++;
@@ -343,7 +343,6 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
343
343
  }
344
344
  } else {
345
345
  logger.warn('Attempting to disconnect a closed socket (ignore)');
346
- //throw 'Attempting to disconnect a closed socket';
347
346
  }
348
347
 
349
348
  return;
@@ -363,7 +362,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
363
362
  // Username and password are not required if those are available in socket options
364
363
  connect: (username?: string, password?: string, reconnectOnFailure = true) => {
365
364
  if (isActive()) {
366
- throw 'Connect may only be used for a closed socket';
365
+ throw new Error('Connect may only be used for a closed socket');
367
366
  }
368
367
 
369
368
  resetSession();
@@ -373,7 +372,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
373
372
 
374
373
  connectRefreshToken: (refreshToken: string, reconnectOnFailure = true) => {
375
374
  if (isActive()) {
376
- throw 'Connect may only be used for a closed socket';
375
+ throw new Error('Connect may only be used for a closed socket');
377
376
  }
378
377
 
379
378
  resetSession();
@@ -384,7 +383,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
384
383
  // Connect and attempt to associate the socket with an existing session
385
384
  reconnect: (token: API.AuthTokenType | undefined = undefined, reconnectOnFailure = true) => {
386
385
  if (isActive()) {
387
- throw 'Reconnect may only be used for a closed socket';
386
+ throw new Error('Reconnect may only be used for a closed socket');
388
387
  }
389
388
 
390
389
  if (token) {
@@ -392,7 +391,7 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
392
391
  }
393
392
 
394
393
  if (!authToken) {
395
- throw 'No session token available for reconnecting';
394
+ throw new Error('No session token available for reconnecting');
396
395
  }
397
396
 
398
397
  logger.info('Reconnecting socket');
@@ -459,11 +458,15 @@ const ApiSocket = (userOptions: Options.APISocketOptions, WebSocketImpl: WebSock
459
458
  return ws;
460
459
  },
461
460
 
461
+ get url() {
462
+ return userOptions.url;
463
+ },
464
+
462
465
  ...subscriptions.socket,
463
466
  ...requests.socket,
464
467
  };
465
468
 
466
- return socket!;
469
+ return socket;
467
470
  };
468
471
 
469
472
  export default ApiSocket;
@@ -59,12 +59,12 @@ const SocketRequestHandler = (
59
59
  // Pre-checks
60
60
  if (!authenticating && !socket().isConnected()) {
61
61
  logger.warn(`Attempting to send request on a non-authenticated socket: ${path}`);
62
- return Promise.reject('Not authorized');
62
+ return Promise.reject(new Error('Not authorized'));
63
63
  }
64
64
 
65
65
  if (!socket().nativeSocket) {
66
66
  logger.warn(`Attempting to send request without a socket: ${path}`);
67
- return Promise.reject('No socket');
67
+ return Promise.reject(new Error('No socket'));
68
68
  }
69
69
 
70
70
  const callbackId = getCallbackId();
@@ -143,12 +143,10 @@ const SocketRequestHandler = (
143
143
  },
144
144
 
145
145
  delete: (path) => {
146
- //invariant(!data, 'No data is allowed for delete command');
147
146
  return sendRequest('DELETE', path);
148
147
  },
149
148
 
150
149
  get: (path) => {
151
- //invariant(!data, 'No data is allowed for get command');
152
150
  return sendRequest('GET', path);
153
151
  },
154
152
 
@@ -188,7 +186,7 @@ const SocketRequestHandler = (
188
186
  if (messageObj.code >= 200 && messageObj.code <= 204) {
189
187
  const { data } = messageObj as APIInternal.RequestSuccessResponse;
190
188
  if (!callbacks[id].ignored) {
191
- logger.verbose(chalk.green(id.toString()), 'SUCCEEDED', data ? data : '(no data)');
189
+ logger.verbose(chalk.green(id.toString()), 'SUCCEEDED', data ?? '(no data)');
192
190
  }
193
191
 
194
192
  callbacks[id].resolver.resolve(data);
@@ -43,7 +43,7 @@ const SocketSubscriptionHandler = (
43
43
  // Subscriptions pending to be added in the API
44
44
  const pendingSubscriptions: { [key: string]: PendingSubscription[] } = {};
45
45
 
46
- const removeSocketListener = (
46
+ const removeSocketListener = async (
47
47
  subscriptionUrl: string,
48
48
  subscriptionId: string,
49
49
  callback: Subscriptions.HookCallback<any, any> | Subscriptions.SubscriptionCallback<any>,
@@ -58,11 +58,12 @@ const SocketSubscriptionHandler = (
58
58
 
59
59
  if (subscriptions[subscriptionId] === 0) {
60
60
  if (sendApi && socket().isConnected()) {
61
- socket().delete(subscriptionUrl)
62
- .catch(
63
- (error: Requests.ErrorResponse) => {
64
- logger.error('Failed to remove socket listener', subscriptionUrl, error);
65
- });
61
+ try {
62
+ await socket().delete(subscriptionUrl);
63
+ } catch (error) {
64
+ const e: Requests.ErrorResponse = error;
65
+ logger.error('Failed to remove socket listener', subscriptionUrl, e);
66
+ };
66
67
  }
67
68
 
68
69
  delete subscriptions[subscriptionId];