@croct/sdk 0.9.1 → 0.11.0-alpha
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.
- package/activeRecord.js +32 -36
- package/cache/fallbackCache.js +15 -32
- package/cache/inMemoryCache.js +9 -10
- package/cache/index.js +1 -1
- package/cache/localStorageCache.js +24 -25
- package/channel/beaconSocketChannel.d.ts +1 -1
- package/channel/beaconSocketChannel.js +49 -79
- package/channel/channel.d.ts +1 -1
- package/channel/encodedChannel.js +8 -10
- package/channel/guaranteedChannel.d.ts +4 -4
- package/channel/guaranteedChannel.js +41 -43
- package/channel/index.js +1 -1
- package/channel/queuedChannel.js +35 -64
- package/channel/retryChannel.d.ts +1 -1
- package/channel/retryChannel.js +44 -77
- package/channel/sandboxChannel.js +17 -18
- package/channel/socketChannel.d.ts +4 -4
- package/channel/socketChannel.js +77 -79
- package/cid/cachedAssigner.js +15 -27
- package/cid/fixedAssigner.js +5 -6
- package/cid/index.js +1 -1
- package/cid/remoteAssigner.js +23 -36
- package/constants.d.ts +3 -2
- package/constants.js +6 -5
- package/container.d.ts +13 -6
- package/container.js +152 -168
- package/contentFetcher.d.ts +59 -0
- package/contentFetcher.js +129 -0
- package/context.d.ts +3 -3
- package/context.js +36 -38
- package/error.js +2 -2
- package/evaluator.d.ts +33 -24
- package/evaluator.js +126 -117
- package/eventManager.d.ts +1 -1
- package/eventManager.js +14 -15
- package/facade/contentFetcherFacade.d.ts +27 -0
- package/facade/contentFetcherFacade.js +40 -0
- package/facade/evaluatorFacade.d.ts +13 -3
- package/facade/evaluatorFacade.js +57 -72
- package/facade/sdkFacade.d.ts +10 -3
- package/facade/sdkFacade.js +129 -141
- package/facade/sessionFacade.js +6 -7
- package/facade/sessionPatch.js +9 -13
- package/facade/trackerFacade.js +32 -38
- package/facade/userFacade.js +10 -11
- package/facade/userPatch.js +9 -13
- package/index.js +2 -2
- package/logging/consoleLogger.js +18 -35
- package/logging/index.js +1 -1
- package/logging/namespacedLogger.js +14 -15
- package/logging/nullLogger.js +10 -13
- package/namespacedStorage.js +30 -47
- package/package.json +13 -16
- package/patch.d.ts +1 -1
- package/queue/capacityRestrictedQueue.js +17 -18
- package/queue/inMemoryQueue.js +22 -28
- package/queue/index.js +1 -1
- package/queue/monitoredQueue.d.ts +2 -2
- package/queue/monitoredQueue.js +39 -40
- package/queue/persistentQueue.js +33 -38
- package/retry/arbitraryPolicy.js +8 -10
- package/retry/backoffPolicy.d.ts +1 -1
- package/retry/backoffPolicy.js +11 -13
- package/retry/index.js +1 -1
- package/retry/maxAttemptsPolicy.js +7 -8
- package/retry/neverPolicy.js +6 -9
- package/schema/attributeSchema.js +1 -1
- package/schema/contentFetcherSchemas.d.ts +2 -0
- package/schema/contentFetcherSchemas.js +22 -0
- package/schema/contentSchemas.js +1 -1
- package/schema/contextSchemas.js +1 -1
- package/schema/ecommerceSchemas.js +1 -1
- package/schema/evaluatorSchemas.d.ts +2 -0
- package/schema/{evaluationSchemas.js → evaluatorSchemas.js} +3 -3
- package/schema/eventSchemas.js +8 -9
- package/schema/index.d.ts +2 -1
- package/schema/index.js +3 -2
- package/schema/loggerSchema.js +1 -1
- package/schema/operationSchemas.js +8 -8
- package/schema/sdkFacadeSchemas.js +9 -6
- package/schema/sdkSchemas.js +8 -5
- package/schema/tokenSchema.js +5 -4
- package/schema/userSchema.js +2 -2
- package/sdk.d.ts +9 -3
- package/sdk.js +81 -127
- package/sdkEvents.d.ts +3 -3
- package/sourceLocation.d.ts +3 -3
- package/sourceLocation.js +13 -14
- package/tab.d.ts +5 -5
- package/tab.js +50 -80
- package/token/cachedTokenStore.js +9 -10
- package/token/inMemoryTokenStore.js +7 -8
- package/token/index.js +1 -1
- package/token/replicatedTokenStore.js +7 -8
- package/token/token.d.ts +9 -5
- package/token/token.js +63 -57
- package/tracker.d.ts +4 -4
- package/tracker.js +145 -122
- package/trackingEvents.d.ts +36 -36
- package/trackingEvents.js +12 -6
- package/transformer.js +1 -1
- package/utilityTypes.d.ts +2 -2
- package/uuid.js +9 -7
- package/validation/arrayType.d.ts +2 -2
- package/validation/arrayType.js +29 -27
- package/validation/booleanType.js +11 -15
- package/validation/functionType.js +11 -15
- package/validation/index.js +1 -1
- package/validation/jsonType.d.ts +2 -2
- package/validation/jsonType.js +61 -80
- package/validation/mixedSchema.js +4 -7
- package/validation/nullType.js +11 -15
- package/validation/numberType.d.ts +1 -1
- package/validation/numberType.js +23 -22
- package/validation/objectType.d.ts +1 -1
- package/validation/objectType.js +61 -73
- package/validation/schema.js +6 -10
- package/validation/stringType.d.ts +1 -1
- package/validation/stringType.js +36 -47
- package/validation/unionType.js +27 -77
- package/validation/violation.js +1 -2
- package/schema/evaluationSchemas.d.ts +0 -2
package/container.js
CHANGED
|
@@ -1,82 +1,102 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Container = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
const logging_1 = require("./logging");
|
|
5
|
+
const context_1 = require("./context");
|
|
6
|
+
const namespacedStorage_1 = require("./namespacedStorage");
|
|
7
|
+
const retry_1 = require("./retry");
|
|
8
|
+
const queue_1 = require("./queue");
|
|
9
|
+
const token_1 = require("./token");
|
|
10
|
+
const tracker_1 = require("./tracker");
|
|
11
|
+
const evaluator_1 = require("./evaluator");
|
|
12
|
+
const transformer_1 = require("./transformer");
|
|
13
|
+
const cid_1 = require("./cid");
|
|
14
|
+
const eventManager_1 = require("./eventManager");
|
|
15
|
+
const cache_1 = require("./cache");
|
|
16
|
+
const guaranteedChannel_1 = require("./channel/guaranteedChannel");
|
|
17
|
+
const channel_1 = require("./channel");
|
|
18
|
+
const contentFetcher_1 = require("./contentFetcher");
|
|
19
|
+
class Container {
|
|
20
|
+
constructor(configuration) {
|
|
20
21
|
this.eventManager = new eventManager_1.SynchronousEventManager();
|
|
21
22
|
this.configuration = configuration;
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
+
getConfiguration() {
|
|
24
25
|
return this.configuration;
|
|
25
|
-
}
|
|
26
|
-
|
|
26
|
+
}
|
|
27
|
+
getEvaluator() {
|
|
27
28
|
if (this.evaluator === undefined) {
|
|
28
29
|
this.evaluator = this.createEvaluator();
|
|
29
30
|
}
|
|
30
31
|
return this.evaluator;
|
|
31
|
-
}
|
|
32
|
-
|
|
32
|
+
}
|
|
33
|
+
createEvaluator() {
|
|
33
34
|
return new evaluator_1.Evaluator({
|
|
34
35
|
appId: this.configuration.appId,
|
|
35
36
|
endpointUrl: this.configuration.evaluationEndpointUrl,
|
|
36
|
-
tokenProvider: this.getTokenProvider(),
|
|
37
|
-
cidAssigner: this.getCidAssigner(),
|
|
38
37
|
});
|
|
39
|
-
}
|
|
40
|
-
|
|
38
|
+
}
|
|
39
|
+
getContentFetcher() {
|
|
40
|
+
if (this.contentFetcher === undefined) {
|
|
41
|
+
this.contentFetcher = this.createContentFetcher();
|
|
42
|
+
}
|
|
43
|
+
return this.contentFetcher;
|
|
44
|
+
}
|
|
45
|
+
createContentFetcher() {
|
|
46
|
+
return new contentFetcher_1.ContentFetcher({
|
|
47
|
+
appId: this.configuration.appId,
|
|
48
|
+
endpointUrl: this.configuration.contentEndpointUrl,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
getPreviewTokenStore() {
|
|
52
|
+
if (this.previewTokenStore === undefined) {
|
|
53
|
+
this.previewTokenStore = new token_1.CachedTokenStore(new cache_1.LocalStorageCache(this.getGlobalBrowserStorage('preview'), 'token'));
|
|
54
|
+
}
|
|
55
|
+
return this.previewTokenStore;
|
|
56
|
+
}
|
|
57
|
+
getTracker() {
|
|
41
58
|
if (this.tracker === undefined) {
|
|
42
59
|
this.tracker = this.createTracker();
|
|
43
60
|
}
|
|
44
61
|
return this.tracker;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
62
|
+
}
|
|
63
|
+
createTracker() {
|
|
64
|
+
const context = this.getContext();
|
|
65
|
+
const tracker = new tracker_1.Tracker({
|
|
49
66
|
tab: context.getTab(),
|
|
50
|
-
tokenProvider: this.
|
|
67
|
+
tokenProvider: this.getUserTokenStore(),
|
|
51
68
|
inactivityRetryPolicy: new retry_1.ArbitraryPolicy([30000, 30000, 120000, 120000, 300000, 300000, 900000]),
|
|
52
69
|
logger: this.getLogger('Tracker'),
|
|
53
70
|
channel: this.getBeaconChannel(),
|
|
54
|
-
eventMetadata: this.configuration.eventMetadata
|
|
71
|
+
eventMetadata: this.configuration.eventMetadata,
|
|
55
72
|
});
|
|
56
|
-
|
|
73
|
+
const queue = this.getBeaconQueue();
|
|
57
74
|
queue.addCallback('halfEmpty', tracker.unsuspend);
|
|
58
75
|
queue.addCallback('full', tracker.suspend);
|
|
59
76
|
return tracker;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (this.
|
|
63
|
-
|
|
64
|
-
this.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
}
|
|
78
|
+
getUserTokenStore() {
|
|
79
|
+
if (this.userTokenProvider === undefined) {
|
|
80
|
+
const context = this.getContext();
|
|
81
|
+
this.userTokenProvider = {
|
|
82
|
+
getToken: context.getToken.bind(context),
|
|
83
|
+
setToken: context.setToken.bind(context),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return this.userTokenProvider;
|
|
87
|
+
}
|
|
88
|
+
getContext() {
|
|
69
89
|
if (this.context === undefined) {
|
|
70
90
|
this.context = this.createContext();
|
|
71
91
|
}
|
|
72
92
|
return this.context;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
93
|
+
}
|
|
94
|
+
createContext() {
|
|
95
|
+
const tokenKey = this.resolveStorageNamespace('token');
|
|
96
|
+
const tabKey = this.resolveStorageNamespace('tab');
|
|
97
|
+
const browserStorage = this.getLocalStorage();
|
|
98
|
+
const browserCache = new cache_1.LocalStorageCache(browserStorage, tokenKey);
|
|
99
|
+
const tabStorage = this.getSessionStorage();
|
|
80
100
|
this.removeTokenSyncListener = cache_1.LocalStorageCache.autoSync(browserCache);
|
|
81
101
|
return context_1.Context.load({
|
|
82
102
|
tokenScope: this.configuration.tokenScope,
|
|
@@ -88,27 +108,27 @@ var Container = /** @class */ (function () {
|
|
|
88
108
|
browserToken: browserCache,
|
|
89
109
|
},
|
|
90
110
|
});
|
|
91
|
-
}
|
|
92
|
-
|
|
111
|
+
}
|
|
112
|
+
getBeaconChannel() {
|
|
93
113
|
if (this.beaconChannel === undefined) {
|
|
94
114
|
this.beaconChannel = this.createBeaconChannel();
|
|
95
115
|
}
|
|
96
116
|
return this.beaconChannel;
|
|
97
|
-
}
|
|
98
|
-
|
|
117
|
+
}
|
|
118
|
+
createBeaconChannel() {
|
|
99
119
|
if (this.configuration.test) {
|
|
100
120
|
return new channel_1.SandboxChannel();
|
|
101
121
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
122
|
+
const channelLogger = this.getLogger('BeaconChannel');
|
|
123
|
+
const { appId, trackerEndpointUrl } = this.configuration;
|
|
124
|
+
const queuedChannel = new channel_1.QueuedChannel(new channel_1.RetryChannel({
|
|
105
125
|
channel: new channel_1.GuaranteedChannel({
|
|
106
126
|
channel: new channel_1.BeaconSocketChannel({
|
|
107
|
-
trackerEndpointUrl:
|
|
127
|
+
trackerEndpointUrl: `${trackerEndpointUrl}/${appId}`,
|
|
108
128
|
tokenParameter: 'token',
|
|
109
129
|
loggerFactory: this.getLogger.bind(this),
|
|
110
130
|
logger: channelLogger,
|
|
111
|
-
channelFactory:
|
|
131
|
+
channelFactory: (url, logger) => (new channel_1.SocketChannel({ url: url, logger: logger })),
|
|
112
132
|
cidAssigner: this.getCidAssigner(),
|
|
113
133
|
cidParameter: 'clientId',
|
|
114
134
|
}),
|
|
@@ -124,44 +144,40 @@ var Container = /** @class */ (function () {
|
|
|
124
144
|
}),
|
|
125
145
|
logger: channelLogger,
|
|
126
146
|
}), this.getBeaconQueue(), channelLogger);
|
|
127
|
-
queuedChannel.flush().catch(
|
|
147
|
+
queuedChannel.flush().catch(() => {
|
|
128
148
|
// Suppress errors as they are already reported by the channel
|
|
129
149
|
});
|
|
130
150
|
return new channel_1.EncodedChannel(queuedChannel, transformer_1.encodeJson);
|
|
131
|
-
}
|
|
132
|
-
|
|
151
|
+
}
|
|
152
|
+
getCidAssigner() {
|
|
133
153
|
if (this.cidAssigner === undefined) {
|
|
134
154
|
this.cidAssigner = this.createCidAssigner();
|
|
135
155
|
}
|
|
136
156
|
return this.cidAssigner;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (this.configuration.
|
|
140
|
-
return new cid_1.FixedAssigner(this.configuration.
|
|
157
|
+
}
|
|
158
|
+
createCidAssigner() {
|
|
159
|
+
if (this.configuration.clientId !== undefined) {
|
|
160
|
+
return new cid_1.FixedAssigner(this.configuration.clientId);
|
|
141
161
|
}
|
|
142
162
|
if (this.configuration.test) {
|
|
143
163
|
return new cid_1.FixedAssigner('00000000-0000-0000-0000-000000000000');
|
|
144
164
|
}
|
|
145
|
-
|
|
146
|
-
return new cid_1.CachedAssigner(new cid_1.RemoteAssigner(this.configuration.
|
|
147
|
-
}
|
|
148
|
-
|
|
165
|
+
const logger = this.getLogger('CidAssigner');
|
|
166
|
+
return new cid_1.CachedAssigner(new cid_1.RemoteAssigner(this.configuration.cidAssignerEndpointUrl, logger), new cache_1.LocalStorageCache(this.getLocalStorage(), 'croct.cid'), logger);
|
|
167
|
+
}
|
|
168
|
+
getBeaconQueue() {
|
|
149
169
|
if (this.beaconQueue === undefined) {
|
|
150
170
|
this.beaconQueue = this.createBeaconQueue();
|
|
151
171
|
}
|
|
152
172
|
return this.beaconQueue;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
173
|
+
}
|
|
174
|
+
createBeaconQueue() {
|
|
175
|
+
const context = this.getContext();
|
|
176
|
+
const tab = context.getTab();
|
|
157
177
|
return new queue_1.MonitoredQueue(new queue_1.CapacityRestrictedQueue(new queue_1.PersistentQueue(this.getGlobalTabStorage('queue'), tab.id), this.configuration.beaconQueueSize), this.getLogger('BeaconQueue'));
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
162
|
-
namespace[_i] = arguments[_i];
|
|
163
|
-
}
|
|
164
|
-
var prefix = "Croct".concat(namespace.length === 0 ? '' : ":".concat(namespace.join(':')));
|
|
178
|
+
}
|
|
179
|
+
getLogger(...namespace) {
|
|
180
|
+
const prefix = `Croct${namespace.length === 0 ? '' : `:${namespace.join(':')}`}`;
|
|
165
181
|
if (this.configuration.logger !== undefined) {
|
|
166
182
|
return new logging_1.NamespacedLogger(this.configuration.logger, prefix);
|
|
167
183
|
}
|
|
@@ -169,96 +185,64 @@ var Container = /** @class */ (function () {
|
|
|
169
185
|
return new logging_1.ConsoleLogger(prefix);
|
|
170
186
|
}
|
|
171
187
|
return new logging_1.NullLogger();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
return new namespacedStorage_1.NamespacedStorage(this.getSessionStorage(), this.resolveStorageNamespace.apply(this, tslib_1.__spreadArray([namespace], tslib_1.__read(subnamespace), false)));
|
|
193
|
-
};
|
|
194
|
-
Container.prototype.getGlobalBrowserStorage = function (namespace) {
|
|
195
|
-
var subnamespace = [];
|
|
196
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
197
|
-
subnamespace[_i - 1] = arguments[_i];
|
|
198
|
-
}
|
|
199
|
-
return new namespacedStorage_1.NamespacedStorage(this.getLocalStorage(), this.resolveStorageNamespace.apply(this, tslib_1.__spreadArray([namespace], tslib_1.__read(subnamespace), false)));
|
|
200
|
-
};
|
|
201
|
-
Container.prototype.resolveStorageNamespace = function (namespace) {
|
|
202
|
-
var subnamespace = [];
|
|
203
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
204
|
-
subnamespace[_i - 1] = arguments[_i];
|
|
205
|
-
}
|
|
206
|
-
return "croct[".concat(this.configuration.appId.toLowerCase(), "].").concat([namespace].concat(subnamespace).join('.'));
|
|
207
|
-
};
|
|
208
|
-
Container.prototype.getLocalStorage = function () {
|
|
188
|
+
}
|
|
189
|
+
getTabStorage(namespace, ...subnamespace) {
|
|
190
|
+
return this.getGlobalTabStorage('external', namespace, ...subnamespace);
|
|
191
|
+
}
|
|
192
|
+
getBrowserStorage(namespace, ...subnamespace) {
|
|
193
|
+
return this.getGlobalBrowserStorage('external', namespace, ...subnamespace);
|
|
194
|
+
}
|
|
195
|
+
getGlobalTabStorage(namespace, ...subnamespace) {
|
|
196
|
+
return new namespacedStorage_1.NamespacedStorage(this.getSessionStorage(), this.resolveStorageNamespace(namespace, ...subnamespace));
|
|
197
|
+
}
|
|
198
|
+
getGlobalBrowserStorage(namespace, ...subnamespace) {
|
|
199
|
+
return new namespacedStorage_1.NamespacedStorage(this.getLocalStorage(), this.resolveStorageNamespace(namespace, ...subnamespace));
|
|
200
|
+
}
|
|
201
|
+
resolveStorageNamespace(namespace, ...subnamespace) {
|
|
202
|
+
return `croct[${this.configuration
|
|
203
|
+
.appId
|
|
204
|
+
.toLowerCase()}].${[namespace].concat(subnamespace).join('.')}`;
|
|
205
|
+
}
|
|
206
|
+
getLocalStorage() {
|
|
209
207
|
return localStorage;
|
|
210
|
-
}
|
|
211
|
-
|
|
208
|
+
}
|
|
209
|
+
getSessionStorage() {
|
|
212
210
|
return sessionStorage;
|
|
213
|
-
}
|
|
214
|
-
|
|
211
|
+
}
|
|
212
|
+
getEventManager() {
|
|
215
213
|
return this.eventManager;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
delete this.cidAssigner;
|
|
251
|
-
delete this.tracker;
|
|
252
|
-
delete this.evaluator;
|
|
253
|
-
delete this.beaconChannel;
|
|
254
|
-
delete this.beaconQueue;
|
|
255
|
-
delete this.removeTokenSyncListener;
|
|
256
|
-
logger.debug('Container resources released.');
|
|
257
|
-
return [2 /*return*/];
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
};
|
|
262
|
-
return Container;
|
|
263
|
-
}());
|
|
214
|
+
}
|
|
215
|
+
async dispose() {
|
|
216
|
+
const logger = this.getLogger();
|
|
217
|
+
if (this.beaconChannel !== undefined) {
|
|
218
|
+
logger.debug('Closing beacon channel...');
|
|
219
|
+
await this.beaconChannel.close();
|
|
220
|
+
}
|
|
221
|
+
if (this.removeTokenSyncListener !== undefined) {
|
|
222
|
+
logger.debug('Removing token sync listener...');
|
|
223
|
+
this.removeTokenSyncListener();
|
|
224
|
+
}
|
|
225
|
+
if (this.tracker !== undefined) {
|
|
226
|
+
if (this.beaconQueue !== undefined) {
|
|
227
|
+
logger.debug('Removing queue listeners...');
|
|
228
|
+
this.beaconQueue.removeCallback('halfEmpty', this.tracker.unsuspend);
|
|
229
|
+
this.beaconQueue.removeCallback('full', this.tracker.suspend);
|
|
230
|
+
}
|
|
231
|
+
logger.debug('Suspending tracker...');
|
|
232
|
+
this.tracker.suspend();
|
|
233
|
+
await this.tracker.flushed;
|
|
234
|
+
}
|
|
235
|
+
delete this.context;
|
|
236
|
+
delete this.userTokenProvider;
|
|
237
|
+
delete this.previewTokenStore;
|
|
238
|
+
delete this.cidAssigner;
|
|
239
|
+
delete this.tracker;
|
|
240
|
+
delete this.evaluator;
|
|
241
|
+
delete this.contentFetcher;
|
|
242
|
+
delete this.beaconChannel;
|
|
243
|
+
delete this.beaconQueue;
|
|
244
|
+
delete this.removeTokenSyncListener;
|
|
245
|
+
logger.debug('Container resources released.');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
264
248
|
exports.Container = Container;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { JsonObject } from '@croct/json';
|
|
2
|
+
import { EvaluationContext } from './evaluator';
|
|
3
|
+
import { Token } from './token';
|
|
4
|
+
export type ErrorResponse = {
|
|
5
|
+
type: string;
|
|
6
|
+
title: string;
|
|
7
|
+
status: number;
|
|
8
|
+
detail?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare enum ContentErrorType {
|
|
11
|
+
TIMEOUT = "https://croct.help/api/content#timeout",
|
|
12
|
+
UNEXPECTED_ERROR = "https://croct.help/api/content#unexpected-error"
|
|
13
|
+
}
|
|
14
|
+
export declare class ContentError<T extends ErrorResponse = ErrorResponse> extends Error {
|
|
15
|
+
readonly response: T;
|
|
16
|
+
constructor(response: T);
|
|
17
|
+
}
|
|
18
|
+
type BasicOptions = {
|
|
19
|
+
version?: `${number}` | number;
|
|
20
|
+
preferredLocale?: string;
|
|
21
|
+
timeout?: number;
|
|
22
|
+
extra?: ExtraFetchOptions;
|
|
23
|
+
};
|
|
24
|
+
export type StaticContentOptions = BasicOptions & {
|
|
25
|
+
static: true;
|
|
26
|
+
};
|
|
27
|
+
export type DynamicContentOptions = BasicOptions & {
|
|
28
|
+
static?: false;
|
|
29
|
+
clientId?: string;
|
|
30
|
+
clientIp?: string;
|
|
31
|
+
userAgent?: string;
|
|
32
|
+
userToken?: Token | string;
|
|
33
|
+
previewToken?: Token | string;
|
|
34
|
+
context?: EvaluationContext;
|
|
35
|
+
};
|
|
36
|
+
type AllowedFetchOptions = Exclude<keyof RequestInit, 'method' | 'body' | 'headers' | 'signal'>;
|
|
37
|
+
type ExtraFetchOptions<T extends keyof RequestInit = AllowedFetchOptions> = Pick<RequestInit, T> & {
|
|
38
|
+
[key in Exclude<keyof RequestInit, T>]?: never;
|
|
39
|
+
} & Record<string, any>;
|
|
40
|
+
export type FetchOptions = StaticContentOptions | DynamicContentOptions;
|
|
41
|
+
export type FetchResponse<P extends JsonObject = JsonObject> = {
|
|
42
|
+
content: P;
|
|
43
|
+
};
|
|
44
|
+
export type Configuration = {
|
|
45
|
+
appId?: string;
|
|
46
|
+
apiKey?: string;
|
|
47
|
+
endpointUrl?: string;
|
|
48
|
+
};
|
|
49
|
+
export declare class ContentFetcher {
|
|
50
|
+
private readonly configuration;
|
|
51
|
+
private readonly dynamicEndpoint;
|
|
52
|
+
private readonly staticEndpoint;
|
|
53
|
+
constructor(configuration: Configuration);
|
|
54
|
+
fetch<P extends JsonObject>(slotId: string, options?: FetchOptions): Promise<FetchResponse<P>>;
|
|
55
|
+
private load;
|
|
56
|
+
private static isDynamicContent;
|
|
57
|
+
toJSON(): never;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContentFetcher = exports.ContentError = exports.ContentErrorType = void 0;
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
const error_1 = require("./error");
|
|
6
|
+
var ContentErrorType;
|
|
7
|
+
(function (ContentErrorType) {
|
|
8
|
+
ContentErrorType["TIMEOUT"] = "https://croct.help/api/content#timeout";
|
|
9
|
+
ContentErrorType["UNEXPECTED_ERROR"] = "https://croct.help/api/content#unexpected-error";
|
|
10
|
+
})(ContentErrorType = exports.ContentErrorType || (exports.ContentErrorType = {}));
|
|
11
|
+
class ContentError extends Error {
|
|
12
|
+
constructor(response) {
|
|
13
|
+
super(response.title);
|
|
14
|
+
this.response = response;
|
|
15
|
+
Object.setPrototypeOf(this, ContentError.prototype);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.ContentError = ContentError;
|
|
19
|
+
class ContentFetcher {
|
|
20
|
+
constructor(configuration) {
|
|
21
|
+
if ((configuration.appId === undefined) === (configuration.apiKey === undefined)) {
|
|
22
|
+
throw new Error('Either the application ID or the API key must be provided.');
|
|
23
|
+
}
|
|
24
|
+
this.configuration = configuration;
|
|
25
|
+
const { apiKey, endpointUrl } = this.configuration;
|
|
26
|
+
// eslint-disable-next-line prefer-template -- Better readability
|
|
27
|
+
const baseEndpoint = (endpointUrl !== null && endpointUrl !== void 0 ? endpointUrl : constants_1.CONTENT_ENDPOINT_URL).replace(/\/+$/, '')
|
|
28
|
+
+ (apiKey === undefined ? '/client' : '/external')
|
|
29
|
+
+ '/web';
|
|
30
|
+
this.dynamicEndpoint = `${baseEndpoint}/content`;
|
|
31
|
+
this.staticEndpoint = `${baseEndpoint}/static-content`;
|
|
32
|
+
}
|
|
33
|
+
fetch(slotId, options = {}) {
|
|
34
|
+
if (options.static === true && this.configuration.apiKey === undefined) {
|
|
35
|
+
throw new Error('The API key must be provided to fetch static content.');
|
|
36
|
+
}
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const abortController = new AbortController();
|
|
39
|
+
if (options.timeout !== undefined) {
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
const response = {
|
|
42
|
+
title: 'Maximum timeout reached before content could be loaded.',
|
|
43
|
+
type: ContentErrorType.TIMEOUT,
|
|
44
|
+
detail: `The content took more than ${options.timeout}ms to load.`,
|
|
45
|
+
status: 408, // Request Timeout
|
|
46
|
+
};
|
|
47
|
+
abortController.abort();
|
|
48
|
+
reject(new ContentError(response));
|
|
49
|
+
}, options.timeout);
|
|
50
|
+
}
|
|
51
|
+
this.load(slotId, abortController.signal, options)
|
|
52
|
+
.then(response => response.json()
|
|
53
|
+
.then(body => {
|
|
54
|
+
if (response.ok) {
|
|
55
|
+
resolve(body);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
reject(new ContentError(body));
|
|
59
|
+
}
|
|
60
|
+
}))
|
|
61
|
+
.catch(error => {
|
|
62
|
+
if (!abortController.signal.aborted) {
|
|
63
|
+
reject(new ContentError({
|
|
64
|
+
title: (0, error_1.formatMessage)(error),
|
|
65
|
+
type: ContentErrorType.UNEXPECTED_ERROR,
|
|
66
|
+
detail: 'Please try again or contact Croct support if the error persists.',
|
|
67
|
+
status: 500, // Internal Server Error
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
load(slotId, signal, options) {
|
|
74
|
+
const payload = {
|
|
75
|
+
slotId: slotId,
|
|
76
|
+
};
|
|
77
|
+
const { apiKey, appId } = this.configuration;
|
|
78
|
+
const headers = new Headers();
|
|
79
|
+
if (appId !== undefined) {
|
|
80
|
+
headers.set('X-App-Id', appId);
|
|
81
|
+
}
|
|
82
|
+
if (apiKey !== undefined) {
|
|
83
|
+
headers.set('X-Api-Key', apiKey);
|
|
84
|
+
}
|
|
85
|
+
const dynamic = ContentFetcher.isDynamicContent(options);
|
|
86
|
+
if (dynamic) {
|
|
87
|
+
if (options.clientId !== undefined) {
|
|
88
|
+
headers.set('X-Client-Id', options.clientId);
|
|
89
|
+
}
|
|
90
|
+
if (options.clientIp !== undefined) {
|
|
91
|
+
headers.set('X-Client-Ip', options.clientIp);
|
|
92
|
+
}
|
|
93
|
+
if (options.userToken !== undefined) {
|
|
94
|
+
headers.set('X-Token', options.userToken.toString());
|
|
95
|
+
}
|
|
96
|
+
if (options.userAgent !== undefined) {
|
|
97
|
+
headers.set('User-Agent', options.userAgent);
|
|
98
|
+
}
|
|
99
|
+
if (options.version !== undefined) {
|
|
100
|
+
payload.version = `${options.version}`;
|
|
101
|
+
}
|
|
102
|
+
if (options.preferredLocale !== undefined) {
|
|
103
|
+
payload.preferredLocale = options.preferredLocale;
|
|
104
|
+
}
|
|
105
|
+
if (options.context !== undefined) {
|
|
106
|
+
payload.context = options.context;
|
|
107
|
+
}
|
|
108
|
+
if (options.previewToken !== undefined) {
|
|
109
|
+
payload.previewToken = `${options.previewToken}`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return fetch(dynamic ? this.dynamicEndpoint : this.staticEndpoint, {
|
|
113
|
+
credentials: 'omit',
|
|
114
|
+
...options.extra,
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers: headers,
|
|
117
|
+
signal: signal,
|
|
118
|
+
body: JSON.stringify(payload),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
static isDynamicContent(options) {
|
|
122
|
+
return options.static !== true;
|
|
123
|
+
}
|
|
124
|
+
toJSON() {
|
|
125
|
+
// Prevent sensitive configuration from being serialized
|
|
126
|
+
throw new Error('Unserializable value.');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.ContentFetcher = ContentFetcher;
|
package/context.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { Tab, UrlSanitizer } from './tab';
|
|
|
3
3
|
import { EventDispatcher } from './eventManager';
|
|
4
4
|
import { SdkEventMap } from './sdkEvents';
|
|
5
5
|
import { LocalStorageCache } from './cache';
|
|
6
|
-
export
|
|
7
|
-
export
|
|
6
|
+
export type TokenScope = 'isolated' | 'global' | 'contextual';
|
|
7
|
+
export type Configuration = {
|
|
8
8
|
tokenScope: TokenScope;
|
|
9
9
|
urlSanitizer?: UrlSanitizer;
|
|
10
10
|
eventDispatcher: ContextEventDispatcher;
|
|
@@ -14,7 +14,7 @@ export declare type Configuration = {
|
|
|
14
14
|
browserToken: LocalStorageCache;
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
|
-
|
|
17
|
+
type ContextEventDispatcher = EventDispatcher<Pick<SdkEventMap, 'tokenChanged'>>;
|
|
18
18
|
export declare class Context {
|
|
19
19
|
private readonly tab;
|
|
20
20
|
private readonly tokenStore;
|