@furystack/websocket-api 11.0.0 → 12.0.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.
@@ -1,7 +1,7 @@
1
1
  /// <reference path="../../../rest-service/esm/incoming-message-extensions.d.ts" />
2
2
  /// <reference path="../../../rest-service/esm/server-response-extensions.d.ts" />
3
3
  /// <reference types="node/http.js" />
4
- import type { Data } from 'ws';
4
+ import type { Data, WebSocket } from 'ws';
5
5
  import type { WebSocketAction } from '../models/websocket-action.js';
6
6
  import type { IncomingMessage } from 'http';
7
7
  /**
@@ -16,8 +16,8 @@ export declare class WhoAmI implements WebSocketAction {
16
16
  execute(options: {
17
17
  data: Data;
18
18
  request: IncomingMessage;
19
+ socket: WebSocket;
19
20
  }): Promise<void>;
20
21
  private readonly httpUserContext;
21
- private readonly websocket;
22
22
  }
23
23
  //# sourceMappingURL=whoami.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/actions/whoami.ts"],"names":[],"mappings":";;;AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAE9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAE3C;;GAEG;AACH,qBACa,MAAO,YAAW,eAAe;IACrC,OAAO;WAGA,UAAU,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,GAAG,OAAO;IAIvE,OAAO,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE;IAUtE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAGlD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAK;CAChC"}
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/actions/whoami.ts"],"names":[],"mappings":";;;AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AACzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAE3C;;GAEG;AACH,qBACa,MAAO,YAAW,eAAe;IACrC,OAAO;WAGA,UAAU,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,GAAG,OAAO;IAIvE,OAAO,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,eAAe,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE;IASzF,iBACyB,eAAe,CAAiB;CAC1D"}
@@ -9,7 +9,6 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  import { HttpUserContext } from '@furystack/rest-service';
11
11
  import { Injectable, Injected } from '@furystack/inject';
12
- import ws from 'ws';
13
12
  /**
14
13
  * Example action that returns the current user instance
15
14
  */
@@ -23,23 +22,17 @@ let WhoAmI = class WhoAmI {
23
22
  async execute(options) {
24
23
  try {
25
24
  const currentUser = await this.httpUserContext.getCurrentUser(options.request);
26
- this.websocket.send(JSON.stringify({ currentUser }));
25
+ options.socket.send(JSON.stringify({ currentUser }));
27
26
  }
28
27
  catch (error) {
29
- this.websocket.send(JSON.stringify({ currentUser: null }));
28
+ options.socket.send(JSON.stringify({ currentUser: null }));
30
29
  }
31
30
  }
32
- httpUserContext;
33
- websocket;
34
31
  };
35
32
  __decorate([
36
33
  Injected(HttpUserContext),
37
34
  __metadata("design:type", HttpUserContext)
38
35
  ], WhoAmI.prototype, "httpUserContext", void 0);
39
- __decorate([
40
- Injected(ws),
41
- __metadata("design:type", ws)
42
- ], WhoAmI.prototype, "websocket", void 0);
43
36
  WhoAmI = __decorate([
44
37
  Injectable({ lifetime: 'transient' })
45
38
  ], WhoAmI);
