remult 0.18.1-exp.24 → 0.18.1-exp.26

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/SseSubscriptionServer.d.ts +23 -0
  2. package/SseSubscriptionServer.js +136 -0
  3. package/esm/SseSubscriptionServer.d.ts +23 -0
  4. package/esm/SseSubscriptionServer.js +101 -0
  5. package/esm/graphql.js +81 -42
  6. package/esm/live-query/ably.js +6 -3
  7. package/esm/remult-express.d.ts +0 -8
  8. package/esm/remult-express.js +0 -122
  9. package/esm/server/core.d.ts +1 -0
  10. package/esm/server/core.js +1 -0
  11. package/esm/server/expressBridge.js +41 -17
  12. package/esm/src/buildRestDataProvider.d.ts +1 -1
  13. package/esm/src/context.js +1 -1
  14. package/esm/src/data-api.d.ts +2 -1
  15. package/esm/src/data-api.js +11 -13
  16. package/esm/src/data-providers/rest-data-provider.d.ts +1 -0
  17. package/esm/src/data-providers/rest-data-provider.js +5 -4
  18. package/esm/src/data-providers/sql-database.js +0 -2
  19. package/esm/src/live-query/LiveQueryClient.js +60 -55
  20. package/esm/src/live-query/SseSubscriptionClient.js +5 -5
  21. package/esm/src/live-query/SubscriptionChannel.d.ts +1 -1
  22. package/esm/src/live-query/SubscriptionChannel.js +14 -11
  23. package/esm/src/server-action.d.ts +1 -1
  24. package/graphql.js +164 -97
  25. package/live-query/ably.js +17 -5
  26. package/package.json +1 -1
  27. package/remult-express.d.ts +0 -8
  28. package/remult-express.js +1 -153
  29. package/server/core.d.ts +1 -0
  30. package/server/core.js +3 -1
  31. package/server/expressBridge.js +59 -26
  32. package/src/buildRestDataProvider.d.ts +1 -1
  33. package/src/context.js +1 -1
  34. package/src/data-api.d.ts +2 -1
  35. package/src/data-api.js +21 -21
  36. package/src/data-providers/rest-data-provider.d.ts +1 -0
  37. package/src/data-providers/rest-data-provider.js +10 -6
  38. package/src/data-providers/sql-database.js +0 -2
  39. package/src/live-query/LiveQueryClient.js +94 -73
  40. package/src/live-query/SseSubscriptionClient.js +34 -19
  41. package/src/live-query/SubscriptionChannel.d.ts +1 -1
  42. package/src/live-query/SubscriptionChannel.js +14 -11
  43. package/src/server-action.d.ts +1 -1
  44. package/esm/live-query/DataProviderLiveQueryStorage.d.ts +0 -21
  45. package/esm/live-query/DataProviderLiveQueryStorage.js +0 -71
  46. package/live-query/DataProviderLiveQueryStorage.d.ts +0 -21
  47. package/live-query/DataProviderLiveQueryStorage.js +0 -184
