@featbit/js-client-sdk 3.0.13 → 4.0.0

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 (120) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +301 -301
  3. package/dist/esm/FbClientCore.d.ts +6 -5
  4. package/dist/esm/FbClientCore.d.ts.map +1 -1
  5. package/dist/esm/FbClientCore.js +27 -4
  6. package/dist/esm/FbClientCore.js.map +1 -1
  7. package/dist/esm/IFbClientCore.d.ts +8 -7
  8. package/dist/esm/IFbClientCore.d.ts.map +1 -1
  9. package/dist/esm/version.d.ts +1 -1
  10. package/dist/esm/version.d.ts.map +1 -1
  11. package/dist/esm/version.js +1 -1
  12. package/dist/esm/version.js.map +1 -1
  13. package/dist/umd/featbit-js-client-sdk-4.0.0.js +2 -0
  14. package/dist/umd/featbit-js-client-sdk-4.0.0.js.map +1 -0
  15. package/dist/umd/featbit-js-client-sdk.js +1 -1
  16. package/dist/umd/featbit-js-client-sdk.js.map +1 -1
  17. package/package.json +46 -46
  18. package/src/Configuration.ts +232 -232
  19. package/src/Context.ts +61 -61
  20. package/src/FbClientBuilder.ts +167 -167
  21. package/src/FbClientCore.ts +428 -405
  22. package/src/IContextProperty.ts +3 -3
  23. package/src/IDataKind.ts +11 -11
  24. package/src/IFbClient.ts +29 -29
  25. package/src/IFbClientCore.ts +291 -290
  26. package/src/IVersionedData.ts +18 -18
  27. package/src/bootstrap/IBootstrapProvider.ts +4 -4
  28. package/src/bootstrap/JsonBootstrapProvider.ts +34 -34
  29. package/src/bootstrap/NullBootstrapProvider.ts +20 -20
  30. package/src/bootstrap/index.ts +2 -2
  31. package/src/constants.ts +1 -1
  32. package/src/data-sources/DataSourceUpdates.ts +116 -116
  33. package/src/data-sources/createStreamListeners.ts +67 -67
  34. package/src/data-sources/index.ts +1 -1
  35. package/src/data-sync/DataSyncMode.ts +3 -3
  36. package/src/data-sync/IDataSynchronizer.ts +15 -15
  37. package/src/data-sync/IRequestor.ts +10 -10
  38. package/src/data-sync/NullDataSynchronizer.ts +14 -14
  39. package/src/data-sync/PollingDataSynchronizer.ts +125 -125
  40. package/src/data-sync/Requestor.ts +61 -61
  41. package/src/data-sync/WebSocketDataSynchronizer.ts +77 -77
  42. package/src/data-sync/index.ts +8 -8
  43. package/src/data-sync/types.ts +19 -19
  44. package/src/data-sync/utils.ts +31 -31
  45. package/src/errors.ts +47 -47
  46. package/src/evaluation/EvalResult.ts +35 -35
  47. package/src/evaluation/Evaluator.ts +26 -26
  48. package/src/evaluation/IEvalDetail.ts +23 -23
  49. package/src/evaluation/ReasonKinds.ts +9 -9
  50. package/src/evaluation/data/IFlag.ts +29 -29
  51. package/src/evaluation/index.ts +4 -4
  52. package/src/events/DefaultEventProcessor.ts +83 -83
  53. package/src/events/DefaultEventQueue.ts +49 -49
  54. package/src/events/DefaultEventSender.ts +73 -73
  55. package/src/events/DefaultEventSerializer.ts +11 -11
  56. package/src/events/EventDispatcher.ts +127 -127
  57. package/src/events/EventSerializer.ts +4 -4
  58. package/src/events/IEventProcessor.ts +8 -8
  59. package/src/events/IEventQueue.ts +16 -16
  60. package/src/events/IEventSender.ts +13 -13
  61. package/src/events/NullEventProcessor.ts +15 -15
  62. package/src/events/event.ts +129 -129
  63. package/src/events/index.ts +11 -11
  64. package/src/index.ts +21 -21
  65. package/src/integrations/TestLogger.ts +24 -24
  66. package/src/integrations/index.ts +1 -1
  67. package/src/integrations/test_data/FlagBuilder.ts +59 -59
  68. package/src/integrations/test_data/TestData.ts +57 -57
  69. package/src/integrations/test_data/TestDataSynchronizer.ts +49 -49
  70. package/src/integrations/test_data/index.ts +4 -4
  71. package/src/logging/BasicLogger.ts +108 -108
  72. package/src/logging/IBasicLoggerOptions.ts +46 -46
  73. package/src/logging/ILogger.ts +49 -49
  74. package/src/logging/LogLevel.ts +8 -8
  75. package/src/logging/SafeLogger.ts +69 -69
  76. package/src/logging/format.ts +154 -154
  77. package/src/logging/index.ts +5 -5
  78. package/src/options/ClientContext.ts +39 -39
  79. package/src/options/IClientContext.ts +53 -53
  80. package/src/options/IOptions.ts +123 -123
  81. package/src/options/IUser.ts +6 -6
  82. package/src/options/IValidatedOptions.ts +29 -29
  83. package/src/options/OptionMessages.ts +35 -35
  84. package/src/options/UserBuilder.ts +35 -35
  85. package/src/options/Validators.ts +300 -300
  86. package/src/options/index.ts +7 -7
  87. package/src/platform/IInfo.ts +102 -102
  88. package/src/platform/IPlatform.ts +20 -20
  89. package/src/platform/IStore.ts +112 -112
  90. package/src/platform/IWebSocket.ts +22 -22
  91. package/src/platform/browser/BrowserInfo.ts +24 -24
  92. package/src/platform/browser/BrowserPlatform.ts +19 -19
  93. package/src/platform/browser/BrowserRequests.ts +6 -6
  94. package/src/platform/browser/BrowserWebSocket.ts +147 -147
  95. package/src/platform/browser/FbClient.ts +65 -65
  96. package/src/platform/browser/LocalStorageStore.ts +59 -59
  97. package/src/platform/index.ts +11 -11
  98. package/src/platform/requests.ts +76 -76
  99. package/src/store/BaseStore.ts +125 -125
  100. package/src/store/DataKinds.ts +6 -6
  101. package/src/store/IDataSourceUpdates.ts +68 -68
  102. package/src/store/InMemoryStore.ts +36 -36
  103. package/src/store/index.ts +5 -5
  104. package/src/store/serialization.ts +52 -52
  105. package/src/store/store.ts +37 -37
  106. package/src/utils/Emits.ts +75 -75
  107. package/src/utils/EventEmitter.ts +128 -128
  108. package/src/utils/IEventEmitter.ts +14 -14
  109. package/src/utils/Regex.ts +21 -21
  110. package/src/utils/ValueConverters.ts +55 -55
  111. package/src/utils/canonicalizeUri.ts +3 -3
  112. package/src/utils/debounce.ts +33 -33
  113. package/src/utils/http.ts +40 -40
  114. package/src/utils/index.ts +5 -5
  115. package/src/utils/isNullOrUndefined.ts +2 -2
  116. package/src/utils/serializeUser.ts +27 -27
  117. package/src/utils/sleep.ts +5 -5
  118. package/src/version.ts +1 -1
  119. package/dist/umd/featbit-js-client-sdk-3.0.13.js +0 -2
  120. 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 *****************************/