@stringpush/runtime-core 0.1.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/dist/index.d.cts +170 -0
- package/dist/index.d.ts +170 -0
- package/dist/index.mjs +413 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.cjs +481 -0
- package/dist/index.umd.cjs.map +1 -0
- package/fixtures/README.md +50 -0
- package/fixtures/bundle.schema.json +11 -0
- package/fixtures/bundles/en.1.json +6 -0
- package/fixtures/bundles/fr.1.json +6 -0
- package/fixtures/manifest.schema.json +50 -0
- package/fixtures/manifest.staging.json +17 -0
- package/package.json +48 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
// src/catalog-versions.ts
|
|
2
|
+
var versions = /* @__PURE__ */ new Map();
|
|
3
|
+
function valueVersionKey(keyPath, localeCode) {
|
|
4
|
+
return `${keyPath}${localeCode}`;
|
|
5
|
+
}
|
|
6
|
+
function getRecordedVersion(keyPath, localeCode) {
|
|
7
|
+
return versions.get(valueVersionKey(keyPath, localeCode));
|
|
8
|
+
}
|
|
9
|
+
function shouldApplyTranslationUpdate(keyPath, localeCode, version) {
|
|
10
|
+
const current = getRecordedVersion(keyPath, localeCode);
|
|
11
|
+
if (current === void 0) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
return version >= current;
|
|
15
|
+
}
|
|
16
|
+
function recordTranslationVersion(keyPath, localeCode, version) {
|
|
17
|
+
const key = valueVersionKey(keyPath, localeCode);
|
|
18
|
+
const current = versions.get(key);
|
|
19
|
+
if (current === void 0 || version > current) {
|
|
20
|
+
versions.set(key, version);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function clearCatalogVersions() {
|
|
24
|
+
versions.clear();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/runtime.ts
|
|
28
|
+
var runtime = {
|
|
29
|
+
options: null,
|
|
30
|
+
manifest: null,
|
|
31
|
+
catalog: {},
|
|
32
|
+
locale: "en"
|
|
33
|
+
};
|
|
34
|
+
function getRuntime() {
|
|
35
|
+
return runtime;
|
|
36
|
+
}
|
|
37
|
+
function resetRuntime() {
|
|
38
|
+
runtime.options = null;
|
|
39
|
+
runtime.manifest = null;
|
|
40
|
+
runtime.catalog = {};
|
|
41
|
+
runtime.locale = "en";
|
|
42
|
+
clearCatalogVersions();
|
|
43
|
+
}
|
|
44
|
+
function assertInitialized() {
|
|
45
|
+
if (!runtime.options) {
|
|
46
|
+
throw new Error("@stringpush/runtime-core: call initializeRuntime() before using the runtime");
|
|
47
|
+
}
|
|
48
|
+
return runtime.options;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/fetch-with-retry.ts
|
|
52
|
+
var DEFAULT_RETRY = {
|
|
53
|
+
maxAttempts: 3,
|
|
54
|
+
initialDelayMs: 300,
|
|
55
|
+
maxDelayMs: 5e3
|
|
56
|
+
};
|
|
57
|
+
function sleep(ms) {
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
setTimeout(resolve, ms);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async function fetchWithRetry(input, init, fetchFn, retry = {}) {
|
|
63
|
+
const { maxAttempts, initialDelayMs, maxDelayMs } = { ...DEFAULT_RETRY, ...retry };
|
|
64
|
+
let lastError;
|
|
65
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
66
|
+
try {
|
|
67
|
+
const response = await fetchFn(input, init);
|
|
68
|
+
if (response.ok || response.status < 500) {
|
|
69
|
+
return response;
|
|
70
|
+
}
|
|
71
|
+
lastError = new Error(`HTTP ${response.status}`);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
lastError = error;
|
|
74
|
+
}
|
|
75
|
+
if (attempt < maxAttempts) {
|
|
76
|
+
const delay = Math.min(initialDelayMs * 2 ** (attempt - 1), maxDelayMs);
|
|
77
|
+
await sleep(delay);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/urls.ts
|
|
84
|
+
function resolveApiBaseUrl(apiBaseUrl) {
|
|
85
|
+
if (apiBaseUrl) {
|
|
86
|
+
return apiBaseUrl.replace(/\/$/, "");
|
|
87
|
+
}
|
|
88
|
+
if (typeof globalThis !== "undefined" && "location" in globalThis) {
|
|
89
|
+
const origin = globalThis.location.origin;
|
|
90
|
+
if (origin && origin !== "null") {
|
|
91
|
+
return origin;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return "http://localhost:3000";
|
|
95
|
+
}
|
|
96
|
+
function resolveRequestOrigin(origin) {
|
|
97
|
+
if (origin) {
|
|
98
|
+
return origin;
|
|
99
|
+
}
|
|
100
|
+
if (typeof globalThis !== "undefined" && "location" in globalThis) {
|
|
101
|
+
const value = globalThis.location.origin;
|
|
102
|
+
return value && value !== "null" ? value : void 0;
|
|
103
|
+
}
|
|
104
|
+
return void 0;
|
|
105
|
+
}
|
|
106
|
+
function buildManifestUrl(apiBaseUrl, applicationId, environment) {
|
|
107
|
+
const params = new URLSearchParams({ environment });
|
|
108
|
+
return `${apiBaseUrl}/v1/applications/${applicationId}/manifest?${params}`;
|
|
109
|
+
}
|
|
110
|
+
function resolveBundleUrl(apiBaseUrl, bundlePath) {
|
|
111
|
+
if (bundlePath.startsWith("http://") || bundlePath.startsWith("https://")) {
|
|
112
|
+
return bundlePath;
|
|
113
|
+
}
|
|
114
|
+
const base = apiBaseUrl.endsWith("/") ? apiBaseUrl : `${apiBaseUrl}/`;
|
|
115
|
+
return new URL(bundlePath.replace(/^\//, ""), base).toString();
|
|
116
|
+
}
|
|
117
|
+
function isCrossOriginBundleUrl(apiBaseUrl, bundleUrl) {
|
|
118
|
+
if (!bundleUrl.startsWith("http://") && !bundleUrl.startsWith("https://")) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
return new URL(bundleUrl).origin !== new URL(apiBaseUrl).origin;
|
|
123
|
+
} catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function bundleFetchInit(options, apiBaseUrl, resolvedBundleUrl) {
|
|
128
|
+
if (isCrossOriginBundleUrl(apiBaseUrl, resolvedBundleUrl)) {
|
|
129
|
+
return {
|
|
130
|
+
credentials: "omit",
|
|
131
|
+
headers: { Accept: "application/json" }
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return runtimeFetchInit(options);
|
|
135
|
+
}
|
|
136
|
+
function runtimeFetchInit(options) {
|
|
137
|
+
const headers = {
|
|
138
|
+
Authorization: `Bearer ${options.apiKey}`,
|
|
139
|
+
Accept: "application/json"
|
|
140
|
+
};
|
|
141
|
+
const origin = resolveRequestOrigin(options.origin);
|
|
142
|
+
if (origin) {
|
|
143
|
+
headers.Origin = origin;
|
|
144
|
+
}
|
|
145
|
+
return { headers };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/loader.ts
|
|
149
|
+
async function fetchManifest(options, fetchFn) {
|
|
150
|
+
const apiBaseUrl = resolveApiBaseUrl(options.apiBaseUrl);
|
|
151
|
+
const url = buildManifestUrl(apiBaseUrl, options.applicationId, options.environment);
|
|
152
|
+
const response = await fetchWithRetry(url, runtimeFetchInit(options), fetchFn, options.retry);
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
throw new Error(`Failed to load translation manifest (HTTP ${response.status})`);
|
|
155
|
+
}
|
|
156
|
+
return await response.json();
|
|
157
|
+
}
|
|
158
|
+
async function fetchBundle(options, manifest, locale, fetchFn, bundleOptions = {}) {
|
|
159
|
+
const entry = manifest.locales[locale];
|
|
160
|
+
if (!entry) {
|
|
161
|
+
throw new Error(`Locale "${locale}" is not available in the translation manifest`);
|
|
162
|
+
}
|
|
163
|
+
const apiBaseUrl = resolveApiBaseUrl(options.apiBaseUrl);
|
|
164
|
+
const url = resolveBundleUrl(apiBaseUrl, entry.url);
|
|
165
|
+
const response = await fetchWithRetry(
|
|
166
|
+
url,
|
|
167
|
+
{ ...bundleFetchInit(options, apiBaseUrl, url), cache: bundleOptions.cache },
|
|
168
|
+
fetchFn,
|
|
169
|
+
options.retry
|
|
170
|
+
);
|
|
171
|
+
if (response.status === 304) {
|
|
172
|
+
return bundleOptions.fallbackCatalog ?? {};
|
|
173
|
+
}
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
throw new Error(`Failed to load translation bundle (HTTP ${response.status})`);
|
|
176
|
+
}
|
|
177
|
+
return await response.json();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/visitor-id.ts
|
|
181
|
+
var DEFAULT_VISITOR_STORAGE_KEY = "@stringpush/sdk/visitor-id";
|
|
182
|
+
function getOrCreateVisitorId(storageKey = DEFAULT_VISITOR_STORAGE_KEY) {
|
|
183
|
+
if (typeof globalThis === "undefined" || !("localStorage" in globalThis)) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
const storage = globalThis.localStorage;
|
|
188
|
+
const existing = storage.getItem(storageKey);
|
|
189
|
+
if (existing) {
|
|
190
|
+
return existing;
|
|
191
|
+
}
|
|
192
|
+
const id = createVisitorId();
|
|
193
|
+
storage.setItem(storageKey, id);
|
|
194
|
+
return id;
|
|
195
|
+
} catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function createVisitorId() {
|
|
200
|
+
if (typeof crypto !== "undefined" && "randomUUID" in crypto) {
|
|
201
|
+
return crypto.randomUUID();
|
|
202
|
+
}
|
|
203
|
+
return `v_${Math.random().toString(36).slice(2)}_${Date.now()}`;
|
|
204
|
+
}
|
|
205
|
+
async function hashVisitorId(visitorId) {
|
|
206
|
+
if (typeof crypto === "undefined" || !crypto.subtle) {
|
|
207
|
+
throw new Error("@stringpush/runtime-core: Web Crypto is required for reportUsage");
|
|
208
|
+
}
|
|
209
|
+
const data = new TextEncoder().encode(visitorId);
|
|
210
|
+
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
211
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/report-usage.ts
|
|
215
|
+
function isReportUsageEnabled(option) {
|
|
216
|
+
return option === true || typeof option === "object" && option !== null;
|
|
217
|
+
}
|
|
218
|
+
function resolveStorageKey(option) {
|
|
219
|
+
if (option === true) {
|
|
220
|
+
return DEFAULT_VISITOR_STORAGE_KEY;
|
|
221
|
+
}
|
|
222
|
+
return option.storageKey ?? DEFAULT_VISITOR_STORAGE_KEY;
|
|
223
|
+
}
|
|
224
|
+
function reportUsageBeacon(options) {
|
|
225
|
+
const reportOption = options.reportUsage;
|
|
226
|
+
if (!isReportUsageEnabled(reportOption)) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
230
|
+
const apiBaseUrl = resolveApiBaseUrl(options.apiBaseUrl);
|
|
231
|
+
const storageKey = resolveStorageKey(reportOption);
|
|
232
|
+
const visitorId = getOrCreateVisitorId(storageKey);
|
|
233
|
+
if (!visitorId) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
void hashVisitorId(visitorId).then(
|
|
237
|
+
(visitorHash) => fetchFn(`${apiBaseUrl}/v1/usage/mau`, {
|
|
238
|
+
method: "POST",
|
|
239
|
+
...runtimeFetchInit(options),
|
|
240
|
+
headers: {
|
|
241
|
+
...runtimeFetchInit(options).headers,
|
|
242
|
+
"Content-Type": "application/json"
|
|
243
|
+
},
|
|
244
|
+
body: JSON.stringify({ visitorHash })
|
|
245
|
+
})
|
|
246
|
+
).catch(() => {
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/translate.ts
|
|
251
|
+
import IntlMessageFormat from "intl-messageformat";
|
|
252
|
+
var ICU_PLURAL_OR_SELECT = /\{[\w$]+,\s*(plural|select)\b/;
|
|
253
|
+
function formatMessage(template, locale, values) {
|
|
254
|
+
const hasValues = values !== void 0 && Object.keys(values).length > 0;
|
|
255
|
+
const needsIcu = hasValues || ICU_PLURAL_OR_SELECT.test(template);
|
|
256
|
+
if (!needsIcu) {
|
|
257
|
+
return template;
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
return String(new IntlMessageFormat(template, locale).format(values ?? {}));
|
|
261
|
+
} catch {
|
|
262
|
+
return template;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function resolveTemplate(key, catalog, options) {
|
|
266
|
+
if (Object.prototype.hasOwnProperty.call(catalog, key)) {
|
|
267
|
+
const value = catalog[key];
|
|
268
|
+
return value ?? key;
|
|
269
|
+
}
|
|
270
|
+
const mode = options.missingKeyFallback ?? "key";
|
|
271
|
+
if (mode === "empty") {
|
|
272
|
+
return "";
|
|
273
|
+
}
|
|
274
|
+
if (mode === "default_message") {
|
|
275
|
+
return options.defaultMessages?.[key] ?? key;
|
|
276
|
+
}
|
|
277
|
+
return key;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/runtime-client.ts
|
|
281
|
+
function resolveFetch(options) {
|
|
282
|
+
return options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
283
|
+
}
|
|
284
|
+
async function loadActiveLocaleCatalog() {
|
|
285
|
+
const state = getRuntime();
|
|
286
|
+
const options = assertInitialized();
|
|
287
|
+
const fetchFn = resolveFetch(options);
|
|
288
|
+
state.manifest = await fetchManifest(options, fetchFn);
|
|
289
|
+
state.catalog = await fetchBundle(options, state.manifest, state.locale, fetchFn);
|
|
290
|
+
}
|
|
291
|
+
async function initializeRuntime(options) {
|
|
292
|
+
const state = getRuntime();
|
|
293
|
+
state.options = options;
|
|
294
|
+
state.locale = options.locale;
|
|
295
|
+
await loadActiveLocaleCatalog();
|
|
296
|
+
options.onTranslationsUpdated?.();
|
|
297
|
+
reportUsageBeacon(options);
|
|
298
|
+
}
|
|
299
|
+
function destroyRuntime() {
|
|
300
|
+
resetRuntime();
|
|
301
|
+
}
|
|
302
|
+
function getRuntimeLocale() {
|
|
303
|
+
return getRuntime().locale;
|
|
304
|
+
}
|
|
305
|
+
async function changeLocale(locale) {
|
|
306
|
+
const state = getRuntime();
|
|
307
|
+
const options = assertInitialized();
|
|
308
|
+
if (state.locale === locale) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const fetchFn = resolveFetch(options);
|
|
312
|
+
const manifest = state.manifest ?? await fetchManifest(options, fetchFn);
|
|
313
|
+
const catalog = await fetchBundle(options, manifest, locale, fetchFn);
|
|
314
|
+
state.manifest = manifest;
|
|
315
|
+
state.catalog = catalog;
|
|
316
|
+
state.locale = locale;
|
|
317
|
+
options.onLocaleChange?.(locale);
|
|
318
|
+
options.onTranslationsUpdated?.();
|
|
319
|
+
}
|
|
320
|
+
function translateKey(key, values) {
|
|
321
|
+
const state = getRuntime();
|
|
322
|
+
const options = assertInitialized();
|
|
323
|
+
const template = resolveTemplate(key, state.catalog, options);
|
|
324
|
+
return formatMessage(template, state.locale, values);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/catalog-patch.ts
|
|
328
|
+
function patchCatalogEntry(keyPath, localeCode, value, version) {
|
|
329
|
+
if (version !== void 0 && !shouldApplyTranslationUpdate(keyPath, localeCode, version)) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
const state = getRuntime();
|
|
333
|
+
if (state.locale !== localeCode) {
|
|
334
|
+
if (version !== void 0) {
|
|
335
|
+
recordTranslationVersion(keyPath, localeCode, version);
|
|
336
|
+
}
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
state.catalog[keyPath] = value;
|
|
340
|
+
if (version !== void 0) {
|
|
341
|
+
recordTranslationVersion(keyPath, localeCode, version);
|
|
342
|
+
}
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/catalog-reload.ts
|
|
347
|
+
function resolveFetch2(options) {
|
|
348
|
+
return options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
349
|
+
}
|
|
350
|
+
async function reloadManifestAndActiveLocale() {
|
|
351
|
+
const state = getRuntime();
|
|
352
|
+
const options = assertInitialized();
|
|
353
|
+
const fetchFn = resolveFetch2(options);
|
|
354
|
+
const manifest = await fetchManifest(options, fetchFn);
|
|
355
|
+
const catalog = await fetchBundle(options, manifest, state.locale, fetchFn, {
|
|
356
|
+
cache: "no-store",
|
|
357
|
+
fallbackCatalog: state.catalog
|
|
358
|
+
});
|
|
359
|
+
state.manifest = manifest;
|
|
360
|
+
state.catalog = catalog;
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
async function reloadIfBundlePublishedNewer(releases) {
|
|
364
|
+
const state = getRuntime();
|
|
365
|
+
const manifest = state.manifest;
|
|
366
|
+
if (!manifest) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
const release = releases.find((row) => row.localeCode === state.locale);
|
|
370
|
+
if (!release) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
const current = manifest.locales[state.locale]?.version ?? 0;
|
|
374
|
+
if (release.bundleVersion <= current) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
return reloadManifestAndActiveLocale();
|
|
378
|
+
}
|
|
379
|
+
export {
|
|
380
|
+
DEFAULT_VISITOR_STORAGE_KEY,
|
|
381
|
+
assertInitialized,
|
|
382
|
+
buildManifestUrl,
|
|
383
|
+
bundleFetchInit,
|
|
384
|
+
changeLocale,
|
|
385
|
+
clearCatalogVersions,
|
|
386
|
+
destroyRuntime,
|
|
387
|
+
fetchBundle,
|
|
388
|
+
fetchManifest,
|
|
389
|
+
fetchWithRetry,
|
|
390
|
+
formatMessage,
|
|
391
|
+
getOrCreateVisitorId,
|
|
392
|
+
getRecordedVersion,
|
|
393
|
+
getRuntime,
|
|
394
|
+
getRuntimeLocale,
|
|
395
|
+
hashVisitorId,
|
|
396
|
+
initializeRuntime,
|
|
397
|
+
isCrossOriginBundleUrl,
|
|
398
|
+
patchCatalogEntry,
|
|
399
|
+
recordTranslationVersion,
|
|
400
|
+
reloadIfBundlePublishedNewer,
|
|
401
|
+
reloadManifestAndActiveLocale,
|
|
402
|
+
reportUsageBeacon,
|
|
403
|
+
resetRuntime,
|
|
404
|
+
resolveApiBaseUrl,
|
|
405
|
+
resolveBundleUrl,
|
|
406
|
+
resolveRequestOrigin,
|
|
407
|
+
resolveTemplate,
|
|
408
|
+
runtimeFetchInit,
|
|
409
|
+
shouldApplyTranslationUpdate,
|
|
410
|
+
translateKey,
|
|
411
|
+
valueVersionKey
|
|
412
|
+
};
|
|
413
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalog-versions.ts","../src/runtime.ts","../src/fetch-with-retry.ts","../src/urls.ts","../src/loader.ts","../src/visitor-id.ts","../src/report-usage.ts","../src/translate.ts","../src/runtime-client.ts","../src/catalog-patch.ts","../src/catalog-reload.ts"],"sourcesContent":["/**\n * Per-key/locale optimistic-lock versions for in-memory catalog patches.\n *\n * Intent: ignore stale `translation.updated` events that arrive out of order.\n */\nconst versions = new Map<string, number>();\n\nexport function valueVersionKey(keyPath: string, localeCode: string): string {\n return `${keyPath}\\u001f${localeCode}`;\n}\n\nexport function getRecordedVersion(keyPath: string, localeCode: string): number | undefined {\n return versions.get(valueVersionKey(keyPath, localeCode));\n}\n\nexport function shouldApplyTranslationUpdate(\n keyPath: string,\n localeCode: string,\n version: number,\n): boolean {\n const current = getRecordedVersion(keyPath, localeCode);\n if (current === undefined) {\n return true;\n }\n return version >= current;\n}\n\nexport function recordTranslationVersion(\n keyPath: string,\n localeCode: string,\n version: number,\n): void {\n const key = valueVersionKey(keyPath, localeCode);\n const current = versions.get(key);\n if (current === undefined || version > current) {\n versions.set(key, version);\n }\n}\n\nexport function clearCatalogVersions(): void {\n versions.clear();\n}\n","/**\n * In-memory runtime singleton (catalog, manifest, active locale).\n *\n * Intent: module-level state for `t()` without framework adapters; cleared by `destroyRuntime()`.\n */\nimport { clearCatalogVersions } from \"./catalog-versions.js\";\nimport type { RuntimeInitOptions, TranslationCatalog, TranslationManifest } from \"./types.js\";\n\nexport type SdkRuntime = {\n options: RuntimeInitOptions | null;\n manifest: TranslationManifest | null;\n catalog: TranslationCatalog;\n locale: string;\n};\n\nconst runtime: SdkRuntime = {\n options: null,\n manifest: null,\n catalog: {},\n locale: \"en\",\n};\n\nexport function getRuntime(): SdkRuntime {\n return runtime;\n}\n\nexport function resetRuntime(): void {\n runtime.options = null;\n runtime.manifest = null;\n runtime.catalog = {};\n runtime.locale = \"en\";\n clearCatalogVersions();\n}\n\nexport function assertInitialized(): RuntimeInitOptions {\n if (!runtime.options) {\n throw new Error(\"@stringpush/runtime-core: call initializeRuntime() before using the runtime\");\n }\n return runtime.options;\n}\n","/**\n * Resilient fetch for manifest and bundle loads.\n *\n * Intent: retry network errors and 5xx only; 4xx fail fast so misconfiguration surfaces clearly.\n */\nimport type { RetryOptions } from \"./types.js\";\n\nconst DEFAULT_RETRY: Required<RetryOptions> = {\n maxAttempts: 3,\n initialDelayMs: 300,\n maxDelayMs: 5_000,\n};\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/**\n * Fetches with exponential backoff on network errors and 5xx responses.\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n fetchFn: typeof fetch,\n retry: RetryOptions = {},\n): Promise<Response> {\n const { maxAttempts, initialDelayMs, maxDelayMs } = { ...DEFAULT_RETRY, ...retry };\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const response = await fetchFn(input, init);\n if (response.ok || response.status < 500) {\n return response;\n }\n lastError = new Error(`HTTP ${response.status}`);\n } catch (error) {\n lastError = error;\n }\n\n if (attempt < maxAttempts) {\n const delay = Math.min(initialDelayMs * 2 ** (attempt - 1), maxDelayMs);\n await sleep(delay);\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n","/**\n * URL builders and runtime auth headers for API delivery routes.\n *\n * Intent: resolve relative bundle paths from manifest against `apiBaseUrl`; set Origin for allowlist.\n */\nimport type { Environment, RuntimeInitOptions } from \"./types.js\";\n\nexport function resolveApiBaseUrl(apiBaseUrl: string | undefined): string {\n if (apiBaseUrl) {\n return apiBaseUrl.replace(/\\/$/, \"\");\n }\n if (typeof globalThis !== \"undefined\" && \"location\" in globalThis) {\n const origin = (globalThis as Window & typeof globalThis).location.origin;\n if (origin && origin !== \"null\") {\n return origin;\n }\n }\n return \"http://localhost:3000\";\n}\n\nexport function resolveRequestOrigin(origin: string | undefined): string | undefined {\n if (origin) {\n return origin;\n }\n if (typeof globalThis !== \"undefined\" && \"location\" in globalThis) {\n const value = (globalThis as Window & typeof globalThis).location.origin;\n return value && value !== \"null\" ? value : undefined;\n }\n return undefined;\n}\n\nexport function buildManifestUrl(\n apiBaseUrl: string,\n applicationId: string,\n environment: Environment,\n): string {\n const params = new URLSearchParams({ environment });\n return `${apiBaseUrl}/v1/applications/${applicationId}/manifest?${params}`;\n}\n\nexport function resolveBundleUrl(apiBaseUrl: string, bundlePath: string): string {\n if (bundlePath.startsWith(\"http://\") || bundlePath.startsWith(\"https://\")) {\n return bundlePath;\n }\n const base = apiBaseUrl.endsWith(\"/\") ? apiBaseUrl : `${apiBaseUrl}/`;\n return new URL(bundlePath.replace(/^\\//, \"\"), base).toString();\n}\n\n/** True when the manifest points at a CDN (or BYO) origin separate from the API. */\nexport function isCrossOriginBundleUrl(apiBaseUrl: string, bundleUrl: string): boolean {\n if (!bundleUrl.startsWith(\"http://\") && !bundleUrl.startsWith(\"https://\")) {\n return false;\n }\n try {\n return new URL(bundleUrl).origin !== new URL(apiBaseUrl).origin;\n } catch {\n return false;\n }\n}\n\n/**\n * Bundle fetch options: runtime auth only when bundles are served from the API origin.\n *\n * Intent: CDN bundles are public immutable JSON — sending Authorization triggers CORS\n * preflight and wrongly treats the delivery plane like the control plane.\n */\nexport function bundleFetchInit(\n options: RuntimeInitOptions,\n apiBaseUrl: string,\n resolvedBundleUrl: string,\n): RequestInit {\n if (isCrossOriginBundleUrl(apiBaseUrl, resolvedBundleUrl)) {\n return {\n credentials: \"omit\",\n headers: { Accept: \"application/json\" },\n };\n }\n return runtimeFetchInit(options);\n}\n\nexport function runtimeFetchInit(options: RuntimeInitOptions): RequestInit {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${options.apiKey}`,\n Accept: \"application/json\",\n };\n const origin = resolveRequestOrigin(options.origin);\n if (origin) {\n headers.Origin = origin;\n }\n return { headers };\n}\n","/**\n * HTTP loaders for manifest and locale bundles (runtime API key auth).\n *\n * Intent: all network I/O lives here; `initializeRuntime` / `changeLocale` orchestrate via runtime state.\n */\nimport { fetchWithRetry } from \"./fetch-with-retry.js\";\nimport {\n buildManifestUrl,\n bundleFetchInit,\n resolveApiBaseUrl,\n resolveBundleUrl,\n runtimeFetchInit,\n} from \"./urls.js\";\nimport type { RuntimeInitOptions, TranslationCatalog, TranslationManifest } from \"./types.js\";\n\nexport type FetchBundleOptions = {\n /** When set, a 304 response returns this catalog instead of `{}`. */\n fallbackCatalog?: TranslationCatalog;\n cache?: RequestCache;\n};\n\nexport async function fetchManifest(\n options: RuntimeInitOptions,\n fetchFn: typeof fetch,\n): Promise<TranslationManifest> {\n const apiBaseUrl = resolveApiBaseUrl(options.apiBaseUrl);\n const url = buildManifestUrl(apiBaseUrl, options.applicationId, options.environment);\n const response = await fetchWithRetry(url, runtimeFetchInit(options), fetchFn, options.retry);\n if (!response.ok) {\n throw new Error(`Failed to load translation manifest (HTTP ${response.status})`);\n }\n return (await response.json()) as TranslationManifest;\n}\n\nexport async function fetchBundle(\n options: RuntimeInitOptions,\n manifest: TranslationManifest,\n locale: string,\n fetchFn: typeof fetch,\n bundleOptions: FetchBundleOptions = {},\n): Promise<TranslationCatalog> {\n const entry = manifest.locales[locale];\n if (!entry) {\n throw new Error(`Locale \"${locale}\" is not available in the translation manifest`);\n }\n\n const apiBaseUrl = resolveApiBaseUrl(options.apiBaseUrl);\n const url = resolveBundleUrl(apiBaseUrl, entry.url);\n const response = await fetchWithRetry(\n url,\n { ...bundleFetchInit(options, apiBaseUrl, url), cache: bundleOptions.cache },\n fetchFn,\n options.retry,\n );\n if (response.status === 304) {\n return bundleOptions.fallbackCatalog ?? {};\n }\n if (!response.ok) {\n throw new Error(`Failed to load translation bundle (HTTP ${response.status})`);\n }\n return (await response.json()) as TranslationCatalog;\n}\n","/**\n * Anonymous visitor id for MAU beacons (M6-MAU-01).\n *\n * Intent: stable random id in localStorage; only SHA-256 hash is sent to the API.\n */\n\nexport const DEFAULT_VISITOR_STORAGE_KEY = \"@stringpush/sdk/visitor-id\";\n\nexport function getOrCreateVisitorId(storageKey: string = DEFAULT_VISITOR_STORAGE_KEY): string | null {\n if (typeof globalThis === \"undefined\" || !(\"localStorage\" in globalThis)) {\n return null;\n }\n\n try {\n const storage = (globalThis as Window & typeof globalThis).localStorage;\n const existing = storage.getItem(storageKey);\n if (existing) {\n return existing;\n }\n\n const id = createVisitorId();\n storage.setItem(storageKey, id);\n return id;\n } catch {\n return null;\n }\n}\n\nfunction createVisitorId(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\n return crypto.randomUUID();\n }\n return `v_${Math.random().toString(36).slice(2)}_${Date.now()}`;\n}\n\nexport async function hashVisitorId(visitorId: string): Promise<string> {\n if (typeof crypto === \"undefined\" || !crypto.subtle) {\n throw new Error(\"@stringpush/runtime-core: Web Crypto is required for reportUsage\");\n }\n\n const data = new TextEncoder().encode(visitorId);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return [...new Uint8Array(digest)]\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n","/**\n * Optional MAU beacon on runtime init (M6-MAU-01).\n *\n * Intent: hash anonymous visitor id client-side; fire-and-forget POST with runtime key — no PII on wire.\n */\nimport { resolveApiBaseUrl, runtimeFetchInit } from \"./urls.js\";\nimport type { ReportUsageOptions, RuntimeInitOptions } from \"./types.js\";\nimport { DEFAULT_VISITOR_STORAGE_KEY, getOrCreateVisitorId, hashVisitorId } from \"./visitor-id.js\";\n\nfunction isReportUsageEnabled(\n option: ReportUsageOptions | undefined,\n): option is true | { storageKey?: string } {\n return option === true || (typeof option === \"object\" && option !== null);\n}\n\nfunction resolveStorageKey(option: true | { storageKey?: string }): string {\n if (option === true) {\n return DEFAULT_VISITOR_STORAGE_KEY;\n }\n return option.storageKey ?? DEFAULT_VISITOR_STORAGE_KEY;\n}\n\n/**\n * Sends one MAU ping for the current calendar month (idempotent server-side per visitor hash).\n */\nexport function reportUsageBeacon(options: RuntimeInitOptions): void {\n const reportOption = options.reportUsage;\n if (!isReportUsageEnabled(reportOption)) {\n return;\n }\n\n const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);\n const apiBaseUrl = resolveApiBaseUrl(options.apiBaseUrl);\n\n const storageKey = resolveStorageKey(reportOption);\n const visitorId = getOrCreateVisitorId(storageKey);\n if (!visitorId) {\n return;\n }\n\n void hashVisitorId(visitorId)\n .then((visitorHash) =>\n fetchFn(`${apiBaseUrl}/v1/usage/mau`, {\n method: \"POST\",\n ...runtimeFetchInit(options),\n headers: {\n ...runtimeFetchInit(options).headers,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ visitorHash }),\n }),\n )\n .catch(() => {\n // Intent: MAU must never break customer apps — swallow network errors.\n });\n}\n","/**\n * ICU formatting and missing-key resolution for `t()`.\n *\n * Intent: bundle strings may use ICU MessageFormat; host apps pass interpolation values at call time.\n */\nimport IntlMessageFormat from \"intl-messageformat\";\nimport type { RuntimeInitOptions, TranslationCatalog } from \"./types.js\";\n\nconst ICU_PLURAL_OR_SELECT = /\\{[\\w$]+,\\s*(plural|select)\\b/;\n\n/**\n * Formats a catalog template with optional ICU values for the active locale.\n */\nexport function formatMessage(\n template: string,\n locale: string,\n values?: Record<string, unknown>,\n): string {\n const hasValues = values !== undefined && Object.keys(values).length > 0;\n const needsIcu = hasValues || ICU_PLURAL_OR_SELECT.test(template);\n\n if (!needsIcu) {\n return template;\n }\n\n try {\n return String(new IntlMessageFormat(template, locale).format(values ?? {}));\n } catch {\n // Intent: malformed ICU in a published string must not break the host application.\n return template;\n }\n}\n\n/**\n * Resolves the message template for a key before ICU formatting.\n */\nexport function resolveTemplate(\n key: string,\n catalog: TranslationCatalog,\n options: Pick<RuntimeInitOptions, \"missingKeyFallback\" | \"defaultMessages\">,\n): string {\n if (Object.prototype.hasOwnProperty.call(catalog, key)) {\n const value = catalog[key];\n return value ?? key;\n }\n\n const mode = options.missingKeyFallback ?? \"key\";\n if (mode === \"empty\") {\n return \"\";\n }\n if (mode === \"default_message\") {\n return options.defaultMessages?.[key] ?? key;\n }\n return key;\n}\n","/**\n * High-level runtime lifecycle — manifest load, locale switch, translate (M14-CORE-01).\n *\n * Intent: framework adapters call these functions; @stringpush/sdk adds overlay/edit on top.\n */\nimport { fetchBundle, fetchManifest } from \"./loader.js\";\nimport { reportUsageBeacon } from \"./report-usage.js\";\nimport { assertInitialized, getRuntime, resetRuntime } from \"./runtime.js\";\nimport { formatMessage, resolveTemplate } from \"./translate.js\";\nimport type { RuntimeInitOptions, TranslateValues } from \"./types.js\";\n\nfunction resolveFetch(options: RuntimeInitOptions): typeof fetch {\n return options.fetch ?? globalThis.fetch.bind(globalThis);\n}\n\nasync function loadActiveLocaleCatalog(): Promise<void> {\n const state = getRuntime();\n const options = assertInitialized();\n const fetchFn = resolveFetch(options);\n\n state.manifest = await fetchManifest(options, fetchFn);\n state.catalog = await fetchBundle(options, state.manifest, state.locale, fetchFn);\n}\n\n/**\n * Loads manifest + active locale bundle into memory and optionally reports MAU.\n */\nexport async function initializeRuntime(options: RuntimeInitOptions): Promise<void> {\n const state = getRuntime();\n state.options = options;\n state.locale = options.locale;\n\n await loadActiveLocaleCatalog();\n options.onTranslationsUpdated?.();\n reportUsageBeacon(options);\n}\n\nexport function destroyRuntime(): void {\n resetRuntime();\n}\n\nexport function getRuntimeLocale(): string {\n return getRuntime().locale;\n}\n\n/**\n * Switch active locale and reload its bundle from the manifest.\n */\nexport async function changeLocale(locale: string): Promise<void> {\n const state = getRuntime();\n const options = assertInitialized();\n\n if (state.locale === locale) {\n return;\n }\n\n const fetchFn = resolveFetch(options);\n const manifest = state.manifest ?? (await fetchManifest(options, fetchFn));\n const catalog = await fetchBundle(options, manifest, locale, fetchFn);\n\n // Intent: commit locale + catalog only after a successful fetch — avoid t() vs getLocale() mismatch.\n state.manifest = manifest;\n state.catalog = catalog;\n state.locale = locale;\n\n options.onLocaleChange?.(locale);\n options.onTranslationsUpdated?.();\n}\n\n/**\n * Translate a key using the loaded catalog and ICU MessageFormat.\n */\nexport function translateKey(key: string, values?: TranslateValues): string {\n const state = getRuntime();\n const options = assertInitialized();\n const template = resolveTemplate(key, state.catalog, options);\n return formatMessage(template, state.locale, values);\n}\n","/**\n * In-memory catalog updates after remote saves or realtime events.\n *\n * Intent: optimistic `t()` refresh for active locale only; other locales wait for reload/realtime.\n */\nimport {\n recordTranslationVersion,\n shouldApplyTranslationUpdate,\n} from \"./catalog-versions.js\";\nimport { getRuntime } from \"./runtime.js\";\n\nexport function patchCatalogEntry(\n keyPath: string,\n localeCode: string,\n value: string,\n version?: number,\n): boolean {\n if (version !== undefined && !shouldApplyTranslationUpdate(keyPath, localeCode, version)) {\n return false;\n }\n\n const state = getRuntime();\n if (state.locale !== localeCode) {\n if (version !== undefined) {\n recordTranslationVersion(keyPath, localeCode, version);\n }\n return false;\n }\n\n state.catalog[keyPath] = value;\n if (version !== undefined) {\n recordTranslationVersion(keyPath, localeCode, version);\n }\n return true;\n}\n","/**\n * Refetches manifest and locale bundles into runtime state.\n *\n * Intent: used by realtime handlers when CDN-published content is newer than the in-memory catalog.\n */\nimport { fetchBundle, fetchManifest } from \"./loader.js\";\nimport { assertInitialized, getRuntime } from \"./runtime.js\";\nimport type { RuntimeInitOptions } from \"./types.js\";\n\nfunction resolveFetch(options: RuntimeInitOptions): typeof fetch {\n return options.fetch ?? globalThis.fetch.bind(globalThis);\n}\n\n/**\n * Reloads manifest and the active locale bundle from the API/CDN.\n */\nexport async function reloadManifestAndActiveLocale(): Promise<boolean> {\n const state = getRuntime();\n const options = assertInitialized();\n const fetchFn = resolveFetch(options);\n\n const manifest = await fetchManifest(options, fetchFn);\n const catalog = await fetchBundle(options, manifest, state.locale, fetchFn, {\n cache: \"no-store\",\n fallbackCatalog: state.catalog,\n });\n\n state.manifest = manifest;\n state.catalog = catalog;\n return true;\n}\n\n/**\n * When `bundle.published` reports a newer bundle for the active locale, refetch manifest + bundle.\n */\nexport async function reloadIfBundlePublishedNewer(\n releases: Array<{ localeCode: string; bundleVersion: number }>,\n): Promise<boolean> {\n const state = getRuntime();\n const manifest = state.manifest;\n if (!manifest) {\n return false;\n }\n\n const release = releases.find((row) => row.localeCode === state.locale);\n if (!release) {\n return false;\n }\n\n const current = manifest.locales[state.locale]?.version ?? 0;\n if (release.bundleVersion <= current) {\n return false;\n }\n\n return reloadManifestAndActiveLocale();\n}\n"],"mappings":";AAKA,IAAM,WAAW,oBAAI,IAAoB;AAElC,SAAS,gBAAgB,SAAiB,YAA4B;AAC3E,SAAO,GAAG,OAAO,IAAS,UAAU;AACtC;AAEO,SAAS,mBAAmB,SAAiB,YAAwC;AAC1F,SAAO,SAAS,IAAI,gBAAgB,SAAS,UAAU,CAAC;AAC1D;AAEO,SAAS,6BACd,SACA,YACA,SACS;AACT,QAAM,UAAU,mBAAmB,SAAS,UAAU;AACtD,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AACA,SAAO,WAAW;AACpB;AAEO,SAAS,yBACd,SACA,YACA,SACM;AACN,QAAM,MAAM,gBAAgB,SAAS,UAAU;AAC/C,QAAM,UAAU,SAAS,IAAI,GAAG;AAChC,MAAI,YAAY,UAAa,UAAU,SAAS;AAC9C,aAAS,IAAI,KAAK,OAAO;AAAA,EAC3B;AACF;AAEO,SAAS,uBAA6B;AAC3C,WAAS,MAAM;AACjB;;;AC1BA,IAAM,UAAsB;AAAA,EAC1B,SAAS;AAAA,EACT,UAAU;AAAA,EACV,SAAS,CAAC;AAAA,EACV,QAAQ;AACV;AAEO,SAAS,aAAyB;AACvC,SAAO;AACT;AAEO,SAAS,eAAqB;AACnC,UAAQ,UAAU;AAClB,UAAQ,WAAW;AACnB,UAAQ,UAAU,CAAC;AACnB,UAAQ,SAAS;AACjB,uBAAqB;AACvB;AAEO,SAAS,oBAAwC;AACtD,MAAI,CAAC,QAAQ,SAAS;AACpB,UAAM,IAAI,MAAM,6EAA6E;AAAA,EAC/F;AACA,SAAO,QAAQ;AACjB;;;AChCA,IAAM,gBAAwC;AAAA,EAC5C,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,YAAY;AACd;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,eAAW,SAAS,EAAE;AAAA,EACxB,CAAC;AACH;AAKA,eAAsB,eACpB,OACA,MACA,SACA,QAAsB,CAAC,GACJ;AACnB,QAAM,EAAE,aAAa,gBAAgB,WAAW,IAAI,EAAE,GAAG,eAAe,GAAG,MAAM;AACjF,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,QAAI;AACF,YAAM,WAAW,MAAM,QAAQ,OAAO,IAAI;AAC1C,UAAI,SAAS,MAAM,SAAS,SAAS,KAAK;AACxC,eAAO;AAAA,MACT;AACA,kBAAY,IAAI,MAAM,QAAQ,SAAS,MAAM,EAAE;AAAA,IACjD,SAAS,OAAO;AACd,kBAAY;AAAA,IACd;AAEA,QAAI,UAAU,aAAa;AACzB,YAAM,QAAQ,KAAK,IAAI,iBAAiB,MAAM,UAAU,IAAI,UAAU;AACtE,YAAM,MAAM,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,qBAAqB,QAAQ,YAAY,IAAI,MAAM,OAAO,SAAS,CAAC;AAC5E;;;AC1CO,SAAS,kBAAkB,YAAwC;AACxE,MAAI,YAAY;AACd,WAAO,WAAW,QAAQ,OAAO,EAAE;AAAA,EACrC;AACA,MAAI,OAAO,eAAe,eAAe,cAAc,YAAY;AACjE,UAAM,SAAU,WAA0C,SAAS;AACnE,QAAI,UAAU,WAAW,QAAQ;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB,QAAgD;AACnF,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AACA,MAAI,OAAO,eAAe,eAAe,cAAc,YAAY;AACjE,UAAM,QAAS,WAA0C,SAAS;AAClE,WAAO,SAAS,UAAU,SAAS,QAAQ;AAAA,EAC7C;AACA,SAAO;AACT;AAEO,SAAS,iBACd,YACA,eACA,aACQ;AACR,QAAM,SAAS,IAAI,gBAAgB,EAAE,YAAY,CAAC;AAClD,SAAO,GAAG,UAAU,oBAAoB,aAAa,aAAa,MAAM;AAC1E;AAEO,SAAS,iBAAiB,YAAoB,YAA4B;AAC/E,MAAI,WAAW,WAAW,SAAS,KAAK,WAAW,WAAW,UAAU,GAAG;AACzE,WAAO;AAAA,EACT;AACA,QAAM,OAAO,WAAW,SAAS,GAAG,IAAI,aAAa,GAAG,UAAU;AAClE,SAAO,IAAI,IAAI,WAAW,QAAQ,OAAO,EAAE,GAAG,IAAI,EAAE,SAAS;AAC/D;AAGO,SAAS,uBAAuB,YAAoB,WAA4B;AACrF,MAAI,CAAC,UAAU,WAAW,SAAS,KAAK,CAAC,UAAU,WAAW,UAAU,GAAG;AACzE,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,IAAI,IAAI,SAAS,EAAE,WAAW,IAAI,IAAI,UAAU,EAAE;AAAA,EAC3D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQO,SAAS,gBACd,SACA,YACA,mBACa;AACb,MAAI,uBAAuB,YAAY,iBAAiB,GAAG;AACzD,WAAO;AAAA,MACL,aAAa;AAAA,MACb,SAAS,EAAE,QAAQ,mBAAmB;AAAA,IACxC;AAAA,EACF;AACA,SAAO,iBAAiB,OAAO;AACjC;AAEO,SAAS,iBAAiB,SAA0C;AACzE,QAAM,UAAkC;AAAA,IACtC,eAAe,UAAU,QAAQ,MAAM;AAAA,IACvC,QAAQ;AAAA,EACV;AACA,QAAM,SAAS,qBAAqB,QAAQ,MAAM;AAClD,MAAI,QAAQ;AACV,YAAQ,SAAS;AAAA,EACnB;AACA,SAAO,EAAE,QAAQ;AACnB;;;ACrEA,eAAsB,cACpB,SACA,SAC8B;AAC9B,QAAM,aAAa,kBAAkB,QAAQ,UAAU;AACvD,QAAM,MAAM,iBAAiB,YAAY,QAAQ,eAAe,QAAQ,WAAW;AACnF,QAAM,WAAW,MAAM,eAAe,KAAK,iBAAiB,OAAO,GAAG,SAAS,QAAQ,KAAK;AAC5F,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,6CAA6C,SAAS,MAAM,GAAG;AAAA,EACjF;AACA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAEA,eAAsB,YACpB,SACA,UACA,QACA,SACA,gBAAoC,CAAC,GACR;AAC7B,QAAM,QAAQ,SAAS,QAAQ,MAAM;AACrC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,WAAW,MAAM,gDAAgD;AAAA,EACnF;AAEA,QAAM,aAAa,kBAAkB,QAAQ,UAAU;AACvD,QAAM,MAAM,iBAAiB,YAAY,MAAM,GAAG;AAClD,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA,EAAE,GAAG,gBAAgB,SAAS,YAAY,GAAG,GAAG,OAAO,cAAc,MAAM;AAAA,IAC3E;AAAA,IACA,QAAQ;AAAA,EACV;AACA,MAAI,SAAS,WAAW,KAAK;AAC3B,WAAO,cAAc,mBAAmB,CAAC;AAAA,EAC3C;AACA,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,2CAA2C,SAAS,MAAM,GAAG;AAAA,EAC/E;AACA,SAAQ,MAAM,SAAS,KAAK;AAC9B;;;ACvDO,IAAM,8BAA8B;AAEpC,SAAS,qBAAqB,aAAqB,6BAA4C;AACpG,MAAI,OAAO,eAAe,eAAe,EAAE,kBAAkB,aAAa;AACxE,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,UAAW,WAA0C;AAC3D,UAAM,WAAW,QAAQ,QAAQ,UAAU;AAC3C,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,UAAM,KAAK,gBAAgB;AAC3B,YAAQ,QAAQ,YAAY,EAAE;AAC9B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,kBAA0B;AACjC,MAAI,OAAO,WAAW,eAAe,gBAAgB,QAAQ;AAC3D,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,KAAK,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC;AAC/D;AAEA,eAAsB,cAAc,WAAoC;AACtE,MAAI,OAAO,WAAW,eAAe,CAAC,OAAO,QAAQ;AACnD,UAAM,IAAI,MAAM,kEAAkE;AAAA,EACpF;AAEA,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,SAAS;AAC/C,QAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACzD,SAAO,CAAC,GAAG,IAAI,WAAW,MAAM,CAAC,EAC9B,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAChD,KAAK,EAAE;AACZ;;;ACpCA,SAAS,qBACP,QAC0C;AAC1C,SAAO,WAAW,QAAS,OAAO,WAAW,YAAY,WAAW;AACtE;AAEA,SAAS,kBAAkB,QAAgD;AACzE,MAAI,WAAW,MAAM;AACnB,WAAO;AAAA,EACT;AACA,SAAO,OAAO,cAAc;AAC9B;AAKO,SAAS,kBAAkB,SAAmC;AACnE,QAAM,eAAe,QAAQ;AAC7B,MAAI,CAAC,qBAAqB,YAAY,GAAG;AACvC;AAAA,EACF;AAEA,QAAM,UAAU,QAAQ,SAAS,WAAW,MAAM,KAAK,UAAU;AACjE,QAAM,aAAa,kBAAkB,QAAQ,UAAU;AAEvD,QAAM,aAAa,kBAAkB,YAAY;AACjD,QAAM,YAAY,qBAAqB,UAAU;AACjD,MAAI,CAAC,WAAW;AACd;AAAA,EACF;AAEA,OAAK,cAAc,SAAS,EACzB;AAAA,IAAK,CAAC,gBACL,QAAQ,GAAG,UAAU,iBAAiB;AAAA,MACpC,QAAQ;AAAA,MACR,GAAG,iBAAiB,OAAO;AAAA,MAC3B,SAAS;AAAA,QACP,GAAG,iBAAiB,OAAO,EAAE;AAAA,QAC7B,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,YAAY,CAAC;AAAA,IACtC,CAAC;AAAA,EACH,EACC,MAAM,MAAM;AAAA,EAEb,CAAC;AACL;;;AClDA,OAAO,uBAAuB;AAG9B,IAAM,uBAAuB;AAKtB,SAAS,cACd,UACA,QACA,QACQ;AACR,QAAM,YAAY,WAAW,UAAa,OAAO,KAAK,MAAM,EAAE,SAAS;AACvE,QAAM,WAAW,aAAa,qBAAqB,KAAK,QAAQ;AAEhE,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,OAAO,IAAI,kBAAkB,UAAU,MAAM,EAAE,OAAO,UAAU,CAAC,CAAC,CAAC;AAAA,EAC5E,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,gBACd,KACA,SACA,SACQ;AACR,MAAI,OAAO,UAAU,eAAe,KAAK,SAAS,GAAG,GAAG;AACtD,UAAM,QAAQ,QAAQ,GAAG;AACzB,WAAO,SAAS;AAAA,EAClB;AAEA,QAAM,OAAO,QAAQ,sBAAsB;AAC3C,MAAI,SAAS,SAAS;AACpB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,mBAAmB;AAC9B,WAAO,QAAQ,kBAAkB,GAAG,KAAK;AAAA,EAC3C;AACA,SAAO;AACT;;;AC3CA,SAAS,aAAa,SAA2C;AAC/D,SAAO,QAAQ,SAAS,WAAW,MAAM,KAAK,UAAU;AAC1D;AAEA,eAAe,0BAAyC;AACtD,QAAM,QAAQ,WAAW;AACzB,QAAM,UAAU,kBAAkB;AAClC,QAAM,UAAU,aAAa,OAAO;AAEpC,QAAM,WAAW,MAAM,cAAc,SAAS,OAAO;AACrD,QAAM,UAAU,MAAM,YAAY,SAAS,MAAM,UAAU,MAAM,QAAQ,OAAO;AAClF;AAKA,eAAsB,kBAAkB,SAA4C;AAClF,QAAM,QAAQ,WAAW;AACzB,QAAM,UAAU;AAChB,QAAM,SAAS,QAAQ;AAEvB,QAAM,wBAAwB;AAC9B,UAAQ,wBAAwB;AAChC,oBAAkB,OAAO;AAC3B;AAEO,SAAS,iBAAuB;AACrC,eAAa;AACf;AAEO,SAAS,mBAA2B;AACzC,SAAO,WAAW,EAAE;AACtB;AAKA,eAAsB,aAAa,QAA+B;AAChE,QAAM,QAAQ,WAAW;AACzB,QAAM,UAAU,kBAAkB;AAElC,MAAI,MAAM,WAAW,QAAQ;AAC3B;AAAA,EACF;AAEA,QAAM,UAAU,aAAa,OAAO;AACpC,QAAM,WAAW,MAAM,YAAa,MAAM,cAAc,SAAS,OAAO;AACxE,QAAM,UAAU,MAAM,YAAY,SAAS,UAAU,QAAQ,OAAO;AAGpE,QAAM,WAAW;AACjB,QAAM,UAAU;AAChB,QAAM,SAAS;AAEf,UAAQ,iBAAiB,MAAM;AAC/B,UAAQ,wBAAwB;AAClC;AAKO,SAAS,aAAa,KAAa,QAAkC;AAC1E,QAAM,QAAQ,WAAW;AACzB,QAAM,UAAU,kBAAkB;AAClC,QAAM,WAAW,gBAAgB,KAAK,MAAM,SAAS,OAAO;AAC5D,SAAO,cAAc,UAAU,MAAM,QAAQ,MAAM;AACrD;;;AClEO,SAAS,kBACd,SACA,YACA,OACA,SACS;AACT,MAAI,YAAY,UAAa,CAAC,6BAA6B,SAAS,YAAY,OAAO,GAAG;AACxF,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW;AACzB,MAAI,MAAM,WAAW,YAAY;AAC/B,QAAI,YAAY,QAAW;AACzB,+BAAyB,SAAS,YAAY,OAAO;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,IAAI;AACzB,MAAI,YAAY,QAAW;AACzB,6BAAyB,SAAS,YAAY,OAAO;AAAA,EACvD;AACA,SAAO;AACT;;;ACzBA,SAASA,cAAa,SAA2C;AAC/D,SAAO,QAAQ,SAAS,WAAW,MAAM,KAAK,UAAU;AAC1D;AAKA,eAAsB,gCAAkD;AACtE,QAAM,QAAQ,WAAW;AACzB,QAAM,UAAU,kBAAkB;AAClC,QAAM,UAAUA,cAAa,OAAO;AAEpC,QAAM,WAAW,MAAM,cAAc,SAAS,OAAO;AACrD,QAAM,UAAU,MAAM,YAAY,SAAS,UAAU,MAAM,QAAQ,SAAS;AAAA,IAC1E,OAAO;AAAA,IACP,iBAAiB,MAAM;AAAA,EACzB,CAAC;AAED,QAAM,WAAW;AACjB,QAAM,UAAU;AAChB,SAAO;AACT;AAKA,eAAsB,6BACpB,UACkB;AAClB,QAAM,QAAQ,WAAW;AACzB,QAAM,WAAW,MAAM;AACvB,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,SAAS,KAAK,CAAC,QAAQ,IAAI,eAAe,MAAM,MAAM;AACtE,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,SAAS,QAAQ,MAAM,MAAM,GAAG,WAAW;AAC3D,MAAI,QAAQ,iBAAiB,SAAS;AACpC,WAAO;AAAA,EACT;AAEA,SAAO,8BAA8B;AACvC;","names":["resolveFetch"]}
|