@croct/sdk 0.16.2 → 0.17.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 (83) hide show
  1. package/cache/cookieCache.d.ts +1 -1
  2. package/cache/cookieCache.js +12 -2
  3. package/cache/cookieCache.js.map +1 -1
  4. package/channel/channel.d.ts +7 -0
  5. package/channel/channel.js +23 -0
  6. package/channel/channel.js.map +1 -1
  7. package/channel/guaranteedChannel.js +4 -3
  8. package/channel/guaranteedChannel.js.map +1 -1
  9. package/channel/httpBeaconChannel.d.ts +23 -0
  10. package/channel/httpBeaconChannel.js +89 -0
  11. package/channel/httpBeaconChannel.js.map +1 -0
  12. package/channel/index.d.ts +1 -2
  13. package/channel/index.js +3 -5
  14. package/channel/index.js.map +1 -1
  15. package/channel/queuedChannel.js +5 -4
  16. package/channel/queuedChannel.js.map +1 -1
  17. package/channel/retryChannel.js +8 -4
  18. package/channel/retryChannel.js.map +1 -1
  19. package/channel/sandboxChannel.js +4 -0
  20. package/channel/sandboxChannel.js.map +1 -1
  21. package/constants.d.ts +2 -2
  22. package/constants.js +1 -1
  23. package/container.d.ts +3 -0
  24. package/container.js +15 -14
  25. package/container.js.map +1 -1
  26. package/contentFetcher.d.ts +3 -4
  27. package/contentFetcher.js +37 -27
  28. package/contentFetcher.js.map +1 -1
  29. package/evaluator.d.ts +2 -4
  30. package/evaluator.js +47 -39
  31. package/evaluator.js.map +1 -1
  32. package/facade/contentFetcherFacade.d.ts +1 -6
  33. package/facade/contentFetcherFacade.js +2 -5
  34. package/facade/contentFetcherFacade.js.map +1 -1
  35. package/facade/sdkFacade.d.ts +3 -6
  36. package/facade/sdkFacade.js +3 -7
  37. package/facade/sdkFacade.js.map +1 -1
  38. package/help.d.ts +3 -0
  39. package/help.js +26 -0
  40. package/help.js.map +1 -0
  41. package/package.json +1 -3
  42. package/queue/persistentQueue.d.ts +1 -3
  43. package/queue/persistentQueue.js +9 -16
  44. package/queue/persistentQueue.js.map +1 -1
  45. package/schema/eventSchemas.js +0 -16
  46. package/schema/eventSchemas.js.map +1 -1
  47. package/schema/sdkFacadeSchemas.js +5 -1
  48. package/schema/sdkFacadeSchemas.js.map +1 -1
  49. package/schema/sdkSchemas.js +7 -0
  50. package/schema/sdkSchemas.js.map +1 -1
  51. package/sdk.d.ts +2 -0
  52. package/sdk.js +1 -2
  53. package/sdk.js.map +1 -1
  54. package/src/cache/cookieCache.ts +13 -2
  55. package/src/channel/channel.ts +32 -0
  56. package/src/channel/guaranteedChannel.ts +4 -4
  57. package/src/channel/httpBeaconChannel.ts +128 -0
  58. package/src/channel/index.ts +1 -2
  59. package/src/channel/queuedChannel.ts +5 -5
  60. package/src/channel/retryChannel.ts +9 -5
  61. package/src/channel/sandboxChannel.ts +5 -1
  62. package/src/container.ts +17 -19
  63. package/src/contentFetcher.ts +41 -29
  64. package/src/evaluator.ts +74 -65
  65. package/src/facade/contentFetcherFacade.ts +2 -11
  66. package/src/facade/sdkFacade.ts +5 -14
  67. package/src/help.ts +24 -0
  68. package/src/queue/persistentQueue.ts +11 -22
  69. package/src/schema/eventSchemas.ts +0 -16
  70. package/src/schema/sdkFacadeSchemas.ts +14 -2
  71. package/src/schema/sdkSchemas.ts +7 -0
  72. package/src/sdk.ts +3 -2
  73. package/src/trackingEvents.ts +0 -4
  74. package/trackingEvents.d.ts +0 -4
  75. package/trackingEvents.js.map +1 -1
  76. package/channel/beaconSocketChannel.d.ts +0 -37
  77. package/channel/beaconSocketChannel.js +0 -83
  78. package/channel/beaconSocketChannel.js.map +0 -1
  79. package/channel/socketChannel.d.ts +0 -31
  80. package/channel/socketChannel.js +0 -145
  81. package/channel/socketChannel.js.map +0 -1
  82. package/src/channel/beaconSocketChannel.ts +0 -153
  83. package/src/channel/socketChannel.ts +0 -217