@@ -0,0 +1,23 @@
1
+ import { GenericResponse } from './server/index';
2
+ import { Remult } from './src/context';
3
+ import { SubscriptionServer } from './src/live-query/SubscriptionServer';
4
+ export declare class SseSubscriptionServer implements SubscriptionServer {
5
+ private canUserConnectToChannel?;
6
+ constructor(canUserConnectToChannel?: (channel: string, remult: Remult) => boolean);
7
+ publishMessage<T>(channel: string, message: any): void;
8
+ }
9
+ export interface ResponseRequiredForSSE {
10
+ write(data: string): void;
11
+ writeHead(status: number, headers: any): void;
12
+ flush?(): void;
13
+ }
14
+ export declare class clientConnection {
15
+ response: GenericResponse & ResponseRequiredForSSE;
16
+ channels: Record<string, boolean>;
17
+ close(): void;
18
+ closed: boolean;
19
+ write(eventData: string, eventType?: string): void;
20
+ connectionId: any;
21
+ constructor(response: GenericResponse & ResponseRequiredForSSE);
22
+ sendLiveMessage(): void;
23
+ }
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientConnection = exports.SseSubscriptionServer = void 0;
4
+ var tslib_1 = require("tslib");
5
+ var uuid_1 = require("uuid");
6
+ var SseSubscriptionServer = /** @class */ (function () {
7
+ function SseSubscriptionServer(canUserConnectToChannel) {
8
+ this.canUserConnectToChannel = canUserConnectToChannel;
9
+ //@internal
10
+ this.connections = [];
11
+ //@internal
12
+ this.debugMessageFileSaver = function (id, channel, message) { };
13
+ //@internal
14
+ this.debugFileSaver = function () { };
15
+ if (!this.canUserConnectToChannel) {
16
+ this.canUserConnectToChannel = function () { return true; };
17
+ }
18
+ }
19
+ //@internal
20
+ SseSubscriptionServer.prototype.subscribeToChannel = function (_a, res, remult, remove) {
21
+ var e_1, _b;
22
+ var channel = _a.channel, clientId = _a.clientId;
23
+ if (remove === void 0) { remove = false; }
24
+ try {
25
+ for (var _c = tslib_1.__values(this.connections), _d = _c.next(); !_d.done; _d = _c.next()) {
26
+ var c = _d.value;
27
+ if (c.connectionId === clientId) {
28
+ if (this.canUserConnectToChannel(channel, remult)) {
29
+ if (remove)
30
+ delete c.channels[channel];
31
+ else
32
+ c.channels[channel] = true;
33
+ res.success("ok");
34
+ this.debug();
35
+ return;
36
+ }
37
+ else {
38
+ res.forbidden();
39
+ this.debug();
40
+ return;
41
+ }
42
+ }
43
+ }
44
+ }
45
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
46
+ finally {
47
+ try {
48
+ if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
49
+ }
50
+ finally { if (e_1) throw e_1.error; }
51
+ }
52
+ res.error({ message: "client connection not found" });
53
+ };
54
+ SseSubscriptionServer.prototype.publishMessage = function (channel, message) {
55
+ var e_2, _a;
56
+ var data = JSON.stringify({ channel: channel, data: message });
57
+ try {
58
+ for (var _b = tslib_1.__values(this.connections), _c = _b.next(); !_c.done; _c = _b.next()) {
59
+ var sc = _c.value;
60
+ if (sc.channels[channel]) {
61
+ this.debugMessageFileSaver(sc.connectionId, channel, message);
62
+ sc.write(data);
63
+ }
64
+ }
65
+ }
66
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
67
+ finally {
68
+ try {
69
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
70
+ }
71
+ finally { if (e_2) throw e_2.error; }
72
+ }
73
+ };
74
+ //@internal
75
+ SseSubscriptionServer.prototype.openHttpServerStream = function (req, res) {
76
+ var _this = this;
77
+ res.writeHead(200, {
78
+ 'Content-Type': 'text/event-stream',
79
+ 'Cache-Control': 'no-cache',
80
+ 'Connection': 'keep-alive'
81
+ });
82
+ var cc = new clientConnection(res);
83
+ //const lastEventId = req.headers['last-event-id'];
84
+ this.connections.push(cc);
85
+ this.debug();
86
+ //@ts-ignore
87
+ req.on("close", function () {
88
+ cc.close();
89
+ _this.connections = _this.connections.filter(function (s) { return s !== cc; });
90
+ _this.debug();
91
+ });
92
+ return cc;
93
+ };
94
+ //@internal
95
+ SseSubscriptionServer.prototype.debug = function () {
96
+ this.debugFileSaver(this.connections.map(function (x) { return ({
97
+ id: x.connectionId,
98
+ channels: x.channels
99
+ }); }));
100
+ };
101
+ return SseSubscriptionServer;
102
+ }());
103
+ exports.SseSubscriptionServer = SseSubscriptionServer;
104
+ var clientConnection = /** @class */ (function () {
105
+ function clientConnection(response) {
106
+ this.response = response;
107
+ this.channels = {};
108
+ this.closed = false;
109
+ this.connectionId = uuid_1.v4();
110
+ this.write(this.connectionId, "connectionId");
111
+ this.sendLiveMessage();
112
+ }
113
+ clientConnection.prototype.close = function () {
114
+ this.closed = true;
115
+ };
116
+ clientConnection.prototype.write = function (eventData, eventType) {
117
+ if (eventType === void 0) { eventType = "message"; }
118
+ var event = "event:" + eventType;
119
+ // if (id != undefined)
120
+ // event += "\nid:" + id;
121
+ this.response.write(event + "\ndata:" + eventData + "\n\n");
122
+ if (this.response.flush)
123
+ this.response.flush();
124
+ };
125
+ clientConnection.prototype.sendLiveMessage = function () {
126
+ var _this = this;
127
+ if (this.closed)
128
+ return;
129
+ this.write("", "keep-alive");
130
+ setTimeout(function () {
131
+ _this.sendLiveMessage();
132
+ }, 45000);
133
+ };
134
+ return clientConnection;
135
+ }());
136
+ exports.clientConnection = clientConnection;
@@ -0,0 +1,23 @@
1
+ import { GenericResponse } from './server/index';
2
+ import { Remult } from './src/context';
3
+ import { SubscriptionServer } from './src/live-query/SubscriptionServer';
4
+ export declare class SseSubscriptionServer implements SubscriptionServer {
5
+ private canUserConnectToChannel?;
6
+ constructor(canUserConnectToChannel?: (channel: string, remult: Remult) => boolean);
7
+ publishMessage<T>(channel: string, message: any): void;
8
+ }
9
+ export interface ResponseRequiredForSSE {
10
+ write(data: string): void;
11
+ writeHead(status: number, headers: any): void;
12
+ flush?(): void;
13
+ }
14
+ export declare class clientConnection {
15
+ response: GenericResponse & ResponseRequiredForSSE;
16
+ channels: Record<string, boolean>;
17
+ close(): void;
18
+ closed: boolean;
19
+ write(eventData: string, eventType?: string): void;
20
+ connectionId: any;
21
+ constructor(response: GenericResponse & ResponseRequiredForSSE);
22
+ sendLiveMessage(): void;
23
+ }
@@ -0,0 +1,101 @@
1
+ import { v4 as uuid } from 'uuid';
2
+ export class SseSubscriptionServer {
3
+ constructor(canUserConnectToChannel) {
4
+ this.canUserConnectToChannel = canUserConnectToChannel;
5
+ //@internal
6
+ this.connections = [];
7
+ //@internal
8
+ this.debugMessageFileSaver = (id, channel, message) => { };
9
+ //@internal
10
+ this.debugFileSaver = () => { };
11
+ if (!this.canUserConnectToChannel) {
12
+ this.canUserConnectToChannel = () => true;
13
+ }
14
+ }
15
+ //@internal
16
+ subscribeToChannel({ channel, clientId }, res, remult, remove = false) {
17
+ for (const c of this.connections) {
18
+ if (c.connectionId === clientId) {
19
+ if (this.canUserConnectToChannel(channel, remult)) {
20
+ if (remove)
21
+ delete c.channels[channel];
22
+ else
23
+ c.channels[channel] = true;
24
+ res.success("ok");
25
+ this.debug();
26
+ return;
27
+ }
28
+ else {
29
+ res.forbidden();
30
+ this.debug();
31
+ return;
32
+ }
33
+ }
34
+ }
35
+ res.error({ message: "client connection not found" });
36
+ }
37
+ publishMessage(channel, message) {
38
+ const data = JSON.stringify({ channel, data: message });
39
+ for (const sc of this.connections) {
40
+ if (sc.channels[channel]) {
41
+ this.debugMessageFileSaver(sc.connectionId, channel, message);
42
+ sc.write(data);
43
+ }
44
+ }
45
+ }
46
+ //@internal
47
+ openHttpServerStream(req, res) {
48
+ res.writeHead(200, {
49
+ 'Content-Type': 'text/event-stream',
50
+ 'Cache-Control': 'no-cache',
51
+ 'Connection': 'keep-alive'
52
+ });
53
+ const cc = new clientConnection(res);
54
+ //const lastEventId = req.headers['last-event-id'];
55
+ this.connections.push(cc);
56
+ this.debug();
57
+ //@ts-ignore
58
+ req.on("close", () => {
59
+ cc.close();
60
+ this.connections = this.connections.filter(s => s !== cc);
61
+ this.debug();
62
+ });
63
+ return cc;
64
+ }
65
+ //@internal
66
+ debug() {
67
+ this.debugFileSaver(this.connections.map(x => ({
68
+ id: x.connectionId,
69
+ channels: x.channels
70
+ })));
71
+ }
72
+ }
73
+ export class clientConnection {
74
+ constructor(response) {
75
+ this.response = response;
76
+ this.channels = {};
77
+ this.closed = false;
78
+ this.connectionId = uuid();
79
+ this.write(this.connectionId, "connectionId");
80
+ this.sendLiveMessage();
81
+ }
82
+ close() {
83
+ this.closed = true;
84
+ }
85
+ write(eventData, eventType = "message") {
86
+ let event = "event:" + eventType;
87
+ // if (id != undefined)
88
+ // event += "\nid:" + id;
89
+ this.response.write(event + "\ndata:" + eventData + "\n\n");
90
+ if (this.response.flush)
91
+ this.response.flush();
92
+ }
93
+ sendLiveMessage() {
94
+ if (this.closed)
95
+ return;
96
+ this.write("", "keep-alive");
97
+ setTimeout(() => {
98
+ this.sendLiveMessage();
99
+ }, 45000);
100
+ }
101
+ }
package/esm/graphql.js CHANGED
@@ -1,17 +1,24 @@
1
1
  import { Remult } from ".";
