@featbit/js-client-sdk 3.0.13 → 3.0.14

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 (113) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +301 -301
  3. package/dist/esm/IFbClientCore.d.ts +1 -1
  4. package/dist/esm/IFbClientCore.d.ts.map +1 -1
  5. package/dist/esm/version.d.ts +1 -1
  6. package/dist/esm/version.js +1 -1
  7. package/dist/umd/{featbit-js-client-sdk-3.0.13.js → featbit-js-client-sdk-3.0.14.js} +2 -2
  8. package/dist/umd/featbit-js-client-sdk-3.0.14.js.map +1 -0
  9. package/dist/umd/featbit-js-client-sdk.js +1 -1
  10. package/dist/umd/featbit-js-client-sdk.js.map +1 -1
  11. package/package.json +46 -46
  12. package/src/Configuration.ts +232 -232
  13. package/src/Context.ts +61 -61
  14. package/src/FbClientBuilder.ts +167 -167
  15. package/src/FbClientCore.ts +405 -405
  16. package/src/IContextProperty.ts +3 -3
  17. package/src/IDataKind.ts +11 -11
  18. package/src/IFbClient.ts +29 -29
  19. package/src/IFbClientCore.ts +290 -290
  20. package/src/IVersionedData.ts +18 -18
  21. package/src/bootstrap/IBootstrapProvider.ts +4 -4
  22. package/src/bootstrap/JsonBootstrapProvider.ts +34 -34
  23. package/src/bootstrap/NullBootstrapProvider.ts +20 -20
  24. package/src/bootstrap/index.ts +2 -2
  25. package/src/constants.ts +1 -1
  26. package/src/data-sources/DataSourceUpdates.ts +116 -116
  27. package/src/data-sources/createStreamListeners.ts +67 -67
  28. package/src/data-sources/index.ts +1 -1
  29. package/src/data-sync/DataSyncMode.ts +3 -3
  30. package/src/data-sync/IDataSynchronizer.ts +15 -15
  31. package/src/data-sync/IRequestor.ts +10 -10
  32. package/src/data-sync/NullDataSynchronizer.ts +14 -14
  33. package/src/data-sync/PollingDataSynchronizer.ts +125 -125
  34. package/src/data-sync/Requestor.ts +61 -61
  35. package/src/data-sync/WebSocketDataSynchronizer.ts +77 -77
  36. package/src/data-sync/index.ts +8 -8
  37. package/src/data-sync/types.ts +19 -19
  38. package/src/data-sync/utils.ts +31 -31
  39. package/src/errors.ts +47 -47
  40. package/src/evaluation/EvalResult.ts +35 -35
  41. package/src/evaluation/Evaluator.ts +26 -26
  42. package/src/evaluation/IEvalDetail.ts +23 -23
  43. package/src/evaluation/ReasonKinds.ts +9 -9
  44. package/src/evaluation/data/IFlag.ts +29 -29
  45. package/src/evaluation/index.ts +4 -4
  46. package/src/events/DefaultEventProcessor.ts +83 -83
  47. package/src/events/DefaultEventQueue.ts +49 -49
  48. package/src/events/DefaultEventSender.ts +73 -73
  49. package/src/events/DefaultEventSerializer.ts +11 -11
  50. package/src/events/EventDispatcher.ts +127 -127
  51. package/src/events/EventSerializer.ts +4 -4
  52. package/src/events/IEventProcessor.ts +8 -8
  53. package/src/events/IEventQueue.ts +16 -16
  54. package/src/events/IEventSender.ts +13 -13
  55. package/src/events/NullEventProcessor.ts +15 -15
  56. package/src/events/event.ts +129 -129
  57. package/src/events/index.ts +11 -11
  58. package/src/index.ts +21 -21
  59. package/src/integrations/TestLogger.ts +24 -24
  60. package/src/integrations/index.ts +1 -1
  61. package/src/integrations/test_data/FlagBuilder.ts +59 -59
  62. package/src/integrations/test_data/TestData.ts +57 -57
  63. package/src/integrations/test_data/TestDataSynchronizer.ts +49 -49
  64. package/src/integrations/test_data/index.ts +4 -4
  65. package/src/logging/BasicLogger.ts +108 -108
  66. package/src/logging/IBasicLoggerOptions.ts +46 -46
  67. package/src/logging/ILogger.ts +49 -49
  68. package/src/logging/LogLevel.ts +8 -8
  69. package/src/logging/SafeLogger.ts +69 -69
  70. package/src/logging/format.ts +154 -154
  71. package/src/logging/index.ts +5 -5
  72. package/src/options/ClientContext.ts +39 -39
  73. package/src/options/IClientContext.ts +53 -53
  74. package/src/options/IOptions.ts +123 -123
  75. package/src/options/IUser.ts +6 -6
  76. package/src/options/IValidatedOptions.ts +29 -29
  77. package/src/options/OptionMessages.ts +35 -35
  78. package/src/options/UserBuilder.ts +35 -35
  79. package/src/options/Validators.ts +300 -300
  80. package/src/options/index.ts +7 -7
  81. package/src/platform/IInfo.ts +102 -102
  82. package/src/platform/IPlatform.ts +20 -20
  83. package/src/platform/IStore.ts +112 -112
  84. package/src/platform/IWebSocket.ts +22 -22
  85. package/src/platform/browser/BrowserInfo.ts +24 -24
  86. package/src/platform/browser/BrowserPlatform.ts +19 -19
  87. package/src/platform/browser/BrowserRequests.ts +6 -6
  88. package/src/platform/browser/BrowserWebSocket.ts +147 -147
  89. package/src/platform/browser/FbClient.ts +65 -65
  90. package/src/platform/browser/LocalStorageStore.ts +59 -59
  91. package/src/platform/index.ts +11 -11
  92. package/src/platform/requests.ts +76 -76
  93. package/src/store/BaseStore.ts +125 -125
  94. package/src/store/DataKinds.ts +6 -6
  95. package/src/store/IDataSourceUpdates.ts +68 -68
  96. package/src/store/InMemoryStore.ts +36 -36
  97. package/src/store/index.ts +5 -5
  98. package/src/store/serialization.ts +52 -52
  99. package/src/store/store.ts +37 -37
  100. package/src/utils/Emits.ts +75 -75
  101. package/src/utils/EventEmitter.ts +128 -128
  102. package/src/utils/IEventEmitter.ts +14 -14
  103. package/src/utils/Regex.ts +21 -21
  104. package/src/utils/ValueConverters.ts +55 -55
  105. package/src/utils/canonicalizeUri.ts +3 -3
  106. package/src/utils/debounce.ts +33 -33
  107. package/src/utils/http.ts +40 -40
  108. package/src/utils/index.ts +5 -5
  109. package/src/utils/isNullOrUndefined.ts +2 -2
  110. package/src/utils/serializeUser.ts +27 -27
  111. package/src/utils/sleep.ts +5 -5
  112. package/src/version.ts +1 -1
  113. package/dist/umd/featbit-js-client-sdk-3.0.13.js.map +0 -1
