@skyporch/daykeeper-react-native 0.1.0 → 0.2.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/CHANGELOG.md +121 -0
- package/COMPATIBILITY.md +91 -5
- package/LICENSE-APACHE-2.0 +201 -0
- package/NOTICE +11 -0
- package/README.md +104 -6
- package/dist/chunk-BAQHY3R2.js +500 -0
- package/dist/chunk-BAQHY3R2.js.map +1 -0
- package/dist/index.cjs +205 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -7
- package/dist/index.d.ts +68 -7
- package/dist/index.js +6 -346
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +548 -0
- package/dist/native.cjs.map +1 -0
- package/dist/native.d.cts +18 -0
- package/dist/native.d.ts +18 -0
- package/dist/native.js +36 -0
- package/dist/native.js.map +1 -0
- package/package.json +16 -10
package/dist/index.cjs
CHANGED
|
@@ -38,23 +38,42 @@ __export(index_exports, {
|
|
|
38
38
|
module.exports = __toCommonJS(index_exports);
|
|
39
39
|
|
|
40
40
|
// src/errors.ts
|
|
41
|
+
var API_CODE_SHAPE = /^[a-z][a-z0-9_]{2,63}$/;
|
|
42
|
+
var DAYKEEPER_GENERIC_API_CODE = "daykeeper_request_failed";
|
|
43
|
+
function isDaykeeperApiErrorCode(value) {
|
|
44
|
+
return typeof value === "string" && API_CODE_SHAPE.test(value);
|
|
45
|
+
}
|
|
46
|
+
var SAFE_NEXT_ACTIONS = /* @__PURE__ */ new Set([
|
|
47
|
+
"review_usage",
|
|
48
|
+
"review_setup",
|
|
49
|
+
"refresh_conversation"
|
|
50
|
+
]);
|
|
41
51
|
var DaykeeperReactNativeApiError = class extends Error {
|
|
42
52
|
constructor(options) {
|
|
43
|
-
|
|
53
|
+
const code = isDaykeeperApiErrorCode(options.code) ? options.code : DAYKEEPER_GENERIC_API_CODE;
|
|
54
|
+
super(code);
|
|
44
55
|
__publicField(this, "status");
|
|
45
56
|
__publicField(this, "code");
|
|
46
57
|
__publicField(this, "retryable");
|
|
58
|
+
__publicField(this, "outcomeUnknown");
|
|
59
|
+
__publicField(this, "nextAction");
|
|
47
60
|
this.name = "DaykeeperReactNativeApiError";
|
|
48
61
|
this.status = options.status;
|
|
49
|
-
this.code =
|
|
50
|
-
this.
|
|
62
|
+
this.code = code;
|
|
63
|
+
this.outcomeUnknown = options.outcomeUnknown ?? false;
|
|
64
|
+
this.retryable = !this.outcomeUnknown && (options.retryable ?? false);
|
|
65
|
+
if (typeof options.nextAction === "string" && SAFE_NEXT_ACTIONS.has(options.nextAction)) {
|
|
66
|
+
this.nextAction = options.nextAction;
|
|
67
|
+
}
|
|
51
68
|
}
|
|
52
69
|
toJSON() {
|
|
53
70
|
return {
|
|
54
71
|
name: this.name,
|
|
55
72
|
status: this.status,
|
|
56
73
|
code: this.code,
|
|
57
|
-
retryable: this.retryable
|
|
74
|
+
retryable: this.retryable,
|
|
75
|
+
outcomeUnknown: this.outcomeUnknown,
|
|
76
|
+
...this.nextAction === void 0 ? {} : { nextAction: this.nextAction }
|
|
58
77
|
};
|
|
59
78
|
}
|
|
60
79
|
};
|
|
@@ -63,20 +82,109 @@ var DaykeeperReactNativeTransportError = class extends Error {
|
|
|
63
82
|
super(options.message);
|
|
64
83
|
__publicField(this, "code");
|
|
65
84
|
__publicField(this, "retryable");
|
|
85
|
+
__publicField(this, "outcomeUnknown");
|
|
66
86
|
this.name = "DaykeeperReactNativeTransportError";
|
|
67
87
|
this.code = options.code;
|
|
68
|
-
this.
|
|
88
|
+
this.outcomeUnknown = options.outcomeUnknown ?? false;
|
|
89
|
+
this.retryable = !this.outcomeUnknown && (options.retryable ?? false);
|
|
69
90
|
}
|
|
70
91
|
toJSON() {
|
|
71
92
|
return {
|
|
72
93
|
name: this.name,
|
|
73
94
|
code: this.code,
|
|
74
95
|
message: this.message,
|
|
75
|
-
retryable: this.retryable
|
|
96
|
+
retryable: this.retryable,
|
|
97
|
+
outcomeUnknown: this.outcomeUnknown
|
|
76
98
|
};
|
|
77
99
|
}
|
|
78
100
|
};
|
|
79
101
|
|
|
102
|
+
// src/requestLifetime.ts
|
|
103
|
+
function createRequestLifetime(timeoutMs, caller) {
|
|
104
|
+
const controller = new AbortController();
|
|
105
|
+
const now = () => typeof performance === "undefined" ? Date.now() : performance.now();
|
|
106
|
+
const deadline = now() + timeoutMs;
|
|
107
|
+
let failure;
|
|
108
|
+
const abort = (code) => {
|
|
109
|
+
if (failure) return;
|
|
110
|
+
failure = new DaykeeperReactNativeTransportError({
|
|
111
|
+
code,
|
|
112
|
+
message: code === "REQUEST_TIMEOUT" ? `The Daykeeper request exceeded ${timeoutMs}ms` : "The Daykeeper request was aborted",
|
|
113
|
+
retryable: code === "REQUEST_TIMEOUT"
|
|
114
|
+
});
|
|
115
|
+
controller.abort();
|
|
116
|
+
};
|
|
117
|
+
const onCallerAbort = () => abort("REQUEST_ABORTED");
|
|
118
|
+
if (caller?.aborted) onCallerAbort();
|
|
119
|
+
else caller?.addEventListener("abort", onCallerAbort, { once: true });
|
|
120
|
+
const timeout = failure ? void 0 : setTimeout(() => abort("REQUEST_TIMEOUT"), timeoutMs);
|
|
121
|
+
const checkDeadline = () => {
|
|
122
|
+
if (!failure && now() >= deadline) abort("REQUEST_TIMEOUT");
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
signal: controller.signal,
|
|
126
|
+
run(work, onLateValue) {
|
|
127
|
+
checkDeadline();
|
|
128
|
+
if (failure) return Promise.reject(failure);
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
let settled = false;
|
|
131
|
+
const finish = () => {
|
|
132
|
+
settled = true;
|
|
133
|
+
controller.signal.removeEventListener("abort", onAbort);
|
|
134
|
+
};
|
|
135
|
+
const onAbort = () => {
|
|
136
|
+
finish();
|
|
137
|
+
reject(failure);
|
|
138
|
+
};
|
|
139
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
140
|
+
Promise.resolve().then(() => {
|
|
141
|
+
checkDeadline();
|
|
142
|
+
if (failure) throw failure;
|
|
143
|
+
return work();
|
|
144
|
+
}).then(
|
|
145
|
+
(value) => {
|
|
146
|
+
checkDeadline();
|
|
147
|
+
if (settled) {
|
|
148
|
+
try {
|
|
149
|
+
onLateValue?.(value);
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
finish();
|
|
155
|
+
resolve(value);
|
|
156
|
+
},
|
|
157
|
+
(error) => {
|
|
158
|
+
if (settled) return;
|
|
159
|
+
finish();
|
|
160
|
+
reject(error);
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
dispose() {
|
|
166
|
+
clearTimeout(timeout);
|
|
167
|
+
caller?.removeEventListener("abort", onCallerAbort);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function discardResponse(response) {
|
|
172
|
+
try {
|
|
173
|
+
void response.body?.cancel().catch(() => void 0);
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function discardReader(reader) {
|
|
178
|
+
try {
|
|
179
|
+
void reader.cancel().catch(() => void 0);
|
|
180
|
+
} catch {
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
reader.releaseLock();
|
|
184
|
+
} catch {
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
80
188
|
// src/client.ts
|
|
81
189
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
82
190
|
var MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
@@ -151,20 +259,21 @@ _getAccessToken = new WeakMap();
|
|
|
151
259
|
_timeoutMs = new WeakMap();
|
|
152
260
|
_DaykeeperReactNativeClient_instances = new WeakSet();
|
|
153
261
|
request_fn = async function(path, options = {}) {
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const onCallerAbort = () => timeoutController.abort();
|
|
161
|
-
if (options.signal?.aborted) timeoutController.abort();
|
|
162
|
-
else
|
|
163
|
-
options.signal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
262
|
+
const lifetime = createRequestLifetime(__privateGet(this, _timeoutMs), options.signal);
|
|
263
|
+
const method = options.method ?? "GET";
|
|
264
|
+
const mutating = method !== "GET";
|
|
265
|
+
const attempts = mutating ? 1 : 2;
|
|
266
|
+
let dispatched = false;
|
|
267
|
+
let response;
|
|
164
268
|
try {
|
|
165
|
-
for (let attempt = 0; attempt <
|
|
269
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
166
270
|
const token = validateToken(
|
|
167
|
-
await
|
|
271
|
+
await lifetime.run(
|
|
272
|
+
() => resolveToken(__privateGet(this, _getAccessToken), {
|
|
273
|
+
forceRefresh: attempt === 1,
|
|
274
|
+
signal: lifetime.signal
|
|
275
|
+
})
|
|
276
|
+
)
|
|
168
277
|
);
|
|
169
278
|
const headers = new Headers({
|
|
170
279
|
accept: "application/json",
|
|
@@ -173,42 +282,48 @@ request_fn = async function(path, options = {}) {
|
|
|
173
282
|
if (options.body !== void 0) {
|
|
174
283
|
headers.set("content-type", "application/json");
|
|
175
284
|
}
|
|
176
|
-
let response;
|
|
177
285
|
try {
|
|
178
|
-
response = await
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
message: `The Daykeeper request exceeded ${__privateGet(this, _timeoutMs)}ms`,
|
|
189
|
-
retryable: true
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
if (options.signal?.aborted) {
|
|
193
|
-
throw new DaykeeperReactNativeTransportError({
|
|
194
|
-
code: "REQUEST_ABORTED",
|
|
195
|
-
message: "The Daykeeper request was aborted"
|
|
286
|
+
response = await lifetime.run(() => {
|
|
287
|
+
dispatched = true;
|
|
288
|
+
return __privateGet(this, _fetch).call(this, `${__privateGet(this, _baseUrl)}${path}`, {
|
|
289
|
+
method,
|
|
290
|
+
body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
|
|
291
|
+
headers,
|
|
292
|
+
signal: lifetime.signal,
|
|
293
|
+
redirect: "error",
|
|
294
|
+
credentials: "omit",
|
|
295
|
+
cache: "no-store"
|
|
196
296
|
});
|
|
297
|
+
}, discardResponse);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (error instanceof DaykeeperReactNativeTransportError) throw error;
|
|
300
|
+
throw networkError();
|
|
301
|
+
}
|
|
302
|
+
const refreshCandidate = !mutating && response.status === 401 && attempt === 0;
|
|
303
|
+
let payload;
|
|
304
|
+
if (refreshCandidate || !response.ok) {
|
|
305
|
+
try {
|
|
306
|
+
payload = await readJson(response, lifetime);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (!(error instanceof DaykeeperReactNativeTransportError) || error.code !== "INVALID_RESPONSE")
|
|
309
|
+
throw error;
|
|
197
310
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
311
|
+
} else {
|
|
312
|
+
payload = await readJson(response, lifetime);
|
|
313
|
+
}
|
|
314
|
+
if (refreshCandidate && !(isRecord(payload) && payload.retryable === false)) {
|
|
315
|
+
discardResponse(response);
|
|
316
|
+
continue;
|
|
203
317
|
}
|
|
204
|
-
const payload = await readJson(response);
|
|
205
|
-
if (response.status === 401 && attempt === 0) continue;
|
|
206
318
|
if (!response.ok) {
|
|
207
|
-
const code = isRecord(payload) && typeof payload.error === "string" ? payload.error : "daykeeper_request_failed";
|
|
208
319
|
throw new DaykeeperReactNativeApiError({
|
|
209
320
|
status: response.status,
|
|
210
|
-
code,
|
|
211
|
-
|
|
321
|
+
code: isRecord(payload) ? payload.error : void 0,
|
|
322
|
+
// The contract's message stays unread; only the bounded
|
|
323
|
+
// nextAction vocabulary is projected.
|
|
324
|
+
nextAction: isRecord(payload) ? payload.nextAction : void 0,
|
|
325
|
+
retryable: !mutating && (isRecord(payload) && typeof payload.retryable === "boolean" ? payload.retryable : response.status === 408 || response.status === 429 || response.status >= 500),
|
|
326
|
+
outcomeUnknown: mutating && (response.status === 408 || response.status >= 500)
|
|
212
327
|
});
|
|
213
328
|
}
|
|
214
329
|
if (!isRecord(payload)) {
|
|
@@ -221,14 +336,41 @@ request_fn = async function(path, options = {}) {
|
|
|
221
336
|
return payload;
|
|
222
337
|
}
|
|
223
338
|
throw new Error("Unreachable Daykeeper request state");
|
|
339
|
+
} catch (error) {
|
|
340
|
+
if (error instanceof DaykeeperReactNativeApiError) throw error;
|
|
341
|
+
const safeError = error instanceof DaykeeperReactNativeTransportError ? error : networkError();
|
|
342
|
+
if (!mutating) throw safeError;
|
|
343
|
+
throw new DaykeeperReactNativeTransportError({
|
|
344
|
+
code: safeError.code,
|
|
345
|
+
message: safeError.message,
|
|
346
|
+
retryable: false,
|
|
347
|
+
outcomeUnknown: dispatched
|
|
348
|
+
});
|
|
224
349
|
} finally {
|
|
225
|
-
|
|
226
|
-
|
|
350
|
+
if (response) discardResponse(response);
|
|
351
|
+
lifetime.dispose();
|
|
227
352
|
}
|
|
228
353
|
};
|
|
229
354
|
function createDaykeeperReactNativeClient(options) {
|
|
230
355
|
return new DaykeeperReactNativeClient(options);
|
|
231
356
|
}
|
|
357
|
+
async function resolveToken(provider, context) {
|
|
358
|
+
try {
|
|
359
|
+
return await provider(context);
|
|
360
|
+
} catch {
|
|
361
|
+
throw new DaykeeperReactNativeTransportError({
|
|
362
|
+
code: "TOKEN_PROVIDER_ERROR",
|
|
363
|
+
message: "The Daykeeper access token could not be obtained"
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function networkError() {
|
|
368
|
+
return new DaykeeperReactNativeTransportError({
|
|
369
|
+
code: "NETWORK_ERROR",
|
|
370
|
+
message: "The Daykeeper customer API transport failed",
|
|
371
|
+
retryable: true
|
|
372
|
+
});
|
|
373
|
+
}
|
|
232
374
|
function parseBaseUrl(value) {
|
|
233
375
|
let url;
|
|
234
376
|
try {
|
|
@@ -236,7 +378,8 @@ function parseBaseUrl(value) {
|
|
|
236
378
|
} catch {
|
|
237
379
|
throw configurationError("baseUrl must be a valid absolute URL");
|
|
238
380
|
}
|
|
239
|
-
const
|
|
381
|
+
const hostname = url.hostname.replace(/^\[(.+)]$/, "$1").toLowerCase();
|
|
382
|
+
const local = ["localhost", "127.0.0.1", "::1"].includes(hostname);
|
|
240
383
|
if (url.protocol !== "https:" && !(local && url.protocol === "http:")) {
|
|
241
384
|
throw configurationError(
|
|
242
385
|
"baseUrl must use HTTPS except for loopback development"
|
|
@@ -281,43 +424,46 @@ function validateMessage(value) {
|
|
|
281
424
|
}
|
|
282
425
|
return normalized;
|
|
283
426
|
}
|
|
284
|
-
async function readJson(response) {
|
|
427
|
+
async function readJson(response, lifetime) {
|
|
285
428
|
const declaredLength = Number(response.headers.get("content-length"));
|
|
286
429
|
if (Number.isFinite(declaredLength) && declaredLength > MAX_RESPONSE_BYTES) {
|
|
287
430
|
throw responseTooLarge();
|
|
288
431
|
}
|
|
289
432
|
const body = response.body;
|
|
290
433
|
if (body && typeof body.getReader === "function" && typeof TextDecoder === "function") {
|
|
291
|
-
return parseJson(await readStream(body));
|
|
434
|
+
return parseJson(await readStream(body, lifetime));
|
|
292
435
|
}
|
|
293
436
|
let text;
|
|
294
437
|
try {
|
|
295
|
-
text = await response.text();
|
|
296
|
-
} catch {
|
|
297
|
-
|
|
438
|
+
text = await lifetime.run(() => response.text());
|
|
439
|
+
} catch (error) {
|
|
440
|
+
if (error instanceof DaykeeperReactNativeTransportError) throw error;
|
|
441
|
+
throw networkError();
|
|
298
442
|
}
|
|
299
443
|
if (utf8LengthExceeds(text, MAX_RESPONSE_BYTES)) {
|
|
300
444
|
throw responseTooLarge();
|
|
301
445
|
}
|
|
302
446
|
return parseJson(text);
|
|
303
447
|
}
|
|
304
|
-
async function readStream(body) {
|
|
448
|
+
async function readStream(body, lifetime) {
|
|
305
449
|
const reader = body.getReader();
|
|
306
450
|
const chunks = [];
|
|
307
451
|
let total = 0;
|
|
308
452
|
try {
|
|
309
453
|
for (; ; ) {
|
|
310
|
-
const { done, value } = await reader.read();
|
|
454
|
+
const { done, value } = await lifetime.run(() => reader.read());
|
|
311
455
|
if (done) break;
|
|
312
456
|
total += value.byteLength;
|
|
313
457
|
if (total > MAX_RESPONSE_BYTES) {
|
|
314
|
-
await reader.cancel();
|
|
315
458
|
throw responseTooLarge();
|
|
316
459
|
}
|
|
317
460
|
chunks.push(value);
|
|
318
461
|
}
|
|
462
|
+
} catch (error) {
|
|
463
|
+
if (error instanceof DaykeeperReactNativeTransportError) throw error;
|
|
464
|
+
throw networkError();
|
|
319
465
|
} finally {
|
|
320
|
-
reader
|
|
466
|
+
discardReader(reader);
|
|
321
467
|
}
|
|
322
468
|
const bytes = new Uint8Array(total);
|
|
323
469
|
let offset = 0;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export {\n createDaykeeperReactNativeClient,\n DaykeeperReactNativeClient,\n} from \"./client.js\";\nexport type {\n DaykeeperReactNativeClientOptions,\n DaykeeperReactNativeRequestOptions,\n DaykeeperReactNativeTokenProvider,\n DaykeeperReactNativeTokenProviderContext,\n} from \"./client.js\";\nexport {\n DaykeeperReactNativeApiError,\n DaykeeperReactNativeTransportError,\n} from \"./errors.js\";\nexport type { DaykeeperReactNativeTransportErrorCode } from \"./errors.js\";\nexport type {\n components as DaykeeperCustomerOpenApiComponents,\n operations as DaykeeperCustomerOpenApiOperations,\n paths as DaykeeperCustomerOpenApiPaths,\n} from \"./generated/schema.js\";\nexport * from \"./types.js\";\n","export type DaykeeperReactNativeTransportErrorCode =\n | \"INVALID_CONFIGURATION\"\n | \"NETWORK_ERROR\"\n | \"REQUEST_ABORTED\"\n | \"REQUEST_TIMEOUT\"\n | \"INVALID_RESPONSE\"\n | \"RESPONSE_TOO_LARGE\";\n\nexport class DaykeeperReactNativeApiError extends Error {\n readonly status: number;\n readonly code: string;\n readonly retryable: boolean;\n\n constructor(options: { status: number; code: string; retryable: boolean }) {\n super(options.code);\n this.name = \"DaykeeperReactNativeApiError\";\n this.status = options.status;\n this.code = options.code;\n this.retryable = options.retryable;\n }\n\n toJSON(): {\n name: string;\n status: number;\n code: string;\n retryable: boolean;\n } {\n return {\n name: this.name,\n status: this.status,\n code: this.code,\n retryable: this.retryable,\n };\n }\n}\n\nexport class DaykeeperReactNativeTransportError extends Error {\n readonly code: DaykeeperReactNativeTransportErrorCode;\n readonly retryable: boolean;\n\n constructor(options: {\n code: DaykeeperReactNativeTransportErrorCode;\n message: string;\n retryable?: boolean;\n }) {\n super(options.message);\n this.name = \"DaykeeperReactNativeTransportError\";\n this.code = options.code;\n this.retryable = options.retryable ?? false;\n }\n\n toJSON(): {\n name: string;\n code: DaykeeperReactNativeTransportErrorCode;\n message: string;\n retryable: boolean;\n } {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n };\n }\n}\n","import {\n DaykeeperReactNativeApiError,\n DaykeeperReactNativeTransportError,\n} from \"./errors.js\";\nimport type {\n DaykeeperClaimConversationResult,\n DaykeeperConversationList,\n DaykeeperConversationResult,\n DaykeeperCustomerIdentity,\n DaykeeperMessageList,\n DaykeeperMessageResult,\n DaykeeperSeenResult,\n DaykeeperUnreadSummary,\n} from \"./types.js\";\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst MAX_RESPONSE_BYTES = 1024 * 1024;\nconst MAX_TOKEN_LENGTH = 16_384;\nconst MAX_MESSAGE_LENGTH = 16_000;\n\nexport interface DaykeeperReactNativeTokenProviderContext {\n /**\n * True only after Daykeeper rejected the first token with HTTP 401. The\n * provider should bypass any token cache and exchange the app session again.\n */\n forceRefresh: boolean;\n}\n\nexport type DaykeeperReactNativeTokenProvider = (\n context: DaykeeperReactNativeTokenProviderContext,\n) => string | Promise<string>;\n\nexport interface DaykeeperReactNativeClientOptions {\n baseUrl: string;\n getAccessToken: DaykeeperReactNativeTokenProvider;\n fetch?: typeof globalThis.fetch;\n timeoutMs?: number;\n}\n\nexport interface DaykeeperReactNativeRequestOptions {\n signal?: AbortSignal;\n}\n\nexport class DaykeeperReactNativeClient {\n readonly #baseUrl: string;\n readonly #fetch: typeof globalThis.fetch;\n readonly #getAccessToken: DaykeeperReactNativeTokenProvider;\n readonly #timeoutMs: number;\n\n constructor(options: DaykeeperReactNativeClientOptions) {\n this.#baseUrl = parseBaseUrl(options.baseUrl);\n this.#fetch = options.fetch ?? globalThis.fetch;\n if (typeof this.#fetch !== \"function\") {\n throw configurationError(\"A Fetch API implementation is required\");\n }\n if (typeof options.getAccessToken !== \"function\") {\n throw configurationError(\"getAccessToken must be a function\");\n }\n this.#getAccessToken = options.getAccessToken;\n this.#timeoutMs = validateTimeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n }\n\n getIdentity(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperCustomerIdentity> {\n return this.#request(\"/v1/identity\", { signal: options?.signal });\n }\n\n listConversations(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperConversationList> {\n return this.#request(\"/v1/conversations\", { signal: options?.signal });\n }\n\n createConversation(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperConversationResult> {\n return this.#request(\"/v1/conversations\", {\n method: \"POST\",\n signal: options?.signal,\n });\n }\n\n getUnread(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperUnreadSummary> {\n return this.#request(\"/v1/unread\", { signal: options?.signal });\n }\n\n markConversationSeen(\n conversationId: number,\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperSeenResult> {\n return this.#request(\n `/v1/conversations/${positiveInteger(conversationId, \"conversationId\")}/seen`,\n { method: \"POST\", signal: options?.signal },\n );\n }\n\n listMessages(\n conversationId: number,\n options: DaykeeperReactNativeRequestOptions & { after?: number } = {},\n ): Promise<DaykeeperMessageList> {\n const id = positiveInteger(conversationId, \"conversationId\");\n const after =\n options.after === undefined\n ? \"\"\n : `?after=${positiveInteger(options.after, \"after\")}`;\n return this.#request(`/v1/conversations/${id}/messages${after}`, {\n signal: options.signal,\n });\n }\n\n sendMessage(\n conversationId: number,\n content: string,\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperMessageResult> {\n const normalizedContent = validateMessage(content);\n return this.#request(\n `/v1/conversations/${positiveInteger(conversationId, \"conversationId\")}/messages`,\n {\n method: \"POST\",\n body: { content: normalizedContent },\n signal: options?.signal,\n },\n );\n }\n\n claimAnonymousConversation(\n widgetToken: string,\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperClaimConversationResult> {\n if (\n typeof widgetToken !== \"string\" ||\n !widgetToken.trim() ||\n widgetToken.length > MAX_TOKEN_LENGTH\n ) {\n throw configurationError(\"widgetToken is invalid\");\n }\n return this.#request(\"/v1/anonymous-conversations/claim\", {\n method: \"POST\",\n body: { widgetToken: widgetToken.trim() },\n signal: options?.signal,\n });\n }\n\n async #request<ResponseBody>(\n path: string,\n options: {\n method?: \"GET\" | \"POST\";\n body?: unknown;\n signal?: AbortSignal;\n } = {},\n ): Promise<ResponseBody> {\n const timeoutController = new AbortController();\n let timedOut = false;\n const timeout = setTimeout(() => {\n timedOut = true;\n timeoutController.abort();\n }, this.#timeoutMs);\n const onCallerAbort = () => timeoutController.abort();\n if (options.signal?.aborted) timeoutController.abort();\n else\n options.signal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n try {\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const token = validateToken(\n await this.#getAccessToken({ forceRefresh: attempt === 1 }),\n );\n const headers = new Headers({\n accept: \"application/json\",\n authorization: `Bearer ${token}`,\n });\n if (options.body !== undefined) {\n headers.set(\"content-type\", \"application/json\");\n }\n\n let response: Response;\n try {\n response = await this.#fetch(`${this.#baseUrl}${path}`, {\n method: options.method ?? \"GET\",\n body:\n options.body === undefined\n ? undefined\n : JSON.stringify(options.body),\n headers,\n signal: timeoutController.signal,\n });\n } catch {\n if (timedOut) {\n throw new DaykeeperReactNativeTransportError({\n code: \"REQUEST_TIMEOUT\",\n message: `The Daykeeper request exceeded ${this.#timeoutMs}ms`,\n retryable: true,\n });\n }\n if (options.signal?.aborted) {\n throw new DaykeeperReactNativeTransportError({\n code: \"REQUEST_ABORTED\",\n message: \"The Daykeeper request was aborted\",\n });\n }\n throw new DaykeeperReactNativeTransportError({\n code: \"NETWORK_ERROR\",\n message: \"The Daykeeper customer API could not be reached\",\n retryable: true,\n });\n }\n\n const payload = await readJson(response);\n if (response.status === 401 && attempt === 0) continue;\n if (!response.ok) {\n const code =\n isRecord(payload) && typeof payload.error === \"string\"\n ? payload.error\n : \"daykeeper_request_failed\";\n throw new DaykeeperReactNativeApiError({\n status: response.status,\n code,\n retryable:\n response.status === 408 ||\n response.status === 429 ||\n response.status >= 500,\n });\n }\n if (!isRecord(payload)) {\n throw new DaykeeperReactNativeTransportError({\n code: \"INVALID_RESPONSE\",\n message: \"The Daykeeper customer API returned an invalid response\",\n retryable: true,\n });\n }\n return payload as ResponseBody;\n }\n throw new Error(\"Unreachable Daykeeper request state\");\n } finally {\n clearTimeout(timeout);\n options.signal?.removeEventListener(\"abort\", onCallerAbort);\n }\n }\n}\n\nexport function createDaykeeperReactNativeClient(\n options: DaykeeperReactNativeClientOptions,\n): DaykeeperReactNativeClient {\n return new DaykeeperReactNativeClient(options);\n}\n\nfunction parseBaseUrl(value: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw configurationError(\"baseUrl must be a valid absolute URL\");\n }\n const local = [\"localhost\", \"127.0.0.1\", \"::1\"].includes(url.hostname);\n if (url.protocol !== \"https:\" && !(local && url.protocol === \"http:\")) {\n throw configurationError(\n \"baseUrl must use HTTPS except for loopback development\",\n );\n }\n if (url.username || url.password || url.search || url.hash) {\n throw configurationError(\n \"baseUrl cannot include credentials, a query, or a fragment\",\n );\n }\n return url.toString().replace(/\\/$/, \"\");\n}\n\nfunction validateTimeout(value: number): number {\n if (!Number.isInteger(value) || value < 1_000 || value > 60_000) {\n throw configurationError(\n \"timeoutMs must be an integer from 1000 through 60000\",\n );\n }\n return value;\n}\n\nfunction validateToken(value: string): string {\n if (\n typeof value !== \"string\" ||\n !value ||\n value.length > MAX_TOKEN_LENGTH ||\n /[\\r\\n]/.test(value)\n ) {\n throw configurationError(\"The customer access token is invalid\");\n }\n return value;\n}\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw configurationError(`${name} must be a positive integer`);\n }\n return value;\n}\n\nfunction validateMessage(value: string): string {\n if (typeof value !== \"string\") {\n throw configurationError(\"Message content must be a string\");\n }\n const normalized = value.trim();\n if (!normalized || normalized.length > MAX_MESSAGE_LENGTH) {\n throw configurationError(\n `Message content must be 1 to ${MAX_MESSAGE_LENGTH} characters`,\n );\n }\n return normalized;\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n const declaredLength = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(declaredLength) && declaredLength > MAX_RESPONSE_BYTES) {\n throw responseTooLarge();\n }\n\n const body = response.body;\n if (\n body &&\n typeof body.getReader === \"function\" &&\n typeof TextDecoder === \"function\"\n ) {\n return parseJson(await readStream(body));\n }\n\n let text: string;\n try {\n text = await response.text();\n } catch {\n throw invalidResponse();\n }\n if (utf8LengthExceeds(text, MAX_RESPONSE_BYTES)) {\n throw responseTooLarge();\n }\n return parseJson(text);\n}\n\nasync function readStream(body: ReadableStream<Uint8Array>): Promise<string> {\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > MAX_RESPONSE_BYTES) {\n await reader.cancel();\n throw responseTooLarge();\n }\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n const bytes = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(bytes);\n}\n\nfunction parseJson(text: string): unknown {\n if (!text) return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw invalidResponse();\n }\n}\n\nfunction utf8LengthExceeds(value: string, maximum: number): boolean {\n let bytes = 0;\n for (let index = 0; index < value.length; index += 1) {\n const codeUnit = value.charCodeAt(index);\n if (codeUnit < 0x80) bytes += 1;\n else if (codeUnit < 0x800) bytes += 2;\n else if (\n codeUnit >= 0xd800 &&\n codeUnit <= 0xdbff &&\n index + 1 < value.length &&\n value.charCodeAt(index + 1) >= 0xdc00 &&\n value.charCodeAt(index + 1) <= 0xdfff\n ) {\n bytes += 4;\n index += 1;\n } else bytes += 3;\n if (bytes > maximum) return true;\n }\n return false;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction responseTooLarge(): DaykeeperReactNativeTransportError {\n return new DaykeeperReactNativeTransportError({\n code: \"RESPONSE_TOO_LARGE\",\n message: \"The Daykeeper response exceeded 1 MiB\",\n });\n}\n\nfunction invalidResponse(): DaykeeperReactNativeTransportError {\n return new DaykeeperReactNativeTransportError({\n code: \"INVALID_RESPONSE\",\n message: \"The Daykeeper customer API returned invalid JSON\",\n retryable: true,\n });\n}\n\nfunction configurationError(\n message: string,\n): DaykeeperReactNativeTransportError {\n return new DaykeeperReactNativeTransportError({\n code: \"INVALID_CONFIGURATION\",\n message,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,IAAM,+BAAN,cAA2C,MAAM;AAAA,EAKtD,YAAY,SAA+D;AACzE,UAAM,QAAQ,IAAI;AALpB,wBAAS;AACT,wBAAS;AACT,wBAAS;AAIP,SAAK,OAAO;AACZ,SAAK,SAAS,QAAQ;AACtB,SAAK,OAAO,QAAQ;AACpB,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA,EAEA,SAKE;AACA,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,IAClB;AAAA,EACF;AACF;AAEO,IAAM,qCAAN,cAAiD,MAAM;AAAA,EAI5D,YAAY,SAIT;AACD,UAAM,QAAQ,OAAO;AARvB,wBAAS;AACT,wBAAS;AAQP,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ;AACpB,SAAK,YAAY,QAAQ,aAAa;AAAA,EACxC;AAAA,EAEA,SAKE;AACA,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,WAAW,KAAK;AAAA,IAClB;AAAA,EACF;AACF;;;ACjDA,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB,OAAO;AAClC,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAlB3B;AA2CO,IAAM,6BAAN,MAAiC;AAAA,EAMtC,YAAY,SAA4C;AANnD;AACL,uBAAS;AACT,uBAAS;AACT,uBAAS;AACT,uBAAS;AAGP,uBAAK,UAAW,aAAa,QAAQ,OAAO;AAC5C,uBAAK,QAAS,QAAQ,SAAS,WAAW;AAC1C,QAAI,OAAO,mBAAK,YAAW,YAAY;AACrC,YAAM,mBAAmB,wCAAwC;AAAA,IACnE;AACA,QAAI,OAAO,QAAQ,mBAAmB,YAAY;AAChD,YAAM,mBAAmB,mCAAmC;AAAA,IAC9D;AACA,uBAAK,iBAAkB,QAAQ;AAC/B,uBAAK,YAAa,gBAAgB,QAAQ,aAAa,kBAAkB;AAAA,EAC3E;AAAA,EAEA,YACE,SACoC;AACpC,WAAO,sBAAK,mDAAL,WAAc,gBAAgB,EAAE,QAAQ,SAAS,OAAO;AAAA,EACjE;AAAA,EAEA,kBACE,SACoC;AACpC,WAAO,sBAAK,mDAAL,WAAc,qBAAqB,EAAE,QAAQ,SAAS,OAAO;AAAA,EACtE;AAAA,EAEA,mBACE,SACsC;AACtC,WAAO,sBAAK,mDAAL,WAAc,qBAAqB;AAAA,MACxC,QAAQ;AAAA,MACR,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,UACE,SACiC;AACjC,WAAO,sBAAK,mDAAL,WAAc,cAAc,EAAE,QAAQ,SAAS,OAAO;AAAA,EAC/D;AAAA,EAEA,qBACE,gBACA,SAC8B;AAC9B,WAAO,sBAAK,mDAAL,WACL,qBAAqB,gBAAgB,gBAAgB,gBAAgB,CAAC,SACtE,EAAE,QAAQ,QAAQ,QAAQ,SAAS,OAAO;AAAA,EAE9C;AAAA,EAEA,aACE,gBACA,UAAmE,CAAC,GACrC;AAC/B,UAAM,KAAK,gBAAgB,gBAAgB,gBAAgB;AAC3D,UAAM,QACJ,QAAQ,UAAU,SACd,KACA,UAAU,gBAAgB,QAAQ,OAAO,OAAO,CAAC;AACvD,WAAO,sBAAK,mDAAL,WAAc,qBAAqB,EAAE,YAAY,KAAK,IAAI;AAAA,MAC/D,QAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AAAA,EAEA,YACE,gBACA,SACA,SACiC;AACjC,UAAM,oBAAoB,gBAAgB,OAAO;AACjD,WAAO,sBAAK,mDAAL,WACL,qBAAqB,gBAAgB,gBAAgB,gBAAgB,CAAC,aACtE;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,EAAE,SAAS,kBAAkB;AAAA,MACnC,QAAQ,SAAS;AAAA,IACnB;AAAA,EAEJ;AAAA,EAEA,2BACE,aACA,SAC2C;AAC3C,QACE,OAAO,gBAAgB,YACvB,CAAC,YAAY,KAAK,KAClB,YAAY,SAAS,kBACrB;AACA,YAAM,mBAAmB,wBAAwB;AAAA,IACnD;AACA,WAAO,sBAAK,mDAAL,WAAc,qCAAqC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM,EAAE,aAAa,YAAY,KAAK,EAAE;AAAA,MACxC,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAiGF;AAtMW;AACA;AACA;AACA;AAJJ;AAwGC,aAAsB,eAC1B,MACA,UAII,CAAC,GACkB;AACvB,QAAM,oBAAoB,IAAI,gBAAgB;AAC9C,MAAI,WAAW;AACf,QAAM,UAAU,WAAW,MAAM;AAC/B,eAAW;AACX,sBAAkB,MAAM;AAAA,EAC1B,GAAG,mBAAK,WAAU;AAClB,QAAM,gBAAgB,MAAM,kBAAkB,MAAM;AACpD,MAAI,QAAQ,QAAQ,QAAS,mBAAkB,MAAM;AAAA;AAEnD,YAAQ,QAAQ,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;AAEzE,MAAI;AACF,aAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,YAAM,QAAQ;AAAA,QACZ,MAAM,mBAAK,iBAAL,WAAqB,EAAE,cAAc,YAAY,EAAE;AAAA,MAC3D;AACA,YAAM,UAAU,IAAI,QAAQ;AAAA,QAC1B,QAAQ;AAAA,QACR,eAAe,UAAU,KAAK;AAAA,MAChC,CAAC;AACD,UAAI,QAAQ,SAAS,QAAW;AAC9B,gBAAQ,IAAI,gBAAgB,kBAAkB;AAAA,MAChD;AAEA,UAAI;AACJ,UAAI;AACF,mBAAW,MAAM,mBAAK,QAAL,WAAY,GAAG,mBAAK,SAAQ,GAAG,IAAI,IAAI;AAAA,UACtD,QAAQ,QAAQ,UAAU;AAAA,UAC1B,MACE,QAAQ,SAAS,SACb,SACA,KAAK,UAAU,QAAQ,IAAI;AAAA,UACjC;AAAA,UACA,QAAQ,kBAAkB;AAAA,QAC5B;AAAA,MACF,QAAQ;AACN,YAAI,UAAU;AACZ,gBAAM,IAAI,mCAAmC;AAAA,YAC3C,MAAM;AAAA,YACN,SAAS,kCAAkC,mBAAK,WAAU;AAAA,YAC1D,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA,YAAI,QAAQ,QAAQ,SAAS;AAC3B,gBAAM,IAAI,mCAAmC;AAAA,YAC3C,MAAM;AAAA,YACN,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AACA,cAAM,IAAI,mCAAmC;AAAA,UAC3C,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAEA,YAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,UAAI,SAAS,WAAW,OAAO,YAAY,EAAG;AAC9C,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,OACJ,SAAS,OAAO,KAAK,OAAO,QAAQ,UAAU,WAC1C,QAAQ,QACR;AACN,cAAM,IAAI,6BAA6B;AAAA,UACrC,QAAQ,SAAS;AAAA,UACjB;AAAA,UACA,WACE,SAAS,WAAW,OACpB,SAAS,WAAW,OACpB,SAAS,UAAU;AAAA,QACvB,CAAC;AAAA,MACH;AACA,UAAI,CAAC,SAAS,OAAO,GAAG;AACtB,cAAM,IAAI,mCAAmC;AAAA,UAC3C,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AACA,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD,UAAE;AACA,iBAAa,OAAO;AACpB,YAAQ,QAAQ,oBAAoB,SAAS,aAAa;AAAA,EAC5D;AACF;AAGK,SAAS,iCACd,SAC4B;AAC5B,SAAO,IAAI,2BAA2B,OAAO;AAC/C;AAEA,SAAS,aAAa,OAAuB;AAC3C,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,KAAK;AAAA,EACrB,QAAQ;AACN,UAAM,mBAAmB,sCAAsC;AAAA,EACjE;AACA,QAAM,QAAQ,CAAC,aAAa,aAAa,KAAK,EAAE,SAAS,IAAI,QAAQ;AACrE,MAAI,IAAI,aAAa,YAAY,EAAE,SAAS,IAAI,aAAa,UAAU;AACrE,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,UAAU,IAAI,MAAM;AAC1D,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,SAAO,IAAI,SAAS,EAAE,QAAQ,OAAO,EAAE;AACzC;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,OAAS,QAAQ,KAAQ;AAC/D,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,OAAuB;AAC5C,MACE,OAAO,UAAU,YACjB,CAAC,SACD,MAAM,SAAS,oBACf,SAAS,KAAK,KAAK,GACnB;AACA,UAAM,mBAAmB,sCAAsC;AAAA,EACjE;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAe,MAAsB;AAC5D,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACzC,UAAM,mBAAmB,GAAG,IAAI,6BAA6B;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,mBAAmB,kCAAkC;AAAA,EAC7D;AACA,QAAM,aAAa,MAAM,KAAK;AAC9B,MAAI,CAAC,cAAc,WAAW,SAAS,oBAAoB;AACzD,UAAM;AAAA,MACJ,gCAAgC,kBAAkB;AAAA,IACpD;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,SAAS,UAAsC;AAC5D,QAAM,iBAAiB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC;AACpE,MAAI,OAAO,SAAS,cAAc,KAAK,iBAAiB,oBAAoB;AAC1E,UAAM,iBAAiB;AAAA,EACzB;AAEA,QAAM,OAAO,SAAS;AACtB,MACE,QACA,OAAO,KAAK,cAAc,cAC1B,OAAO,gBAAgB,YACvB;AACA,WAAO,UAAU,MAAM,WAAW,IAAI,CAAC;AAAA,EACzC;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B,QAAQ;AACN,UAAM,gBAAgB;AAAA,EACxB;AACA,MAAI,kBAAkB,MAAM,kBAAkB,GAAG;AAC/C,UAAM,iBAAiB;AAAA,EACzB;AACA,SAAO,UAAU,IAAI;AACvB;AAEA,eAAe,WAAW,MAAmD;AAC3E,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,SAAuB,CAAC;AAC9B,MAAI,QAAQ;AACZ,MAAI;AACF,eAAS;AACP,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,eAAS,MAAM;AACf,UAAI,QAAQ,oBAAoB;AAC9B,cAAM,OAAO,OAAO;AACpB,cAAM,iBAAiB;AAAA,MACzB;AACA,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AAEA,QAAM,QAAQ,IAAI,WAAW,KAAK;AAClC,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,UAAM,IAAI,OAAO,MAAM;AACvB,cAAU,MAAM;AAAA,EAClB;AACA,SAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AACvC;AAEA,SAAS,UAAU,MAAuB;AACxC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,UAAM,gBAAgB;AAAA,EACxB;AACF;AAEA,SAAS,kBAAkB,OAAe,SAA0B;AAClE,MAAI,QAAQ;AACZ,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;AACpD,UAAM,WAAW,MAAM,WAAW,KAAK;AACvC,QAAI,WAAW,IAAM,UAAS;AAAA,aACrB,WAAW,KAAO,UAAS;AAAA,aAElC,YAAY,SACZ,YAAY,SACZ,QAAQ,IAAI,MAAM,UAClB,MAAM,WAAW,QAAQ,CAAC,KAAK,SAC/B,MAAM,WAAW,QAAQ,CAAC,KAAK,OAC/B;AACA,eAAS;AACT,eAAS;AAAA,IACX,MAAO,UAAS;AAChB,QAAI,QAAQ,QAAS,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,mBAAuD;AAC9D,SAAO,IAAI,mCAAmC;AAAA,IAC5C,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AACH;AAEA,SAAS,kBAAsD;AAC7D,SAAO,IAAI,mCAAmC;AAAA,IAC5C,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,mBACP,SACoC;AACpC,SAAO,IAAI,mCAAmC;AAAA,IAC5C,MAAM;AAAA,IACN;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/requestLifetime.ts","../src/client.ts"],"sourcesContent":["export {\n createDaykeeperReactNativeClient,\n DaykeeperReactNativeClient,\n} from \"./client.js\";\nexport type {\n DaykeeperReactNativeClientOptions,\n DaykeeperReactNativeRequestOptions,\n DaykeeperReactNativeTokenProvider,\n DaykeeperReactNativeTokenProviderContext,\n} from \"./client.js\";\nexport {\n DaykeeperReactNativeApiError,\n DaykeeperReactNativeTransportError,\n} from \"./errors.js\";\nexport type {\n DaykeeperReactNativeNextAction,\n DaykeeperReactNativeTransportErrorCode,\n} from \"./errors.js\";\nexport type {\n components as DaykeeperCustomerOpenApiComponents,\n operations as DaykeeperCustomerOpenApiOperations,\n paths as DaykeeperCustomerOpenApiPaths,\n} from \"./generated/schema.js\";\nexport * from \"./types.js\";\n","export type DaykeeperReactNativeTransportErrorCode =\n | \"INVALID_CONFIGURATION\"\n | \"TOKEN_PROVIDER_ERROR\"\n | \"NETWORK_ERROR\"\n | \"REQUEST_ABORTED\"\n | \"REQUEST_TIMEOUT\"\n | \"INVALID_RESPONSE\"\n | \"RESPONSE_TOO_LARGE\";\n\n// Error bodies are untrusted, so a code is only allowed through when its\n// *shape* proves it is a code and not prose, a token, or an identifier: ASCII\n// lowercase snake_case, 3 to 64 characters. The gateway's error vocabulary is\n// open and grows without an SDK release, so an allowlist would silently\n// collapse codes that consuming apps switch on. Anything failing the shape --\n// free-form English messages, mixed case, punctuation, whitespace, non-string\n// values -- is replaced with the generic code below. Message projection is\n// unchanged: the error message is the code itself, never raw body text.\nconst API_CODE_SHAPE = /^[a-z][a-z0-9_]{2,63}$/;\n\nexport const DAYKEEPER_GENERIC_API_CODE = \"daykeeper_request_failed\";\n\n/** True when `value` has the documented customer API error-code shape. */\nexport function isDaykeeperApiErrorCode(value: unknown): value is string {\n return typeof value === \"string\" && API_CODE_SHAPE.test(value);\n}\n\n/**\n * Contract-documented next steps. The envelope is open and its values are\n * extensible, so an unrecognized hint is dropped rather than surfaced: a\n * gateway string is untrusted and none of these grant account authority.\n *\n * This is deliberately narrower than the error-code rule above. A code is only\n * ever compared by the app, so an unknown one is inert; a next action is a UI\n * instruction the app acts on, so only the three the contract defines are\n * allowed through.\n */\nexport type DaykeeperReactNativeNextAction =\n \"review_usage\" | \"review_setup\" | \"refresh_conversation\";\n\nconst SAFE_NEXT_ACTIONS = new Set<string>([\n \"review_usage\",\n \"review_setup\",\n \"refresh_conversation\",\n]);\n\nexport class DaykeeperReactNativeApiError extends Error {\n readonly status: number;\n readonly code: string;\n readonly retryable: boolean;\n readonly outcomeUnknown: boolean;\n readonly nextAction?: DaykeeperReactNativeNextAction;\n\n constructor(options: {\n status: number;\n code?: unknown;\n nextAction?: unknown;\n retryable?: boolean;\n outcomeUnknown?: boolean;\n }) {\n const code = isDaykeeperApiErrorCode(options.code)\n ? options.code\n : DAYKEEPER_GENERIC_API_CODE;\n super(code);\n this.name = \"DaykeeperReactNativeApiError\";\n this.status = options.status;\n this.code = code;\n this.outcomeUnknown = options.outcomeUnknown ?? false;\n this.retryable = !this.outcomeUnknown && (options.retryable ?? false);\n if (\n typeof options.nextAction === \"string\" &&\n SAFE_NEXT_ACTIONS.has(options.nextAction)\n ) {\n this.nextAction = options.nextAction as DaykeeperReactNativeNextAction;\n }\n }\n\n toJSON(): {\n name: string;\n status: number;\n code: string;\n retryable: boolean;\n outcomeUnknown: boolean;\n nextAction?: DaykeeperReactNativeNextAction;\n } {\n return {\n name: this.name,\n status: this.status,\n code: this.code,\n retryable: this.retryable,\n outcomeUnknown: this.outcomeUnknown,\n ...(this.nextAction === undefined ? {} : { nextAction: this.nextAction }),\n };\n }\n}\n\nexport class DaykeeperReactNativeTransportError extends Error {\n readonly code: DaykeeperReactNativeTransportErrorCode;\n readonly retryable: boolean;\n readonly outcomeUnknown: boolean;\n\n constructor(options: {\n code: DaykeeperReactNativeTransportErrorCode;\n message: string;\n retryable?: boolean;\n outcomeUnknown?: boolean;\n }) {\n super(options.message);\n this.name = \"DaykeeperReactNativeTransportError\";\n this.code = options.code;\n this.outcomeUnknown = options.outcomeUnknown ?? false;\n this.retryable = !this.outcomeUnknown && (options.retryable ?? false);\n }\n\n toJSON(): {\n name: string;\n code: DaykeeperReactNativeTransportErrorCode;\n message: string;\n retryable: boolean;\n outcomeUnknown: boolean;\n } {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n retryable: this.retryable,\n outcomeUnknown: this.outcomeUnknown,\n };\n }\n}\n","import { DaykeeperReactNativeTransportError } from \"./errors.js\";\n\n// One budget covers credentials, both authentication attempts, and the body.\n// Aborting fetch alone cannot bound a provider or custom transport that stalls.\nexport function createRequestLifetime(timeoutMs: number, caller?: AbortSignal) {\n const controller = new AbortController();\n const now = () =>\n typeof performance === \"undefined\" ? Date.now() : performance.now();\n const deadline = now() + timeoutMs;\n let failure: DaykeeperReactNativeTransportError | undefined;\n const abort = (code: \"REQUEST_ABORTED\" | \"REQUEST_TIMEOUT\") => {\n if (failure) return;\n failure = new DaykeeperReactNativeTransportError({\n code,\n message:\n code === \"REQUEST_TIMEOUT\"\n ? `The Daykeeper request exceeded ${timeoutMs}ms`\n : \"The Daykeeper request was aborted\",\n retryable: code === \"REQUEST_TIMEOUT\",\n });\n controller.abort();\n };\n const onCallerAbort = () => abort(\"REQUEST_ABORTED\");\n if (caller?.aborted) onCallerAbort();\n else caller?.addEventListener(\"abort\", onCallerAbort, { once: true });\n const timeout = failure\n ? undefined\n : setTimeout(() => abort(\"REQUEST_TIMEOUT\"), timeoutMs);\n const checkDeadline = () => {\n if (!failure && now() >= deadline) abort(\"REQUEST_TIMEOUT\");\n };\n\n return {\n signal: controller.signal,\n run<T>(\n work: () => T | PromiseLike<T>,\n onLateValue?: (value: T) => void,\n ): Promise<T> {\n checkDeadline();\n if (failure) return Promise.reject(failure);\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n const finish = () => {\n settled = true;\n controller.signal.removeEventListener(\"abort\", onAbort);\n };\n const onAbort = () => {\n finish();\n reject(failure);\n };\n controller.signal.addEventListener(\"abort\", onAbort, { once: true });\n Promise.resolve()\n .then(() => {\n // Do not start work queued before an abort, or send with a late token.\n checkDeadline();\n if (failure) throw failure;\n return work();\n })\n .then(\n (value) => {\n checkDeadline();\n if (settled) {\n try {\n onLateValue?.(value);\n } catch {\n // Late cleanup must not cause an unhandled rejection.\n }\n return;\n }\n finish();\n resolve(value);\n },\n (error: unknown) => {\n if (settled) return;\n finish();\n reject(error);\n },\n );\n });\n },\n dispose() {\n clearTimeout(timeout);\n caller?.removeEventListener(\"abort\", onCallerAbort);\n },\n };\n}\n\n// Cleanup must not delay timeout/error delivery, including with custom streams.\nexport function discardResponse(response: Response): void {\n try {\n void response.body?.cancel().catch(() => undefined);\n } catch {\n // A consumed/locked or non-streaming body may not support cancellation.\n }\n}\n\nexport function discardReader(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n): void {\n try {\n void reader.cancel().catch(() => undefined);\n } catch {\n // A failed transport may already have released the reader.\n }\n try {\n reader.releaseLock();\n } catch {\n // Some stream polyfills cannot release a pending read. Preserve the\n // original timeout/abort/error even when their cleanup is unsupported.\n }\n}\n","import {\n DaykeeperReactNativeApiError,\n DaykeeperReactNativeTransportError,\n} from \"./errors.js\";\nimport {\n createRequestLifetime,\n discardResponse,\n discardReader,\n} from \"./requestLifetime.js\";\nimport type {\n DaykeeperClaimConversationResult,\n DaykeeperConversationList,\n DaykeeperConversationResult,\n DaykeeperCustomerIdentity,\n DaykeeperMessageList,\n DaykeeperMessageResult,\n DaykeeperSeenResult,\n DaykeeperUnreadSummary,\n} from \"./types.js\";\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst MAX_RESPONSE_BYTES = 1024 * 1024;\nconst MAX_TOKEN_LENGTH = 16_384;\nconst MAX_MESSAGE_LENGTH = 16_000;\n\nexport interface DaykeeperReactNativeTokenProviderContext {\n /**\n * True only after a GET rejected the first token with HTTP 401 and did not\n * explicitly forbid replay with retryable: false. The\n * provider should bypass any token cache and exchange the app session again.\n */\n forceRefresh: boolean;\n /** Cancel credential exchange when the request is aborted or expires. */\n signal?: AbortSignal;\n}\n\nexport type DaykeeperReactNativeTokenProvider = (\n context: DaykeeperReactNativeTokenProviderContext,\n) => string | Promise<string>;\n\nexport interface DaykeeperReactNativeClientOptions {\n baseUrl: string;\n getAccessToken: DaykeeperReactNativeTokenProvider;\n /** Must reject redirects, omit ambient cookies, and honor cache policy. */\n fetch?: typeof globalThis.fetch;\n timeoutMs?: number;\n}\n\nexport interface DaykeeperReactNativeRequestOptions {\n signal?: AbortSignal;\n}\n\nexport class DaykeeperReactNativeClient {\n readonly #baseUrl: string;\n readonly #fetch: typeof globalThis.fetch;\n readonly #getAccessToken: DaykeeperReactNativeTokenProvider;\n readonly #timeoutMs: number;\n\n constructor(options: DaykeeperReactNativeClientOptions) {\n this.#baseUrl = parseBaseUrl(options.baseUrl);\n this.#fetch = options.fetch ?? globalThis.fetch;\n if (typeof this.#fetch !== \"function\") {\n throw configurationError(\"A Fetch API implementation is required\");\n }\n if (typeof options.getAccessToken !== \"function\") {\n throw configurationError(\"getAccessToken must be a function\");\n }\n this.#getAccessToken = options.getAccessToken;\n this.#timeoutMs = validateTimeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n }\n\n getIdentity(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperCustomerIdentity> {\n return this.#request(\"/v1/identity\", { signal: options?.signal });\n }\n\n listConversations(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperConversationList> {\n return this.#request(\"/v1/conversations\", { signal: options?.signal });\n }\n\n createConversation(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperConversationResult> {\n return this.#request(\"/v1/conversations\", {\n method: \"POST\",\n signal: options?.signal,\n });\n }\n\n getUnread(\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperUnreadSummary> {\n return this.#request(\"/v1/unread\", { signal: options?.signal });\n }\n\n markConversationSeen(\n conversationId: number,\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperSeenResult> {\n return this.#request(\n `/v1/conversations/${positiveInteger(conversationId, \"conversationId\")}/seen`,\n { method: \"POST\", signal: options?.signal },\n );\n }\n\n listMessages(\n conversationId: number,\n options: DaykeeperReactNativeRequestOptions & { after?: number } = {},\n ): Promise<DaykeeperMessageList> {\n const id = positiveInteger(conversationId, \"conversationId\");\n const after =\n options.after === undefined\n ? \"\"\n : `?after=${positiveInteger(options.after, \"after\")}`;\n return this.#request(`/v1/conversations/${id}/messages${after}`, {\n signal: options.signal,\n });\n }\n\n sendMessage(\n conversationId: number,\n content: string,\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperMessageResult> {\n const normalizedContent = validateMessage(content);\n return this.#request(\n `/v1/conversations/${positiveInteger(conversationId, \"conversationId\")}/messages`,\n {\n method: \"POST\",\n body: { content: normalizedContent },\n signal: options?.signal,\n },\n );\n }\n\n claimAnonymousConversation(\n widgetToken: string,\n options?: DaykeeperReactNativeRequestOptions,\n ): Promise<DaykeeperClaimConversationResult> {\n if (\n typeof widgetToken !== \"string\" ||\n !widgetToken.trim() ||\n widgetToken.length > MAX_TOKEN_LENGTH\n ) {\n throw configurationError(\"widgetToken is invalid\");\n }\n return this.#request(\"/v1/anonymous-conversations/claim\", {\n method: \"POST\",\n body: { widgetToken: widgetToken.trim() },\n signal: options?.signal,\n });\n }\n\n async #request<ResponseBody>(\n path: string,\n options: {\n method?: \"GET\" | \"POST\";\n body?: unknown;\n signal?: AbortSignal;\n } = {},\n ): Promise<ResponseBody> {\n const lifetime = createRequestLifetime(this.#timeoutMs, options.signal);\n const method = options.method ?? \"GET\";\n const mutating = method !== \"GET\";\n const attempts = mutating ? 1 : 2;\n let dispatched = false;\n let response: Response | undefined;\n\n try {\n for (let attempt = 0; attempt < attempts; attempt += 1) {\n const token = validateToken(\n await lifetime.run(() =>\n resolveToken(this.#getAccessToken, {\n forceRefresh: attempt === 1,\n signal: lifetime.signal,\n }),\n ),\n );\n const headers = new Headers({\n accept: \"application/json\",\n authorization: `Bearer ${token}`,\n });\n if (options.body !== undefined) {\n headers.set(\"content-type\", \"application/json\");\n }\n\n try {\n response = await lifetime.run(() => {\n dispatched = true;\n return this.#fetch(`${this.#baseUrl}${path}`, {\n method,\n body:\n options.body === undefined\n ? undefined\n : JSON.stringify(options.body),\n headers,\n signal: lifetime.signal,\n redirect: \"error\",\n credentials: \"omit\",\n cache: \"no-store\",\n });\n }, discardResponse);\n } catch (error) {\n if (error instanceof DaykeeperReactNativeTransportError) throw error;\n throw networkError();\n }\n\n // A read that may still refresh its credentials once, on the first\n // 401 only, unless the server explicitly forbids the replay.\n const refreshCandidate =\n !mutating && response.status === 401 && attempt === 0;\n\n let payload: unknown;\n if (refreshCandidate || !response.ok) {\n // The HTTP status decides the outcome, so the body is read for\n // advice only. A gateway, proxy or CDN can answer any error status\n // with an HTML page instead of the contract envelope; parsing that\n // first used to throw INVALID_RESPONSE and lose both the status and,\n // on a 401, the one permitted credential refresh.\n try {\n payload = await readJson(response, lifetime);\n } catch (error) {\n // Only a completed, unparseable body is tolerated. Failed,\n // stalled, oversized, or cancelled reads never authorize a replay.\n if (\n !(error instanceof DaykeeperReactNativeTransportError) ||\n error.code !== \"INVALID_RESPONSE\"\n )\n throw error;\n }\n } else {\n payload = await readJson(response, lifetime);\n }\n if (\n refreshCandidate &&\n !(isRecord(payload) && payload.retryable === false)\n ) {\n discardResponse(response);\n continue;\n }\n if (!response.ok) {\n throw new DaykeeperReactNativeApiError({\n status: response.status,\n code: isRecord(payload) ? payload.error : undefined,\n // The contract's message stays unread; only the bounded\n // nextAction vocabulary is projected.\n nextAction: isRecord(payload) ? payload.nextAction : undefined,\n retryable:\n !mutating &&\n (isRecord(payload) && typeof payload.retryable === \"boolean\"\n ? payload.retryable\n : response.status === 408 ||\n response.status === 429 ||\n response.status >= 500),\n outcomeUnknown:\n mutating && (response.status === 408 || response.status >= 500),\n });\n }\n if (!isRecord(payload)) {\n throw new DaykeeperReactNativeTransportError({\n code: \"INVALID_RESPONSE\",\n message: \"The Daykeeper customer API returned an invalid response\",\n retryable: true,\n });\n }\n return payload as ResponseBody;\n }\n throw new Error(\"Unreachable Daykeeper request state\");\n } catch (error) {\n if (error instanceof DaykeeperReactNativeApiError) throw error;\n const safeError =\n error instanceof DaykeeperReactNativeTransportError\n ? error\n : networkError();\n if (!mutating) throw safeError;\n throw new DaykeeperReactNativeTransportError({\n code: safeError.code,\n message: safeError.message,\n retryable: false,\n outcomeUnknown: dispatched,\n });\n } finally {\n if (response) discardResponse(response);\n lifetime.dispose();\n }\n }\n}\n\nexport function createDaykeeperReactNativeClient(\n options: DaykeeperReactNativeClientOptions,\n): DaykeeperReactNativeClient {\n return new DaykeeperReactNativeClient(options);\n}\n\nasync function resolveToken(\n provider: DaykeeperReactNativeTokenProvider,\n context: DaykeeperReactNativeTokenProviderContext,\n): Promise<string> {\n try {\n return await provider(context);\n } catch {\n throw new DaykeeperReactNativeTransportError({\n code: \"TOKEN_PROVIDER_ERROR\",\n message: \"The Daykeeper access token could not be obtained\",\n });\n }\n}\n\nfunction networkError(): DaykeeperReactNativeTransportError {\n return new DaykeeperReactNativeTransportError({\n code: \"NETWORK_ERROR\",\n message: \"The Daykeeper customer API transport failed\",\n retryable: true,\n });\n}\n\nfunction parseBaseUrl(value: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw configurationError(\"baseUrl must be a valid absolute URL\");\n }\n // URL.hostname keeps the brackets around an IPv6 literal, so a bare \"::1\"\n // comparison never matched http://[::1]:3002 and rejected local development.\n const hostname = url.hostname.replace(/^\\[(.+)]$/, \"$1\").toLowerCase();\n const local = [\"localhost\", \"127.0.0.1\", \"::1\"].includes(hostname);\n if (url.protocol !== \"https:\" && !(local && url.protocol === \"http:\")) {\n throw configurationError(\n \"baseUrl must use HTTPS except for loopback development\",\n );\n }\n if (url.username || url.password || url.search || url.hash) {\n throw configurationError(\n \"baseUrl cannot include credentials, a query, or a fragment\",\n );\n }\n return url.toString().replace(/\\/$/, \"\");\n}\n\nfunction validateTimeout(value: number): number {\n if (!Number.isInteger(value) || value < 1_000 || value > 60_000) {\n throw configurationError(\n \"timeoutMs must be an integer from 1000 through 60000\",\n );\n }\n return value;\n}\n\nfunction validateToken(value: string): string {\n if (\n typeof value !== \"string\" ||\n !value ||\n value.length > MAX_TOKEN_LENGTH ||\n /[\\r\\n]/.test(value)\n ) {\n throw configurationError(\"The customer access token is invalid\");\n }\n return value;\n}\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw configurationError(`${name} must be a positive integer`);\n }\n return value;\n}\n\nfunction validateMessage(value: string): string {\n if (typeof value !== \"string\") {\n throw configurationError(\"Message content must be a string\");\n }\n const normalized = value.trim();\n if (!normalized || normalized.length > MAX_MESSAGE_LENGTH) {\n throw configurationError(\n `Message content must be 1 to ${MAX_MESSAGE_LENGTH} characters`,\n );\n }\n return normalized;\n}\n\nasync function readJson(\n response: Response,\n lifetime: ReturnType<typeof createRequestLifetime>,\n): Promise<unknown> {\n const declaredLength = Number(response.headers.get(\"content-length\"));\n if (Number.isFinite(declaredLength) && declaredLength > MAX_RESPONSE_BYTES) {\n throw responseTooLarge();\n }\n\n const body = response.body;\n if (\n body &&\n typeof body.getReader === \"function\" &&\n typeof TextDecoder === \"function\"\n ) {\n return parseJson(await readStream(body, lifetime));\n }\n\n let text: string;\n try {\n text = await lifetime.run(() => response.text());\n } catch (error) {\n if (error instanceof DaykeeperReactNativeTransportError) throw error;\n throw networkError();\n }\n if (utf8LengthExceeds(text, MAX_RESPONSE_BYTES)) {\n throw responseTooLarge();\n }\n return parseJson(text);\n}\n\nasync function readStream(\n body: ReadableStream<Uint8Array>,\n lifetime: ReturnType<typeof createRequestLifetime>,\n): Promise<string> {\n const reader = body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n for (;;) {\n const { done, value } = await lifetime.run(() => reader.read());\n if (done) break;\n total += value.byteLength;\n if (total > MAX_RESPONSE_BYTES) {\n throw responseTooLarge();\n }\n chunks.push(value);\n }\n } catch (error) {\n if (error instanceof DaykeeperReactNativeTransportError) throw error;\n throw networkError();\n } finally {\n discardReader(reader);\n }\n\n const bytes = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return new TextDecoder().decode(bytes);\n}\n\nfunction parseJson(text: string): unknown {\n if (!text) return undefined;\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw invalidResponse();\n }\n}\n\nfunction utf8LengthExceeds(value: string, maximum: number): boolean {\n let bytes = 0;\n for (let index = 0; index < value.length; index += 1) {\n const codeUnit = value.charCodeAt(index);\n if (codeUnit < 0x80) bytes += 1;\n else if (codeUnit < 0x800) bytes += 2;\n else if (\n codeUnit >= 0xd800 &&\n codeUnit <= 0xdbff &&\n index + 1 < value.length &&\n value.charCodeAt(index + 1) >= 0xdc00 &&\n value.charCodeAt(index + 1) <= 0xdfff\n ) {\n bytes += 4;\n index += 1;\n } else bytes += 3;\n if (bytes > maximum) return true;\n }\n return false;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction responseTooLarge(): DaykeeperReactNativeTransportError {\n return new DaykeeperReactNativeTransportError({\n code: \"RESPONSE_TOO_LARGE\",\n message: \"The Daykeeper response exceeded 1 MiB\",\n });\n}\n\nfunction invalidResponse(): DaykeeperReactNativeTransportError {\n return new DaykeeperReactNativeTransportError({\n code: \"INVALID_RESPONSE\",\n message: \"The Daykeeper customer API returned invalid JSON\",\n retryable: true,\n });\n}\n\nfunction configurationError(\n message: string,\n): DaykeeperReactNativeTransportError {\n return new DaykeeperReactNativeTransportError({\n code: \"INVALID_CONFIGURATION\",\n message,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACiBA,IAAM,iBAAiB;AAEhB,IAAM,6BAA6B;AAGnC,SAAS,wBAAwB,OAAiC;AACvE,SAAO,OAAO,UAAU,YAAY,eAAe,KAAK,KAAK;AAC/D;AAeA,IAAM,oBAAoB,oBAAI,IAAY;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,+BAAN,cAA2C,MAAM;AAAA,EAOtD,YAAY,SAMT;AACD,UAAM,OAAO,wBAAwB,QAAQ,IAAI,IAC7C,QAAQ,OACR;AACJ,UAAM,IAAI;AAhBZ,wBAAS;AACT,wBAAS;AACT,wBAAS;AACT,wBAAS;AACT,wBAAS;AAaP,SAAK,OAAO;AACZ,SAAK,SAAS,QAAQ;AACtB,SAAK,OAAO;AACZ,SAAK,iBAAiB,QAAQ,kBAAkB;AAChD,SAAK,YAAY,CAAC,KAAK,mBAAmB,QAAQ,aAAa;AAC/D,QACE,OAAO,QAAQ,eAAe,YAC9B,kBAAkB,IAAI,QAAQ,UAAU,GACxC;AACA,WAAK,aAAa,QAAQ;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,SAOE;AACA,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,MAChB,gBAAgB,KAAK;AAAA,MACrB,GAAI,KAAK,eAAe,SAAY,CAAC,IAAI,EAAE,YAAY,KAAK,WAAW;AAAA,IACzE;AAAA,EACF;AACF;AAEO,IAAM,qCAAN,cAAiD,MAAM;AAAA,EAK5D,YAAY,SAKT;AACD,UAAM,QAAQ,OAAO;AAVvB,wBAAS;AACT,wBAAS;AACT,wBAAS;AASP,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ;AACpB,SAAK,iBAAiB,QAAQ,kBAAkB;AAChD,SAAK,YAAY,CAAC,KAAK,mBAAmB,QAAQ,aAAa;AAAA,EACjE;AAAA,EAEA,SAME;AACA,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,WAAW,KAAK;AAAA,MAChB,gBAAgB,KAAK;AAAA,IACvB;AAAA,EACF;AACF;;;AC5HO,SAAS,sBAAsB,WAAmB,QAAsB;AAC7E,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,MAAM,MACV,OAAO,gBAAgB,cAAc,KAAK,IAAI,IAAI,YAAY,IAAI;AACpE,QAAM,WAAW,IAAI,IAAI;AACzB,MAAI;AACJ,QAAM,QAAQ,CAAC,SAAgD;AAC7D,QAAI,QAAS;AACb,cAAU,IAAI,mCAAmC;AAAA,MAC/C;AAAA,MACA,SACE,SAAS,oBACL,kCAAkC,SAAS,OAC3C;AAAA,MACN,WAAW,SAAS;AAAA,IACtB,CAAC;AACD,eAAW,MAAM;AAAA,EACnB;AACA,QAAM,gBAAgB,MAAM,MAAM,iBAAiB;AACnD,MAAI,QAAQ,QAAS,eAAc;AAAA,MAC9B,SAAQ,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;AACpE,QAAM,UAAU,UACZ,SACA,WAAW,MAAM,MAAM,iBAAiB,GAAG,SAAS;AACxD,QAAM,gBAAgB,MAAM;AAC1B,QAAI,CAAC,WAAW,IAAI,KAAK,SAAU,OAAM,iBAAiB;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL,QAAQ,WAAW;AAAA,IACnB,IACE,MACA,aACY;AACZ,oBAAc;AACd,UAAI,QAAS,QAAO,QAAQ,OAAO,OAAO;AAC1C,aAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,YAAI,UAAU;AACd,cAAM,SAAS,MAAM;AACnB,oBAAU;AACV,qBAAW,OAAO,oBAAoB,SAAS,OAAO;AAAA,QACxD;AACA,cAAM,UAAU,MAAM;AACpB,iBAAO;AACP,iBAAO,OAAO;AAAA,QAChB;AACA,mBAAW,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACnE,gBAAQ,QAAQ,EACb,KAAK,MAAM;AAEV,wBAAc;AACd,cAAI,QAAS,OAAM;AACnB,iBAAO,KAAK;AAAA,QACd,CAAC,EACA;AAAA,UACC,CAAC,UAAU;AACT,0BAAc;AACd,gBAAI,SAAS;AACX,kBAAI;AACF,8BAAc,KAAK;AAAA,cACrB,QAAQ;AAAA,cAER;AACA;AAAA,YACF;AACA,mBAAO;AACP,oBAAQ,KAAK;AAAA,UACf;AAAA,UACA,CAAC,UAAmB;AAClB,gBAAI,QAAS;AACb,mBAAO;AACP,mBAAO,KAAK;AAAA,UACd;AAAA,QACF;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,IACA,UAAU;AACR,mBAAa,OAAO;AACpB,cAAQ,oBAAoB,SAAS,aAAa;AAAA,IACpD;AAAA,EACF;AACF;AAGO,SAAS,gBAAgB,UAA0B;AACxD,MAAI;AACF,SAAK,SAAS,MAAM,OAAO,EAAE,MAAM,MAAM,MAAS;AAAA,EACpD,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,cACd,QACM;AACN,MAAI;AACF,SAAK,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAAA,EAC5C,QAAQ;AAAA,EAER;AACA,MAAI;AACF,WAAO,YAAY;AAAA,EACrB,QAAQ;AAAA,EAGR;AACF;;;AC1FA,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB,OAAO;AAClC,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAvB3B;AAoDO,IAAM,6BAAN,MAAiC;AAAA,EAMtC,YAAY,SAA4C;AANnD;AACL,uBAAS;AACT,uBAAS;AACT,uBAAS;AACT,uBAAS;AAGP,uBAAK,UAAW,aAAa,QAAQ,OAAO;AAC5C,uBAAK,QAAS,QAAQ,SAAS,WAAW;AAC1C,QAAI,OAAO,mBAAK,YAAW,YAAY;AACrC,YAAM,mBAAmB,wCAAwC;AAAA,IACnE;AACA,QAAI,OAAO,QAAQ,mBAAmB,YAAY;AAChD,YAAM,mBAAmB,mCAAmC;AAAA,IAC9D;AACA,uBAAK,iBAAkB,QAAQ;AAC/B,uBAAK,YAAa,gBAAgB,QAAQ,aAAa,kBAAkB;AAAA,EAC3E;AAAA,EAEA,YACE,SACoC;AACpC,WAAO,sBAAK,mDAAL,WAAc,gBAAgB,EAAE,QAAQ,SAAS,OAAO;AAAA,EACjE;AAAA,EAEA,kBACE,SACoC;AACpC,WAAO,sBAAK,mDAAL,WAAc,qBAAqB,EAAE,QAAQ,SAAS,OAAO;AAAA,EACtE;AAAA,EAEA,mBACE,SACsC;AACtC,WAAO,sBAAK,mDAAL,WAAc,qBAAqB;AAAA,MACxC,QAAQ;AAAA,MACR,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,UACE,SACiC;AACjC,WAAO,sBAAK,mDAAL,WAAc,cAAc,EAAE,QAAQ,SAAS,OAAO;AAAA,EAC/D;AAAA,EAEA,qBACE,gBACA,SAC8B;AAC9B,WAAO,sBAAK,mDAAL,WACL,qBAAqB,gBAAgB,gBAAgB,gBAAgB,CAAC,SACtE,EAAE,QAAQ,QAAQ,QAAQ,SAAS,OAAO;AAAA,EAE9C;AAAA,EAEA,aACE,gBACA,UAAmE,CAAC,GACrC;AAC/B,UAAM,KAAK,gBAAgB,gBAAgB,gBAAgB;AAC3D,UAAM,QACJ,QAAQ,UAAU,SACd,KACA,UAAU,gBAAgB,QAAQ,OAAO,OAAO,CAAC;AACvD,WAAO,sBAAK,mDAAL,WAAc,qBAAqB,EAAE,YAAY,KAAK,IAAI;AAAA,MAC/D,QAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AAAA,EAEA,YACE,gBACA,SACA,SACiC;AACjC,UAAM,oBAAoB,gBAAgB,OAAO;AACjD,WAAO,sBAAK,mDAAL,WACL,qBAAqB,gBAAgB,gBAAgB,gBAAgB,CAAC,aACtE;AAAA,MACE,QAAQ;AAAA,MACR,MAAM,EAAE,SAAS,kBAAkB;AAAA,MACnC,QAAQ,SAAS;AAAA,IACnB;AAAA,EAEJ;AAAA,EAEA,2BACE,aACA,SAC2C;AAC3C,QACE,OAAO,gBAAgB,YACvB,CAAC,YAAY,KAAK,KAClB,YAAY,SAAS,kBACrB;AACA,YAAM,mBAAmB,wBAAwB;AAAA,IACnD;AACA,WAAO,sBAAK,mDAAL,WAAc,qCAAqC;AAAA,MACxD,QAAQ;AAAA,MACR,MAAM,EAAE,aAAa,YAAY,KAAK,EAAE;AAAA,MACxC,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AAuIF;AA5OW;AACA;AACA;AACA;AAJJ;AAwGC,aAAsB,eAC1B,MACA,UAII,CAAC,GACkB;AACvB,QAAM,WAAW,sBAAsB,mBAAK,aAAY,QAAQ,MAAM;AACtE,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,WAAW,WAAW;AAC5B,QAAM,WAAW,WAAW,IAAI;AAChC,MAAI,aAAa;AACjB,MAAI;AAEJ,MAAI;AACF,aAAS,UAAU,GAAG,UAAU,UAAU,WAAW,GAAG;AACtD,YAAM,QAAQ;AAAA,QACZ,MAAM,SAAS;AAAA,UAAI,MACjB,aAAa,mBAAK,kBAAiB;AAAA,YACjC,cAAc,YAAY;AAAA,YAC1B,QAAQ,SAAS;AAAA,UACnB,CAAC;AAAA,QACH;AAAA,MACF;AACA,YAAM,UAAU,IAAI,QAAQ;AAAA,QAC1B,QAAQ;AAAA,QACR,eAAe,UAAU,KAAK;AAAA,MAChC,CAAC;AACD,UAAI,QAAQ,SAAS,QAAW;AAC9B,gBAAQ,IAAI,gBAAgB,kBAAkB;AAAA,MAChD;AAEA,UAAI;AACF,mBAAW,MAAM,SAAS,IAAI,MAAM;AAClC,uBAAa;AACb,iBAAO,mBAAK,QAAL,WAAY,GAAG,mBAAK,SAAQ,GAAG,IAAI,IAAI;AAAA,YAC5C;AAAA,YACA,MACE,QAAQ,SAAS,SACb,SACA,KAAK,UAAU,QAAQ,IAAI;AAAA,YACjC;AAAA,YACA,QAAQ,SAAS;AAAA,YACjB,UAAU;AAAA,YACV,aAAa;AAAA,YACb,OAAO;AAAA,UACT;AAAA,QACF,GAAG,eAAe;AAAA,MACpB,SAAS,OAAO;AACd,YAAI,iBAAiB,mCAAoC,OAAM;AAC/D,cAAM,aAAa;AAAA,MACrB;AAIA,YAAM,mBACJ,CAAC,YAAY,SAAS,WAAW,OAAO,YAAY;AAEtD,UAAI;AACJ,UAAI,oBAAoB,CAAC,SAAS,IAAI;AAMpC,YAAI;AACF,oBAAU,MAAM,SAAS,UAAU,QAAQ;AAAA,QAC7C,SAAS,OAAO;AAGd,cACE,EAAE,iBAAiB,uCACnB,MAAM,SAAS;AAEf,kBAAM;AAAA,QACV;AAAA,MACF,OAAO;AACL,kBAAU,MAAM,SAAS,UAAU,QAAQ;AAAA,MAC7C;AACA,UACE,oBACA,EAAE,SAAS,OAAO,KAAK,QAAQ,cAAc,QAC7C;AACA,wBAAgB,QAAQ;AACxB;AAAA,MACF;AACA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,6BAA6B;AAAA,UACrC,QAAQ,SAAS;AAAA,UACjB,MAAM,SAAS,OAAO,IAAI,QAAQ,QAAQ;AAAA;AAAA;AAAA,UAG1C,YAAY,SAAS,OAAO,IAAI,QAAQ,aAAa;AAAA,UACrD,WACE,CAAC,aACA,SAAS,OAAO,KAAK,OAAO,QAAQ,cAAc,YAC/C,QAAQ,YACR,SAAS,WAAW,OACpB,SAAS,WAAW,OACpB,SAAS,UAAU;AAAA,UACzB,gBACE,aAAa,SAAS,WAAW,OAAO,SAAS,UAAU;AAAA,QAC/D,CAAC;AAAA,MACH;AACA,UAAI,CAAC,SAAS,OAAO,GAAG;AACtB,cAAM,IAAI,mCAAmC;AAAA,UAC3C,MAAM;AAAA,UACN,SAAS;AAAA,UACT,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AACA,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACvD,SAAS,OAAO;AACd,QAAI,iBAAiB,6BAA8B,OAAM;AACzD,UAAM,YACJ,iBAAiB,qCACb,QACA,aAAa;AACnB,QAAI,CAAC,SAAU,OAAM;AACrB,UAAM,IAAI,mCAAmC;AAAA,MAC3C,MAAM,UAAU;AAAA,MAChB,SAAS,UAAU;AAAA,MACnB,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH,UAAE;AACA,QAAI,SAAU,iBAAgB,QAAQ;AACtC,aAAS,QAAQ;AAAA,EACnB;AACF;AAGK,SAAS,iCACd,SAC4B;AAC5B,SAAO,IAAI,2BAA2B,OAAO;AAC/C;AAEA,eAAe,aACb,UACA,SACiB;AACjB,MAAI;AACF,WAAO,MAAM,SAAS,OAAO;AAAA,EAC/B,QAAQ;AACN,UAAM,IAAI,mCAAmC;AAAA,MAC3C,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,SAAS,eAAmD;AAC1D,SAAO,IAAI,mCAAmC;AAAA,IAC5C,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,aAAa,OAAuB;AAC3C,MAAI;AACJ,MAAI;AACF,UAAM,IAAI,IAAI,KAAK;AAAA,EACrB,QAAQ;AACN,UAAM,mBAAmB,sCAAsC;AAAA,EACjE;AAGA,QAAM,WAAW,IAAI,SAAS,QAAQ,aAAa,IAAI,EAAE,YAAY;AACrE,QAAM,QAAQ,CAAC,aAAa,aAAa,KAAK,EAAE,SAAS,QAAQ;AACjE,MAAI,IAAI,aAAa,YAAY,EAAE,SAAS,IAAI,aAAa,UAAU;AACrE,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,MAAI,IAAI,YAAY,IAAI,YAAY,IAAI,UAAU,IAAI,MAAM;AAC1D,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,SAAO,IAAI,SAAS,EAAE,QAAQ,OAAO,EAAE;AACzC;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,OAAS,QAAQ,KAAQ;AAC/D,UAAM;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,OAAuB;AAC5C,MACE,OAAO,UAAU,YACjB,CAAC,SACD,MAAM,SAAS,oBACf,SAAS,KAAK,KAAK,GACnB;AACA,UAAM,mBAAmB,sCAAsC;AAAA,EACjE;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAe,MAAsB;AAC5D,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACzC,UAAM,mBAAmB,GAAG,IAAI,6BAA6B;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAuB;AAC9C,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,mBAAmB,kCAAkC;AAAA,EAC7D;AACA,QAAM,aAAa,MAAM,KAAK;AAC9B,MAAI,CAAC,cAAc,WAAW,SAAS,oBAAoB;AACzD,UAAM;AAAA,MACJ,gCAAgC,kBAAkB;AAAA,IACpD;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,SACb,UACA,UACkB;AAClB,QAAM,iBAAiB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC;AACpE,MAAI,OAAO,SAAS,cAAc,KAAK,iBAAiB,oBAAoB;AAC1E,UAAM,iBAAiB;AAAA,EACzB;AAEA,QAAM,OAAO,SAAS;AACtB,MACE,QACA,OAAO,KAAK,cAAc,cAC1B,OAAO,gBAAgB,YACvB;AACA,WAAO,UAAU,MAAM,WAAW,MAAM,QAAQ,CAAC;AAAA,EACnD;AAEA,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,IAAI,MAAM,SAAS,KAAK,CAAC;AAAA,EACjD,SAAS,OAAO;AACd,QAAI,iBAAiB,mCAAoC,OAAM;AAC/D,UAAM,aAAa;AAAA,EACrB;AACA,MAAI,kBAAkB,MAAM,kBAAkB,GAAG;AAC/C,UAAM,iBAAiB;AAAA,EACzB;AACA,SAAO,UAAU,IAAI;AACvB;AAEA,eAAe,WACb,MACA,UACiB;AACjB,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,SAAuB,CAAC;AAC9B,MAAI,QAAQ;AACZ,MAAI;AACF,eAAS;AACP,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,SAAS,IAAI,MAAM,OAAO,KAAK,CAAC;AAC9D,UAAI,KAAM;AACV,eAAS,MAAM;AACf,UAAI,QAAQ,oBAAoB;AAC9B,cAAM,iBAAiB;AAAA,MACzB;AACA,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,mCAAoC,OAAM;AAC/D,UAAM,aAAa;AAAA,EACrB,UAAE;AACA,kBAAc,MAAM;AAAA,EACtB;AAEA,QAAM,QAAQ,IAAI,WAAW,KAAK;AAClC,MAAI,SAAS;AACb,aAAW,SAAS,QAAQ;AAC1B,UAAM,IAAI,OAAO,MAAM;AACvB,cAAU,MAAM;AAAA,EAClB;AACA,SAAO,IAAI,YAAY,EAAE,OAAO,KAAK;AACvC;AAEA,SAAS,UAAU,MAAuB;AACxC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,UAAM,gBAAgB;AAAA,EACxB;AACF;AAEA,SAAS,kBAAkB,OAAe,SAA0B;AAClE,MAAI,QAAQ;AACZ,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GAAG;AACpD,UAAM,WAAW,MAAM,WAAW,KAAK;AACvC,QAAI,WAAW,IAAM,UAAS;AAAA,aACrB,WAAW,KAAO,UAAS;AAAA,aAElC,YAAY,SACZ,YAAY,SACZ,QAAQ,IAAI,MAAM,UAClB,MAAM,WAAW,QAAQ,CAAC,KAAK,SAC/B,MAAM,WAAW,QAAQ,CAAC,KAAK,OAC/B;AACA,eAAS;AACT,eAAS;AAAA,IACX,MAAO,UAAS;AAChB,QAAI,QAAQ,QAAS,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,mBAAuD;AAC9D,SAAO,IAAI,mCAAmC;AAAA,IAC5C,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AACH;AAEA,SAAS,kBAAsD;AAC7D,SAAO,IAAI,mCAAmC;AAAA,IAC5C,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,EACb,CAAC;AACH;AAEA,SAAS,mBACP,SACoC;AACpC,SAAO,IAAI,mCAAmC;AAAA,IAC5C,MAAM;AAAA,IACN;AAAA,EACF,CAAC;AACH;","names":[]}
|