@@ -1 +1 @@
1
- {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/actions/whoami.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,MAAM,IAAI,CAAA;AAInB;;GAEG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAM;IACV,OAAO;QACZ,MAAM;IACR,CAAC;IACM,MAAM,CAAC,UAAU,CAAC,OAAiD;QACxE,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,gBAAgB,CAAA;IAC7F,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,OAAiD;QACpE,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YAC9E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAC5D,CAAC;IACH,CAAC;IAGgB,eAAe,CAAkB;IAGjC,SAAS,CAAK;CAChC,CAAA;AAJkB;IADhB,QAAQ,CAAC,eAAe,CAAC;8BACS,eAAe;+CAAA;AAGjC;IADhB,QAAQ,CAAC,EAAE,CAAC;8BACgB,EAAE;yCAAA;AArBpB,MAAM;IADlB,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;GACzB,MAAM,CAsBlB"}
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/actions/whoami.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAKxD;;GAEG;AAEI,IAAM,MAAM,GAAZ,MAAM,MAAM;IACV,OAAO;QACZ,MAAM;IACR,CAAC;IACM,MAAM,CAAC,UAAU,CAAC,OAAiD;QACxE,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,gBAAgB,CAAA;IAC7F,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,OAAoE;QACvF,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YAC9E,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAC5D,CAAC;IACH,CAAC;CAIF,CAAA;AAD0B;IADxB,QAAQ,CAAC,eAAe,CAAC;8BACgB,eAAe;+CAAA;AAlB9C,MAAM;IADlB,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;GACzB,MAAM,CAmBlB"}
@@ -25,7 +25,7 @@ describe('Whoami action', () => {
25
25
  injector.setExplicitInstance(contextMock, HttpUserContext);
26
26
  injector.setExplicitInstance(wsMock, ws);
27
27
  const instance = injector.getInstance(WhoAmI);
28
- await instance.execute({ request, data: '' });
28
+ await instance.execute({ request, data: '', socket: wsMock });
29
29
  expect(wsMock.send).toBeCalledWith(JSON.stringify({ currentUser }));
30
30
  });
31
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"whoami.spec.js","sourceRoot":"","sources":["../../src/actions/whoami.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEjD,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,MAAM,WAAW,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAA;IAC5C,MAAM,WAAW,GAAoB,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,WAAW,EAAgC,CAAA;IAE9G,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,oBAAoB,EAAqB,CAAA;IAEhE,MAAM,MAAM,GAAO;QACjB,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;KACZ,CAAA;IAElB,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;IACjE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IACrE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IAC7E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,UAAU,CAAC,IAAI,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,eAAe,CAAC,CAAA;YAC1D,QAAQ,CAAC,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;YACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;YAE7C,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;YAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QACrE,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"whoami.spec.js","sourceRoot":"","sources":["../../src/actions/whoami.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAEjD,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,MAAM,WAAW,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAA;IAC5C,MAAM,WAAW,GAAoB,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,WAAW,EAAgC,CAAA;IAE9G,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,oBAAoB,EAAqB,CAAA;IAEhE,MAAM,MAAM,GAAO;QACjB,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;KACZ,CAAA;IAElB,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAA;IACjE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IACrE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IAC7E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,UAAU,CAAC,IAAI,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YAClD,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,eAAe,CAAC,CAAA;YAC1D,QAAQ,CAAC,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;YACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;YAC7C,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;YAC7D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;QACrE,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,11 +1,17 @@
1
+ /// <reference path="../../../rest-service/esm/incoming-message-extensions.d.ts" />
2
+ /// <reference path="../../../rest-service/esm/server-response-extensions.d.ts" />
3
+ /// <reference types="node/http.js" />
1
4
  import type { Disposable } from '@furystack/utils';
2
- import type { Data } from 'ws';
5
+ import type { Data, WebSocket } from 'ws';
6
+ import type { IncomingMessage } from 'http';
3
7
  /**
4
8
  * Static methods of a WebSocket Action
5
9
  */
6
10
  export interface WebSocketActionStatic {
7
11
  canExecute(options: {
8
12
  data: Data;
13
+ request: IncomingMessage;
14
+ socket: WebSocket;
9
15
  }): boolean;
10
16
  }
11
17
  /**
@@ -14,6 +20,8 @@ export interface WebSocketActionStatic {
14
20
  export interface WebSocketAction extends Disposable {
15
21
  execute(options: {
16
22
  data: Data;
23
+ request: IncomingMessage;
24
+ socket: WebSocket;
17
25
  }): void;
18
26
  }
19
27
  //# sourceMappingURL=websocket-action.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-action.d.ts","sourceRoot":"","sources":["../../src/models/websocket-action.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAE9B;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAA;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,OAAO,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;CACvC"}
1
+ {"version":3,"file":"websocket-action.d.ts","sourceRoot":"","sources":["../../src/models/websocket-action.ts"],"names":[],"mappings":";;;AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AACzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAE3C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,eAAe,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,GAAG,OAAO,CAAA;CAC1F;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,OAAO,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,eAAe,CAAC;QAAC,MAAM,EAAE,SAAS,CAAA;KAAE,GAAG,IAAI,CAAA;CACpF"}
@@ -3,15 +3,16 @@
3
3
  /// <reference types="node/http.js" />
4
4
  /// <reference types="node/http.js" />
5
5
  import { IncomingMessage } from 'http';
6
- import { Injector } from '@furystack/inject';
7
- import type { Disposable } from '@furystack/utils';
6
+ import type { Injector } from '@furystack/inject';
7
+ import { type Disposable } from '@furystack/utils';
8
8
  import type { Data } from 'ws';
9
+ import type WebSocket from 'ws';
9
10
  import ws from 'ws';
10
11
  /**
11
12
  * A WebSocket API implementation for FuryStack
12
13
  */
13
14
  export declare class WebSocketApi implements Disposable {
14
- readonly socket: ws.Server<typeof ws, typeof IncomingMessage>;
15
+ readonly socket: WebSocket.Server<typeof WebSocket, typeof IncomingMessage>;
15
16
  private clients;
16
17
  private readonly settings;
17
18
  private readonly serverManager;
@@ -24,6 +25,6 @@ export declare class WebSocketApi implements Disposable {
24
25
  ws: ws;
25
26
  message: IncomingMessage;
26
27
  }) => void | Promise<void>): Promise<void>;
27
- execute(data: Data, injector: Injector): void;
28
+ execute(data: Data, request: IncomingMessage, injector: Injector, socket: WebSocket): Promise<void>;
28
29
  }
29
30
  //# sourceMappingURL=websocket-api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-api.d.ts","sourceRoot":"","sources":["../src/websocket-api.ts"],"names":[],"mappings":";;;;AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAEtC,OAAO,EAAwB,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAE9B,OAAO,EAAE,MAAM,IAAI,CAAA;AAMnB;;GAEG;AACH,qBACa,YAAa,YAAW,UAAU;IAC7C,SAAgB,MAAM,+CAA0C;IAEhE,OAAO,CAAC,OAAO,CAA0E;IAGzF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAGhD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAG9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IAEpC,OAAO,CAAC,aAAa,CAAQ;IACtB,IAAI;IA+BE,OAAO;IAMP,SAAS,CACpB,QAAQ,EAAE,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,EAAE,EAAE,EAAE,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBhG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ;CAO9C"}
1
+ {"version":3,"file":"websocket-api.d.ts","sourceRoot":"","sources":["../src/websocket-api.ts"],"names":[],"mappings":";;;;AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAC9B,OAAO,KAAK,SAAS,MAAM,IAAI,CAAA;AAE/B,OAAO,EAAE,MAAM,IAAI,CAAA;AAKnB;;GAEG;AACH,qBACa,YAAa,YAAW,UAAU;IAC7C,SAAgB,MAAM,6DAA0C;IAEhE,OAAO,CAAC,OAAO,CAA0E;IAEzF,iBACyB,QAAQ,CAAsB;IAEvD,iBACyB,aAAa,CAAe;IAErD,iBAAyB,QAAQ,CAAU;IAE3C,OAAO,CAAC,aAAa,CAAQ;IACtB,IAAI;IA+BE,OAAO;IAMP,SAAS,CACpB,QAAQ,EAAE,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,EAAE,EAAE,EAAE,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB1F,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS;CAQjG"}
@@ -9,22 +9,19 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  import { URL } from 'url';
11
11
  import { IncomingMessage } from 'http';
12
- import { ServerManager } from '@furystack/rest-service';
13
- import { Injectable, Injected, Injector } from '@furystack/inject';
12
+ import { HttpUserContext, ServerManager } from '@furystack/rest-service';
13
+ import { Injectable, Injected } from '@furystack/inject';
14
+ import { usingAsync } from '@furystack/utils';
14
15
  import { WebSocketServer } from 'ws';
15
16
  import ws from 'ws';
16
17
  import { WebSocketApiSettings } from './websocket-api-settings.js';