2
2
  import { allEntities } from "./src/context";
3
- import { getEntityKey } from "./src/remult3";
4
3
  import { DataApi } from "./src/data-api";
5
4
  export function remultGraphql(api) {
6
5
  let r = new Remult();
7
- let types = '';
6
+ let types = [];
7
+ let filterTypes = '';
8
8
  let query = '';
9
9
  let root = {};
10
+ function getType(key) {
11
+ let t = types.find(t => t.key === key);
12
+ if (!t)
13
+ types.push((t = ({ fields: "", key, moreFields: "", resultProcessors: [] })));
14
+ return t;
15
+ }
10
16
  for (const e of allEntities) {
11
17
  let meta = r.repo(e).metadata;
12
- let fields = '';
13
18
  let filterFields = '';
14
- let key = getEntityKey(e);
19
+ let key = meta.key;
20
+ const t = getType(key);
21
+ let q = "\n\t" + key + "(options: options, filter:" + key + "Filter): [" + key + "]";
15
22
  if (key) {
16
23
  for (const f of meta.fields) {
17
24
  {
@@ -19,6 +26,7 @@ export function remultGraphql(api) {
19
26
  switch (f.valueType) {
20
27
  case Boolean:
21
28
  type = "Boolean";
29
+ break;
22
30
  case Number:
23
31
  {
24
32
  if (f.valueConverter?.fieldTypeInDb == 'integer')
@@ -26,8 +34,31 @@ export function remultGraphql(api) {
26
34
  else
27
35
  type = "Float";
28
36
  }
37
+ break;
38
+ }
39
+ if (allEntities.includes(f.valueType)) {
40
+ const refKey = r.repo(f.valueType).metadata.key;
41
+ t.fields += "\n\t" + f.key + ":" + refKey;
42
+ t.resultProcessors.push(r => {
43
+ const val = r[f.key];
44
+ r[f.key] = async (args, req, gqlInfo) => {
45
+ const queryResult = await root[refKey]({ ...args.filter, filter: { id: val }, options: { limit: 1 } }, req, gqlInfo);
46
+ if (queryResult.length > 0)
47
+ return queryResult[0];
48
+ return null;
49
+ };
50
+ });
51
+ let refT = getType(refKey);
52
+ refT.moreFields += q;
53
+ refT.resultProcessors.push(r => {
54
+ const val = r.id;
55
+ r[key] = async (args, req, gqlInfo) => {
56
+ return await root[key]({ filter: { ...args.filter, [f.key]: val }, options: args.options }, req, gqlInfo);
57
+ };
58
+ });
29
59
  }
30
- fields += "\n\t" + f.key + ":" + type;
60
+ else
61
+ t.fields += "\n\t" + f.key + ":" + type;
31
62
  for (const operator of ["", "_ne"]) {
32
63
  filterFields += "\n\t" + f.key + operator + ":" + type;
33
64
  }
@@ -44,41 +75,49 @@ export function remultGraphql(api) {
44
75
  filterFields += "\n\t" + f.key + "_in:[" + type + "]";
45
76
  }
46
77
  }
47
- types += "type " + key + "{" + fields + "\n}\n";
48
- types += "input " + key + "Filter{" + filterFields + "\n\tOR:[" + key + "Filter]\n}\n";
49
- query += "\n\t" + key + "(options: options, filter:" + key + "Filter): [" + key + "]";
50
- root[key] = async ({ options, filter }, req) => {
51
- let remult = await api.getRemult(req);
52
- let repo = remult.repo(e);
53
- let dApi = new DataApi(repo, remult);
54
- let result;
55
- let err;
56
- await dApi.getArray({
57
- success: x => result = x,
58
- created: undefined,
59
- deleted: undefined,
60
- error: x => err = x,
61
- forbidden: () => err = 'forbidden',
62
- notFound: () => err = 'not found',
63
- progress: undefined
64
- }, {
65
- get: key => {
66
- if (options)
67
- switch (key) {
68
- case "_limit":
69
- return options.limit;
70
- case "_page":
71
- return options.page;
72
- case "_sort":
73
- return options.sort;
74
- case "_order":
75
- return options.order;
78
+ filterTypes += "input " + key + "Filter{" + filterFields + "\n\tOR:[" + key + "Filter]\n}\n";
79
+ query += q;
80
+ root[key] = async ({ options, filter }, req, a) => {
81
+ return new Promise(async (res, error) => {
82
+ api.withRemult(req, undefined, async () => {
83
+ let remult = await api.getRemult(req);
84
+ let repo = remult.repo(e);
85
+ let dApi = new DataApi(repo, remult);
86
+ let result;
87
+ let err;
88
+ await dApi.getArray({
89
+ success: x => result = x.map(y => {
90
+ t.resultProcessors.forEach(z => z(y));
91
+ return y;
92
+ }),
93
+ created: undefined,
94
+ deleted: undefined,
95
+ error: x => err = x,
96
+ forbidden: () => err = 'forbidden',
97
+ notFound: () => err = 'not found',
98
+ progress: undefined
99
+ }, {
100
+ get: key => {
101
+ if (options)
102
+ switch (key) {
103
+ case "_limit":
104
+ return options.limit;
105
+ case "_page":
106
+ return options.page;
107
+ case "_sort":
108
+ return options.sort;
109
+ case "_order":
110
+ return options.order;
111
+ }
76
112
  }
77
- }
78
- }, filter);
79
- if (err)
80
- throw err;
81
- return result;
113
+ }, filter);
114
+ if (err) {
115
+ error(err);
116
+ return;
117
+ }
118
+ res(result);
119
+ });
120
+ });
82
121
  };
83
122
  }
84
123
  }
@@ -88,15 +127,15 @@ export function remultGraphql(api) {
88
127
  }
89
128
  return {
90
129
  rootValue: root,
91
- schema: `
130
+ schema: `${types.map(({ key, fields, moreFields }) => "type " + key + "{" + fields + moreFields + "\n}\n").join('')}
131
+ ${query}
132
+ ${filterTypes}
92
133
  input options{
93
134
  limit:Int
94
135
  page:Int
95
136
  sort:String
96
137
  order:String
97
138
  }
98
- ${types}
99
- ${query}
100
139
  `
101
140
  };
102
141
  }
@@ -7,10 +7,13 @@ export class AblySubscriptionClient {
7
7
  close: () => {
8
8
  this.ably.connection.close();
9
9
  },
10
- subscribe: (channel, handler) => {
10
+ subscribe: async (channel, handler) => {
11
11
  let myHandler = (y) => handler(y.data);
12
- this.ably.channels.get(channel).subscribe(y => myHandler(y));
13
- return () => { myHandler = () => { }; };
12
+ await this.ably.channels.get(channel).subscribe(y => myHandler(y));
13
+ return () => {
14
+ myHandler = () => { };
15
+ this.ably.channels.get(channel).unsubscribe();
16
+ };
14
17
  }
15
18
  };
16
19
  }
@@ -1,14 +1,6 @@
1
1
  import * as express from 'express';
2
2
  import { RemultServer, RemultServerOptions } from './server/expressBridge';
3
- import { Remult } from './src/context';
4
- import { SubscriptionServer } from './src/live-query/SubscriptionServer';
5
3
  export declare function remultExpress(options?: RemultServerOptions<express.Request> & {
6
4
  bodyParser?: boolean;
7
5
  bodySizeLimit?: string;
8
6
  }): express.RequestHandler & RemultServer;
9
- export declare class SseSubscriptionServer implements SubscriptionServer {
10
- private canUserConnectToChannel?;
11
- constructor(canUserConnectToChannel?: (channel: string, remult: Remult) => boolean);
12
- publishMessage<T>(channel: string, message: any): void;
13
- registerRoutes(router: express.Router, apiPath: string, server: RemultServer): void;
14
- }
@@ -1,8 +1,5 @@
1
1
  import * as express from 'express';
2
2
  import { createRemultServer } from './server/index';
3
- import { streamUrl } from './src/live-query/SubscriptionChannel';
4
- import { v4 as uuid } from 'uuid';
5
- import { remult } from './src/remult-proxy';
6
3
  export function remultExpress(options) {
7
4
  let app = express.Router();
8
5
  if (!options) {
@@ -15,15 +12,8 @@ export function remultExpress(options) {
15
12
  app.use(express.json({ limit: options.bodySizeLimit }));
16
13
  app.use(express.urlencoded({ extended: true, limit: options.bodySizeLimit }));
17
14
  }
18
- if (!options.subscriptionServer) {
19
- options.subscriptionServer = new SseSubscriptionServer();
20
- }
21
15
  const server = createRemultServer(options);
22
16
  server.registerRouter(app);
23
- const canRegisterRoute = options.subscriptionServer;
24
- if (canRegisterRoute.registerRoutes) {
25
- canRegisterRoute.registerRoutes(app, options.rootPath, server);
26
- }
27
17
  return Object.assign(app, {
28
18
  getRemult: (req) => server.getRemult(req),
29
19
  openApiDoc: (options) => server.openApiDoc(options),
@@ -31,115 +21,3 @@ export function remultExpress(options) {
31
21
  withRemult: (...args) => server.withRemult(...args)
32
22
  });
33
23
  }
34
- export class SseSubscriptionServer {
35
- constructor(canUserConnectToChannel) {
36
- this.canUserConnectToChannel = canUserConnectToChannel;
37
- //@internal
38
- this.connections = [];
39
- //@internal
40
- this.debugMessageFileSaver = (id, channel, message) => { };
41
- //@internal
42
- this.debugFileSaver = () => { };
43
- if (!this.canUserConnectToChannel) {
44
- this.canUserConnectToChannel = () => true;
45
- }
46
- }
47
- //@internal
48
- subscribeToChannel({ channel, clientId }, res, remult, remove = false) {
49
- for (const c of this.connections) {
50
- if (c.connectionId === clientId) {
51
- if (this.canUserConnectToChannel(channel, remult)) {
52
- if (remove)
53
- delete c.channels[channel];
54
- else
55
- c.channels[channel] = true;
56
- res.json("ok");
57
- this.debug();
58
- return;
59
- }
60
- else {
61
- res.sendStatus(403);
62
- this.debug();
63
- return;
64
- }
65
- }
66
- }
67
- res.sendStatus(404);
68
- }
69
- publishMessage(channel, message) {
70
- const data = JSON.stringify({ channel, data: message });
71
- for (const sc of this.connections) {
72
- if (sc.channels[channel]) {
73
- this.debugMessageFileSaver(sc.connectionId, channel, message);
74
- sc.write(data);
75
- }
76
- }
77
- }
78
- //@internal
79
- openHttpServerStream(req, res) {
80
- res.writeHead(200, {
81
- 'Content-Type': 'text/event-stream',
82
- 'Cache-Control': 'no-cache',
83
- 'Connection': 'keep-alive'
84
- });
85
- const cc = new clientConnection(res);
86
- //const lastEventId = req.headers['last-event-id'];
87
- this.connections.push(cc);
88
- this.debug();
89
- req.on("close", () => {
90
- cc.close();
91
- this.connections = this.connections.filter(s => s !== cc);
92
- this.debug();
93
- });
94
- return cc;
95
- }
96
- //@internal
97
- debug() {
98
- this.debugFileSaver(this.connections.map(x => ({
99
- id: x.connectionId,
100
- channels: x.channels
101
- })));
102
- }
103
- registerRoutes(router, apiPath, server) {
104
- const streamPath = apiPath + '/' + streamUrl;
105
- router.get(streamPath, (r, res, next) => server.withRemult(r, res, next), (req, res) => {
106
- remult.subscriptionServer.openHttpServerStream(req, res);
107
- });
108
- router.post(streamPath + '/subscribe', (r, res, next) => server.withRemult(r, res, next), (req, res) => {
109
- remult.subscriptionServer.subscribeToChannel(req.body, res, remult);
110
- });
111
- router.post(streamPath + '/unsubscribe', (r, res, next) => server.withRemult(r, res, next), (req, res) => {
112
- remult.subscriptionServer.subscribeToChannel(req.body, res, remult, true);
113
- });
114
- }
115
- }
116
- class clientConnection {
117
- constructor(response) {
118
- this.response = response;
119
- this.channels = {};
120
- this.closed = false;
121
- this.connectionId = uuid();
122
- this.write(this.connectionId, "connectionId");
123
- this.sendLiveMessage();
124
- }
125
- close() {
126
- this.closed = true;
127
- }
128
- write(eventData, eventType = "message") {
129
- let event = "event:" + eventType;
130
- // if (id != undefined)
131
- // event += "\nid:" + id;
132
- this.response.write(event + "\ndata:" + eventData + "\n\n");
133
- let r = this.response;
134
- if (r.flush)
135
- r.flush();
136
- }
137
- sendLiveMessage() {
138
- if (this.closed)
139
- return;
140
- this.write("", "keep-alive");
141
- setTimeout(() => {
142
- this.sendLiveMessage();
143
- }, 45000);
144
- }
145
- }
@@ -1,2 +1,3 @@
1
1
  export { queuedJobInfo, QueueStorage, GenericRequest, GenericRequestHandler, GenericResponse, GenericRouter, createRemultServerCore, RemultServerOptions, SpecificRoute, RemultServer } from './expressBridge';
2
2
  export { JsonEntityFileStorage, JsonFileDataProvider } from './JsonEntityFileStorage';
3
+ export { SseSubscriptionServer } from '../SseSubscriptionServer';
@@ -1,2 +1,3 @@
1
1
  export { createRemultServerCore } from './expressBridge';
2
2
  export { JsonEntityFileStorage, JsonFileDataProvider } from './JsonEntityFileStorage';
3
+ export { SseSubscriptionServer } from '../SseSubscriptionServer';