@@ -1,125 +1,125 @@
1
- import { isHttpRecoverable, PollingError } from "../errors";
2
- import { IDataSynchronizer } from "./IDataSynchronizer";
3
- import { ILogger } from "../logging/ILogger";
4
- import Configuration from "../Configuration";
5
- import { EventName, PollingErrorHandler, ProcessStreamResponse, StreamResponseEventType } from "./types";
6
- import Requestor from "./Requestor";
7
- import { httpErrorMessage } from "../utils/http";
8
- import { IUser } from "../options/IUser";
9
-
10
- export default class PollingDataSynchronizer implements IDataSynchronizer {
11
- private stopped = false;
12
-
13
- private logger?: ILogger;
14
-
15
- private pollingInterval: number;
16
-
17
- private user: IUser | undefined;
18
-
19
- private timeoutHandle: any;
20
-
21
- constructor(
22
- config: Configuration,
23
- private readonly requestor: Requestor,
24
- private readonly getStoreTimestamp: () => number,
25
- private readonly listeners: Map<EventName, ProcessStreamResponse>,
26
- private readonly errorHandler?: PollingErrorHandler,
27
- ) {
28
- this.logger = config.logger;
29
- this.pollingInterval = config.pollingInterval;
30
- this.user = config.user;
31
- }
32
-
33
- private poll(resolve?: () => void, reject?: () => void) {
34
- if (this.stopped) {
35
- return;
36
- }
37
-
38
- const startTime = Date.now();
39
- this.logger?.debug('Polling for feature flag and segments updates');
40
- this.requestor.requestData(this.getStoreTimestamp(), this.user, async (err, body) => {
41
- const elapsed = Date.now() - startTime;
42
- const sleepFor = Math.max(this.pollingInterval - elapsed, 0);
43
-
44
- this.logger?.debug('Elapsed: %d ms, sleeping for %d ms', elapsed, sleepFor);
45
- if (err) {
46
- const {status} = err;
47
- if (status && !isHttpRecoverable(status)) {
48
- const message = httpErrorMessage(err, 'polling request');
49
- this.logger?.error(message);
50
- this.errorHandler?.(new PollingError(message, status));
51
- // It is not recoverable, return and do not trigger another
52
- // poll.
53
- reject?.();
54
- return;
55
- }
56
- this.logger?.warn(httpErrorMessage(err, 'polling request', 'will retry'));
57
- // Falling through, there was some type of error, we need to trigger
58
- // a new poll.
59
- this.timeoutHandle = setTimeout(() => {
60
- this.poll(resolve, reject);
61
- }, sleepFor);
62
- } else {
63
- let featureFlags = [];
64
- let userKeyId = this.user?.keyId!;
65
- let processStreamResponse: ProcessStreamResponse | undefined = this.listeners.get('patch');
66
-
67
- if (body) {
68
- const message = JSON.parse(body);
69
- if (message.messageType === 'data-sync') {
70
- switch (message.data.eventType) {
71
- case StreamResponseEventType.patch:
72
- processStreamResponse = this.listeners.get('patch');
73
- break;
74
- case StreamResponseEventType.full:
75
- processStreamResponse = this.listeners.get('put');
76
- break;
77
- }
78
-
79
- ({featureFlags, userKeyId} = message.data);
80
- }
81
- }
82
-
83
- const data = processStreamResponse?.deserializeData?.(featureFlags);
84
- await processStreamResponse?.processJson?.(userKeyId, data);
85
- resolve?.();
86
- // Falling through, there was some type of error, we need to trigger
87
- // a new poll.
88
- this.timeoutHandle = setTimeout(() => {
89
- this.poll();
90
- }, sleepFor);
91
- }
92
- });
93
- }
94
-
95
- async identify(user: IUser): Promise<void> {
96
- this.user = {...user};
97
- if (this.timeoutHandle) {
98
- clearTimeout(this.timeoutHandle);
99
- this.timeoutHandle = undefined;
100
- }
101
-
102
- return new Promise((resolve, reject) => {
103
- this.poll(resolve, reject);
104
- });
105
- }
106
-
107
- close(): void {
108
- this.stop();
109
- }
110
-
111
- start(): void {
112
- this.poll();
113
- }
114
-
115
- stop(): void {
116
- if (this.timeoutHandle) {
117
- clearTimeout(this.timeoutHandle);
118
- this.timeoutHandle = undefined;
119
- }
120
- this.stopped = true;
121
- }
122
- }
123
-
124
-
125
-
1
+ import { isHttpRecoverable, PollingError } from "../errors";
2
+ import { IDataSynchronizer } from "./IDataSynchronizer";
3
+ import { ILogger } from "../logging/ILogger";
4
+ import Configuration from "../Configuration";
5
+ import { EventName, PollingErrorHandler, ProcessStreamResponse, StreamResponseEventType } from "./types";
6
+ import Requestor from "./Requestor";
7
+ import { httpErrorMessage } from "../utils/http";
8
+ import { IUser } from "../options/IUser";
9
+
10
+ export default class PollingDataSynchronizer implements IDataSynchronizer {
11
+ private stopped = false;
12
+
13
+ private logger?: ILogger;
14
+
15
+ private pollingInterval: number;
16
+
17
+ private user: IUser | undefined;
18
+
19
+ private timeoutHandle: any;
20
+
21
+ constructor(
22
+ config: Configuration,
23
+ private readonly requestor: Requestor,
24
+ private readonly getStoreTimestamp: () => number,
25
+ private readonly listeners: Map<EventName, ProcessStreamResponse>,
26
+ private readonly errorHandler?: PollingErrorHandler,
27
+ ) {
28
+ this.logger = config.logger;
29
+ this.pollingInterval = config.pollingInterval;
30
+ this.user = config.user;
31
+ }
32
+
33
+ private poll(resolve?: () => void, reject?: () => void) {
34
+ if (this.stopped) {
35
+ return;
36
+ }
37
+
38
+ const startTime = Date.now();
39
+ this.logger?.debug('Polling for feature flag and segments updates');
40
+ this.requestor.requestData(this.getStoreTimestamp(), this.user, async (err, body) => {
41
+ const elapsed = Date.now() - startTime;
42
+ const sleepFor = Math.max(this.pollingInterval - elapsed, 0);
43
+
44
+ this.logger?.debug('Elapsed: %d ms, sleeping for %d ms', elapsed, sleepFor);
45
+ if (err) {
46
+ const {status} = err;
47
+ if (status && !isHttpRecoverable(status)) {
48
+ const message = httpErrorMessage(err, 'polling request');
49
+ this.logger?.error(message);
50
+ this.errorHandler?.(new PollingError(message, status));
51
+ // It is not recoverable, return and do not trigger another
52
+ // poll.
53
+ reject?.();
54
+ return;
55
+ }
56
+ this.logger?.warn(httpErrorMessage(err, 'polling request', 'will retry'));
57
+ // Falling through, there was some type of error, we need to trigger
58
+ // a new poll.
59
+ this.timeoutHandle = setTimeout(() => {
60
+ this.poll(resolve, reject);
61
+ }, sleepFor);
62
+ } else {
63
+ let featureFlags = [];
64
+ let userKeyId = this.user?.keyId!;
65
+ let processStreamResponse: ProcessStreamResponse | undefined = this.listeners.get('patch');
66
+
67
+ if (body) {
68
+ const message = JSON.parse(body);
69
+ if (message.messageType === 'data-sync') {
70
+ switch (message.data.eventType) {
71
+ case StreamResponseEventType.patch:
72
+ processStreamResponse = this.listeners.get('patch');
73
+ break;
74
+ case StreamResponseEventType.full:
75
+ processStreamResponse = this.listeners.get('put');
76
+ break;
77
+ }
78
+
79
+ ({featureFlags, userKeyId} = message.data);
80
+ }
81
+ }
82
+
83
+ const data = processStreamResponse?.deserializeData?.(featureFlags);
84
+ await processStreamResponse?.processJson?.(userKeyId, data);
85
+ resolve?.();
86
+ // Falling through, there was some type of error, we need to trigger
87
+ // a new poll.
88
+ this.timeoutHandle = setTimeout(() => {
89
+ this.poll();
90
+ }, sleepFor);
91
+ }
92
+ });
93
+ }
94
+
95
+ async identify(user: IUser): Promise<void> {
96
+ this.user = {...user};
97
+ if (this.timeoutHandle) {
98
+ clearTimeout(this.timeoutHandle);
99
+ this.timeoutHandle = undefined;
100
+ }
101
+
102
+ return new Promise((resolve, reject) => {
103
+ this.poll(resolve, reject);
104
+ });
105
+ }
106
+
107
+ close(): void {
108
+ this.stop();
109
+ }
110
+
111
+ start(): void {
112
+ this.poll();
113
+ }
114
+
115
+ stop(): void {
116
+ if (this.timeoutHandle) {
117
+ clearTimeout(this.timeoutHandle);
118
+ this.timeoutHandle = undefined;
119
+ }
120
+ this.stopped = true;
121
+ }
122
+ }
123
+
124
+
125
+
@@ -1,61 +1,61 @@
1
- import { IRequestor } from "./IRequestor";
2
- import Configuration from "../Configuration";
3
- import { IInfo } from "../platform/IInfo";
4
- import { IRequestOptions, IRequests, IResponse } from "../platform/requests";
5
- import { StreamingError } from "../errors";
6
- import { defaultHeaders } from "../utils/http";
7
-
8
- /**
9
- * @internal
10
- */
11
- export default class Requestor implements IRequestor {
12
- private readonly headers: Record<string, string>;
13
-
14
- private readonly uri: string;
15
-
16
- constructor(
17
- sdkKey: string,
18
- config: Configuration,
19
- info: IInfo,
20
- private readonly requests: IRequests,
21
- ) {
22
- this.headers = defaultHeaders(sdkKey, info);
23
- this.uri = config.pollingUri;
24
- }
25
-
26
- /**
27
- * Perform a request and utilize the ETag cache. The ETags are cached in the
28
- * requestor instance.
29
- */
30
- private async request(
31
- requestUrl: string,
32
- options: IRequestOptions,
33
- ): Promise<{
34
- res: IResponse;
35
- body: string;
36
- }> {
37
- const res = await this.requests.fetch(requestUrl, options);
38
-
39
- const body = await res.text();
40
-
41
- return {res, body};
42
- }
43
-
44
- async requestData(timestamp: number, payload: any, cb: (err: any, body: any) => void) {
45
- const options: IRequestOptions = {
46
- method: 'POST',
47
- headers: this.headers,
48
- body: JSON.stringify(payload)
49
- };
50
- try {
51
- const {res, body} = await this.request(`${ this.uri }?timestamp=${ timestamp ?? 0 }`, options);
52
- if (res.status !== 200 && res.status !== 304) {
53
- const err = new StreamingError(`Unexpected status code: ${ res.status }`, res.status);
54
- return cb(err, undefined);
55
- }
56
- return cb(undefined, res.status === 304 ? null : body);
57
- } catch (err) {
58
- return cb(err, undefined);
59
- }
60
- }
61
- }
1
+ import { IRequestor } from "./IRequestor";
2
+ import Configuration from "../Configuration";
3
+ import { IInfo } from "../platform/IInfo";
4
+ import { IRequestOptions, IRequests, IResponse } from "../platform/requests";
5
+ import { StreamingError } from "../errors";
6
+ import { defaultHeaders } from "../utils/http";
7
+
8
+ /**
9
+ * @internal
10
+ */
11
+ export default class Requestor implements IRequestor {
12
+ private readonly headers: Record<string, string>;
13
+
14
+ private readonly uri: string;
15
+
16
+ constructor(
17
+ sdkKey: string,
18
+ config: Configuration,
19
+ info: IInfo,
20
+ private readonly requests: IRequests,
21
+ ) {
22
+ this.headers = defaultHeaders(sdkKey, info);
23
+ this.uri = config.pollingUri;
24
+ }
25
+
26
+ /**
27
+ * Perform a request and utilize the ETag cache. The ETags are cached in the
28
+ * requestor instance.
29
+ */
30
+ private async request(
31
+ requestUrl: string,
32
+ options: IRequestOptions,
33
+ ): Promise<{
34
+ res: IResponse;
35
+ body: string;
36
+ }> {
37
+ const res = await this.requests.fetch(requestUrl, options);
38
+
39
+ const body = await res.text();
40
+
41
+ return {res, body};
42
+ }
43
+
44
+ async requestData(timestamp: number, payload: any, cb: (err: any, body: any) => void) {
45
+ const options: IRequestOptions = {
46
+ method: 'POST',
47
+ headers: this.headers,
48
+ body: JSON.stringify(payload)
49
+ };
50
+ try {
51
+ const {res, body} = await this.request(`${ this.uri }?timestamp=${ timestamp ?? 0 }`, options);
52
+ if (res.status !== 200 && res.status !== 304) {
53
+ const err = new StreamingError(`Unexpected status code: ${ res.status }`, res.status);
54
+ return cb(err, undefined);
55
+ }
56
+ return cb(undefined, res.status === 304 ? null : body);
57
+ } catch (err) {
58
+ return cb(err, undefined);
59
+ }
60
+ }
61
+ }
@@ -1,78 +1,78 @@
1
- import { IDataSynchronizer } from "./IDataSynchronizer";
2
- import ClientContext from "../options/ClientContext";
3
- import { EventName, ProcessStreamResponse } from "./types";
4
- import { ILogger } from "../logging/ILogger";
5
- import { IWebSocketWithEvents } from "../platform/IWebSocket";
6
- import { IUser } from "../options/IUser";
7
-
8
- class WebSocketDataSynchronizer implements IDataSynchronizer {
9
- private socket?: IWebSocketWithEvents;
10
- private readonly logger?: ILogger;
11
- private identifyResolve?: () => void;
12
-
13
- private connectionAttemptStartTime?: number;
14
-
15
- constructor(
16
- sdkKey: string,
17
- user: IUser,
18
- clientContext: ClientContext,
19
- socket: IWebSocketWithEvents,
20
- private readonly getStoreTimestamp: () => number,
21
- private readonly listeners: Map<EventName, ProcessStreamResponse>,
22
- webSocketPingInterval: number
23
- ) {
24
- const {logger, streamingUri} = clientContext;
25
-
26
- this.logger = logger;
27
- this.socket = socket;
28
- this.socket.config({
29
- sdkKey,
30
- streamingUri,
31
- pingInterval: webSocketPingInterval,
32
- user,
33
- logger,
34
- getStoreTimestamp
35
- });
36
-
37
- this.listeners.forEach(({deserializeData, processJson}, eventName) => {
38
- this.socket?.addListener(eventName, async (event) => {
39
- this.logger?.debug(`Received ${ eventName } event`);
40
-
41
- if (event?.data) {
42
- const {featureFlags, userKeyId} = event.data;
43
- const data = deserializeData(featureFlags);
44
- await processJson(userKeyId, data);
45
- this.identifyResolve?.();
46
- this.identifyResolve = undefined;
47
- }
48
- });
49
- })
50
- }
51
-
52
- async identify(user: IUser): Promise<void> {
53
- this.socket?.identify(user);
54
- return new Promise(resolve => this.identifyResolve = resolve);
55
- }
56
-
57
- start(): void {
58
- this.logConnectionStarted();
59
-
60
- this.socket?.connect();
61
- }
62
-
63
- private logConnectionStarted() {
64
- this.connectionAttemptStartTime = Date.now();
65
- this.logger?.info(`Stream connection attempt StartTime ${ this.connectionAttemptStartTime }`);
66
- }
67
-
68
- close(): void {
69
- this.stop();
70
- }
71
-
72
- stop(): void {
73
- this.socket?.close();
74
- this.socket = undefined;
75
- }
76
- }
77
-
1
+ import { IDataSynchronizer } from "./IDataSynchronizer";
2
+ import ClientContext from "../options/ClientContext";
3
+ import { EventName, ProcessStreamResponse } from "./types";
4
+ import { ILogger } from "../logging/ILogger";
5
+ import { IWebSocketWithEvents } from "../platform/IWebSocket";
6
+ import { IUser } from "../options/IUser";
7
+
8
+ class WebSocketDataSynchronizer implements IDataSynchronizer {
9
+ private socket?: IWebSocketWithEvents;
10
+ private readonly logger?: ILogger;
11
+ private identifyResolve?: () => void;
12
+
13
+ private connectionAttemptStartTime?: number;
14
+
15
+ constructor(
16
+ sdkKey: string,
17
+ user: IUser,
18
+ clientContext: ClientContext,
19
+ socket: IWebSocketWithEvents,
20
+ private readonly getStoreTimestamp: () => number,
21
+ private readonly listeners: Map<EventName, ProcessStreamResponse>,
22
+ webSocketPingInterval: number
23
+ ) {
24
+ const {logger, streamingUri} = clientContext;
25
+
26
+ this.logger = logger;
27
+ this.socket = socket;
28
+ this.socket.config({
29
+ sdkKey,
30
+ streamingUri,
31
+ pingInterval: webSocketPingInterval,
32
+ user,
33
+ logger,
34
+ getStoreTimestamp
35
+ });
36
+
37
+ this.listeners.forEach(({deserializeData, processJson}, eventName) => {
38
+ this.socket?.addListener(eventName, async (event) => {
39
+ this.logger?.debug(`Received ${ eventName } event`);
40
+
41
+ if (event?.data) {
42
+ const {featureFlags, userKeyId} = event.data;
43
+ const data = deserializeData(featureFlags);
44
+ await processJson(userKeyId, data);
45
+ this.identifyResolve?.();
46
+ this.identifyResolve = undefined;
47
+ }
48
+ });
49
+ })
50
+ }
51
+
52
+ async identify(user: IUser): Promise<void> {
53
+ this.socket?.identify(user);
54
+ return new Promise(resolve => this.identifyResolve = resolve);
55
+ }
56
+
57
+ start(): void {
58
+ this.logConnectionStarted();
59
+
60
+ this.socket?.connect();
61
+ }
62
+
63
+ private logConnectionStarted() {
64
+ this.connectionAttemptStartTime = Date.now();
65
+ this.logger?.info(`Stream connection attempt StartTime ${ this.connectionAttemptStartTime }`);
66
+ }
67
+
68
+ close(): void {
69
+ this.stop();
70
+ }
71
+
72
+ stop(): void {
73
+ this.socket?.close();
74
+ this.socket = undefined;
75
+ }
76
+ }
77
+
78
78
  export default WebSocketDataSynchronizer;