@@ -5,6 +5,7 @@ import {BASE_ENDPOINT_URL, CLIENT_LIBRARY} from './constants';
5
5
  import {formatMessage} from './error';
6
6
  import {Logger, NullLogger} from './logging';
7
7
  import type {ApiKey} from './apiKey';
8
+ import {Help} from './help';
8
9
 
9
10
  export type ErrorResponse = {
10
11
  type: string,
@@ -54,10 +55,6 @@ export type DynamicContentOptions = BasicOptions & {
54
55
  clientId?: string,
55
56
  clientIp?: string,
56
57
  clientAgent?: string,
57
- /**
58
- * @deprecated Use `clientAgent` instead. This option will be removed in future releases.
59
- */
60
- userAgent?: string,
61
58
  userToken?: Token|string,
62
59
  previewToken?: Token|string,
63
60
  context?: EvaluationContext,
@@ -80,11 +77,15 @@ export type Configuration = {
80
77
  apiKey?: string|ApiKey,
81
78
  baseEndpointUrl?: string,
82
79
  logger?: Logger,
80
+ defaultTimeout?: number,
81
+ defaultPreferredLocale?: string,
83
82
  };
84
83
 
85
84
  type InternalConfiguration = {
86
85
  appId?: string,
87
86
  apiKey?: string,
87
+ defaultTimeout?: number,
88
+ defaultPreferredLocale?: string,
88
89
  };
89
90
 
90
91
  export class ContentFetcher {
@@ -117,6 +118,8 @@ export class ContentFetcher {
117
118
  this.configuration = {
118
119
  appId: configuration.appId,
119
120
  apiKey: apiKey,
121
+ defaultTimeout: configuration.defaultTimeout,
122
+ defaultPreferredLocale: configuration.defaultPreferredLocale,
120
123
  };
121
124
  }
122
125
 
@@ -127,34 +130,44 @@ export class ContentFetcher {
127
130
 
128
131
  return new Promise((resolve, reject) => {
129
132
  const abortController = new AbortController();
133
+ const timeout = options.timeout ?? this.configuration.defaultTimeout;
130
134
 
131
- if (options.timeout !== undefined) {
135
+ if (timeout !== undefined) {
132
136
  setTimeout(
133
137
  () => {
134
138
  const response: ErrorResponse = {
135
139
  title: 'Maximum timeout reached before content could be loaded.',
136
140
  type: ContentErrorType.TIMEOUT,
137
- detail: `The content took more than ${options.timeout}ms to load.`,
141
+ detail: `The content took more than ${timeout}ms to load.`,
138
142
  status: 408, // Request Timeout
139
143
  };
140
144
 
141
145
  abortController.abort();
142
146
 
147
+ this.logHelp(response.status);
148
+
143
149
  reject(new ContentError(response));
144
150
  },
145
- options.timeout,
151
+ timeout,
146
152
  );
147
153
  }
148
154
 
149
155
  this.load(slotId, abortController.signal, options)
150
- .then(
151
- response => response.json()
156
+ .then(response => {
157
+ const region = response.headers.get('X-Croct-Region');
158
+ const timing = response.headers.get('X-Croct-Timing');
159
+
160
+ this.logger.debug(`Request processed by region ${region} in ${timing}`);
161
+
162
+ return response.json()
152
163
  .then(body => {
153
164
  if (response.ok) {
154
- resolve(body);
155
- } else {
156
- reject(new ContentError(body));
165
+ return resolve(body);
157
166
  }
167
+
168
+ this.logHelp(response.status);
169
+
170
+ reject(new ContentError(body));
158
171
  })
159
172
  .catch(error => {
160
173
  if (!response.ok) {
@@ -162,8 +175,8 @@ export class ContentFetcher {
162
175
  }
163
176
 
164
177
  throw error;
165
- }),
166
- )
178
+ });
179
+ })
167
180
  .catch(error => {
168
181
  if (!abortController.signal.aborted) {
169
182
  reject(
@@ -204,22 +217,15 @@ export class ContentFetcher {
204
217
  payload.version = `${options.version}`;
205
218
  }
206
219
 
207
- if (options.preferredLocale !== undefined) {
208
- payload.preferredLocale = options.preferredLocale;
220
+ const preferredLocale = options.preferredLocale ?? this.configuration.defaultPreferredLocale;
221
+
222
+ if (preferredLocale !== undefined) {
223
+ payload.preferredLocale = preferredLocale;
209
224
  }
210
225
 
211
226
  const dynamic = ContentFetcher.isDynamicContent(options);
212
227
 
213
228
  if (dynamic) {
214
- if (options.userAgent !== undefined) {
215
- this.logger.warn(
216
- 'The `userAgent` option is deprecated and '
217
- + 'will be removed in future releases. '
218
- + 'Please update the part of your code calling the `fetch` method '
219
- + 'to use the `clientAgent` option instead.',
220
- );
221
- }
222
-
223
229
  if (options.clientId !== undefined) {
224
230
  headers['X-Client-Id'] = options.clientId;
225
231
  }
@@ -232,10 +238,8 @@ export class ContentFetcher {
232
238
  headers['X-Token'] = options.userToken.toString();
233
239
  }
234
240
 
235
- const clientAgent = options.clientAgent ?? options.userAgent;
236
-
237
- if (clientAgent !== undefined) {
238
- headers['X-Client-Agent'] = clientAgent;
241
+ if (options.clientAgent !== undefined) {
242
+ headers['X-Client-Agent'] = options.clientAgent;
239
243
  }
240
244
 
241
245
  if (options.context !== undefined) {
@@ -264,6 +268,14 @@ export class ContentFetcher {
264
268
  });
265
269
  }
266
270
 
271
+ private logHelp(statusCode: number): void {
272
+ const help = Help.forStatusCode(statusCode);
273
+
274
+ if (help !== undefined) {
275
+ this.logger.error(help);
276
+ }
277
+ }
278
+
267
279
  private static isDynamicContent(options: FetchOptions): options is DynamicContentOptions {
268
280
  return options.static !== true;
269
281
  }
package/src/evaluator.ts CHANGED
@@ -5,6 +5,7 @@ import {formatMessage} from './error';
5
5
  import {getLength, getLocation, Location} from './sourceLocation';
6
6
  import {Logger, NullLogger} from './logging';
7
7
  import type {ApiKey} from './apiKey';
8
+ import {Help} from './help';
8
9
 
9
10
  export type Campaign = {
10
11
  name?: string,
@@ -37,10 +38,6 @@ export type EvaluationOptions = {
37
38
  clientId?: string,
38
39
  clientIp?: string,
39
40
  clientAgent?: string,
40
- /**
41
- * @deprecated Use `clientAgent` instead. This option will be removed in future releases.
42
- */
43
- userAgent?: string,
44
41
  userToken?: Token|string,
45
42
  timeout?: number,
46
43
  context?: EvaluationContext,
@@ -98,11 +95,13 @@ export type Configuration = {
98
95
  apiKey?: string|ApiKey,
99
96
  baseEndpointUrl?: string,
100
97
  logger?: Logger,
98
+ defaultTimeout?: number,
101
99
  };
102
100
 
103
101
  type InternalConfiguration = {
104
102
  appId?: string,
105
103
  apiKey?: string,
104
+ defaultTimeout?: number,
106
105
  };
107
106
 
108
107
  export class Evaluator {
@@ -132,6 +131,7 @@ export class Evaluator {
132
131
  this.configuration = {
133
132
  appId: configuration.appId,
134
133
  apiKey: apiKey,
134
+ defaultTimeout: configuration.defaultTimeout,
135
135
  };
136
136
  }
137
137
 
@@ -154,98 +154,99 @@ export class Evaluator {
154
154
  return Promise.reject(new QueryError(response));
155
155
  }
156
156
 
157
- const body: JsonObject = {
157
+ const payload: JsonObject = {
158
158
  query: query,
159
159
  };
160
160
 
161
161
  if (options.context !== undefined) {
162
- body.context = options.context;
162
+ payload.context = options.context;
163
163
  }
164
164
 
165
165
  return new Promise((resolve, reject) => {
166
166
  const abortController = new AbortController();
167
+ const timeout = options.timeout ?? this.configuration.defaultTimeout;
167
168
 
168
- if (options.timeout !== undefined) {
169
+ if (timeout !== undefined) {
169
170
  setTimeout(
170
171
  () => {
171
172
  const response: ErrorResponse = {
172
173
  title: 'Maximum evaluation timeout reached before evaluation could complete.',
173
174
  type: EvaluationErrorType.TIMEOUT,
174
- detail: `The evaluation took more than ${options.timeout}ms to complete.`,
175
+ detail: `The evaluation took more than ${timeout}ms to complete.`,
175
176
  status: 408, // Request Timeout
176
177
  };
177
178
 
178
179
  abortController.abort();
179
180
 
181
+ this.logHelp(response.status);
182
+
180
183
  reject(new EvaluationError(response));
181
184
  },
182
- options.timeout,
185
+ timeout,
183
186
  );
184
187
  }
185
188
 
186
- const promise = this.fetch(body, abortController.signal, options);
189
+ const promise = this.fetch(payload, abortController.signal, options);
187
190
 
188
191
  promise.then(
189
- response => response.json()
190
- .then(data => {
191
- if (response.ok) {
192
- return resolve(data);
193
- }
194
-
195
- const errorResponse: ErrorResponse = data;
196
-
197
- switch (errorResponse.type) {
198
- case EvaluationErrorType.INVALID_QUERY:
199
- case EvaluationErrorType.EVALUATION_FAILED:
200
- case EvaluationErrorType.TOO_COMPLEX_QUERY:
201
- reject(new QueryError(errorResponse as QueryErrorResponse));
202
-
203
- break;
204
-
205
- default:
206
- reject(new EvaluationError(errorResponse));
207
-
208
- break;
209
- }
210
- })
211
- .catch(error => {
212
- if (!response.ok) {
213
- throw new Error(`Error ${response.status} - ${response.statusText}`);
214
- }
215
-
216
- throw error;
217
- }),
218
- )
219
- .catch(
220
- error => {
221
- if (!abortController.signal.aborted) {
222
- reject(
223
- new EvaluationError({
224
- title: formatMessage(error),
225
- type: EvaluationErrorType.UNEXPECTED_ERROR,
226
- detail: 'Please try again or contact Croct support if the error persists.',
227
- status: 500, // Internal Server Error
228
- }),
229
- );
230
- }
231
- },
232
- );
192
+ response => {
193
+ const region = response.headers.get('X-Croct-Region');
194
+ const timing = response.headers.get('X-Croct-Timing');
195
+
196
+ this.logger.debug(`Request processed by region ${region} in ${timing}`);
197
+
198
+ return response.json()
199
+ .then(body => {
200
+ if (response.ok) {
201
+ return resolve(body);
202
+ }
203
+
204
+ this.logHelp(response.status);
205
+
206
+ const problem: ErrorResponse = body;
207
+
208
+ switch (problem.type) {
209
+ case EvaluationErrorType.INVALID_QUERY:
210
+ case EvaluationErrorType.EVALUATION_FAILED:
211
+ case EvaluationErrorType.TOO_COMPLEX_QUERY:
212
+ reject(new QueryError(problem as QueryErrorResponse));
213
+
214
+ break;
215
+
216
+ default:
217
+ reject(new EvaluationError(problem));
218
+
219
+ break;
220
+ }
221
+ })
222
+ .catch(error => {
223
+ if (!response.ok) {
224
+ throw new Error(`Error ${response.status} - ${response.statusText}`);
225
+ }
226
+
227
+ throw error;
228
+ });
229
+ },
230
+ ).catch(
231
+ error => {
232
+ if (!abortController.signal.aborted) {
233
+ reject(
234
+ new EvaluationError({
235
+ title: formatMessage(error),
236
+ type: EvaluationErrorType.UNEXPECTED_ERROR,
237
+ detail: 'Please try again or contact Croct support if the error persists.',
238
+ status: 500, // Internal Server Error
239
+ }),
240
+ );
241
+ }
242
+ },
243
+ );
233
244
  });
234
245
  }
235
246
 
236
247
  private fetch(body: JsonObject, signal: AbortSignal, options: EvaluationOptions): Promise<Response> {
237
248
  const {appId, apiKey} = this.configuration;
238
- const {clientId, clientIp, userToken} = options;
239
- const clientAgent = options.clientAgent ?? options.userAgent;
240
-
241
- if (options.userAgent !== undefined) {
242
- this.logger.warn(
243
- 'The `userAgent` option is deprecated and '
244
- + 'will be removed in future releases. '
245
- + 'Please update the part of your code calling the `evaluate` method '
246
- + 'to use the `clientAgent` option instead.',
247
- );
248
- }
249
+ const {clientId, clientIp, userToken, clientAgent} = options;
249
250
 
250
251
  const headers: Record<string, string> = {
251
252
  'Content-Type': 'application/json',
@@ -292,6 +293,14 @@ export class Evaluator {
292
293
  });
293
294
  }
294
295
 
296
+ private logHelp(statusCode: number): void {
297
+ const help = Help.forStatusCode(statusCode);
298
+
299
+ if (help !== undefined) {
300
+ this.logger.error(help);
301
+ }
302
+ }
303
+
295
304
  public toJSON(): never {
296
305
  // Prevent sensitive configuration from being serialized
297
306
  throw new Error('Unserializable value.');
@@ -21,11 +21,7 @@ function validate(options: unknown): asserts options is FetchOptions {
21
21
  }
22
22
  }
23
23
 
24
- type Options = {
25
- preferredLocale?: string,
26
- };
27
-
28
- export type Configuration = Options & {
24
+ export type Configuration = {
29
25
  contentFetcher: ContentFetcher,
30
26
  contextFactory: ContextFactory,
31
27
  previewTokenProvider: TokenProvider,
@@ -44,17 +40,12 @@ export class ContentFetcherFacade {
44
40
 
45
41
  private readonly cidAssigner: CidAssigner;
46
42
 
47
- private readonly options: Options;
48
-
49
43
  public constructor(configuration: Configuration) {
50
44
  this.fetcher = configuration.contentFetcher;
51
45
  this.previewTokenProvider = configuration.previewTokenProvider;
52
46
  this.userTokenProvider = configuration.userTokenProvider;
53
47
  this.cidAssigner = configuration.cidAssigner;
54
48
  this.contextFactory = configuration.contextFactory;
55
- this.options = {
56
- preferredLocale: configuration.preferredLocale,
57
- };
58
49
  }
59
50
 
60
51
  public async fetch<P extends JsonObject>(slotId: string, options: FetchOptions = {}): Promise<FetchResponse<P>> {
@@ -72,7 +63,7 @@ export class ContentFetcherFacade {
72
63
  version: options.version,
73
64
  context: this.contextFactory.createContext(options.attributes),
74
65
  timeout: options.timeout,
75
- preferredLocale: options.preferredLocale ?? this.options.preferredLocale,
66
+ preferredLocale: options.preferredLocale,
76
67
  });
77
68
  }
78
69
  }
@@ -17,11 +17,7 @@ import {ContentFetcherFacade} from './contentFetcherFacade';
17
17
  import {CookieCacheConfiguration} from '../cache/cookieCache';
18
18
  import {EventSubjectProcessor} from '../eventSubjectProcessor';
19
19
 
20
- type Options = {
21
- preferredLocale?: string,
22
- };
23
-
24
- export type Configuration = Options & {
20
+ export type Configuration = {
25
21
  appId: string,
26
22
  tokenScope?: TokenScope,
27
23
  debug?: boolean,
@@ -41,6 +37,8 @@ export type Configuration = Options & {
41
37
  userToken?: CookieCacheConfiguration,
42
38
  previewToken?: CookieCacheConfiguration,
43
39
  },
40
+ defaultFetchTimeout?: number,
41
+ defaultPreferredLocale?: string,
44
42
  };
45
43
 
46
44
  function validateConfiguration(configuration: unknown): asserts configuration is Configuration {
@@ -64,17 +62,14 @@ export class SdkFacade {
64
62
 
65
63
  private contentFetcherFacade?: ContentFetcherFacade;
66
64
 
67
- private readonly options: Options;
68
-
69
- private constructor(sdk: Sdk, options: Options = {}) {
65
+ private constructor(sdk: Sdk) {
70
66
  this.sdk = sdk;
71
- this.options = options;
72
67
  }
73
68
 
74
69
  public static init(configuration: Configuration): SdkFacade {
75
70
  validateConfiguration(configuration);
76
71
 
77
- const {track = true, userId, token, preferredLocale, ...containerConfiguration} = configuration;
72
+ const {track = true, userId, token, ...containerConfiguration} = configuration;
78
73
 
79
74
  if (userId !== undefined && token !== undefined) {
80
75
  throw new Error('Either the user ID or token can be specified, but not both.');
@@ -89,9 +84,6 @@ export class SdkFacade {
89
84
  disableCidMirroring: containerConfiguration.disableCidMirroring ?? false,
90
85
  eventProcessor: container => new EventSubjectProcessor(container.getLogger('EventSubjectProcessor')),
91
86
  }),
92
- {
93
- preferredLocale: preferredLocale,
94
- },
95
87
  );
96
88
 
97
89
  if (userId !== undefined) {
@@ -184,7 +176,6 @@ export class SdkFacade {
184
176
  cidAssigner: this.sdk.cidAssigner,
185
177
  previewTokenProvider: this.sdk.previewTokenStore,
186
178
  userTokenProvider: this.sdk.userTokenStore,
187
- preferredLocale: this.options.preferredLocale,
188
179
  });
189
180
  }
190
181
 
package/src/help.ts ADDED
@@ -0,0 +1,24 @@
1
+ export namespace Help {
2
+ export function forStatusCode(statusCode: number): string|undefined {
3
+ switch (statusCode) {
4
+ case 401:
5
+ return 'The request was not authorized, most likely due to invalid credentials. '
6
+ + 'For help, see https://croct.help/sdk/js/invalid-credentials';
7
+
8
+ case 403:
9
+ return 'The origin of the request is not allowed in your application settings. '
10
+ + 'For help, see https://croct.help/sdk/js/cors';
11
+
12
+ case 408:
13
+ return 'The request timed out. '
14
+ + 'For help, see https://croct.help/sdk/js/timeout';
15
+
16
+ case 423:
17
+ return 'The application has exceeded the monthly active users (MAU) quota. '
18
+ + 'For help, see https://croct.help/sdk/js/mau-exceeded';
19
+
20
+ default:
21
+ return undefined;
22
+ }
23
+ }
24
+ }
@@ -1,8 +1,6 @@
1
1
  import {Queue} from './queue';
2
2
 
3
3
  export class PersistentQueue<T> implements Queue<T> {
4
- private cache: T[];
5
-
6
4
  private readonly storage: Storage;
7
5
 
8
6
  private readonly key: string;
@@ -17,7 +15,7 @@ export class PersistentQueue<T> implements Queue<T> {
17
15
  }
18
16
 
19
17
  public getCapacity(): number {
20
- return Infinity;
18
+ return Number.MAX_SAFE_INTEGER;
21
19
  }
22
20
 
23
21
  public isEmpty(): boolean {
@@ -29,9 +27,7 @@ export class PersistentQueue<T> implements Queue<T> {
29
27
  }
30
28
 
31
29
  public push(value: T): void {
32
- this.queue.push(value);
33
-
34
- this.flush();
30
+ this.save([...this.queue, value]);
35
31
  }
36
32
 
37
33
  public peek(): T | null {
@@ -45,30 +41,19 @@ export class PersistentQueue<T> implements Queue<T> {
45
41
  }
46
42
 
47
43
  public shift(): T {
48
- const value = this.queue.shift();
44
+ const queue = [...this.queue];
45
+ const value = queue.shift();
49
46
 
50
47
  if (value === undefined) {
51
48
  throw new Error('The queue is empty.');
52
49
  }
53
50
 
54
- this.flush();
51
+ this.save(queue);
55
52
 
56
53
  return value;
57
54
  }
58
55
 
59
- private get queue(): T[] {
60
- if (this.cache === undefined) {
61
- this.cache = this.load();
62
- }
63
-
64
- return this.cache;
65
- }
66
-
67
- private flush(): void {
68
- this.storage.setItem(this.key, JSON.stringify(this.cache ?? []));
69
- }
70
-
71
- private load(): T[] {
56
+ private get queue(): readonly T[] {
72
57
  const data = this.storage.getItem(this.key);
73
58
 
74
59
  if (data === null) {
@@ -77,8 +62,12 @@ export class PersistentQueue<T> implements Queue<T> {
77
62
 
78
63
  try {
79
64
  return JSON.parse(data);
80
- } catch (error) {
65
+ } catch {
81
66
  return [];
82
67
  }
83
68
  }
69
+
70
+ private save(data: T[]): void {
71
+ this.storage.setItem(this.key, JSON.stringify(data));
72
+ }
84
73
  }
@@ -114,22 +114,6 @@ export const eventOccurred = new ObjectType({
114
114
  minLength: 1,
115
115
  maxLength: 50,
116
116
  }),
117
- testId: new StringType({
118
- minLength: 1,
119
- maxLength: 50,
120
- }),
121
- groupId: new StringType({
122
- minLength: 1,
123
- maxLength: 50,
124
- }),
125
- personalizationId: new StringType({
126
- minLength: 1,
127
- maxLength: 50,
128
- }),
129
- audience: new StringType({
130
- minLength: 1,
131
- maxLength: 50,
132
- }),
133
117
  details: new ObjectType({
134
118
  additionalProperties: new UnionType(
135
119
  new NullType(),
@@ -1,4 +1,12 @@
1
- import {ObjectType, StringType, BooleanType, UnionType, NullType, FunctionType} from '../validation';
1
+ import {
2
+ ObjectType,
3
+ StringType,
4
+ BooleanType,
5
+ UnionType,
6
+ NullType,
7
+ FunctionType,
8
+ NumberType,
9
+ } from '../validation';
2
10
  import {tokenScopeSchema} from './contextSchemas';
3
11
  import {cookieOptionsSchema, eventMetadataSchema} from './sdkSchemas';
4
12
  import {loggerSchema} from './loggerSchema';
@@ -45,7 +53,11 @@ export const sdkFacadeConfigurationSchema = new ObjectType({
45
53
  previewToken: cookieOptionsSchema,
46
54
  },
47
55
  }),
48
- preferredLocale: new StringType({
56
+ defaultFetchTimeout: new NumberType({
57
+ integer: true,
58
+ minimum: 1,
59
+ }),
60
+ defaultPreferredLocale: new StringType({
49
61
  pattern: /^[a-z]{2,3}([-_][a-z]{2,3})?$/i,
50
62
  }),
51
63
  },
@@ -71,5 +71,12 @@ export const sdkConfigurationSchema = new ObjectType({
71
71
  urlSanitizer: new FunctionType(),
72
72
  eventMetadata: eventMetadataSchema,
73
73
  eventProcessor: new FunctionType(),
74
+ defaultFetchTimeout: new NumberType({
75
+ integer: true,
76
+ minimum: 1,
77
+ }),
78
+ defaultPreferredLocale: new StringType({
79
+ pattern: /^[a-z]{2,3}([-_][a-z]{2,3})?$/i,
80
+ }),
74
81
  },
75
82
  });
package/src/sdk.ts CHANGED
@@ -33,6 +33,8 @@ export type Configuration = {
33
33
  previewToken?: CookieCacheConfiguration,
34
34
  },
35
35
  eventProcessor?: DependencyResolver<TrackingEventProcessor>,
36
+ defaultFetchTimeout?: number,
37
+ defaultPreferredLocale?: string,
36
38
  };
37
39
 
38
40
  function validateConfiguration(configuration: unknown): asserts configuration is Configuration {
@@ -75,13 +77,12 @@ export class Sdk {
75
77
  }
76
78
 
77
79
  const baseHttpEndpoint = baseEndpointUrl.replace(/\/+$/, '');
78
- const baseWsEndpoint = baseHttpEndpoint.replace(/^http/i, 'ws');
79
80
 
80
81
  const container = new Container({
81
82
  ...containerConfiguration,
82
83
  evaluationBaseEndpointUrl: baseHttpEndpoint,
83
84
  contentBaseEndpointUrl: baseHttpEndpoint,
84
- trackerEndpointUrl: `${baseWsEndpoint}/client/web/connect`,
85
+ trackerEndpointUrl: `${baseHttpEndpoint}/client/web/track`,
85
86
  cidAssignerEndpointUrl: cidAssignerEndpointUrl ?? `${baseHttpEndpoint}/client/web/cid`,
86
87
  beaconQueueSize: containerConfiguration.beaconQueueSize ?? 100,
87
88
  eventMetadata: eventMetadata,
@@ -325,10 +325,6 @@ export interface PostViewed extends BaseEvent {
325
325
  export interface EventOccurred extends BaseEvent {
326
326
  type: 'eventOccurred';
327
327
  name: string;
328
- testId?: string;
329
- groupId?: string;
330
- personalizationId?: string;
331
- audience?: string;
332
328
  details?: {[key: string]: string|number|boolean|null};
333
329
  }
334
330