17
18
  import { AggregatedError, IdentityContext } from '@furystack/core';
18
- import { WebsocketUserContext } from './websocket-user-context.js';
19
19
  /**
20
20
  * A WebSocket API implementation for FuryStack
21
21
  */
22
22
  let WebSocketApi = class WebSocketApi {
23
23
  socket = new WebSocketServer({ noServer: true });
24
24
  clients = new Map();
25
- settings;
26
- serverManager;
27
- injector;
28
25
  isInitialized = false;
29
26
  init() {
30
27
  if (!this.isInitialized) {
@@ -32,10 +29,10 @@ let WebSocketApi = class WebSocketApi {
32
29
  const connectionInjector = this.injector.createChild({ owner: msg });
33
30
  connectionInjector.setExplicitInstance(websocket, ws);
34
31
  connectionInjector.setExplicitInstance(msg, IncomingMessage);
35
- connectionInjector.setExplicitInstance(connectionInjector.getInstance(WebsocketUserContext), IdentityContext);
32
+ connectionInjector.setExplicitInstance(connectionInjector.getInstance(HttpUserContext), IdentityContext);
36
33
  this.clients.set(websocket, { injector: connectionInjector, message: msg, ws: websocket });
37
34
  websocket.on('message', (message) => {
38
- this.execute(message, connectionInjector);
35
+ this.execute(message, msg, connectionInjector, websocket);
39
36
  });
40
37
  websocket.on('close', () => {
41
38
  this.clients.delete(websocket);
@@ -77,11 +74,12 @@ let WebSocketApi = class WebSocketApi {
77
74
  throw new AggregatedError('The Broadcast operation encountered some errors', errors);
78
75
  }
79
76
  }
80
- execute(data, injector) {
81
- const action = this.settings.actions.find((a) => a.canExecute({ data }));
82
- if (action) {
83
- const actionInstance = injector.getInstance(action);
84
- actionInstance.execute({ data });
77
+ async execute(data, request, injector, socket) {
78
+ const Action = this.settings.actions.find((a) => a.canExecute({ data, request, socket }));
79
+ if (Action) {
80
+ await usingAsync(injector.getInstance(Action), async (action) => {
81
+ await action.execute({ data, request, socket });
82
+ });
85
83
  }
86
84
  }
87
85
  };
@@ -93,10 +91,6 @@ __decorate([
93
91
  Injected(ServerManager),
94
92
  __metadata("design:type", ServerManager)
95
93
  ], WebSocketApi.prototype, "serverManager", void 0);
96
- __decorate([
97
- Injected(Injector),
98
- __metadata("design:type", Injector)
99
- ], WebSocketApi.prototype, "injector", void 0);
100
94
  WebSocketApi = __decorate([
101
95
  Injectable({ lifetime: 'scoped' })
102
96
  ], WebSocketApi);
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-api.js","sourceRoot":"","sources":["../src/websocket-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket-api.js","sourceRoot":"","sources":["../src/websocket-api.ts"],"names":[],"mappings":"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"}
@@ -7,19 +7,23 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { Injector, Injectable } from '@furystack/inject';
8
8
  import { usingAsync } from '@furystack/utils';
9
9
  import { WebSocketApi } from './websocket-api.js';
10
- import WebSocket from 'ws';
10
+ import { WebSocket } from 'ws';
11
11
  import { useWebsockets } from './helpers.js';
12
12
  import { describe, it, expect } from 'vitest';
13
13
  import { getPort } from '@furystack/core/port-generator';
14
+ import { InMemoryStore, User, addStore } from '@furystack/core';
15
+ import { DefaultSession } from '@furystack/rest-service';
14
16
  describe('WebSocketApi', () => {
15
17
  it('Should be built', async () => {
16
18
  await usingAsync(new Injector(), async (i) => {
19
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }));
17
20
  useWebsockets(i, { port: getPort() });
18
21
  expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi);
19
22
  });
20
23
  });
21
24
  it('Should be built with settings', async () => {
22
25
  await usingAsync(new Injector(), async (i) => {
26
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }));
23
27
  useWebsockets(i, { path: '/web-socket', port: getPort() });
24
28
  expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi);
25
29
  });
@@ -27,6 +31,7 @@ describe('WebSocketApi', () => {
27
31
  it('Should broadcast messages', async () => {
28
32
  const port = getPort();
29
33
  await usingAsync(new Injector(), async (i) => {
34
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }));
30
35
  expect.assertions(5); // All 5 clients should receive the message
31
36
  useWebsockets(i, { path: '/web-socket', port });
32
37
  const api = i.getInstance(WebSocketApi);
@@ -49,6 +54,7 @@ describe('WebSocketApi', () => {
49
54
  it('Should receive client messages', async () => {
50
55
  const port = getPort();
51
56
  await usingAsync(new Injector(), async (i) => {
57
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }));
52
58
  expect.assertions(1);
53
59
  const data = { value: 'alma' };
54
60
  let ExampleWsAction = class ExampleWsAction {
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-api.spec.js","sourceRoot":"","sources":["../src/websocket-api.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket-api.spec.js","sourceRoot":"","sources":["../src/websocket-api.spec.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,21 @@
1
1
  import { Injector } from '@furystack/inject';
2
2
  import { WhoAmI } from './actions/whoami.js';
3
- import ws from 'ws';
4
- import { addStore, InMemoryStore, User } from '@furystack/core';
5
- import { DefaultSession, ServerManager, useHttpAuthentication } from '@furystack/rest-service';
3
+ import { WebSocket } from 'ws';
4
+ import { addStore, InMemoryStore, StoreManager, User } from '@furystack/core';
5
+ import { DefaultSession, HttpUserContext, ServerManager, useHttpAuthentication } from '@furystack/rest-service';
6
6
  import { useRestService } from '@furystack/rest-service';
7
7
  import { useWebsockets } from './helpers.js';
8
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
9
9
  import { getPort } from '@furystack/core/port-generator';
10
10
  describe('WebSocket Integration tests', () => {
11
11
  const host = 'localhost';
12
12
  const path = '/ws';
13
13
  let i;
14
14
  let client;
15
+ let port;
15
16
  beforeEach(async () => {
16
17
  i = new Injector();
17
- const port = getPort();
18
+ port = getPort();
18
19
  useRestService({
19
20
  injector: i,
20
21
  api: {},
@@ -29,7 +30,7 @@ describe('WebSocket Integration tests', () => {
29
30
  i.getInstance(ServerManager)
30
31
  .getOrCreate({ port })
31
32
  .then(() => {
32
- client = new ws(`ws://${host}:${port}/ws`);
33
+ client = new WebSocket(`ws://${host}:${port}/ws`);
33
34
  client
34
35
  .on('open', () => {
35
36
  done();
@@ -41,15 +42,54 @@ describe('WebSocket Integration tests', () => {
41
42
  afterEach(async () => {
42
43
  await i.dispose();
43
44
  });
44
- it('Should be connected', async () => {
45
- await new Promise((done) => {
46
- client.on('message', (data) => {
47
- expect(data.toString()).toBe('{"currentUser":null}');
48
- client.close();
49
- done();
45
+ const getWhoAmIResult = async (subjectClient) => {
46
+ return new Promise((resolve, reject) => {
47
+ subjectClient.once('message', (data) => {
48
+ resolve(JSON.parse(data.toString()));
50
49
  });
51
- client.send('whoami');
50
+ subjectClient.once('error', reject);
51
+ subjectClient.send('whoami');
52
52
  });
53
+ };
54
+ describe('Authentication', () => {
55
+ it('Should be unauthenticated by default', async () => {
56
+ expect((await getWhoAmIResult(client)).currentUser).toBe(null);
57
+ });
58
+ });
59
+ it('Should be authenticated, roles should be updated and should be logged out', async () => {
60
+ const testUser = { username: 'test', password: 'test', roles: [] };
61
+ const userStore = i.getInstance(StoreManager).getStoreFor(User, 'username');
62
+ userStore.add(testUser);
63
+ const userCtx = i.getInstance(HttpUserContext);
64
+ let cookie = '';
65
+ await userCtx.cookieLogin(testUser, {
66
+ setHeader: (_setCookie, cookieValue) => {
67
+ cookie = cookieValue;
68
+ return {};
69
+ },
70
+ });
71
+ const authenticatedClient = await new Promise((done, reject) => {
72
+ const cl = new WebSocket(`ws://${host}:${port}/ws`, {
73
+ headers: { cookie },
74
+ });
75
+ cl.once('open', () => {
76
+ done(cl);
77
+ }).once('error', reject);
78
+ });
79
+ const whoAmIResult = await getWhoAmIResult(authenticatedClient);
80
+ expect(whoAmIResult.currentUser).toEqual(testUser);
81
+ userStore.update(testUser.username, { ...testUser, roles: ['newFancyRole'] });
82
+ const updatedWhoAmIResult = await getWhoAmIResult(authenticatedClient);
83
+ expect(updatedWhoAmIResult.currentUser.roles).toEqual(['newFancyRole']);
84
+ await userCtx.cookieLogout({
85
+ headers: {
86
+ cookie,
87
+ },
88
+ }, {
89
+ setHeader: vi.fn(),
90
+ });
91
+ const loggedOutWhoAmIResult = await getWhoAmIResult(authenticatedClient);
92
+ expect(loggedOutWhoAmIResult.currentUser).toBe(null);
53
93
  });
54
94
  });
55
95
  //# sourceMappingURL=websocket-integration.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-integration.spec.js","sourceRoot":"","sources":["../src/websocket-integration.spec.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket-integration.spec.js","sourceRoot":"","sources":["../src/websocket-integration.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@furystack/websocket-api",
3
- "version": "11.0.0",
3
+ "version": "12.0.1",
4
4
  "description": "HTTP Api FuryStack package",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -34,16 +34,16 @@
34
34
  },
35
35
  "homepage": "https://github.com/furystack/furystack",
36
36
  "dependencies": {
37
- "@furystack/core": "^14.0.0",
38
- "@furystack/inject": "^10.0.0",
39
- "@furystack/rest-service": "^9.0.0",
40
- "@furystack/utils": "^6.0.0",
37
+ "@furystack/core": "^14.0.2",
38
+ "@furystack/inject": "^11.0.1",
39
+ "@furystack/rest-service": "^9.0.2",
40
+ "@furystack/utils": "^7.0.0",
41
41
  "ws": "^8.16.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/ws": "^8.5.10",
45
- "typescript": "^5.4.2",
46
- "vitest": "^1.4.0"
45
+ "typescript": "^5.4.5",
46
+ "vitest": "^1.5.0"
47
47
  },
48
48
  "gitHead": "1045d854bfd8c475b7035471d130d401417a2321"
49
49
  }
@@ -33,8 +33,7 @@ describe('Whoami action', () => {
33
33
  injector.setExplicitInstance(contextMock, HttpUserContext)
34
34
  injector.setExplicitInstance(wsMock, ws)
35
35
  const instance = injector.getInstance(WhoAmI)
36
-
37
- await instance.execute({ request, data: '' })
36
+ await instance.execute({ request, data: '', socket: wsMock })
38
37
  expect(wsMock.send).toBeCalledWith(JSON.stringify({ currentUser }))
39
38
  })
40
39
  })
@@ -1,7 +1,6 @@
1
1
  import { HttpUserContext } from '@furystack/rest-service'
2
2
  import { Injectable, Injected } from '@furystack/inject'
3
- import type { Data } from 'ws'
4
- import ws from 'ws'
3
+ import type { Data, WebSocket } from 'ws'
5
4
  import type { WebSocketAction } from '../models/websocket-action.js'
6
5
  import type { IncomingMessage } from 'http'
7
6
 
@@ -17,18 +16,15 @@ export class WhoAmI implements WebSocketAction {
17
16
  return options.data.toString() === 'whoami' || options.data.toString() === 'whoami /claims'
18
17
  }
19
18
 
20
- public async execute(options: { data: Data; request: IncomingMessage }) {
19
+ public async execute(options: { data: Data; request: IncomingMessage; socket: WebSocket }) {
21
20
  try {
22
21
  const currentUser = await this.httpUserContext.getCurrentUser(options.request)
23
- this.websocket.send(JSON.stringify({ currentUser }))
22
+ options.socket.send(JSON.stringify({ currentUser }))
24
23
  } catch (error) {
25
- this.websocket.send(JSON.stringify({ currentUser: null }))
24
+ options.socket.send(JSON.stringify({ currentUser: null }))
26
25
  }
27
26
  }
28
27
 
29
28
  @Injected(HttpUserContext)
30
- private readonly httpUserContext!: HttpUserContext
31
-
32
- @Injected(ws)
33
- private readonly websocket!: ws
29
+ private declare readonly httpUserContext: HttpUserContext
34
30
  }
@@ -1,16 +1,17 @@
1
1
  import type { Disposable } from '@furystack/utils'
2
- import type { Data } from 'ws'
2
+ import type { Data, WebSocket } from 'ws'
3
+ import type { IncomingMessage } from 'http'
3
4
 
4
5
  /**
5
6
  * Static methods of a WebSocket Action
6
7
  */
7
8
  export interface WebSocketActionStatic {
8
- canExecute(options: { data: Data }): boolean
9
+ canExecute(options: { data: Data; request: IncomingMessage; socket: WebSocket }): boolean
9
10
  }
10
11
 
11
12
  /**
12
13
  * A WebSocket action implementaion
13
14
  */
14
15
  export interface WebSocketAction extends Disposable {
15
- execute(options: { data: Data }): void
16
+ execute(options: { data: Data; request: IncomingMessage; socket: WebSocket }): void
16
17
  }
@@ -1,21 +1,30 @@
1
1
  import { Injector, Injectable } from '@furystack/inject'
2
2
  import { usingAsync } from '@furystack/utils'
3
3
  import { WebSocketApi } from './websocket-api.js'
4
- import WebSocket from 'ws'
4
+ import { WebSocket } from 'ws'
5
5
  import type { WebSocketAction } from './models/websocket-action.js'
6
6
  import { useWebsockets } from './helpers.js'
7
7
  import { describe, it, expect } from 'vitest'
8
8
  import { getPort } from '@furystack/core/port-generator'
9
+ import { InMemoryStore, User, addStore } from '@furystack/core'
10
+ import { DefaultSession } from '@furystack/rest-service'
9
11
 
10
12
  describe('WebSocketApi', () => {
11
13
  it('Should be built', async () => {
12
14
  await usingAsync(new Injector(), async (i) => {
15
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(
16
+ new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
17
+ )
13
18
  useWebsockets(i, { port: getPort() })
14
19
  expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi)
15
20
  })
16
21
  })
17
22
  it('Should be built with settings', async () => {
18
23
  await usingAsync(new Injector(), async (i) => {
24
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(
25
+ new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
26
+ )
27
+
19
28
  useWebsockets(i, { path: '/web-socket', port: getPort() })
20
29
  expect(i.getInstance(WebSocketApi)).toBeInstanceOf(WebSocketApi)
21
30
  })
@@ -24,6 +33,10 @@ describe('WebSocketApi', () => {
24
33
  it('Should broadcast messages', async () => {
25
34
  const port = getPort()
26
35
  await usingAsync(new Injector(), async (i) => {
36
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(
37
+ new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
38
+ )
39
+
27
40
  expect.assertions(5) // All 5 clients should receive the message
28
41
  useWebsockets(i, { path: '/web-socket', port })
29
42
  const api = i.getInstance(WebSocketApi)
@@ -51,6 +64,10 @@ describe('WebSocketApi', () => {
51
64
  it('Should receive client messages', async () => {
52
65
  const port = getPort()
53
66
  await usingAsync(new Injector(), async (i) => {
67
+ addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(
68
+ new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
69
+ )
70
+
54
71
  expect.assertions(1)
55
72
  const data = { value: 'alma' }
56
73
  @Injectable()
@@ -1,16 +1,17 @@
1
1
  import { URL } from 'url'
2
2
  import type { Socket } from 'net'
3
3
  import { IncomingMessage } from 'http'
4
- import { ServerManager } from '@furystack/rest-service'
5
- import { Injectable, Injected, Injector } from '@furystack/inject'
6
- import type { Disposable } from '@furystack/utils'
4
+ import { HttpUserContext, ServerManager } from '@furystack/rest-service'
5
+ import type { Injector } from '@furystack/inject'
6
+ import { Injectable, Injected } from '@furystack/inject'
7
+ import { usingAsync, type Disposable } from '@furystack/utils'
7
8
  import type { Data } from 'ws'
9
+ import type WebSocket from 'ws'
8
10
  import { WebSocketServer } from 'ws'
9
11
  import ws from 'ws'
10
12
  import { WebSocketApiSettings } from './websocket-api-settings.js'
11
13
  import type { WebSocketAction } from './models/websocket-action.js'
12
14
  import { AggregatedError, IdentityContext } from '@furystack/core'
13
- import { WebsocketUserContext } from './websocket-user-context.js'
14
15
 
15
16
  /**
16
17
  * A WebSocket API implementation for FuryStack
@@ -22,13 +23,12 @@ export class WebSocketApi implements Disposable {
22
23
  private clients = new Map<ws, { injector: Injector; ws: ws; message: IncomingMessage }>()
23
24
 
24
25
  @Injected(WebSocketApiSettings)
25
- private readonly settings!: WebSocketApiSettings
26
+ private declare readonly settings: WebSocketApiSettings
26
27
 
27
28
  @Injected(ServerManager)
28
- private readonly serverManager!: ServerManager
29
+ private declare readonly serverManager: ServerManager
29
30
 
30
- @Injected(Injector)
31
- private readonly injector!: Injector
31
+ private declare readonly injector: Injector
32
32
 
33
33
  private isInitialized = false
34
34
  public init() {
@@ -37,10 +37,10 @@ export class WebSocketApi implements Disposable {
37
37
  const connectionInjector = this.injector.createChild({ owner: msg })
38
38
  connectionInjector.setExplicitInstance(websocket, ws)
39
39
  connectionInjector.setExplicitInstance(msg, IncomingMessage)
40
- connectionInjector.setExplicitInstance(connectionInjector.getInstance(WebsocketUserContext), IdentityContext)
40
+ connectionInjector.setExplicitInstance(connectionInjector.getInstance(HttpUserContext), IdentityContext)
41
41
  this.clients.set(websocket, { injector: connectionInjector, message: msg, ws: websocket })
42
42
  websocket.on('message', (message) => {
43
- this.execute(message, connectionInjector)
43
+ this.execute(message, msg, connectionInjector, websocket)
44
44
  })
45
45
 
46
46
  websocket.on('close', () => {
@@ -88,11 +88,12 @@ export class WebSocketApi implements Disposable {
88
88
  }
89
89
  }
90
90
 
91
- public execute(data: Data, injector: Injector) {
92
- const action = this.settings.actions.find((a) => a.canExecute({ data }))
93
- if (action) {
94
- const actionInstance = injector.getInstance<WebSocketAction>(action)
95
- actionInstance.execute({ data })
91
+ public async execute(data: Data, request: IncomingMessage, injector: Injector, socket: WebSocket) {
92
+ const Action = this.settings.actions.find((a) => a.canExecute({ data, request, socket }))
93
+ if (Action) {
94
+ await usingAsync(injector.getInstance<WebSocketAction>(Action), async (action) => {
95
+ await action.execute({ data, request, socket })
96
+ })
96
97
  }
97
98
  }
98
99
  }
@@ -1,22 +1,23 @@
1
1
  import { Injector } from '@furystack/inject'
2
2
  import { WhoAmI } from './actions/whoami.js'
3
- import ws from 'ws'
4
- import { addStore, InMemoryStore, User } from '@furystack/core'
5
- import { DefaultSession, ServerManager, useHttpAuthentication } from '@furystack/rest-service'
3
+ import { WebSocket } from 'ws'
4
+ import { addStore, InMemoryStore, StoreManager, User } from '@furystack/core'
5
+ import { DefaultSession, HttpUserContext, ServerManager, useHttpAuthentication } from '@furystack/rest-service'
6
6
  import { useRestService } from '@furystack/rest-service'
7
7
  import { useWebsockets } from './helpers.js'
8
- import { describe, it, expect, beforeEach, afterEach } from 'vitest'
8
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
9
9
  import { getPort } from '@furystack/core/port-generator'
10
10
 
11
11
  describe('WebSocket Integration tests', () => {
12
12
  const host = 'localhost'
13
13
  const path = '/ws'
14
14
  let i!: Injector
15
- let client: ws
15
+ let client: WebSocket
16
+ let port: number
16
17
 
17
18
  beforeEach(async () => {
18
19
  i = new Injector()
19
- const port = getPort()
20
+ port = getPort()
20
21
  useRestService({
21
22
  injector: i,
22
23
  api: {},
@@ -34,7 +35,7 @@ describe('WebSocket Integration tests', () => {
34
35
  i.getInstance(ServerManager)
35
36
  .getOrCreate({ port })
36
37
  .then(() => {
37
- client = new ws(`ws://${host}:${port}/ws`)
38
+ client = new WebSocket(`ws://${host}:${port}/ws`)
38
39
  client
39
40
  .on('open', () => {
40
41
  done()
@@ -47,15 +48,66 @@ describe('WebSocket Integration tests', () => {
47
48
  afterEach(async () => {
48
49
  await i.dispose()
49
50
  })
51
+ const getWhoAmIResult = async (subjectClient: WebSocket) => {
52
+ return new Promise<{ currentUser: User }>((resolve, reject) => {
53
+ subjectClient.once('message', (data: any) => {
54
+ resolve(JSON.parse(data.toString()))
55
+ })
56
+ subjectClient.once('error', reject)
57
+ subjectClient.send('whoami')
58
+ })
59
+ }
60
+
61
+ describe('Authentication', () => {
62
+ it('Should be unauthenticated by default', async () => {
63
+ expect((await getWhoAmIResult(client)).currentUser).toBe(null)
64
+ })
65
+ })
66
+
67
+ it('Should be authenticated, roles should be updated and should be logged out', async () => {
68
+ const testUser = { username: 'test', password: 'test', roles: [] } as User
69
+
70
+ const userStore = i.getInstance(StoreManager).getStoreFor(User, 'username')
71
+ userStore.add(testUser)
72
+
73
+ const userCtx = i.getInstance(HttpUserContext)
50
74
 
51
- it('Should be connected', async () => {
52
- await new Promise<void>((done) => {
53
- client.on('message', (data) => {
54
- expect(data.toString()).toBe('{"currentUser":null}')
55
- client.close()
56
- done()
75
+ let cookie = ''
76
+ await userCtx.cookieLogin(testUser, {
77
+ setHeader: (_setCookie, cookieValue) => {
78
+ cookie = cookieValue as string
79
+ return {} as any
80
+ },
81
+ })
82
+
83
+ const authenticatedClient = await new Promise<WebSocket>((done, reject) => {
84
+ const cl = new WebSocket(`ws://${host}:${port}/ws`, {
85
+ headers: { cookie },
57
86
  })
58
- client.send('whoami')
87
+ cl.once('open', () => {
88
+ done(cl)
89
+ }).once('error', reject)
59
90
  })
91
+ const whoAmIResult = await getWhoAmIResult(authenticatedClient)
92
+ expect(whoAmIResult.currentUser).toEqual(testUser)
93
+
94
+ userStore.update(testUser.username, { ...testUser, roles: ['newFancyRole'] })
95
+
96
+ const updatedWhoAmIResult = await getWhoAmIResult(authenticatedClient)
97
+ expect(updatedWhoAmIResult.currentUser.roles).toEqual(['newFancyRole'])
98
+
99
+ await userCtx.cookieLogout(
100
+ {
101
+ headers: {
102
+ cookie,
103
+ },
104
+ },
105
+ {
106
+ setHeader: vi.fn(),
107
+ },
108
+ )
109
+
110
+ const loggedOutWhoAmIResult = await getWhoAmIResult(authenticatedClient)
111
+ expect(loggedOutWhoAmIResult.currentUser).toBe(null)
60
112
  })
61
113
  })
@@ -1,8 +0,0 @@
1
- import type { IdentityContext, User } from '@furystack/core';
2
- export declare class WebsocketUserContext implements IdentityContext {
3
- isAuthenticated(): Promise<boolean>;
4
- isAuthorized(...roles: string[]): Promise<boolean>;
5
- getCurrentUser<TUser extends User>(): Promise<TUser>;
6
- private readonly injector;
7
- }
8
- //# sourceMappingURL=websocket-user-context.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-user-context.d.ts","sourceRoot":"","sources":["../src/websocket-user-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAI5D,qBACa,oBAAqB,YAAW,eAAe;IAC7C,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAOnC,YAAY,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAalD,cAAc,CAAC,KAAK,SAAS,IAAI,KAAK,OAAO,CAAC,KAAK,CAAC;IAQjE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;CACrC"}
@@ -1,52 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- var __metadata = (this && this.__metadata) || function (k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- };
10
- import { IncomingMessage } from 'http';
11
- import { Injectable, Injected, Injector } from '@furystack/inject';
12
- import { HttpUserContext } from '@furystack/rest-service';
13
- let WebsocketUserContext = class WebsocketUserContext {
14
- async isAuthenticated() {
15
- try {
16
- return (await this.getCurrentUser()) ? true : false;
17
- }
18
- catch (error) {
19
- return false;
20
- }
21
- }
22
- async isAuthorized(...roles) {
23
- try {
24
- const currentUser = await this.getCurrentUser();
25
- for (const role of roles) {
26
- if (!currentUser || !currentUser.roles.some((c) => c === role)) {
27
- return false;
28
- }
29
- }
30
- return true;
31
- }
32
- catch (error) {
33
- return false;
34
- }
35
- }
36
- async getCurrentUser() {
37
- const user = await this.injector
38
- .getInstance(HttpUserContext)
39
- .authenticateRequest(this.injector.getInstance(IncomingMessage));
40
- return user;
41
- }
42
- injector;
43
- };
44
- __decorate([
45
- Injected(Injector),
46
- __metadata("design:type", Injector)
47
- ], WebsocketUserContext.prototype, "injector", void 0);
48
- WebsocketUserContext = __decorate([
49
- Injectable({ lifetime: 'scoped' })
50
- ], WebsocketUserContext);
51
- export { WebsocketUserContext };
52
- //# sourceMappingURL=websocket-user-context.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-user-context.js","sourceRoot":"","sources":["../src/websocket-user-context.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAEtC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAGlD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACxB,KAAK,CAAC,eAAe;QAC1B,IAAI,CAAC;YACH,OAAO,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAA;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IACM,KAAK,CAAC,YAAY,CAAC,GAAG,KAAe;QAC1C,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAA;YAC/C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;oBAC/D,OAAO,KAAK,CAAA;gBACd,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IACM,KAAK,CAAC,cAAc;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ;aAC7B,WAAW,CAAC,eAAe,CAAC;aAC5B,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAA;QAClE,OAAO,IAAa,CAAA;IACtB,CAAC;IAGgB,QAAQ,CAAW;CACrC,CAAA;AADkB;IADhB,QAAQ,CAAC,QAAQ,CAAC;8BACS,QAAQ;sDAAA;AA7BzB,oBAAoB;IADhC,UAAU,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;GACtB,oBAAoB,CA8BhC"}
@@ -1,2 +0,0 @@
1
- import '.';
2
- //# sourceMappingURL=websocket-user-context.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-user-context.spec.d.ts","sourceRoot":"","sources":["../src/websocket-user-context.spec.ts"],"names":[],"mappings":"AAEA,OAAO,GAAG,CAAA"}
@@ -1,68 +0,0 @@
1
- import { Injector } from '@furystack/inject';
2
- import { IncomingMessage } from 'http';
3
- import '.';
4
- import { HttpUserContext } from '@furystack/rest-service';
5
- import { usingAsync } from '@furystack/utils';
6
- import { WebsocketUserContext } from './websocket-user-context.js';
7
- import { describe, it, expect, vi } from 'vitest';
8
- describe('WebSocket User Context', () => {
9
- const mockUser = { username: 'mock@gmail.com', roles: [] };
10
- const mockAdmin = { username: 'mock@gmail.com', roles: ['admin'] };
11
- describe('isAuthenticated', () => {
12
- it('should authenticate with HttpUserContext and the IncomingMessage', async () => {
13
- await usingAsync(new Injector(), async (i) => {
14
- const authFn = vi.fn(async () => mockUser);
15
- const incomingMessage = {};
16
- i.setExplicitInstance(incomingMessage, IncomingMessage);
17
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext);
18
- const authResult = await i.getInstance(WebsocketUserContext).isAuthenticated();
19
- expect(authResult).toBeTruthy();
20
- expect(authFn).toBeCalledWith(incomingMessage);
21
- });
22
- });
23
- it('should return false if HttpUserContext throws', async () => {
24
- await usingAsync(new Injector(), async (i) => {
25
- const authFn = vi.fn(() => Promise.reject('Hey! No user here!'));
26
- const incomingMessage = {};
27
- i.setExplicitInstance(incomingMessage, IncomingMessage);
28
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext);
29
- const authResult = await i.getInstance(WebsocketUserContext).isAuthenticated();
30
- expect(authResult).toBeFalsy();
31
- expect(authFn).toBeCalledWith(incomingMessage);
32
- });
33
- });
34
- });
35
- describe('isAuthorized', () => {
36
- it('should return true if the user has the role', async () => {
37
- await usingAsync(new Injector(), async (i) => {
38
- const authFn = vi.fn(async () => mockAdmin);
39
- const incomingMessage = {};
40
- i.setExplicitInstance(incomingMessage, IncomingMessage);
41
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext);
42
- const authResult = await i.getInstance(WebsocketUserContext).isAuthorized('admin');
43
- expect(authResult).toBe(true);
44
- });
45
- });
46
- it('should return false if the user does not have the role', async () => {
47
- await usingAsync(new Injector(), async (i) => {
48
- const authFn = vi.fn(async () => mockUser);
49
- const incomingMessage = {};
50
- i.setExplicitInstance(incomingMessage, IncomingMessage);
51
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext);
52
- const authResult = await i.getInstance(WebsocketUserContext).isAuthorized('admin');
53
- expect(authResult).toBe(false);
54
- });
55
- });
56
- it('should return false if getting the current user throws', async () => {
57
- await usingAsync(new Injector(), async (i) => {
58
- const authFn = vi.fn(() => Promise.reject('Hey! No user here!'));
59
- const incomingMessage = {};
60
- i.setExplicitInstance(incomingMessage, IncomingMessage);
61
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext);
62
- const authResult = await i.getInstance(WebsocketUserContext).isAuthorized('admin');
63
- expect(authResult).toBe(false);
64
- });
65
- });
66
- });
67
- });
68
- //# sourceMappingURL=websocket-user-context.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"websocket-user-context.spec.js","sourceRoot":"","sources":["../src/websocket-user-context.spec.ts"],"names":[],"mappings":"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"}
@@ -1,73 +0,0 @@
1
- import { Injector } from '@furystack/inject'
2
- import { IncomingMessage } from 'http'
3
- import '.'
4
- import { HttpUserContext } from '@furystack/rest-service'
5
- import { usingAsync } from '@furystack/utils'
6
- import { WebsocketUserContext } from './websocket-user-context.js'
7
- import { describe, it, expect, vi } from 'vitest'
8
-
9
- describe('WebSocket User Context', () => {
10
- const mockUser = { username: 'mock@gmail.com', roles: [] }
11
- const mockAdmin = { username: 'mock@gmail.com', roles: ['admin'] }
12
-
13
- describe('isAuthenticated', () => {
14
- it('should authenticate with HttpUserContext and the IncomingMessage', async () => {
15
- await usingAsync(new Injector(), async (i) => {
16
- const authFn = vi.fn(async () => mockUser)
17
- const incomingMessage = {}
18
- i.setExplicitInstance(incomingMessage, IncomingMessage)
19
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext)
20
- const authResult = await i.getInstance(WebsocketUserContext).isAuthenticated()
21
- expect(authResult).toBeTruthy()
22
- expect(authFn).toBeCalledWith(incomingMessage)
23
- })
24
- })
25
-
26
- it('should return false if HttpUserContext throws', async () => {
27
- await usingAsync(new Injector(), async (i) => {
28
- const authFn = vi.fn(() => Promise.reject('Hey! No user here!'))
29
- const incomingMessage = {}
30
- i.setExplicitInstance(incomingMessage, IncomingMessage)
31
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext)
32
- const authResult = await i.getInstance(WebsocketUserContext).isAuthenticated()
33
- expect(authResult).toBeFalsy()
34
- expect(authFn).toBeCalledWith(incomingMessage)
35
- })
36
- })
37
- })
38
-
39
- describe('isAuthorized', () => {
40
- it('should return true if the user has the role', async () => {
41
- await usingAsync(new Injector(), async (i) => {
42
- const authFn = vi.fn(async () => mockAdmin)
43
- const incomingMessage = {}
44
- i.setExplicitInstance(incomingMessage, IncomingMessage)
45
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext)
46
- const authResult = await i.getInstance(WebsocketUserContext).isAuthorized('admin')
47
- expect(authResult).toBe(true)
48
- })
49
- })
50
-
51
- it('should return false if the user does not have the role', async () => {
52
- await usingAsync(new Injector(), async (i) => {
53
- const authFn = vi.fn(async () => mockUser)
54
- const incomingMessage = {}
55
- i.setExplicitInstance(incomingMessage, IncomingMessage)
56
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext)
57
- const authResult = await i.getInstance(WebsocketUserContext).isAuthorized('admin')
58
- expect(authResult).toBe(false)
59
- })
60
- })
61
-
62
- it('should return false if getting the current user throws', async () => {
63
- await usingAsync(new Injector(), async (i) => {
64
- const authFn = vi.fn(() => Promise.reject('Hey! No user here!'))
65
- const incomingMessage = {}
66
- i.setExplicitInstance(incomingMessage, IncomingMessage)
67
- i.setExplicitInstance({ authenticateRequest: authFn }, HttpUserContext)
68
- const authResult = await i.getInstance(WebsocketUserContext).isAuthorized('admin')
69
- expect(authResult).toBe(false)
70
- })
71
- })
72
- })
73
- })
@@ -1,37 +0,0 @@
1
- import { IncomingMessage } from 'http'
2
- import type { IdentityContext, User } from '@furystack/core'
3
- import { Injectable, Injected, Injector } from '@furystack/inject'
4
- import { HttpUserContext } from '@furystack/rest-service'
5
-
6
- @Injectable({ lifetime: 'scoped' })
7
- export class WebsocketUserContext implements IdentityContext {
8
- public async isAuthenticated(): Promise<boolean> {
9
- try {
10
- return (await this.getCurrentUser()) ? true : false
11
- } catch (error) {
12
- return false
13
- }
14
- }
15
- public async isAuthorized(...roles: string[]): Promise<boolean> {
16
- try {
17
- const currentUser = await this.getCurrentUser()
18
- for (const role of roles) {
19
- if (!currentUser || !currentUser.roles.some((c) => c === role)) {
20
- return false
21
- }
22
- }
23
- return true
24
- } catch (error) {
25
- return false
26
- }
27
- }
28
- public async getCurrentUser<TUser extends User>(): Promise<TUser> {
29
- const user = await this.injector
30
- .getInstance(HttpUserContext)
31
- .authenticateRequest(this.injector.getInstance(IncomingMessage))
32
- return user as TUser
33
- }
34
-
35
- @Injected(Injector)
36
- private readonly injector!: Injector
37
- }