@configdirector/react-native-sdk 1.5.0 → 1.6.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.
- package/README.md +43 -0
- package/dist/configdirector-react-native-testing.d.mts +157 -0
- package/dist/configdirector-react-native-testing.mjs +398 -0
- package/dist/configdirector-react-native.d.mts +48 -294
- package/dist/configdirector-react-native.mjs +224 -1335
- package/dist/installedTestClient-CxGEAMOE.mjs +1341 -0
- package/dist/types-fcPMBgiX.d.mts +295 -0
- package/package.json +14 -1
|
@@ -1,1307 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as CLIENT_BASE_URL, d as _defineProperty, i as fetchWithTimeout, n as readInstalledTestClient, o as createDefaultLogger, r as DefaultConfigDirectorClient, s as isFetchErrorFatal } from "./installedTestClient-CxGEAMOE.mjs";
|
|
2
2
|
import React, { Component, useContext as useContext$1 } from "react";
|
|
3
|
-
import { AppState } from "react-native";
|
|
3
|
+
import { AppState, NativeModules } from "react-native";
|
|
4
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
//#region \0@oxc-project+runtime@0.122.0/helpers/typeof.js
|
|
6
|
-
function _typeof(o) {
|
|
7
|
-
"@babel/helpers - typeof";
|
|
8
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
9
|
-
return typeof o;
|
|
10
|
-
} : function(o) {
|
|
11
|
-
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
12
|
-
}, _typeof(o);
|
|
13
|
-
}
|
|
14
|
-
//#endregion
|
|
15
|
-
//#region \0@oxc-project+runtime@0.122.0/helpers/toPrimitive.js
|
|
16
|
-
function toPrimitive(t, r) {
|
|
17
|
-
if ("object" != _typeof(t) || !t) return t;
|
|
18
|
-
var e = t[Symbol.toPrimitive];
|
|
19
|
-
if (void 0 !== e) {
|
|
20
|
-
var i = e.call(t, r || "default");
|
|
21
|
-
if ("object" != _typeof(i)) return i;
|
|
22
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
23
|
-
}
|
|
24
|
-
return ("string" === r ? String : Number)(t);
|
|
25
|
-
}
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region \0@oxc-project+runtime@0.122.0/helpers/toPropertyKey.js
|
|
28
|
-
function toPropertyKey(t) {
|
|
29
|
-
var i = toPrimitive(t, "string");
|
|
30
|
-
return "symbol" == _typeof(i) ? i : i + "";
|
|
31
|
-
}
|
|
32
|
-
//#endregion
|
|
33
|
-
//#region \0@oxc-project+runtime@0.122.0/helpers/defineProperty.js
|
|
34
|
-
function _defineProperty(e, r, t) {
|
|
35
|
-
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
36
|
-
value: t,
|
|
37
|
-
enumerable: !0,
|
|
38
|
-
configurable: !0,
|
|
39
|
-
writable: !0
|
|
40
|
-
}) : e[r] = t, e;
|
|
41
|
-
}
|
|
42
|
-
//#endregion
|
|
43
|
-
//#region ../js-client-core/src/Emitter.ts
|
|
44
|
-
var Emitter = class {
|
|
45
|
-
constructor() {
|
|
46
|
-
_defineProperty(this, "handlerMap", /* @__PURE__ */ new Map());
|
|
47
|
-
}
|
|
48
|
-
on(name, handler) {
|
|
49
|
-
const handlers = this.handlerMap.get(name);
|
|
50
|
-
if (handlers) handlers.push(handler);
|
|
51
|
-
else this.handlerMap.set(name, [handler]);
|
|
52
|
-
}
|
|
53
|
-
once(name, handler) {
|
|
54
|
-
const self = this;
|
|
55
|
-
function onceHandler(payload) {
|
|
56
|
-
self.off(name, onceHandler);
|
|
57
|
-
handler.apply(self, payload);
|
|
58
|
-
}
|
|
59
|
-
this.on(name, onceHandler);
|
|
60
|
-
}
|
|
61
|
-
off(name, handler) {
|
|
62
|
-
const handlers = this.handlerMap.get(name);
|
|
63
|
-
if (!handlers) return;
|
|
64
|
-
if (handler) {
|
|
65
|
-
const listenerIndex = handlers.indexOf(handler);
|
|
66
|
-
if (listenerIndex >= 0) handlers.splice(listenerIndex, 1);
|
|
67
|
-
} else this.handlerMap.set(name, []);
|
|
68
|
-
}
|
|
69
|
-
clear() {
|
|
70
|
-
this.handlerMap.clear();
|
|
71
|
-
}
|
|
72
|
-
emit(name, payload) {
|
|
73
|
-
const handlers = this.handlerMap.get(name);
|
|
74
|
-
if (!handlers) return;
|
|
75
|
-
handlers.slice().map((h) => h(payload));
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
//#endregion
|
|
79
|
-
//#region ../shared/src/errors.ts
|
|
80
|
-
var ConfigDirectorConnectionError = class ConfigDirectorConnectionError extends Error {
|
|
81
|
-
constructor(message, status) {
|
|
82
|
-
super(message);
|
|
83
|
-
_defineProperty(this, "name", "ConfigDirectorConnectionError");
|
|
84
|
-
_defineProperty(this, "status", void 0);
|
|
85
|
-
this.status = status;
|
|
86
|
-
Object.setPrototypeOf(this, ConfigDirectorConnectionError.prototype);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
var ConfigDirectorValidationError = class ConfigDirectorValidationError extends Error {
|
|
90
|
-
constructor(message) {
|
|
91
|
-
super(message);
|
|
92
|
-
_defineProperty(this, "name", "ConfigDirectorValidationError");
|
|
93
|
-
Object.setPrototypeOf(this, ConfigDirectorValidationError.prototype);
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
//#endregion
|
|
97
|
-
//#region ../js-client-core/src/errors.ts
|
|
98
|
-
const isFetchErrorFatal = (fetchError) => {
|
|
99
|
-
if ((fetchError === null || fetchError === void 0 ? void 0 : fetchError.name) === "NotAllowedError") return true;
|
|
100
|
-
else if (fetchError instanceof TypeError) return true;
|
|
101
|
-
return false;
|
|
102
|
-
};
|
|
103
|
-
//#endregion
|
|
104
|
-
//#region ../eventsource/src/errors.ts
|
|
105
|
-
var StreamClosedError = class StreamClosedError extends Error {
|
|
106
|
-
constructor(message) {
|
|
107
|
-
super(message);
|
|
108
|
-
_defineProperty(this, "name", "StreamClosedError");
|
|
109
|
-
Object.setPrototypeOf(this, StreamClosedError.prototype);
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
var MissingResponseBodyError = class MissingResponseBodyError extends Error {
|
|
113
|
-
constructor(message) {
|
|
114
|
-
super(message);
|
|
115
|
-
_defineProperty(this, "name", "MissingResponseBodyError");
|
|
116
|
-
Object.setPrototypeOf(this, MissingResponseBodyError.prototype);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
var InvalidOptionError = class InvalidOptionError extends Error {
|
|
120
|
-
constructor(message) {
|
|
121
|
-
super(message);
|
|
122
|
-
_defineProperty(this, "name", "InvalidOptionError");
|
|
123
|
-
Object.setPrototypeOf(this, InvalidOptionError.prototype);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
var ValueOutOfRangeError = class ValueOutOfRangeError extends Error {
|
|
127
|
-
constructor(message) {
|
|
128
|
-
super(message);
|
|
129
|
-
_defineProperty(this, "name", "ValueOutOfRangeError");
|
|
130
|
-
Object.setPrototypeOf(this, ValueOutOfRangeError.prototype);
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
//#endregion
|
|
134
|
-
//#region ../eventsource/src/types.ts
|
|
135
|
-
let ReadyState = /* @__PURE__ */ function(ReadyState) {
|
|
136
|
-
ReadyState["OPEN"] = "open";
|
|
137
|
-
ReadyState["CLOSED"] = "closed";
|
|
138
|
-
ReadyState["CONNECTING"] = "connecting";
|
|
139
|
-
return ReadyState;
|
|
140
|
-
}({});
|
|
141
|
-
//#endregion
|
|
142
|
-
//#region ../eventsource/src/EventSourceParser.ts
|
|
143
|
-
var EventSourceParser = class {
|
|
144
|
-
constructor(options) {
|
|
145
|
-
var _options$onEvent;
|
|
146
|
-
_defineProperty(this, "isFirstChunk", true);
|
|
147
|
-
_defineProperty(this, "bufferedInput", "");
|
|
148
|
-
_defineProperty(this, "currentEvent", { data: "" });
|
|
149
|
-
_defineProperty(this, "lastEventId", void 0);
|
|
150
|
-
_defineProperty(this, "onEvent", void 0);
|
|
151
|
-
_defineProperty(this, "onRetry", void 0);
|
|
152
|
-
_defineProperty(this, "onComment", void 0);
|
|
153
|
-
this.currentEvent = { data: "" };
|
|
154
|
-
this.onEvent = (_options$onEvent = options.onEvent) !== null && _options$onEvent !== void 0 ? _options$onEvent : (() => {});
|
|
155
|
-
this.onRetry = options.onRetry;
|
|
156
|
-
this.onComment = options.onComment;
|
|
157
|
-
}
|
|
158
|
-
parse(chunk) {
|
|
159
|
-
let input = chunk;
|
|
160
|
-
if (this.isFirstChunk) {
|
|
161
|
-
this.isFirstChunk = false;
|
|
162
|
-
if (input.startsWith("")) input = input.slice(1);
|
|
163
|
-
else if (input.startsWith("")) input = input.slice(3);
|
|
164
|
-
}
|
|
165
|
-
const lines = this.scanLines(this.bufferedInput + input);
|
|
166
|
-
for (const line of lines) this.dispatchLine(line);
|
|
167
|
-
}
|
|
168
|
-
finish() {
|
|
169
|
-
this.bufferedInput = "";
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Scans `text` character by character to extract complete lines, recognizing
|
|
173
|
-
* CR, LF, and CRLF as line terminators per the SSE spec. Any unterminated
|
|
174
|
-
* trailing text is buffered and prepended to the next chunk.
|
|
175
|
-
*/
|
|
176
|
-
scanLines(text) {
|
|
177
|
-
const lines = [];
|
|
178
|
-
let lineStart = 0;
|
|
179
|
-
let i = 0;
|
|
180
|
-
while (i < text.length) {
|
|
181
|
-
const ch = text[i];
|
|
182
|
-
if (ch === "\r" || ch === "\n") {
|
|
183
|
-
lines.push(text.slice(lineStart, i));
|
|
184
|
-
if (ch === "\r" && text[i + 1] === "\n") i++;
|
|
185
|
-
i++;
|
|
186
|
-
lineStart = i;
|
|
187
|
-
} else i++;
|
|
188
|
-
}
|
|
189
|
-
this.bufferedInput = text.slice(lineStart);
|
|
190
|
-
return lines;
|
|
191
|
-
}
|
|
192
|
-
dispatchLine(line) {
|
|
193
|
-
if (line.startsWith(":")) {
|
|
194
|
-
var _this$onComment;
|
|
195
|
-
(_this$onComment = this.onComment) === null || _this$onComment === void 0 || _this$onComment.call(this, this.extractValue(line, 1));
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
if (line === "") {
|
|
199
|
-
this.emitEvent();
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
this.applyField(this.parseField(line));
|
|
203
|
-
}
|
|
204
|
-
emitEvent() {
|
|
205
|
-
const data = this.currentEvent.data.endsWith("\n") ? this.currentEvent.data.slice(0, -1) : this.currentEvent.data;
|
|
206
|
-
if (data !== "") this.onEvent({
|
|
207
|
-
...this.currentEvent,
|
|
208
|
-
id: this.lastEventId,
|
|
209
|
-
data
|
|
210
|
-
});
|
|
211
|
-
this.currentEvent = { data: "" };
|
|
212
|
-
}
|
|
213
|
-
applyField(parsed) {
|
|
214
|
-
switch (parsed.field) {
|
|
215
|
-
case "event":
|
|
216
|
-
this.currentEvent.type = parsed.value;
|
|
217
|
-
break;
|
|
218
|
-
case "data":
|
|
219
|
-
this.currentEvent.data += parsed.value + "\n";
|
|
220
|
-
break;
|
|
221
|
-
case "id":
|
|
222
|
-
if (!parsed.value.includes("\0")) this.lastEventId = parsed.value;
|
|
223
|
-
break;
|
|
224
|
-
case "retry":
|
|
225
|
-
if (/^\d+$/.test(parsed.value)) {
|
|
226
|
-
var _this$onRetry;
|
|
227
|
-
(_this$onRetry = this.onRetry) === null || _this$onRetry === void 0 || _this$onRetry.call(this, Number.parseInt(parsed.value, 10));
|
|
228
|
-
}
|
|
229
|
-
break;
|
|
230
|
-
default: break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
parseField(line) {
|
|
234
|
-
const colon = line.indexOf(":");
|
|
235
|
-
if (colon === -1) return {
|
|
236
|
-
field: line,
|
|
237
|
-
value: ""
|
|
238
|
-
};
|
|
239
|
-
return {
|
|
240
|
-
field: line.slice(0, colon),
|
|
241
|
-
value: this.extractValue(line, colon + 1)
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
/** Returns the value portion of a line, stripping a single leading space per spec. */
|
|
245
|
-
extractValue(line, from) {
|
|
246
|
-
return line[from] === " " ? line.slice(from + 1) : line.slice(from);
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
//#endregion
|
|
250
|
-
//#region ../eventsource/src/EventSourceClient.ts
|
|
251
|
-
var EventSourceClient = class {
|
|
252
|
-
constructor(options) {
|
|
253
|
-
var _options$method, _options$fetch;
|
|
254
|
-
_defineProperty(this, "DEFAULT_SHOULD_RECONNECT", () => true);
|
|
255
|
-
_defineProperty(this, "DEFAULT_CALCULATE_RECONNECT_DELAY", () => this.serverReconnectionTime);
|
|
256
|
-
_defineProperty(this, "url", void 0);
|
|
257
|
-
_defineProperty(this, "headers", void 0);
|
|
258
|
-
_defineProperty(this, "body", void 0);
|
|
259
|
-
_defineProperty(this, "requestOptions", void 0);
|
|
260
|
-
_defineProperty(this, "lastEventId", void 0);
|
|
261
|
-
_defineProperty(this, "reconnectAttempt", 0);
|
|
262
|
-
_defineProperty(this, "abortController", new AbortController());
|
|
263
|
-
_defineProperty(this, "reconnectTimeout", void 0);
|
|
264
|
-
_defineProperty(this, "_readyState", ReadyState.CLOSED);
|
|
265
|
-
_defineProperty(this, "serverReconnectionTime", 2e3);
|
|
266
|
-
_defineProperty(this, "_fetch", void 0);
|
|
267
|
-
_defineProperty(this, "_onError", void 0);
|
|
268
|
-
_defineProperty(this, "_onMessage", void 0);
|
|
269
|
-
_defineProperty(this, "_onComment", void 0);
|
|
270
|
-
_defineProperty(this, "_onConnect", void 0);
|
|
271
|
-
_defineProperty(this, "_onDisconnect", void 0);
|
|
272
|
-
_defineProperty(this, "_shouldReconnect", void 0);
|
|
273
|
-
_defineProperty(this, "_calculateReconnectDelay", void 0);
|
|
274
|
-
this.url = options.url.toString();
|
|
275
|
-
this.lastEventId = options.lastEventId;
|
|
276
|
-
this.headers = {
|
|
277
|
-
Accept: "text/event-stream",
|
|
278
|
-
...options.headers
|
|
279
|
-
};
|
|
280
|
-
const body = options.body;
|
|
281
|
-
this.body = typeof body === "function" ? body : () => body;
|
|
282
|
-
this.requestOptions = {
|
|
283
|
-
method: (_options$method = options.method) !== null && _options$method !== void 0 ? _options$method : "GET",
|
|
284
|
-
mode: options.mode,
|
|
285
|
-
credentials: options.credentials,
|
|
286
|
-
redirect: options.redirect,
|
|
287
|
-
referrer: options.referrer,
|
|
288
|
-
referrerPolicy: options.referrerPolicy
|
|
289
|
-
};
|
|
290
|
-
this._fetch = (_options$fetch = options.fetch) !== null && _options$fetch !== void 0 ? _options$fetch : ((url, init) => fetch(url, init));
|
|
291
|
-
this._onError = this.resolveCallback(options.onError, () => {}, "onError");
|
|
292
|
-
this._onConnect = this.resolveCallback(options.onConnect, () => {}, "onConnect");
|
|
293
|
-
this._onDisconnect = this.resolveCallback(options.onDisconnect, () => {}, "onDisconnect");
|
|
294
|
-
this._onMessage = this.resolveCallback(options.onMessage, () => {}, "onMessage");
|
|
295
|
-
this._onComment = this.resolveCallback(options.onComment, () => {}, "onComment");
|
|
296
|
-
this._shouldReconnect = this.resolveCallback(options.shouldReconnect, this.DEFAULT_SHOULD_RECONNECT, "shouldReconnect");
|
|
297
|
-
this._calculateReconnectDelay = this.resolveCallback(options.calculateReconnectDelay, this.DEFAULT_CALCULATE_RECONNECT_DELAY, "calculateReconnectDelay");
|
|
298
|
-
}
|
|
299
|
-
set onError(value) {
|
|
300
|
-
this._onError = this.resolveCallback(value, () => {}, "onError");
|
|
301
|
-
}
|
|
302
|
-
set onMessage(value) {
|
|
303
|
-
this._onMessage = this.resolveCallback(value, () => {}, "onMessage");
|
|
304
|
-
}
|
|
305
|
-
set onComment(value) {
|
|
306
|
-
this._onComment = this.resolveCallback(value, () => {}, "onComment");
|
|
307
|
-
}
|
|
308
|
-
set onConnect(value) {
|
|
309
|
-
this._onConnect = this.resolveCallback(value, () => {}, "onConnect");
|
|
310
|
-
}
|
|
311
|
-
set onDisconnect(value) {
|
|
312
|
-
this._onDisconnect = this.resolveCallback(value, () => {}, "onDisconnect");
|
|
313
|
-
}
|
|
314
|
-
set shouldReconnect(value) {
|
|
315
|
-
this._shouldReconnect = this.resolveCallback(value, this.DEFAULT_SHOULD_RECONNECT, "shouldReconnect");
|
|
316
|
-
}
|
|
317
|
-
set calculateReconnectDelay(value) {
|
|
318
|
-
this._calculateReconnectDelay = this.resolveCallback(value, this.DEFAULT_CALCULATE_RECONNECT_DELAY, "shouldReconnect");
|
|
319
|
-
}
|
|
320
|
-
get readyState() {
|
|
321
|
-
return this._readyState;
|
|
322
|
-
}
|
|
323
|
-
connect() {
|
|
324
|
-
if (this._readyState !== ReadyState.CLOSED) return;
|
|
325
|
-
this.reconnectAttempt = 0;
|
|
326
|
-
this.initiateConnection();
|
|
327
|
-
}
|
|
328
|
-
close() {
|
|
329
|
-
clearTimeout(this.reconnectTimeout);
|
|
330
|
-
this._readyState = ReadyState.CLOSED;
|
|
331
|
-
this.abortController.abort();
|
|
332
|
-
}
|
|
333
|
-
initiateConnection() {
|
|
334
|
-
this.abortController = new AbortController();
|
|
335
|
-
this._readyState = ReadyState.CONNECTING;
|
|
336
|
-
this._fetch(this.url, {
|
|
337
|
-
...this.requestOptions,
|
|
338
|
-
body: this.body(),
|
|
339
|
-
headers: this.buildRequestHeaders(),
|
|
340
|
-
signal: this.abortController.signal,
|
|
341
|
-
cache: "no-store"
|
|
342
|
-
}).then((response) => this.handleFetchResponse(response)).catch((error) => {
|
|
343
|
-
if (error.name === "AbortError" || this.abortController.signal.aborted) {
|
|
344
|
-
this.close();
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
this._onError(error);
|
|
348
|
-
this.scheduleReconnect({ error });
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
async handleFetchResponse(response) {
|
|
352
|
-
const { body, status } = response;
|
|
353
|
-
if (status === 204) {
|
|
354
|
-
this.disconnected();
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
if (status >= 400) {
|
|
358
|
-
this.scheduleReconnect({ status });
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
if (!body) throw new MissingResponseBodyError("The server response did not have a body");
|
|
362
|
-
this._readyState = ReadyState.OPEN;
|
|
363
|
-
this._onConnect();
|
|
364
|
-
this.reconnectAttempt = 0;
|
|
365
|
-
const parser = new EventSourceParser({
|
|
366
|
-
onEvent: (event) => {
|
|
367
|
-
if (typeof event.id === "string") this.lastEventId = event.id;
|
|
368
|
-
this._onMessage(event);
|
|
369
|
-
},
|
|
370
|
-
onComment: (comment) => this._onComment(comment),
|
|
371
|
-
onRetry: (retryDelay) => this.serverReconnectionTime = retryDelay
|
|
372
|
-
});
|
|
373
|
-
await this.readResponseStream(body, parser);
|
|
374
|
-
this.scheduleReconnect({
|
|
375
|
-
status,
|
|
376
|
-
error: new StreamClosedError("The server response stream was closed")
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
async readResponseStream(body, parser) {
|
|
380
|
-
const reader = body.getReader();
|
|
381
|
-
const decoder = new TextDecoder();
|
|
382
|
-
let done = false;
|
|
383
|
-
while (!done) {
|
|
384
|
-
const result = await reader.read();
|
|
385
|
-
if (result.value) parser.parse(decoder.decode(result.value, { stream: true }));
|
|
386
|
-
done = result.done;
|
|
387
|
-
}
|
|
388
|
-
parser.finish();
|
|
389
|
-
}
|
|
390
|
-
disconnected() {
|
|
391
|
-
clearTimeout(this.reconnectTimeout);
|
|
392
|
-
this._readyState = ReadyState.CLOSED;
|
|
393
|
-
this._onDisconnect();
|
|
394
|
-
}
|
|
395
|
-
buildRequestHeaders() {
|
|
396
|
-
const lastEventIdHeader = this.lastEventId ? { "Last-Event-ID": this.lastEventId } : void 0;
|
|
397
|
-
return {
|
|
398
|
-
...this.headers,
|
|
399
|
-
...lastEventIdHeader
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
scheduleReconnect(state) {
|
|
403
|
-
if (this.abortController.signal.aborted) return;
|
|
404
|
-
clearTimeout(this.reconnectTimeout);
|
|
405
|
-
this.reconnectAttempt += 1;
|
|
406
|
-
const reconnectionState = {
|
|
407
|
-
attempt: this.reconnectAttempt,
|
|
408
|
-
status: state.status,
|
|
409
|
-
error: state.error,
|
|
410
|
-
serverReconnectionTime: this.serverReconnectionTime
|
|
411
|
-
};
|
|
412
|
-
if (!this._shouldReconnect(reconnectionState)) {
|
|
413
|
-
this.disconnected();
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
this._readyState = ReadyState.CONNECTING;
|
|
417
|
-
let delay = this._calculateReconnectDelay(reconnectionState);
|
|
418
|
-
if (!Number.isFinite(delay) || delay < 1 || delay > 1e3 * 60 * 60) {
|
|
419
|
-
this._onError(new ValueOutOfRangeError(`The calculated reconnect delay is out of range: ${delay}. Defaulting to ${this.serverReconnectionTime}`));
|
|
420
|
-
delay = this.serverReconnectionTime;
|
|
421
|
-
}
|
|
422
|
-
this.reconnectTimeout = setTimeout(() => this.initiateConnection(), delay);
|
|
423
|
-
}
|
|
424
|
-
resolveCallback(provided, fallback, optionName) {
|
|
425
|
-
if (provided == null) return fallback;
|
|
426
|
-
if (typeof provided !== "function") throw new InvalidOptionError(`${optionName} must be a function`);
|
|
427
|
-
return provided;
|
|
428
|
-
}
|
|
429
|
-
};
|
|
430
|
-
//#endregion
|
|
431
|
-
//#region ../eventsource/src/index.ts
|
|
432
|
-
const createEventSourceClient = (options) => {
|
|
433
|
-
return new EventSourceClient(options);
|
|
434
|
-
};
|
|
435
|
-
//#endregion
|
|
436
|
-
//#region ../js-client-core/src/StreamingTransport.ts
|
|
437
|
-
var StreamingTransport = class {
|
|
438
|
-
constructor(options) {
|
|
439
|
-
this.options = options;
|
|
440
|
-
_defineProperty(this, "logger", void 0);
|
|
441
|
-
_defineProperty(this, "eventSource", void 0);
|
|
442
|
-
_defineProperty(this, "eventEmitter", new Emitter());
|
|
443
|
-
_defineProperty(this, "url", void 0);
|
|
444
|
-
_defineProperty(this, "timeoutTimer", void 0);
|
|
445
|
-
this.options = options;
|
|
446
|
-
this.logger = options.logger;
|
|
447
|
-
this.url = options.resolveUrl("client/sse/v1", options.baseUrl);
|
|
448
|
-
}
|
|
449
|
-
async connect(context, timeout) {
|
|
450
|
-
if (this.eventSource) this.close();
|
|
451
|
-
const eventSourcePromise = new Promise((resolve, reject) => {
|
|
452
|
-
this.eventSource = createEventSourceClient({
|
|
453
|
-
url: this.url,
|
|
454
|
-
method: "POST",
|
|
455
|
-
headers: { "Content-Type": "application/json" },
|
|
456
|
-
fetch: this.options.fetch,
|
|
457
|
-
body: JSON.stringify({
|
|
458
|
-
givenContext: context,
|
|
459
|
-
metaContext: this.options.metaContext,
|
|
460
|
-
clientSdkKey: this.options.clientSdkKey,
|
|
461
|
-
instanceId: this.options.instanceId
|
|
462
|
-
}),
|
|
463
|
-
onMessage: ({ data }) => {
|
|
464
|
-
this.dispatchMessage(data);
|
|
465
|
-
},
|
|
466
|
-
onConnect: () => {
|
|
467
|
-
this.logger.debug("[StreamingTransport] Connected");
|
|
468
|
-
resolve(this);
|
|
469
|
-
},
|
|
470
|
-
shouldReconnect: (state) => {
|
|
471
|
-
const reconnect = !this.isStatusFatal(state.status);
|
|
472
|
-
if (!reconnect) {
|
|
473
|
-
const error = this.prepareFatalError(state.status, state.error);
|
|
474
|
-
this.eventEmitter.emit("connectionError", error);
|
|
475
|
-
reject(error);
|
|
476
|
-
}
|
|
477
|
-
return reconnect;
|
|
478
|
-
},
|
|
479
|
-
calculateReconnectDelay: (state) => {
|
|
480
|
-
const delay = this.options.connectionRetryDelay(state.attempt);
|
|
481
|
-
const logMessage = `[StreamingTransport] Scheduling reconnect attempt #${state.attempt} in ${delay}ms.`;
|
|
482
|
-
if (state.attempt <= 5) this.logger.info(logMessage);
|
|
483
|
-
else this.logger.warn(logMessage);
|
|
484
|
-
return delay;
|
|
485
|
-
},
|
|
486
|
-
onError: (error) => {
|
|
487
|
-
this.logger.debug("[StreamingTransport] Error: ", error);
|
|
488
|
-
},
|
|
489
|
-
onDisconnect: () => {
|
|
490
|
-
this.logger.debug("[StreamingTransport] Disconnected");
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
this.eventSource.connect();
|
|
494
|
-
});
|
|
495
|
-
clearTimeout(this.timeoutTimer);
|
|
496
|
-
this.timeoutTimer = void 0;
|
|
497
|
-
return Promise.race([eventSourcePromise, new Promise((resolve) => {
|
|
498
|
-
this.timeoutTimer = setTimeout(() => resolve(this), timeout);
|
|
499
|
-
})]).finally(() => clearTimeout(this.timeoutTimer));
|
|
500
|
-
}
|
|
501
|
-
dispatchMessage(data) {
|
|
502
|
-
try {
|
|
503
|
-
const json = JSON.parse(data);
|
|
504
|
-
this.eventEmitter.emit("configSetReceived", json);
|
|
505
|
-
} catch (error) {
|
|
506
|
-
this.logger.error("[StreamingTransport] Error parsing and dispatching config data update: ", error);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
prepareFatalError(responseStatus, error) {
|
|
510
|
-
const status = responseStatus !== null && responseStatus !== void 0 ? responseStatus : 0;
|
|
511
|
-
return new ConfigDirectorConnectionError(`${`Connection failed with status: ${responseStatus !== null && responseStatus !== void 0 ? responseStatus : "unknown"}.`}${error ? ` Error: ${error}` : ""}. This is an unrecoverable error, will not attempt to reconnect.`, status);
|
|
512
|
-
}
|
|
513
|
-
isStatusFatal(status) {
|
|
514
|
-
return !!status && status >= 400 && status < 500 && status != 429;
|
|
515
|
-
}
|
|
516
|
-
on(name, handler) {
|
|
517
|
-
this.eventEmitter.on(name, handler);
|
|
518
|
-
}
|
|
519
|
-
off(name, handler) {
|
|
520
|
-
this.eventEmitter.off(name, handler);
|
|
521
|
-
}
|
|
522
|
-
clear() {
|
|
523
|
-
this.eventEmitter.clear();
|
|
524
|
-
}
|
|
525
|
-
close() {
|
|
526
|
-
var _this$eventSource;
|
|
527
|
-
(_this$eventSource = this.eventSource) === null || _this$eventSource === void 0 || _this$eventSource.close();
|
|
528
|
-
clearTimeout(this.timeoutTimer);
|
|
529
|
-
}
|
|
530
|
-
dispose() {
|
|
531
|
-
this.close();
|
|
532
|
-
this.clear();
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
//#endregion
|
|
536
|
-
//#region ../shared/src/value-parser.ts
|
|
537
|
-
const getRequestedType = (defaultValue) => {
|
|
538
|
-
const baseType = typeof defaultValue;
|
|
539
|
-
if (baseType === "object") try {
|
|
540
|
-
var _constructor$name, _constructor;
|
|
541
|
-
return (_constructor$name = (_constructor = defaultValue.constructor) === null || _constructor === void 0 ? void 0 : _constructor.name) !== null && _constructor$name !== void 0 ? _constructor$name : baseType;
|
|
542
|
-
} catch {
|
|
543
|
-
return baseType;
|
|
544
|
-
}
|
|
545
|
-
else if (baseType === "function") try {
|
|
546
|
-
const functionName = defaultValue.name;
|
|
547
|
-
return functionName ? `function: ${functionName}` : baseType;
|
|
548
|
-
} catch {
|
|
549
|
-
return baseType;
|
|
550
|
-
}
|
|
551
|
-
return baseType;
|
|
552
|
-
};
|
|
553
|
-
const isNumericNativeType = (requestedType) => {
|
|
554
|
-
return requestedType === "number" || requestedType === "bigint";
|
|
555
|
-
};
|
|
556
|
-
const configTypesNotReadableAsString = new Set([
|
|
557
|
-
"boolean",
|
|
558
|
-
"integer",
|
|
559
|
-
"float"
|
|
560
|
-
]);
|
|
561
|
-
const parseConfigValue = (configState, defaultValue) => {
|
|
562
|
-
const value = configState.value;
|
|
563
|
-
const requestedType = getRequestedType(defaultValue);
|
|
564
|
-
if (value == null) return {
|
|
565
|
-
parsedValue: defaultValue,
|
|
566
|
-
parsedValueId: void 0,
|
|
567
|
-
requestedType,
|
|
568
|
-
usedDefault: true,
|
|
569
|
-
reason: "value-missing"
|
|
570
|
-
};
|
|
571
|
-
if (configState.type === "json") return parseJson(value, defaultValue, requestedType, configState.valueId);
|
|
572
|
-
if (typeof defaultValue === "string") {
|
|
573
|
-
if (configTypesNotReadableAsString.has(configState.type)) return {
|
|
574
|
-
parsedValue: defaultValue,
|
|
575
|
-
parsedValueId: void 0,
|
|
576
|
-
requestedType,
|
|
577
|
-
usedDefault: true,
|
|
578
|
-
reason: "type-mismatch"
|
|
579
|
-
};
|
|
580
|
-
return {
|
|
581
|
-
parsedValue: value,
|
|
582
|
-
parsedValueId: configState.valueId,
|
|
583
|
-
requestedType,
|
|
584
|
-
usedDefault: false,
|
|
585
|
-
reason: "found-match"
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
if (typeof defaultValue === "boolean" && (configState.type === "boolean" || configState.type === "string" || configState.type === "enum")) {
|
|
589
|
-
const boolValue = parseConfigBoolean(value);
|
|
590
|
-
const hasBoolean = typeof boolValue === "boolean";
|
|
591
|
-
return {
|
|
592
|
-
parsedValue: hasBoolean ? boolValue : defaultValue,
|
|
593
|
-
parsedValueId: hasBoolean ? configState.valueId : void 0,
|
|
594
|
-
requestedType,
|
|
595
|
-
usedDefault: !hasBoolean,
|
|
596
|
-
reason: hasBoolean ? "found-match" : "invalid-boolean"
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
if (isNumericNativeType(typeof defaultValue) && configState.type === "integer") {
|
|
600
|
-
const numValue = parseConfigInteger(value);
|
|
601
|
-
const hasNumber = typeof numValue === "number";
|
|
602
|
-
return {
|
|
603
|
-
parsedValue: hasNumber ? numValue : defaultValue,
|
|
604
|
-
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
605
|
-
requestedType,
|
|
606
|
-
usedDefault: !hasNumber,
|
|
607
|
-
reason: hasNumber ? "found-match" : "invalid-number"
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
|
-
if (isNumericNativeType(typeof defaultValue) && (configState.type === "float" || configState.type === "enum" || configState.type === "string")) {
|
|
611
|
-
const numValue = parseConfigFloat(value);
|
|
612
|
-
const hasNumber = typeof numValue === "number";
|
|
613
|
-
return {
|
|
614
|
-
parsedValue: hasNumber ? numValue : defaultValue,
|
|
615
|
-
parsedValueId: hasNumber ? configState.valueId : void 0,
|
|
616
|
-
requestedType,
|
|
617
|
-
usedDefault: !hasNumber,
|
|
618
|
-
reason: hasNumber ? "found-match" : "invalid-number"
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
return {
|
|
622
|
-
parsedValue: defaultValue,
|
|
623
|
-
parsedValueId: void 0,
|
|
624
|
-
requestedType,
|
|
625
|
-
usedDefault: true,
|
|
626
|
-
reason: "type-mismatch"
|
|
627
|
-
};
|
|
628
|
-
};
|
|
629
|
-
const parseConfigBoolean = (value) => {
|
|
630
|
-
if (!value) return;
|
|
631
|
-
const lowerValue = value.toLowerCase();
|
|
632
|
-
if (lowerValue != "true" && lowerValue != "false") return;
|
|
633
|
-
return lowerValue === "true";
|
|
634
|
-
};
|
|
635
|
-
const parseConfigInteger = (value) => {
|
|
636
|
-
const num = parseStrictNumber(value);
|
|
637
|
-
return num == null ? void 0 : Math.trunc(num);
|
|
638
|
-
};
|
|
639
|
-
const parseConfigFloat = (value) => {
|
|
640
|
-
return parseStrictNumber(value);
|
|
641
|
-
};
|
|
642
|
-
const parseStrictNumber = (value) => {
|
|
643
|
-
if (!value || !isDecimalCharacters(value)) return;
|
|
644
|
-
const num = Number(value);
|
|
645
|
-
if (isNaN(num) || !isFinite(num)) return;
|
|
646
|
-
return num;
|
|
647
|
-
};
|
|
648
|
-
const isDecimalCharacters = (value) => {
|
|
649
|
-
for (const character of value) if (!(character >= "0" && character <= "9") && !"+-.eE".includes(character)) return false;
|
|
650
|
-
return true;
|
|
651
|
-
};
|
|
652
|
-
const parseJson = (jsonString, defaultValue, requestedType, valueId) => {
|
|
653
|
-
if (typeof defaultValue === "string") return {
|
|
654
|
-
parsedValue: jsonString,
|
|
655
|
-
parsedValueId: valueId,
|
|
656
|
-
requestedType,
|
|
657
|
-
usedDefault: false,
|
|
658
|
-
reason: "found-match"
|
|
659
|
-
};
|
|
660
|
-
try {
|
|
661
|
-
const parsed = JSON.parse(jsonString);
|
|
662
|
-
if (!isJsonTypeCompatible(parsed, defaultValue)) return {
|
|
663
|
-
parsedValue: defaultValue,
|
|
664
|
-
parsedValueId: void 0,
|
|
665
|
-
requestedType,
|
|
666
|
-
usedDefault: true,
|
|
667
|
-
reason: "type-mismatch"
|
|
668
|
-
};
|
|
669
|
-
return {
|
|
670
|
-
parsedValue: parsed,
|
|
671
|
-
parsedValueId: valueId,
|
|
672
|
-
requestedType,
|
|
673
|
-
usedDefault: false,
|
|
674
|
-
reason: "found-match"
|
|
675
|
-
};
|
|
676
|
-
} catch {
|
|
677
|
-
return {
|
|
678
|
-
parsedValue: defaultValue,
|
|
679
|
-
parsedValueId: void 0,
|
|
680
|
-
requestedType,
|
|
681
|
-
usedDefault: true,
|
|
682
|
-
reason: "invalid-json"
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
};
|
|
686
|
-
const isJsonTypeCompatible = (parsed, defaultValue) => {
|
|
687
|
-
if (parsed === null) return false;
|
|
688
|
-
const defaultType = typeof defaultValue;
|
|
689
|
-
if (defaultType === "bigint") return typeof parsed === "number";
|
|
690
|
-
return typeof parsed === defaultType;
|
|
691
|
-
};
|
|
692
|
-
//#endregion
|
|
693
|
-
//#region ../shared/src/logger.ts
|
|
694
|
-
const LEVELS = {
|
|
695
|
-
off: -1,
|
|
696
|
-
error: 0,
|
|
697
|
-
warn: 1,
|
|
698
|
-
info: 2,
|
|
699
|
-
debug: 3
|
|
700
|
-
};
|
|
701
|
-
const buildDateFormatter = () => {
|
|
702
|
-
const baseOptions = {
|
|
703
|
-
year: "numeric",
|
|
704
|
-
month: "2-digit",
|
|
705
|
-
day: "2-digit",
|
|
706
|
-
hour: "2-digit",
|
|
707
|
-
minute: "2-digit",
|
|
708
|
-
second: "2-digit",
|
|
709
|
-
timeZoneName: "short"
|
|
710
|
-
};
|
|
711
|
-
try {
|
|
712
|
-
return new Intl.DateTimeFormat(void 0, {
|
|
713
|
-
...baseOptions,
|
|
714
|
-
fractionalSecondDigits: 3
|
|
715
|
-
});
|
|
716
|
-
} catch {
|
|
717
|
-
return new Intl.DateTimeFormat(void 0, baseOptions);
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
var DefaultConsoleLogger = class {
|
|
721
|
-
constructor(level, decorator) {
|
|
722
|
-
this.level = level;
|
|
723
|
-
this.decorator = decorator;
|
|
724
|
-
_defineProperty(this, "dateFormatter", void 0);
|
|
725
|
-
this.level = level;
|
|
726
|
-
this.decorator = decorator;
|
|
727
|
-
this.dateFormatter = buildDateFormatter();
|
|
728
|
-
}
|
|
729
|
-
debug(message, ...args) {
|
|
730
|
-
this.log(console.debug, "debug", message, ...args);
|
|
731
|
-
}
|
|
732
|
-
info(message, ...args) {
|
|
733
|
-
this.log(console.info, "info", message, ...args);
|
|
734
|
-
}
|
|
735
|
-
warn(message, ...args) {
|
|
736
|
-
this.log(console.warn, "warn", message, ...args);
|
|
737
|
-
}
|
|
738
|
-
error(message, ...args) {
|
|
739
|
-
this.log(console.error, "error", message, ...args);
|
|
740
|
-
}
|
|
741
|
-
log(loggerFunction, level, message, ...args) {
|
|
742
|
-
if (LEVELS[this.level] >= LEVELS[level]) {
|
|
743
|
-
var _this$decorator;
|
|
744
|
-
loggerFunction(`[${this.dateFormatter.format(/* @__PURE__ */ new Date())}] ${(_this$decorator = this.decorator) === null || _this$decorator === void 0 ? void 0 : _this$decorator.decorateMessage(message)}`, ...args);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
};
|
|
748
|
-
//#endregion
|
|
749
|
-
//#region ../js-client-core/src/logger.ts
|
|
750
|
-
var LogMessageDecorator = class {
|
|
751
|
-
decorateMessage(message) {
|
|
752
|
-
return `[ConfigDirector:js-client-sdk] ${message}`;
|
|
753
|
-
}
|
|
754
|
-
};
|
|
755
|
-
const createDefaultLogger = (level, messageDecorator) => {
|
|
756
|
-
return new DefaultConsoleLogger(level !== null && level !== void 0 ? level : "warn", messageDecorator !== null && messageDecorator !== void 0 ? messageDecorator : new LogMessageDecorator());
|
|
757
|
-
};
|
|
758
|
-
//#endregion
|
|
759
|
-
//#region ../shared/src/url.ts
|
|
760
|
-
const defaultUrlFactory = (input, base) => new URL(input, base === null || base === void 0 ? void 0 : base.toString());
|
|
761
|
-
//#endregion
|
|
762
|
-
//#region ../shared/src/constants.ts
|
|
763
|
-
const CLIENT_BASE_URL = "https://client-sdk-api.configdirector.com";
|
|
764
|
-
//#endregion
|
|
765
|
-
//#region ../shared/src/instance-id.ts
|
|
766
|
-
const generateInstanceId = () => {
|
|
767
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
768
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (placeholder) => {
|
|
769
|
-
const random = Math.random() * 16 | 0;
|
|
770
|
-
return (placeholder === "x" ? random : random & 3 | 8).toString(16);
|
|
771
|
-
});
|
|
772
|
-
};
|
|
773
|
-
//#endregion
|
|
774
|
-
//#region ../js-client-core/src/instance-id.ts
|
|
775
|
-
const STORAGE_KEY = "configdirector-sdk:instance-id";
|
|
776
|
-
const RECORD_VERSION = 1;
|
|
777
|
-
const MAX_AGE_MS = 360 * 60 * 1e3;
|
|
778
|
-
const CHECKSUM_SALT = "configdirector.instanceId.v1";
|
|
779
|
-
const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
780
|
-
const fnv1a = (input, offsetBasis) => {
|
|
781
|
-
let hash = offsetBasis;
|
|
782
|
-
for (let i = 0; i < input.length; i++) {
|
|
783
|
-
hash ^= input.charCodeAt(i);
|
|
784
|
-
hash = Math.imul(hash, 16777619);
|
|
785
|
-
}
|
|
786
|
-
return hash >>> 0;
|
|
787
|
-
};
|
|
788
|
-
const checksumFor = (id, createdAt) => {
|
|
789
|
-
const payload = `${CHECKSUM_SALT}|${id}|${createdAt}`;
|
|
790
|
-
const low = fnv1a(payload, 2166136261);
|
|
791
|
-
return fnv1a(`${low}|${payload}`, 16777619).toString(16).padStart(8, "0") + low.toString(16).padStart(8, "0");
|
|
792
|
-
};
|
|
793
|
-
const getLocalStorage = () => {
|
|
794
|
-
try {
|
|
795
|
-
var _localStorage;
|
|
796
|
-
return (_localStorage = globalThis.localStorage) !== null && _localStorage !== void 0 ? _localStorage : void 0;
|
|
797
|
-
} catch {
|
|
798
|
-
return;
|
|
799
|
-
}
|
|
800
|
-
};
|
|
801
|
-
const isUsableRecord = (record) => {
|
|
802
|
-
if (!record || typeof record !== "object") return false;
|
|
803
|
-
const { v, id, createdAt, checksum } = record;
|
|
804
|
-
if (v !== RECORD_VERSION || typeof id !== "string" || typeof checksum !== "string") return false;
|
|
805
|
-
if (typeof createdAt !== "number" || !Number.isInteger(createdAt) || createdAt <= 0) return false;
|
|
806
|
-
if (!UUID_V4_PATTERN.test(id)) return false;
|
|
807
|
-
return checksum === checksumFor(id, createdAt);
|
|
808
|
-
};
|
|
809
|
-
const readStoredInstanceId = (storage, logger) => {
|
|
810
|
-
let raw;
|
|
811
|
-
try {
|
|
812
|
-
raw = storage.getItem(STORAGE_KEY);
|
|
813
|
-
} catch (error) {
|
|
814
|
-
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] Could not read the stored instance id, generating a new one", error);
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
if (!raw) return;
|
|
818
|
-
let record;
|
|
819
|
-
try {
|
|
820
|
-
record = JSON.parse(raw);
|
|
821
|
-
} catch {
|
|
822
|
-
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one");
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
if (!isUsableRecord(record)) {
|
|
826
|
-
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] The stored instance id failed validation, generating a new one");
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
const age = Date.now() - record.createdAt;
|
|
830
|
-
if (age < 0 || age >= MAX_AGE_MS) {
|
|
831
|
-
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] The stored instance id has expired, generating a new one");
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
return record.id;
|
|
835
|
-
};
|
|
836
|
-
const storeInstanceId = (storage, id, logger) => {
|
|
837
|
-
const createdAt = Date.now();
|
|
838
|
-
const record = {
|
|
839
|
-
v: RECORD_VERSION,
|
|
840
|
-
id,
|
|
841
|
-
createdAt,
|
|
842
|
-
checksum: checksumFor(id, createdAt)
|
|
843
|
-
};
|
|
844
|
-
try {
|
|
845
|
-
storage.setItem(STORAGE_KEY, JSON.stringify(record));
|
|
846
|
-
} catch (error) {
|
|
847
|
-
logger === null || logger === void 0 || logger.debug("[ConfigDirectorClient] Could not persist the instance id", error);
|
|
848
|
-
}
|
|
849
|
-
};
|
|
850
|
-
const resolveInstanceId = (logger) => {
|
|
851
|
-
const storage = getLocalStorage();
|
|
852
|
-
if (!storage) return generateInstanceId();
|
|
853
|
-
const storedInstanceId = readStoredInstanceId(storage, logger);
|
|
854
|
-
if (storedInstanceId) return storedInstanceId;
|
|
855
|
-
const instanceId = generateInstanceId();
|
|
856
|
-
storeInstanceId(storage, instanceId, logger);
|
|
857
|
-
return instanceId;
|
|
858
|
-
};
|
|
859
|
-
//#endregion
|
|
860
|
-
//#region ../shared/src/transport/AbstractPollingTransport.ts
|
|
861
|
-
var AbstractPollingTransport = class {
|
|
862
|
-
constructor() {
|
|
863
|
-
_defineProperty(this, "fatalError", false);
|
|
864
|
-
_defineProperty(this, "pollingInterval", void 0);
|
|
865
|
-
_defineProperty(this, "pollingIntervalSeconds", 60);
|
|
866
|
-
}
|
|
867
|
-
clearPollingInterval() {
|
|
868
|
-
clearInterval(this.pollingInterval);
|
|
869
|
-
}
|
|
870
|
-
schedulePollingInterval(callback) {
|
|
871
|
-
clearInterval(this.pollingInterval);
|
|
872
|
-
if (this.pollingIntervalSeconds <= 0) return;
|
|
873
|
-
this.pollingInterval = setInterval(callback, this.pollingIntervalSeconds * 1e3);
|
|
874
|
-
}
|
|
875
|
-
async handleNonOkResponse(response) {
|
|
876
|
-
if (!response.ok) if (this.isStatusFatal(response.status)) {
|
|
877
|
-
this.fatalError = true;
|
|
878
|
-
this.close();
|
|
879
|
-
throw this.prepareFatalResponseStatusError(response.status, await response.text());
|
|
880
|
-
} else throw new ConfigDirectorConnectionError(`Connection failed with status: ${response.status}`, response.status);
|
|
881
|
-
}
|
|
882
|
-
handleFetchError(fetchError) {
|
|
883
|
-
if (this.isFetchErrorFatal(fetchError)) {
|
|
884
|
-
this.fatalError = true;
|
|
885
|
-
this.close();
|
|
886
|
-
throw new ConfigDirectorConnectionError(`Connection failed with fatal error: ${fetchError}. This is an unrecoverable error, retry attempts will be ignored.`);
|
|
887
|
-
} else if (fetchError instanceof SyntaxError) throw new ConfigDirectorConnectionError(`Failed to parse the response from the server: ${fetchError}`);
|
|
888
|
-
else throw new ConfigDirectorConnectionError(`Connection failed with error: ${fetchError}.`);
|
|
889
|
-
}
|
|
890
|
-
prepareFatalResponseStatusError(responseStatus, errorBody) {
|
|
891
|
-
var _errorBody$trim$lengt, _errorBody$trim;
|
|
892
|
-
const status = responseStatus !== null && responseStatus !== void 0 ? responseStatus : 0;
|
|
893
|
-
return new ConfigDirectorConnectionError(`${`Connection failed with status: ${responseStatus !== null && responseStatus !== void 0 ? responseStatus : "unknown"}`}${((_errorBody$trim$lengt = errorBody === null || errorBody === void 0 || (_errorBody$trim = errorBody.trim()) === null || _errorBody$trim === void 0 ? void 0 : _errorBody$trim.length) !== null && _errorBody$trim$lengt !== void 0 ? _errorBody$trim$lengt : 0) > 0 ? ` (${errorBody})` : ""}. This is an unrecoverable error, retry attempts will be ignored.`, status);
|
|
894
|
-
}
|
|
895
|
-
isStatusFatal(status) {
|
|
896
|
-
return !!status && status >= 400 && status < 500 && status != 429;
|
|
897
|
-
}
|
|
898
|
-
isFetchErrorFatal(fetchError) {
|
|
899
|
-
return (fetchError === null || fetchError === void 0 ? void 0 : fetchError.name) === "NotAllowedError";
|
|
900
|
-
}
|
|
901
|
-
get isConnected() {
|
|
902
|
-
return this.pollingInterval !== void 0;
|
|
903
|
-
}
|
|
904
|
-
close() {
|
|
905
|
-
clearInterval(this.pollingInterval);
|
|
906
|
-
this.pollingInterval = void 0;
|
|
907
|
-
}
|
|
908
|
-
dispose() {
|
|
909
|
-
this.close();
|
|
910
|
-
this.clear();
|
|
911
|
-
}
|
|
912
|
-
};
|
|
913
|
-
//#endregion
|
|
914
|
-
//#region ../shared/src/fetchWithTimeout.ts
|
|
915
|
-
const fetchWithTimeout = async (timeout, resource, options, logger) => {
|
|
916
|
-
const abortController = new AbortController();
|
|
917
|
-
const abortTimeoutId = setTimeout(() => {
|
|
918
|
-
logger.debug("[fetchWithTimeout] Reached timeout, aborting request");
|
|
919
|
-
abortController.abort();
|
|
920
|
-
}, timeout);
|
|
921
|
-
try {
|
|
922
|
-
const response = await fetch(typeof resource === "string" || resource instanceof Request ? resource : resource.toString(), {
|
|
923
|
-
...options,
|
|
924
|
-
signal: abortController.signal
|
|
925
|
-
});
|
|
926
|
-
clearTimeout(abortTimeoutId);
|
|
927
|
-
return response;
|
|
928
|
-
} catch (error) {
|
|
929
|
-
logger.warn("[fetchWithTimeout] Fetch error: ", error);
|
|
930
|
-
clearTimeout(abortTimeoutId);
|
|
931
|
-
throw error;
|
|
932
|
-
}
|
|
933
|
-
};
|
|
934
|
-
//#endregion
|
|
935
|
-
//#region ../js-client-core/src/PollingTransport.ts
|
|
936
|
-
var PollingTransport = class extends AbstractPollingTransport {
|
|
937
|
-
constructor(options) {
|
|
938
|
-
var _options$pollingInter;
|
|
939
|
-
super();
|
|
940
|
-
this.options = options;
|
|
941
|
-
_defineProperty(this, "logger", void 0);
|
|
942
|
-
_defineProperty(this, "eventEmitter", new Emitter());
|
|
943
|
-
_defineProperty(this, "url", void 0);
|
|
944
|
-
_defineProperty(this, "lastUpdateTimestamp", void 0);
|
|
945
|
-
this.options = options;
|
|
946
|
-
this.logger = options.logger;
|
|
947
|
-
this.url = options.resolveUrl("client/polling/v1", options.baseUrl);
|
|
948
|
-
const requestedInterval = (_options$pollingInter = options.pollingInterval) !== null && _options$pollingInter !== void 0 ? _options$pollingInter : 300;
|
|
949
|
-
if (requestedInterval < 60) this.logger.warn(`[PollingTransport] pollingInterval of ${requestedInterval} seconds is below the minimum of 60 seconds. Using 60 seconds.`);
|
|
950
|
-
this.pollingIntervalSeconds = Math.max(requestedInterval, 60);
|
|
951
|
-
}
|
|
952
|
-
async connect(context, timeout) {
|
|
953
|
-
this.clearPollingInterval();
|
|
954
|
-
try {
|
|
955
|
-
await this.fetchConfigs(context, timeout);
|
|
956
|
-
} finally {
|
|
957
|
-
if (!this.fatalError) this.schedulePollingInterval(() => {
|
|
958
|
-
this.fetchConfigs(context, timeout).catch((error) => {
|
|
959
|
-
this.logger.error("[PollingTransport] Error during polling:", error);
|
|
960
|
-
});
|
|
961
|
-
});
|
|
962
|
-
}
|
|
963
|
-
return this;
|
|
964
|
-
}
|
|
965
|
-
async fetchConfigs(context, timeout) {
|
|
966
|
-
if (this.fatalError) {
|
|
967
|
-
this.logger.warn("[PollingTransport] There was a prior unrecoverable error. Ignoring attempt to reconnect.");
|
|
968
|
-
return;
|
|
969
|
-
}
|
|
970
|
-
try {
|
|
971
|
-
const response = await fetchWithTimeout(timeout, this.url, {
|
|
972
|
-
method: "POST",
|
|
973
|
-
headers: { "Content-Type": "application/json" },
|
|
974
|
-
body: JSON.stringify({
|
|
975
|
-
givenContext: context,
|
|
976
|
-
metaContext: this.options.metaContext,
|
|
977
|
-
clientSdkKey: this.options.clientSdkKey,
|
|
978
|
-
instanceId: this.options.instanceId,
|
|
979
|
-
lastUpdateTimestamp: this.lastUpdateTimestamp
|
|
980
|
-
})
|
|
981
|
-
}, this.logger);
|
|
982
|
-
await this.handleNonOkResponse(response);
|
|
983
|
-
if (response.status == 200) {
|
|
984
|
-
const json = JSON.parse(await response.text());
|
|
985
|
-
this.lastUpdateTimestamp = json.timestamp;
|
|
986
|
-
this.eventEmitter.emit("configSetReceived", json);
|
|
987
|
-
}
|
|
988
|
-
} catch (fetchError) {
|
|
989
|
-
try {
|
|
990
|
-
this.handleFetchError(fetchError);
|
|
991
|
-
} catch (handledError) {
|
|
992
|
-
if (this.fatalError) this.eventEmitter.emit("connectionError", handledError);
|
|
993
|
-
throw handledError;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
on(name, handler) {
|
|
998
|
-
this.eventEmitter.on(name, handler);
|
|
999
|
-
}
|
|
1000
|
-
off(name, handler) {
|
|
1001
|
-
this.eventEmitter.off(name, handler);
|
|
1002
|
-
}
|
|
1003
|
-
clear() {
|
|
1004
|
-
this.eventEmitter.clear();
|
|
1005
|
-
}
|
|
1006
|
-
};
|
|
1007
|
-
//#endregion
|
|
1008
|
-
//#region ../js-client-core/src/browser-globals.ts
|
|
1009
|
-
const read = (readValue) => {
|
|
1010
|
-
try {
|
|
1011
|
-
return readValue(globalThis);
|
|
1012
|
-
} catch {
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
};
|
|
1016
|
-
const readUserAgent = () => read((globals) => {
|
|
1017
|
-
var _globals$navigator;
|
|
1018
|
-
return (_globals$navigator = globals.navigator) === null || _globals$navigator === void 0 ? void 0 : _globals$navigator.userAgent;
|
|
1019
|
-
});
|
|
1020
|
-
const readHost = () => read((globals) => {
|
|
1021
|
-
var _globals$location;
|
|
1022
|
-
return (_globals$location = globals.location) === null || _globals$location === void 0 ? void 0 : _globals$location.host;
|
|
1023
|
-
});
|
|
1024
|
-
//#endregion
|
|
1025
|
-
//#region ../js-client-core/src/DefaultConfigDirectorClient.ts
|
|
1026
|
-
const MAX_EXPONENTIAL_DELAY = 9;
|
|
1027
|
-
var DefaultConfigDirectorClient = class {
|
|
1028
|
-
constructor(telemetryClient, clientSdkKey, sdkOptions, clientOptions, internalClientOptions) {
|
|
1029
|
-
var _clientOptions$logger, _clientOptions$connec, _clientOptions$connec2, _internalClientOption, _this$parseUrl, _clientOptions$connec3, _clientOptions$connec4, _clientOptions$connec5, _internalClientOption2, _clientOptions$connec6, _clientOptions$hooks, _clientOptions$hooks2, _clientOptions$hooks3, _clientOptions$hooks4, _clientOptions$hooks5;
|
|
1030
|
-
_defineProperty(this, "logger", void 0);
|
|
1031
|
-
_defineProperty(this, "telemetryClient", void 0);
|
|
1032
|
-
_defineProperty(this, "configSet", void 0);
|
|
1033
|
-
_defineProperty(this, "handlersMap", /* @__PURE__ */ new Map());
|
|
1034
|
-
_defineProperty(this, "transport", void 0);
|
|
1035
|
-
_defineProperty(this, "eventEmitter", new Emitter());
|
|
1036
|
-
_defineProperty(this, "timeout", void 0);
|
|
1037
|
-
_defineProperty(this, "timeoutTimer", void 0);
|
|
1038
|
-
_defineProperty(this, "ready", false);
|
|
1039
|
-
_defineProperty(this, "initializing", false);
|
|
1040
|
-
_defineProperty(this, "readyPromise", void 0);
|
|
1041
|
-
_defineProperty(this, "readyResolve", void 0);
|
|
1042
|
-
_defineProperty(this, "currentContext", void 0);
|
|
1043
|
-
_defineProperty(this, "connectionMode", void 0);
|
|
1044
|
-
_defineProperty(this, "instanceId", void 0);
|
|
1045
|
-
this.logger = (_clientOptions$logger = clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.logger) !== null && _clientOptions$logger !== void 0 ? _clientOptions$logger : createDefaultLogger();
|
|
1046
|
-
this.instanceId = resolveInstanceId(this.logger);
|
|
1047
|
-
this.timeout = (_clientOptions$connec = clientOptions === null || clientOptions === void 0 || (_clientOptions$connec2 = clientOptions.connection) === null || _clientOptions$connec2 === void 0 ? void 0 : _clientOptions$connec2.timeout) !== null && _clientOptions$connec !== void 0 ? _clientOptions$connec : 3e3;
|
|
1048
|
-
this.validateSdkKeyPresence(clientSdkKey);
|
|
1049
|
-
const urlFactory = (_internalClientOption = internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.urlFactory) !== null && _internalClientOption !== void 0 ? _internalClientOption : defaultUrlFactory;
|
|
1050
|
-
const baseUrl = (_this$parseUrl = this.parseUrl(clientOptions === null || clientOptions === void 0 || (_clientOptions$connec3 = clientOptions.connection) === null || _clientOptions$connec3 === void 0 ? void 0 : _clientOptions$connec3.url, urlFactory)) !== null && _this$parseUrl !== void 0 ? _this$parseUrl : CLIENT_BASE_URL;
|
|
1051
|
-
this.connectionMode = (_clientOptions$connec4 = clientOptions === null || clientOptions === void 0 || (_clientOptions$connec5 = clientOptions.connection) === null || _clientOptions$connec5 === void 0 ? void 0 : _clientOptions$connec5.mode) !== null && _clientOptions$connec4 !== void 0 ? _clientOptions$connec4 : "streaming";
|
|
1052
|
-
const transportConstructor = this.getTransportConstructor(this.connectionMode);
|
|
1053
|
-
this.telemetryClient = telemetryClient;
|
|
1054
|
-
this.transport = new transportConstructor({
|
|
1055
|
-
instanceId: this.instanceId,
|
|
1056
|
-
clientSdkKey,
|
|
1057
|
-
baseUrl,
|
|
1058
|
-
resolveUrl: urlFactory,
|
|
1059
|
-
metaContext: {
|
|
1060
|
-
...clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.metadata,
|
|
1061
|
-
sdkName: sdkOptions.sdkName,
|
|
1062
|
-
sdkVersion: sdkOptions.sdkVersion,
|
|
1063
|
-
userAgent: readUserAgent(),
|
|
1064
|
-
host: readHost()
|
|
1065
|
-
},
|
|
1066
|
-
logger: this.logger,
|
|
1067
|
-
fetch: internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.fetch,
|
|
1068
|
-
connectionRetryDelay: (_internalClientOption2 = internalClientOptions === null || internalClientOptions === void 0 ? void 0 : internalClientOptions.connectionRetryDelay) !== null && _internalClientOption2 !== void 0 ? _internalClientOption2 : ((attempt) => {
|
|
1069
|
-
return Math.pow(2, Math.min(attempt, MAX_EXPONENTIAL_DELAY)) * 1e3;
|
|
1070
|
-
}),
|
|
1071
|
-
pollingInterval: clientOptions === null || clientOptions === void 0 || (_clientOptions$connec6 = clientOptions.connection) === null || _clientOptions$connec6 === void 0 ? void 0 : _clientOptions$connec6.pollingInterval
|
|
1072
|
-
});
|
|
1073
|
-
this.transport.on("configSetReceived", (configSet) => {
|
|
1074
|
-
var _this$readyResolve;
|
|
1075
|
-
(_this$readyResolve = this.readyResolve) === null || _this$readyResolve === void 0 || _this$readyResolve.call(this);
|
|
1076
|
-
const configKeys = Object.keys(configSet.configs);
|
|
1077
|
-
if (!this.configSet || configSet.kind == "full") {
|
|
1078
|
-
this.configSet = configSet;
|
|
1079
|
-
this.emit("configsUpdated", { keys: configKeys });
|
|
1080
|
-
this.updateWatchers(configSet.configs);
|
|
1081
|
-
} else {
|
|
1082
|
-
this.configSet.configs = {
|
|
1083
|
-
...this.configSet.configs,
|
|
1084
|
-
...configSet.configs
|
|
1085
|
-
};
|
|
1086
|
-
this.emit("configsUpdated", { keys: configKeys });
|
|
1087
|
-
this.updateWatchers(configSet.configs);
|
|
1088
|
-
}
|
|
1089
|
-
this.logger.debug("[ConfigDirectorClient] ConfigSet updated from server:", { keys: configKeys });
|
|
1090
|
-
});
|
|
1091
|
-
this.transport.on("connectionError", (error) => {
|
|
1092
|
-
this.logger.error("[ConfigDirectorClient] The connection encountered an unrecoverable error and will not be retried. Configs will no longer receive updates.", error);
|
|
1093
|
-
this.emit("connectionError", { error });
|
|
1094
|
-
});
|
|
1095
|
-
this.registerHandler("clientReady", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks = clientOptions.hooks) === null || _clientOptions$hooks === void 0 ? void 0 : _clientOptions$hooks.clientReady);
|
|
1096
|
-
this.registerHandler("configEvaluated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks2 = clientOptions.hooks) === null || _clientOptions$hooks2 === void 0 ? void 0 : _clientOptions$hooks2.configEvaluated);
|
|
1097
|
-
this.registerHandler("configsUpdated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks3 = clientOptions.hooks) === null || _clientOptions$hooks3 === void 0 ? void 0 : _clientOptions$hooks3.configsUpdated);
|
|
1098
|
-
this.registerHandler("contextUpdated", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks4 = clientOptions.hooks) === null || _clientOptions$hooks4 === void 0 ? void 0 : _clientOptions$hooks4.contextUpdated);
|
|
1099
|
-
this.registerHandler("connectionError", clientOptions === null || clientOptions === void 0 || (_clientOptions$hooks5 = clientOptions.hooks) === null || _clientOptions$hooks5 === void 0 ? void 0 : _clientOptions$hooks5.connectionError);
|
|
1100
|
-
}
|
|
1101
|
-
registerHandler(event, handler) {
|
|
1102
|
-
if (!handler) return;
|
|
1103
|
-
const handlers = Array.isArray(handler) ? handler : [handler];
|
|
1104
|
-
for (const h of handlers) if (typeof h === "function") this.on(event, h);
|
|
1105
|
-
}
|
|
1106
|
-
getTransportConstructor(connectionMode) {
|
|
1107
|
-
switch (connectionMode) {
|
|
1108
|
-
case "polling": return PollingTransport;
|
|
1109
|
-
default: return StreamingTransport;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
async initialize(context) {
|
|
1113
|
-
this.initializing = true;
|
|
1114
|
-
await this.connectToTransport(context, "initialization");
|
|
1115
|
-
}
|
|
1116
|
-
async updateContext(context) {
|
|
1117
|
-
await this.connectToTransport(context, "context update");
|
|
1118
|
-
}
|
|
1119
|
-
get context() {
|
|
1120
|
-
return this.currentContext;
|
|
1121
|
-
}
|
|
1122
|
-
async connectToTransport(context, caller) {
|
|
1123
|
-
try {
|
|
1124
|
-
this.ready = false;
|
|
1125
|
-
this.readyPromise = new Promise((resolve) => {
|
|
1126
|
-
this.readyResolve = resolve;
|
|
1127
|
-
}).then((cancelled) => {
|
|
1128
|
-
if (cancelled) return;
|
|
1129
|
-
this.ready = true;
|
|
1130
|
-
this.initializing = false;
|
|
1131
|
-
this.emit("clientReady", { action: caller });
|
|
1132
|
-
this.logger.debug("[ConfigDirectorClient] Received initial payload from the server, client is ready");
|
|
1133
|
-
});
|
|
1134
|
-
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
1135
|
-
await this.transport.connect(context !== null && context !== void 0 ? context : {}, this.timeout);
|
|
1136
|
-
this.currentContext = context;
|
|
1137
|
-
this.telemetryClient.updateContext(context);
|
|
1138
|
-
this.emit("contextUpdated", { context });
|
|
1139
|
-
const elapsedTime = (/* @__PURE__ */ new Date()).getTime() - startTime;
|
|
1140
|
-
const remainingTimeout = this.timeout - elapsedTime;
|
|
1141
|
-
clearTimeout(this.timeoutTimer);
|
|
1142
|
-
this.timeoutTimer = void 0;
|
|
1143
|
-
if (remainingTimeout > 0) await Promise.race([this.readyPromise, new Promise((resolve) => {
|
|
1144
|
-
this.timeoutTimer = setTimeout(() => resolve(), remainingTimeout);
|
|
1145
|
-
})]).finally(() => clearTimeout(this.timeoutTimer));
|
|
1146
|
-
if (!this.ready) this.logger.warn(`[ConfigDirectorClient] Timed out waiting for ${caller} after ${this.timeout}ms. The client will continue to retry since there were no fatal errors detected. Configs will return the default value until the connection succeeds.`);
|
|
1147
|
-
} catch (error) {
|
|
1148
|
-
this.logger.error(`[ConfigDirectorClient] An error occurred during ${caller}: `, error);
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
updateWatchers(configsMap) {
|
|
1152
|
-
Object.values(configsMap).forEach((v) => this.updateWatchersForConfig(v));
|
|
1153
|
-
}
|
|
1154
|
-
updateWatchersForConfig(configState) {
|
|
1155
|
-
var _this$handlersMap$get;
|
|
1156
|
-
(_this$handlersMap$get = this.handlersMap.get(configState.key)) === null || _this$handlersMap$get === void 0 || _this$handlersMap$get.forEach((h) => {
|
|
1157
|
-
const value = this.getValueFromConfigState(configState.key, configState, h.defaultValue);
|
|
1158
|
-
h.handler(value);
|
|
1159
|
-
});
|
|
1160
|
-
}
|
|
1161
|
-
watch(configKey, defaultValue, callback) {
|
|
1162
|
-
this.validateDefaultValue(defaultValue);
|
|
1163
|
-
const handlers = this.handlersMap.get(configKey);
|
|
1164
|
-
const handlerWithOptions = {
|
|
1165
|
-
handler: callback,
|
|
1166
|
-
defaultValue,
|
|
1167
|
-
requestedType: typeof defaultValue
|
|
1168
|
-
};
|
|
1169
|
-
if (handlers) handlers.push(handlerWithOptions);
|
|
1170
|
-
else this.handlersMap.set(configKey, [handlerWithOptions]);
|
|
1171
|
-
return () => this.unwatch(configKey, callback);
|
|
1172
|
-
}
|
|
1173
|
-
unwatch(configKey, callback) {
|
|
1174
|
-
const handlers = this.handlersMap.get(configKey);
|
|
1175
|
-
if (!handlers) return;
|
|
1176
|
-
if (callback) {
|
|
1177
|
-
const index = handlers.findIndex((h) => h.handler == callback);
|
|
1178
|
-
if (index >= 0) handlers === null || handlers === void 0 || handlers.splice(index, 1);
|
|
1179
|
-
} else handlers.splice(0);
|
|
1180
|
-
}
|
|
1181
|
-
getValue(configKey, defaultValue) {
|
|
1182
|
-
var _this$configSet;
|
|
1183
|
-
this.validateDefaultValue(defaultValue);
|
|
1184
|
-
const configState = (_this$configSet = this.configSet) === null || _this$configSet === void 0 ? void 0 : _this$configSet.configs[configKey];
|
|
1185
|
-
return this.getValueFromConfigState(configKey, configState, defaultValue);
|
|
1186
|
-
}
|
|
1187
|
-
getValueFromConfigState(configKey, configState, defaultValue) {
|
|
1188
|
-
var _this$currentContext2, _parseResult$parsedVa;
|
|
1189
|
-
if (!configState) {
|
|
1190
|
-
var _this$currentContext;
|
|
1191
|
-
this.logger.debug(`[ConfigDirectorClient] No config state found for '${configKey}', returning default value '${defaultValue}'`);
|
|
1192
|
-
const reason = this.isReady ? "config-state-missing" : "client-not-ready";
|
|
1193
|
-
this.telemetryClient.evaluatedConfig({
|
|
1194
|
-
contextId: (_this$currentContext = this.currentContext) === null || _this$currentContext === void 0 ? void 0 : _this$currentContext.id,
|
|
1195
|
-
key: configKey,
|
|
1196
|
-
defaultValue,
|
|
1197
|
-
requestedType: getRequestedType(defaultValue),
|
|
1198
|
-
evaluatedValue: defaultValue,
|
|
1199
|
-
usedDefault: true,
|
|
1200
|
-
evaluationReason: reason
|
|
1201
|
-
});
|
|
1202
|
-
this.dispatchEvaluationEvent({
|
|
1203
|
-
key: configKey,
|
|
1204
|
-
value: defaultValue,
|
|
1205
|
-
isDefaultValue: true,
|
|
1206
|
-
reason,
|
|
1207
|
-
context: this.context
|
|
1208
|
-
});
|
|
1209
|
-
return defaultValue;
|
|
1210
|
-
}
|
|
1211
|
-
const parseResult = parseConfigValue(configState, defaultValue);
|
|
1212
|
-
this.telemetryClient.evaluatedConfig({
|
|
1213
|
-
contextId: (_this$currentContext2 = this.currentContext) === null || _this$currentContext2 === void 0 ? void 0 : _this$currentContext2.id,
|
|
1214
|
-
type: configState.type,
|
|
1215
|
-
key: configKey,
|
|
1216
|
-
defaultValue,
|
|
1217
|
-
requestedType: parseResult.requestedType,
|
|
1218
|
-
evaluatedValue: parseResult.parsedValue,
|
|
1219
|
-
evaluatedValueId: parseResult.parsedValueId,
|
|
1220
|
-
usedDefault: parseResult.usedDefault,
|
|
1221
|
-
evaluationReason: parseResult.reason
|
|
1222
|
-
});
|
|
1223
|
-
this.dispatchEvaluationEvent({
|
|
1224
|
-
key: configKey,
|
|
1225
|
-
value: parseResult.parsedValue,
|
|
1226
|
-
valueId: (_parseResult$parsedVa = parseResult.parsedValueId) !== null && _parseResult$parsedVa !== void 0 ? _parseResult$parsedVa : void 0,
|
|
1227
|
-
isDefaultValue: parseResult.usedDefault,
|
|
1228
|
-
reason: parseResult.reason,
|
|
1229
|
-
context: this.context
|
|
1230
|
-
});
|
|
1231
|
-
this.logger.debug(`[ConfigDirectorClient] Evaluated '${configKey}' to '${parseResult.parsedValue}'`);
|
|
1232
|
-
return parseResult.parsedValue;
|
|
1233
|
-
}
|
|
1234
|
-
dispatchEvaluationEvent(event) {
|
|
1235
|
-
setTimeout(() => this.emit("configEvaluated", { evaluation: event }), 0);
|
|
1236
|
-
}
|
|
1237
|
-
emit(name, payload) {
|
|
1238
|
-
try {
|
|
1239
|
-
this.eventEmitter.emit(name, payload);
|
|
1240
|
-
} catch (error) {
|
|
1241
|
-
this.logger.error(`[ConfigDirectorClient] Error executing event handlers for '${name}'`, error);
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
parseUrl(url, urlFactory) {
|
|
1245
|
-
if (!url) return;
|
|
1246
|
-
try {
|
|
1247
|
-
return urlFactory(url);
|
|
1248
|
-
} catch (error) {
|
|
1249
|
-
throw new ConfigDirectorValidationError(`Invalid base URL '${url}'. Parsing failed: ${error}`);
|
|
1250
|
-
}
|
|
1251
|
-
}
|
|
1252
|
-
validateSdkKeyPresence(sdkKey) {
|
|
1253
|
-
if (!sdkKey || sdkKey.trim().length == 0) throw new ConfigDirectorValidationError("No client SDK key was provided, the client cannot be instantiated without a valid client SDK key");
|
|
1254
|
-
}
|
|
1255
|
-
validateDefaultValue(defaultValue) {
|
|
1256
|
-
if (defaultValue === void 0 || defaultValue === null) throw new ConfigDirectorValidationError("Invalid default value. The default value for a config must be defined and non-null.");
|
|
1257
|
-
if (typeof defaultValue === "function") throw new ConfigDirectorValidationError("Invalid default value. The default value for a config cannot be a function.");
|
|
1258
|
-
}
|
|
1259
|
-
get isReady() {
|
|
1260
|
-
return this.ready;
|
|
1261
|
-
}
|
|
1262
|
-
get isInitializing() {
|
|
1263
|
-
return this.initializing;
|
|
1264
|
-
}
|
|
1265
|
-
on(eventName, handler) {
|
|
1266
|
-
this.eventEmitter.on(eventName, handler);
|
|
1267
|
-
}
|
|
1268
|
-
off(eventName, handler) {
|
|
1269
|
-
this.eventEmitter.off(eventName, handler);
|
|
1270
|
-
}
|
|
1271
|
-
clear() {
|
|
1272
|
-
this.logger.debug("[ConfigDirectorClient] clear() has been called, removing all observers");
|
|
1273
|
-
this.eventEmitter.clear();
|
|
1274
|
-
this.handlersMap.clear();
|
|
1275
|
-
}
|
|
1276
|
-
unwatchAll() {
|
|
1277
|
-
this.handlersMap.clear();
|
|
1278
|
-
}
|
|
1279
|
-
pauseNetwork() {
|
|
1280
|
-
this.logger.debug("[ConfigDirectorClient] pauseNetwork() called, pausing transport connection");
|
|
1281
|
-
clearTimeout(this.timeoutTimer);
|
|
1282
|
-
this.timeoutTimer = void 0;
|
|
1283
|
-
this.transport.close();
|
|
1284
|
-
this.ready = false;
|
|
1285
|
-
}
|
|
1286
|
-
async resumeNetwork() {
|
|
1287
|
-
await this.connectToTransport(this.currentContext, "network resume");
|
|
1288
|
-
}
|
|
1289
|
-
async close() {
|
|
1290
|
-
var _this$readyResolve2;
|
|
1291
|
-
this.logger.debug("[ConfigDirectorClient] close() has been called, closing connection to server");
|
|
1292
|
-
clearTimeout(this.timeoutTimer);
|
|
1293
|
-
(_this$readyResolve2 = this.readyResolve) === null || _this$readyResolve2 === void 0 || _this$readyResolve2.call(this, true);
|
|
1294
|
-
this.telemetryClient.close();
|
|
1295
|
-
this.transport.close();
|
|
1296
|
-
this.ready = false;
|
|
1297
|
-
this.initializing = false;
|
|
1298
|
-
}
|
|
1299
|
-
dispose() {
|
|
1300
|
-
this.clear();
|
|
1301
|
-
this.close();
|
|
1302
|
-
}
|
|
1303
|
-
};
|
|
1304
|
-
//#endregion
|
|
1305
6
|
//#region ../shared/src/telemetry/utils.ts
|
|
1306
7
|
const CONFIG_VALUE_MAX_LENGTH = 500;
|
|
1307
8
|
const compactTelemetryValue = async (tv, valueIdGenerator) => {
|
|
@@ -1360,12 +61,14 @@ var ClientEventReporter = class {
|
|
|
1360
61
|
constructor(options) {
|
|
1361
62
|
_defineProperty(this, "sdkKey", void 0);
|
|
1362
63
|
_defineProperty(this, "sdkIdentity", void 0);
|
|
64
|
+
_defineProperty(this, "metaContext", void 0);
|
|
1363
65
|
_defineProperty(this, "logger", void 0);
|
|
1364
66
|
_defineProperty(this, "url", void 0);
|
|
1365
67
|
_defineProperty(this, "executeRequests", true);
|
|
1366
68
|
this.sdkKey = options.sdkKey;
|
|
1367
69
|
this.logger = options.logger;
|
|
1368
70
|
this.sdkIdentity = options.sdkIdentity;
|
|
71
|
+
this.metaContext = options.metaContext;
|
|
1369
72
|
this.url = options.urlFactory("client/telemetry/v1", options.baseUrl);
|
|
1370
73
|
}
|
|
1371
74
|
async report({ context, discreteEvents, aggregatedEvents, droppedEvents }) {
|
|
@@ -1377,7 +80,9 @@ var ClientEventReporter = class {
|
|
|
1377
80
|
clientSdkKey: this.sdkKey,
|
|
1378
81
|
metaContext: {
|
|
1379
82
|
sdkName: this.sdkIdentity.sdkName,
|
|
1380
|
-
sdkVersion: this.sdkIdentity.sdkVersion
|
|
83
|
+
sdkVersion: this.sdkIdentity.sdkVersion,
|
|
84
|
+
appName: this.metaContext.appName,
|
|
85
|
+
appVersion: this.metaContext.appVersion
|
|
1381
86
|
},
|
|
1382
87
|
context,
|
|
1383
88
|
discreteEvents,
|
|
@@ -1509,11 +214,17 @@ var TelemetryEventCollector = class {
|
|
|
1509
214
|
_defineProperty(this, "flushIntervalDelay", void 0);
|
|
1510
215
|
_defineProperty(this, "flushTimeout", void 0);
|
|
1511
216
|
_defineProperty(this, "collectEvents", true);
|
|
217
|
+
_defineProperty(this, "initialFlushIntervalDelay", void 0);
|
|
218
|
+
_defineProperty(this, "started", false);
|
|
1512
219
|
this.logger = options.logger;
|
|
1513
220
|
this.evaluationEventQueue = new EventQueue((_options$evaluationQu = options.evaluationQueueLimit) !== null && _options$evaluationQu !== void 0 ? _options$evaluationQu : 1e3);
|
|
1514
221
|
this.flushIntervalDelay = (_options$flushInterva = options.flushIntervalDelay) !== null && _options$flushInterva !== void 0 ? _options$flushInterva : 3e4;
|
|
1515
|
-
|
|
1516
|
-
|
|
222
|
+
this.initialFlushIntervalDelay = (_options$initialFlush = options.initialFlushIntervalDelay) !== null && _options$initialFlush !== void 0 ? _options$initialFlush : 5e3;
|
|
223
|
+
}
|
|
224
|
+
start() {
|
|
225
|
+
if (this.started || !this.collectEvents) return;
|
|
226
|
+
this.started = true;
|
|
227
|
+
this.flushTimeout = setTimeout(() => this.flushAndScheduleNext(), this.initialFlushIntervalDelay);
|
|
1517
228
|
}
|
|
1518
229
|
async flushAndScheduleNext() {
|
|
1519
230
|
if (!this.collectEvents) return;
|
|
@@ -1623,6 +334,125 @@ var MessageDecorator = class {
|
|
|
1623
334
|
};
|
|
1624
335
|
const createConsoleLogger = (level) => createDefaultLogger(level, new MessageDecorator());
|
|
1625
336
|
//#endregion
|
|
337
|
+
//#region src/context.tsx
|
|
338
|
+
const createReactContext = () => React.createContext({ status: "loading" });
|
|
339
|
+
const reactContext = createReactContext();
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region ../js-client-core/src/clientHandlers.ts
|
|
342
|
+
var ClientHandlers = class {
|
|
343
|
+
constructor(client) {
|
|
344
|
+
this.client = client;
|
|
345
|
+
_defineProperty(this, "registrations", []);
|
|
346
|
+
}
|
|
347
|
+
on(event, handler) {
|
|
348
|
+
this.client.on(event, handler);
|
|
349
|
+
this.registrations.push({
|
|
350
|
+
event,
|
|
351
|
+
handler
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
registerHooks(hooks) {
|
|
355
|
+
for (const [event, handlerOrHandlers] of Object.entries(hooks !== null && hooks !== void 0 ? hooks : {})) {
|
|
356
|
+
const handlers = Array.isArray(handlerOrHandlers) ? handlerOrHandlers : [handlerOrHandlers];
|
|
357
|
+
for (const handler of handlers) if (typeof handler === "function") this.on(event, handler);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
removeAll() {
|
|
361
|
+
for (const { event, handler } of this.registrations) this.client.off(event, handler);
|
|
362
|
+
this.registrations = [];
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region ../shared/src/deepEqual.ts
|
|
367
|
+
const deepEqual = (left, right) => {
|
|
368
|
+
if (Object.is(left, right)) return true;
|
|
369
|
+
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) return false;
|
|
370
|
+
if (Object.getPrototypeOf(left) !== Object.getPrototypeOf(right)) return false;
|
|
371
|
+
if (left instanceof Date && right instanceof Date) return left.getTime() === right.getTime();
|
|
372
|
+
if (Array.isArray(left) && Array.isArray(right)) return left.length === right.length && left.every((item, index) => deepEqual(item, right[index]));
|
|
373
|
+
if (!isPlainObject(left) || !isPlainObject(right)) return false;
|
|
374
|
+
const leftKeys = Object.keys(left);
|
|
375
|
+
const rightKeys = Object.keys(right);
|
|
376
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && deepEqual(left[key], right[key]));
|
|
377
|
+
};
|
|
378
|
+
const isPlainObject = (value) => {
|
|
379
|
+
const prototype = Object.getPrototypeOf(value);
|
|
380
|
+
return prototype === Object.prototype || prototype === null;
|
|
381
|
+
};
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region ../js-client-core/src/mountAction.ts
|
|
384
|
+
const decideMountAction = (client, context) => {
|
|
385
|
+
if (client.isInitializing) return "none";
|
|
386
|
+
if (!client.isReady) return "initialize";
|
|
387
|
+
if (context !== void 0 && !deepEqual(context, client.context)) return "updateContext";
|
|
388
|
+
return "none";
|
|
389
|
+
};
|
|
390
|
+
//#endregion
|
|
391
|
+
//#region src/appInfo.ts
|
|
392
|
+
const APP_INFO_SOURCES = [{
|
|
393
|
+
module: (sources) => {
|
|
394
|
+
var _sources$expoModules;
|
|
395
|
+
return (_sources$expoModules = sources.expoModules) === null || _sources$expoModules === void 0 ? void 0 : _sources$expoModules.ExpoApplication;
|
|
396
|
+
},
|
|
397
|
+
constantNames: {
|
|
398
|
+
appName: "applicationName",
|
|
399
|
+
appVersion: "nativeApplicationVersion"
|
|
400
|
+
}
|
|
401
|
+
}, {
|
|
402
|
+
module: (sources) => {
|
|
403
|
+
var _sources$nativeModule;
|
|
404
|
+
return (_sources$nativeModule = sources.nativeModules) === null || _sources$nativeModule === void 0 ? void 0 : _sources$nativeModule.RNDeviceInfo;
|
|
405
|
+
},
|
|
406
|
+
constantNames: {
|
|
407
|
+
appName: "appName",
|
|
408
|
+
appVersion: "appVersion"
|
|
409
|
+
}
|
|
410
|
+
}];
|
|
411
|
+
const constantsOf = (module) => {
|
|
412
|
+
if (typeof module !== "object" || module === null) return;
|
|
413
|
+
const nativeModule = module;
|
|
414
|
+
try {
|
|
415
|
+
return typeof nativeModule.getConstants === "function" ? nativeModule.getConstants() : nativeModule;
|
|
416
|
+
} catch {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
const nonBlankString = (value) => typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
421
|
+
const readAppInfo = (sources) => {
|
|
422
|
+
const reported = APP_INFO_SOURCES.map((source) => ({
|
|
423
|
+
constantNames: source.constantNames,
|
|
424
|
+
constants: constantsOf(source.module(sources))
|
|
425
|
+
}));
|
|
426
|
+
const firstReported = (field) => reported.map(({ constantNames, constants }) => nonBlankString(constants === null || constants === void 0 ? void 0 : constants[constantNames[field]])).find((value) => value !== void 0);
|
|
427
|
+
const appName = firstReported("appName");
|
|
428
|
+
const appVersion = firstReported("appVersion");
|
|
429
|
+
return {
|
|
430
|
+
...appName !== void 0 && { appName },
|
|
431
|
+
...appVersion !== void 0 && { appVersion }
|
|
432
|
+
};
|
|
433
|
+
};
|
|
434
|
+
const platformAppInfoSources = () => {
|
|
435
|
+
var _expo;
|
|
436
|
+
return {
|
|
437
|
+
expoModules: (_expo = globalThis.expo) === null || _expo === void 0 ? void 0 : _expo.modules,
|
|
438
|
+
nativeModules: NativeModules
|
|
439
|
+
};
|
|
440
|
+
};
|
|
441
|
+
const resolveMetadata = (provided, logger) => {
|
|
442
|
+
var _provided$appName, _provided$appVersion;
|
|
443
|
+
const detected = (provided === null || provided === void 0 ? void 0 : provided.appName) !== void 0 && (provided === null || provided === void 0 ? void 0 : provided.appVersion) !== void 0 ? {} : readAppInfo(platformAppInfoSources());
|
|
444
|
+
const metadata = {
|
|
445
|
+
appName: (_provided$appName = provided === null || provided === void 0 ? void 0 : provided.appName) !== null && _provided$appName !== void 0 ? _provided$appName : detected.appName,
|
|
446
|
+
appVersion: (_provided$appVersion = provided === null || provided === void 0 ? void 0 : provided.appVersion) !== null && _provided$appVersion !== void 0 ? _provided$appVersion : detected.appVersion
|
|
447
|
+
};
|
|
448
|
+
const missing = [...metadata.appName === void 0 ? ["name"] : [], ...metadata.appVersion === void 0 ? ["version"] : []];
|
|
449
|
+
if (missing.length > 0) {
|
|
450
|
+
const pronoun = missing.length === 1 ? "it" : "them";
|
|
451
|
+
logger.info(`The ConfigDirector SDK could not find an app ${missing.join(" and ")}, so targeting rules that use ${pronoun} will not match. Provide ${pronoun} through the appName and appVersion props of ConfigDirectorProvider or the metadata option of createClient, or install expo-application or react-native-device-info for the SDK to read ${pronoun} from.`);
|
|
452
|
+
}
|
|
453
|
+
return metadata;
|
|
454
|
+
};
|
|
455
|
+
//#endregion
|
|
1626
456
|
//#region src/utf8Encoder.ts
|
|
1627
457
|
/**
|
|
1628
458
|
* Encodes a string to a UTF-8 byte sequence.
|
|
@@ -1771,6 +601,7 @@ var ReactNativeTelemetryClient = class {
|
|
|
1771
601
|
});
|
|
1772
602
|
}
|
|
1773
603
|
async updateContext(value) {
|
|
604
|
+
this.collector.start();
|
|
1774
605
|
return await this.collector.updateContext(value);
|
|
1775
606
|
}
|
|
1776
607
|
evaluatedConfig(event) {
|
|
@@ -1815,36 +646,72 @@ const createClient = (clientSdkKey, clientOptions) => {
|
|
|
1815
646
|
var _clientOptions$logger, _clientOptions$connec;
|
|
1816
647
|
const sdkIdentity = {
|
|
1817
648
|
sdkName: "react-native-sdk",
|
|
1818
|
-
sdkVersion: "1.
|
|
649
|
+
sdkVersion: "1.6.0"
|
|
1819
650
|
};
|
|
1820
651
|
const logger = (_clientOptions$logger = clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.logger) !== null && _clientOptions$logger !== void 0 ? _clientOptions$logger : createConsoleLogger("warn");
|
|
652
|
+
const metadata = resolveMetadata(clientOptions === null || clientOptions === void 0 ? void 0 : clientOptions.metadata, logger);
|
|
1821
653
|
return new DefaultConfigDirectorClient(new ReactNativeTelemetryClient({
|
|
1822
654
|
sdkKey: clientSdkKey,
|
|
1823
655
|
sdkIdentity,
|
|
656
|
+
metaContext: metadata,
|
|
1824
657
|
baseUrl: (clientOptions === null || clientOptions === void 0 || (_clientOptions$connec = clientOptions.connection) === null || _clientOptions$connec === void 0 ? void 0 : _clientOptions$connec.url) ? urlFactory(clientOptions.connection.url) : CLIENT_BASE_URL,
|
|
1825
658
|
logger,
|
|
1826
659
|
urlFactory
|
|
1827
660
|
}), clientSdkKey, sdkIdentity, {
|
|
1828
661
|
...clientOptions,
|
|
1829
|
-
logger
|
|
662
|
+
logger,
|
|
663
|
+
metadata
|
|
1830
664
|
}, {
|
|
1831
665
|
fetch: reactNativeStreamingFetch,
|
|
1832
666
|
urlFactory
|
|
1833
667
|
});
|
|
1834
668
|
};
|
|
1835
669
|
//#endregion
|
|
1836
|
-
//#region src/
|
|
1837
|
-
const
|
|
1838
|
-
|
|
670
|
+
//#region src/clientSource.ts
|
|
671
|
+
const buildClient = (options) => {
|
|
672
|
+
var _options$logger;
|
|
673
|
+
return createClient(options.sdkKey, {
|
|
674
|
+
connection: {
|
|
675
|
+
url: options.url,
|
|
676
|
+
timeout: options.timeout,
|
|
677
|
+
mode: options.mode,
|
|
678
|
+
pollingInterval: options.pollingInterval
|
|
679
|
+
},
|
|
680
|
+
metadata: {
|
|
681
|
+
appName: options.appName,
|
|
682
|
+
appVersion: options.appVersion
|
|
683
|
+
},
|
|
684
|
+
logger: (_options$logger = options.logger) !== null && _options$logger !== void 0 ? _options$logger : createConsoleLogger("warn"),
|
|
685
|
+
hooks: options.hooks
|
|
686
|
+
});
|
|
687
|
+
};
|
|
688
|
+
const hasGivenClient = (props) => "client" in props && props.client !== void 0;
|
|
689
|
+
const resolveClientSource = (props) => {
|
|
690
|
+
if (hasGivenClient(props)) return {
|
|
691
|
+
client: props.client,
|
|
692
|
+
owned: false
|
|
693
|
+
};
|
|
694
|
+
const installed = readInstalledTestClient();
|
|
695
|
+
if (installed) return {
|
|
696
|
+
client: installed,
|
|
697
|
+
owned: false
|
|
698
|
+
};
|
|
699
|
+
return {
|
|
700
|
+
client: buildClient(props),
|
|
701
|
+
owned: true
|
|
702
|
+
};
|
|
703
|
+
};
|
|
1839
704
|
//#endregion
|
|
1840
705
|
//#region src/provider.tsx
|
|
1841
706
|
var ConfigDirectorProvider = class extends Component {
|
|
1842
707
|
constructor(props) {
|
|
1843
|
-
var _props$logger;
|
|
1844
708
|
super(props);
|
|
1845
709
|
_defineProperty(this, "appStateSubscription", null);
|
|
1846
710
|
_defineProperty(this, "netInfoUnsubscribe", null);
|
|
1847
711
|
_defineProperty(this, "wasOffline", false);
|
|
712
|
+
_defineProperty(this, "ownsClient", void 0);
|
|
713
|
+
_defineProperty(this, "disposedOwnClient", false);
|
|
714
|
+
_defineProperty(this, "handlers", void 0);
|
|
1848
715
|
_defineProperty(this, "handleAppStateChange", async (nextState) => {
|
|
1849
716
|
if (nextState === "active") await this.reconnect();
|
|
1850
717
|
else if (nextState === "background") {
|
|
@@ -1863,48 +730,70 @@ var ConfigDirectorProvider = class extends Component {
|
|
|
1863
730
|
var _this$state$client2;
|
|
1864
731
|
await ((_this$state$client2 = this.state.client) === null || _this$state$client2 === void 0 ? void 0 : _this$state$client2.resumeNetwork());
|
|
1865
732
|
});
|
|
733
|
+
const source = resolveClientSource(props);
|
|
734
|
+
this.ownsClient = source.owned;
|
|
1866
735
|
this.state = {
|
|
1867
|
-
client:
|
|
1868
|
-
|
|
1869
|
-
url: props.url,
|
|
1870
|
-
timeout: props.timeout
|
|
1871
|
-
},
|
|
1872
|
-
metadata: {
|
|
1873
|
-
appName: props.appName,
|
|
1874
|
-
appVersion: props.appVersion
|
|
1875
|
-
},
|
|
1876
|
-
logger: (_props$logger = props.logger) !== null && _props$logger !== void 0 ? _props$logger : createConsoleLogger("warn"),
|
|
1877
|
-
hooks: props.hooks
|
|
1878
|
-
}),
|
|
1879
|
-
status: "loading"
|
|
736
|
+
client: source.client,
|
|
737
|
+
status: source.client.isReady ? "ready" : "loading"
|
|
1880
738
|
};
|
|
1881
739
|
}
|
|
1882
740
|
async componentDidMount() {
|
|
1883
|
-
|
|
1884
|
-
(
|
|
741
|
+
let client = this.state.client;
|
|
742
|
+
if (this.ownsClient && this.disposedOwnClient) {
|
|
743
|
+
client = buildClient(this.props);
|
|
744
|
+
this.disposedOwnClient = false;
|
|
745
|
+
this.setState({
|
|
746
|
+
client,
|
|
747
|
+
status: "loading"
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
this.handlers = new ClientHandlers(client);
|
|
751
|
+
this.handlers.on("configsUpdated", () => {
|
|
1885
752
|
this.setState({ updatedAt: /* @__PURE__ */ new Date() });
|
|
1886
753
|
});
|
|
1887
|
-
|
|
754
|
+
this.handlers.on("clientReady", () => {
|
|
1888
755
|
this.setState({ status: "ready" });
|
|
1889
756
|
});
|
|
1890
|
-
|
|
1891
|
-
if (!((_this$state$client6 = this.state.client) === null || _this$state$client6 === void 0 ? void 0 : _this$state$client6.isReady)) this.setState({ status: "default" });
|
|
757
|
+
if (!this.ownsClient) this.handlers.registerHooks(this.props.hooks);
|
|
1892
758
|
this.appStateSubscription = AppState.addEventListener("change", this.handleAppStateChange);
|
|
1893
759
|
if (this.props.netInfoSubscribe) this.netInfoUnsubscribe = this.props.netInfoSubscribe(this.handleConnectivityChange);
|
|
760
|
+
await this.connect(client, this.props.context);
|
|
761
|
+
}
|
|
762
|
+
async connect(client, context) {
|
|
763
|
+
switch (decideMountAction(client, context)) {
|
|
764
|
+
case "initialize":
|
|
765
|
+
await client.initialize(context);
|
|
766
|
+
break;
|
|
767
|
+
case "updateContext":
|
|
768
|
+
this.setState({ status: "loading" });
|
|
769
|
+
await client.updateContext(context);
|
|
770
|
+
break;
|
|
771
|
+
case "none": return;
|
|
772
|
+
}
|
|
773
|
+
if (!client.isReady) this.setState({ status: "default" });
|
|
1894
774
|
}
|
|
1895
775
|
async componentDidUpdate(prevProps) {
|
|
1896
|
-
if (prevProps.
|
|
1897
|
-
|
|
776
|
+
if (hasGivenClient(prevProps) && hasGivenClient(this.props) && prevProps.client !== this.props.client) createConsoleLogger("warn").warn("The client prop of ConfigDirectorProvider changed after it mounted and is ignored. Remount the provider, for example with a new key, to use another client.");
|
|
777
|
+
if (!deepEqual(prevProps.context, this.props.context)) {
|
|
778
|
+
var _this$state$client3, _this$props$context, _this$state$client4;
|
|
1898
779
|
this.setState({ status: "loading" });
|
|
1899
|
-
await ((_this$state$
|
|
1900
|
-
if (!((_this$state$
|
|
780
|
+
await ((_this$state$client3 = this.state.client) === null || _this$state$client3 === void 0 ? void 0 : _this$state$client3.updateContext((_this$props$context = this.props.context) !== null && _this$props$context !== void 0 ? _this$props$context : {}));
|
|
781
|
+
if (!((_this$state$client4 = this.state.client) === null || _this$state$client4 === void 0 ? void 0 : _this$state$client4.isReady)) this.setState({ status: "default" });
|
|
1901
782
|
}
|
|
1902
783
|
}
|
|
1903
784
|
componentWillUnmount() {
|
|
1904
|
-
var _this$appStateSubscri, _this$netInfoUnsubscr, _this$
|
|
785
|
+
var _this$appStateSubscri, _this$netInfoUnsubscr, _this$handlers;
|
|
1905
786
|
(_this$appStateSubscri = this.appStateSubscription) === null || _this$appStateSubscri === void 0 || _this$appStateSubscri.remove();
|
|
787
|
+
this.appStateSubscription = null;
|
|
1906
788
|
(_this$netInfoUnsubscr = this.netInfoUnsubscribe) === null || _this$netInfoUnsubscr === void 0 || _this$netInfoUnsubscr.call(this);
|
|
1907
|
-
|
|
789
|
+
this.netInfoUnsubscribe = null;
|
|
790
|
+
(_this$handlers = this.handlers) === null || _this$handlers === void 0 || _this$handlers.removeAll();
|
|
791
|
+
this.handlers = void 0;
|
|
792
|
+
if (this.ownsClient) {
|
|
793
|
+
var _this$state$client5;
|
|
794
|
+
(_this$state$client5 = this.state.client) === null || _this$state$client5 === void 0 || _this$state$client5.dispose();
|
|
795
|
+
this.disposedOwnClient = true;
|
|
796
|
+
}
|
|
1908
797
|
}
|
|
1909
798
|
render() {
|
|
1910
799
|
return /* @__PURE__ */ jsx(reactContext.Provider, {
|