@@ -1,9 +1,9 @@
1
- export * from './DataSyncMode';
2
- export * from './IDataSynchronizer';
3
- export * from './IRequestor';
4
- export * from './NullDataSynchronizer';
5
- export * from './PollingDataSynchronizer';
6
- export * from './Requestor';
7
- export * from './types';
8
- export * from './utils';
1
+ export * from './DataSyncMode';
2
+ export * from './IDataSynchronizer';
3
+ export * from './IRequestor';
4
+ export * from './NullDataSynchronizer';
5
+ export * from './PollingDataSynchronizer';
6
+ export * from './Requestor';
7
+ export * from './types';
8
+ export * from './utils';
9
9
  export * from './WebSocketDataSynchronizer';
@@ -1,20 +1,20 @@
1
- import { PollingError } from "../errors";
2
- import { IFlag } from "../evaluation/data/IFlag";
3
-
4
- export type PollingErrorHandler = (err: PollingError) => void;
5
-
6
- export enum StreamResponseEventType {
7
- full = 'full',
8
- patch = 'patch'
9
- }
10
-
11
- export interface IStreamResponse {
12
- eventType: StreamResponseEventType,
13
- featureFlags: IFlag[]
14
- }
15
-
16
- export type EventName = 'delete' | 'patch' | 'ping' | 'put';
17
- export type ProcessStreamResponse = {
18
- deserializeData: (flags: IFlag[]) => any;
19
- processJson: (userKeyId: string, json: any) => Promise<void>;
1
+ import { PollingError } from "../errors";
2
+ import { IFlag } from "../evaluation/data/IFlag";
3
+
4
+ export type PollingErrorHandler = (err: PollingError) => void;
5
+
6
+ export enum StreamResponseEventType {
7
+ full = 'full',
8
+ patch = 'patch'
9
+ }
10
+
11
+ export interface IStreamResponse {
12
+ eventType: StreamResponseEventType,
13
+ featureFlags: IFlag[]
14
+ }
15
+
16
+ export type EventName = 'delete' | 'patch' | 'ping' | 'put';
17
+ export type ProcessStreamResponse = {
18
+ deserializeData: (flags: IFlag[]) => any;
19
+ processJson: (userKeyId: string, json: any) => Promise<void>;
20
20
  };
@@ -1,32 +1,32 @@
1
- /********************** encode text begin *****************************/
2
- const alphabet: Record<string, string> = {
3
- "0": "Q",
4
- "1": "B",
5
- "2": "W",
6
- "3": "S",
7
- "4": "P",
8
- "5": "H",
9
- "6": "D",
10
- "7": "X",
11
- "8": "Z",
12
- "9": "U",
13
- }
14
-
15
- function encodeNumber(param: number, length: number): string {
16
- var s = "000000000000" + param;
17
- const numberWithLeadingZeros = s.slice(s.length - length);
18
- return numberWithLeadingZeros.split('').map(n => alphabet[n]).join('');
19
- }
20
-
21
- // generate connection token
22
- export function generateConnectionToken(text: string): string {
23
- text = text.replace(/=*$/, '');
24
- const timestamp = Date.now();
25
- const timestampCode = encodeNumber(timestamp, timestamp.toString().length);
26
- // get random number less than the length of the text as the start point, and it must be greater or equal to 2
27
- const start = Math.max(Math.floor(Math.random() * text.length), 2);
28
-
29
- return `${ encodeNumber(start, 3) }${ encodeNumber(timestampCode.length, 2) }${ text.slice(0, start) }${ timestampCode }${ text.slice(start) }`;
30
- }
31
-
1
+ /********************** encode text begin *****************************/
2
+ const alphabet: Record<string, string> = {
3
+ "0": "Q",
4
+ "1": "B",
5
+ "2": "W",
6
+ "3": "S",
7
+ "4": "P",
8
+ "5": "H",
9
+ "6": "D",
10
+ "7": "X",
11
+ "8": "Z",
12
+ "9": "U",
13
+ }
14
+
15
+ function encodeNumber(param: number, length: number): string {
16
+ var s = "000000000000" + param;
17
+ const numberWithLeadingZeros = s.slice(s.length - length);
18
+ return numberWithLeadingZeros.split('').map(n => alphabet[n]).join('');
19
+ }
20
+
21
+ // generate connection token
22
+ export function generateConnectionToken(text: string): string {
23
+ text = text.replace(/=*$/, '');
24
+ const timestamp = Date.now();
25
+ const timestampCode = encodeNumber(timestamp, timestamp.toString().length);
26
+ // get random number less than the length of the text as the start point, and it must be greater or equal to 2
27
+ const start = Math.max(Math.floor(Math.random() * text.length), 2);
28
+
29
+ return `${ encodeNumber(start, 3) }${ encodeNumber(timestampCode.length, 2) }${ text.slice(0, start) }${ timestampCode }${ text.slice(start) }`;
30
+ }
31
+
32
32
  /********************** encode text end *****************************/