@axcode/axcloud-sdk 0.2.0-dev.1e6c3d5 → 0.2.0-dev.85285e0

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.
@@ -0,0 +1,461 @@
1
+ import { useAxCloudContext } from './chunk-2A5NJAFA.mjs';
2
+ import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
3
+
4
+ // src/core/errors.ts
5
+ var AxCloudError = class _AxCloudError extends Error {
6
+ constructor(message, code, status, details) {
7
+ super(message);
8
+ this.name = "AxCloudError";
9
+ this.code = code;
10
+ this.status = status;
11
+ this.details = details;
12
+ const ErrorWithCapture = Error;
13
+ if (ErrorWithCapture.captureStackTrace) {
14
+ ErrorWithCapture.captureStackTrace(this, _AxCloudError);
15
+ }
16
+ }
17
+ static fromResponse(status, body) {
18
+ const details = typeof body === "object" ? body : void 0;
19
+ const message = (typeof details?.message === "string" ? details.message : void 0) || (typeof details?.error === "string" ? details.error : void 0);
20
+ switch (status) {
21
+ case 401:
22
+ return new _AxCloudError(
23
+ message || "Authentication required",
24
+ "UNAUTHORIZED",
25
+ status,
26
+ details
27
+ );
28
+ case 403:
29
+ return new _AxCloudError(message || "Access denied", "FORBIDDEN", status, details);
30
+ case 404:
31
+ return new _AxCloudError(message || "Resource not found", "NOT_FOUND", status, details);
32
+ case 422:
33
+ return new _AxCloudError(
34
+ message || "Validation failed",
35
+ "VALIDATION_ERROR",
36
+ status,
37
+ details
38
+ );
39
+ default:
40
+ if (status >= 500) {
41
+ return new _AxCloudError(message || "Server error", "SERVER_ERROR", status, details);
42
+ }
43
+ return new _AxCloudError(message || "An error occurred", "UNKNOWN_ERROR", status, details);
44
+ }
45
+ }
46
+ static networkError(originalError) {
47
+ const isDev = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
48
+ const message = isDev && originalError?.message ? originalError.message : "Network request failed";
49
+ return new _AxCloudError(
50
+ message,
51
+ "NETWORK_ERROR",
52
+ 0,
53
+ isDev ? { originalError: originalError?.message } : void 0
54
+ );
55
+ }
56
+ static timeoutError(timeoutMs) {
57
+ return new _AxCloudError(`Request timed out after ${timeoutMs}ms`, "TIMEOUT_ERROR", 0, {
58
+ timeout: timeoutMs
59
+ });
60
+ }
61
+ };
62
+ function isAxCloudError(error) {
63
+ return error instanceof AxCloudError;
64
+ }
65
+
66
+ // src/core/client.ts
67
+ var AxCloudClient = class {
68
+ constructor(config) {
69
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
70
+ this.getAccessToken = config.getAccessToken;
71
+ this.apiKey = config.apiKey;
72
+ this.defaultTimeout = config.timeout ?? 3e4;
73
+ }
74
+ /**
75
+ * Update the access token getter (used when auth state changes)
76
+ */
77
+ setAccessTokenGetter(getter) {
78
+ this.getAccessToken = getter;
79
+ }
80
+ /**
81
+ * Build URL with query parameters
82
+ */
83
+ buildUrl(path, params) {
84
+ const url = new URL(`${this.baseUrl}${path}`);
85
+ if (params) {
86
+ Object.entries(params).forEach(([key, value]) => {
87
+ if (value !== void 0) {
88
+ url.searchParams.append(key, String(value));
89
+ }
90
+ });
91
+ }
92
+ return url.toString();
93
+ }
94
+ /**
95
+ * API key should only be sent to public endpoints.
96
+ * This avoids leaking public keys to authenticated/internal routes.
97
+ */
98
+ shouldAttachApiKey(path) {
99
+ const normalized = path.startsWith("/") ? path : `/${path}`;
100
+ return normalized.startsWith("/public/") || normalized.startsWith("/api/public/") || normalized.startsWith("/content/public/") || normalized.startsWith("/media/public/") || normalized.startsWith("/documents/public/") || normalized.startsWith("/barnsport/public/") || normalized.startsWith("/api/barnsport/public/");
101
+ }
102
+ /**
103
+ * Make an authenticated request
104
+ */
105
+ async request(path, options = {}) {
106
+ const { body, params, headers: customHeaders, timeout, ...restOptions } = options;
107
+ const headers = {
108
+ "Content-Type": "application/json"
109
+ };
110
+ if (customHeaders) {
111
+ const customHeadersRecord = customHeaders;
112
+ Object.assign(headers, customHeadersRecord);
113
+ }
114
+ if (this.apiKey && this.shouldAttachApiKey(path)) {
115
+ headers["x-api-key"] = this.apiKey;
116
+ }
117
+ if (this.getAccessToken) {
118
+ try {
119
+ const token = await this.getAccessToken();
120
+ if (token) {
121
+ headers["Authorization"] = `Bearer ${token}`;
122
+ }
123
+ } catch (error) {
124
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
125
+ console.warn(
126
+ "[AxCloud SDK] Failed to fetch access token:",
127
+ error instanceof Error ? error.message : error
128
+ );
129
+ }
130
+ }
131
+ }
132
+ const url = this.buildUrl(path, params);
133
+ const controller = new AbortController();
134
+ const requestTimeout = timeout ?? this.defaultTimeout;
135
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
136
+ try {
137
+ const response = await fetch(url, {
138
+ ...restOptions,
139
+ headers,
140
+ body: body ? JSON.stringify(body) : void 0,
141
+ signal: controller.signal
142
+ });
143
+ const contentType = response.headers.get("content-type");
144
+ const isJson = contentType?.includes("application/json");
145
+ if (!response.ok) {
146
+ const errorBody = isJson ? await response.json().catch(() => null) : null;
147
+ throw AxCloudError.fromResponse(response.status, errorBody);
148
+ }
149
+ if (response.status === 204) {
150
+ return {};
151
+ }
152
+ return isJson ? await response.json() : {};
153
+ } catch (error) {
154
+ if (error instanceof AxCloudError) {
155
+ throw error;
156
+ }
157
+ if (error instanceof Error && error.name === "AbortError") {
158
+ throw AxCloudError.timeoutError(requestTimeout);
159
+ }
160
+ throw AxCloudError.networkError(error instanceof Error ? error : void 0);
161
+ } finally {
162
+ clearTimeout(timeoutId);
163
+ }
164
+ }
165
+ /**
166
+ * GET request
167
+ */
168
+ get(path, params) {
169
+ return this.request(path, { method: "GET", params });
170
+ }
171
+ /**
172
+ * POST request
173
+ */
174
+ post(path, body) {
175
+ return this.request(path, { method: "POST", body });
176
+ }
177
+ /**
178
+ * PUT request
179
+ */
180
+ put(path, body) {
181
+ return this.request(path, { method: "PUT", body });
182
+ }
183
+ /**
184
+ * PATCH request
185
+ */
186
+ patch(path, body) {
187
+ return this.request(path, { method: "PATCH", body });
188
+ }
189
+ /**
190
+ * DELETE request
191
+ */
192
+ delete(path) {
193
+ return this.request(path, { method: "DELETE" });
194
+ }
195
+ };
196
+ var clientRegistry = /* @__PURE__ */ new WeakMap();
197
+ function createClient(config, key) {
198
+ const client = new AxCloudClient(config);
199
+ if (key) {
200
+ clientRegistry.set(key, client);
201
+ }
202
+ return client;
203
+ }
204
+ function getClient(key) {
205
+ if (key) {
206
+ const client = clientRegistry.get(key);
207
+ if (client) {
208
+ return client;
209
+ }
210
+ }
211
+ throw new Error("AxCloud client not found. Make sure AxCloudProvider is mounted and use useAxCloudContext() to get the client.");
212
+ }
213
+
214
+ // src/core/analytics.ts
215
+ var EVENT_NAME_PATTERN = /^[a-z][a-z0-9_]{1,63}$/;
216
+ var PROPERTY_KEY_PATTERN = /^[a-z][a-z0-9_]{0,47}$/;
217
+ var SENSITIVE_PROPERTY_PATTERN = /(^|_)(auth0|email|name|password|query|search|secret|token|trace|user|userid)($|_)/;
218
+ var EMAIL_VALUE_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
219
+ var OPAQUE_SEGMENT_PATTERNS = [
220
+ /^[0-9a-f]{8}-[0-9a-f-]{27,}$/i,
221
+ /^(org|user|section|document|content|poll|invitation|invite|trace|chan)[_-][a-z0-9_-]+$/i,
222
+ /^[a-f0-9]{20,}$/i,
223
+ /^[a-z0-9_-]{32,}$/i
224
+ ];
225
+ var scriptLoads = /* @__PURE__ */ new Map();
226
+ function isLocalAnalyticsHostname(hostname) {
227
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
228
+ }
229
+ function sanitizeAnalyticsPath(pathname, customNormalizer) {
230
+ const rawPath = pathname.split(/[?#]/, 1)[0] || "/";
231
+ const normalizedInput = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
232
+ const custom = customNormalizer?.(normalizedInput);
233
+ if (custom === null) return null;
234
+ const path = custom ?? normalizedInput;
235
+ const cleanPath = path.split(/[?#]/, 1)[0] || "/";
236
+ const segments = cleanPath.split("/").map((segment) => {
237
+ if (!segment) return segment;
238
+ let decoded = segment;
239
+ try {
240
+ decoded = decodeURIComponent(segment);
241
+ } catch {
242
+ }
243
+ return OPAQUE_SEGMENT_PATTERNS.some((pattern) => pattern.test(decoded)) ? ":id" : segment;
244
+ });
245
+ return segments.join("/") || "/";
246
+ }
247
+ function sanitizeAnalyticsEventData(data) {
248
+ if (!data) return void 0;
249
+ const sanitized = {};
250
+ for (const [rawKey, rawValue] of Object.entries(data).slice(0, 20)) {
251
+ const key = rawKey.trim().toLowerCase();
252
+ if (!PROPERTY_KEY_PATTERN.test(key) || SENSITIVE_PROPERTY_PATTERN.test(key)) continue;
253
+ if (typeof rawValue === "string") {
254
+ const value = rawValue.trim();
255
+ if (!value || value.length > 100 || EMAIL_VALUE_PATTERN.test(value)) continue;
256
+ sanitized[key] = value;
257
+ continue;
258
+ }
259
+ if (typeof rawValue === "number" && Number.isFinite(rawValue)) {
260
+ sanitized[key] = rawValue;
261
+ continue;
262
+ }
263
+ if (typeof rawValue === "boolean") sanitized[key] = rawValue;
264
+ }
265
+ return Object.keys(sanitized).length > 0 ? sanitized : void 0;
266
+ }
267
+ function isAllowedAnalyticsEvent(eventName, allowedEvents) {
268
+ return EVENT_NAME_PATTERN.test(eventName) && Boolean(allowedEvents?.includes(eventName));
269
+ }
270
+ async function fetchAnalyticsPublicConfig(input) {
271
+ const baseUrl = input.apiUrl.replace(/\/$/, "");
272
+ const url = new URL(`${baseUrl}/analytics/public/config`);
273
+ url.searchParams.set("orgId", input.orgId);
274
+ url.searchParams.set("siteKey", input.siteKey);
275
+ url.searchParams.set("stage", input.stage);
276
+ url.searchParams.set("hostname", input.hostname);
277
+ const response = await fetch(url, {
278
+ method: "GET",
279
+ headers: { Accept: "application/json" },
280
+ signal: input.signal
281
+ });
282
+ if (!response.ok) throw new Error(`Analytics configuration returned ${response.status}`);
283
+ return response.json();
284
+ }
285
+ function loadAnalyticsScript(config, doc = document) {
286
+ if (!config.enabled || !config.websiteId || !config.scriptUrl) {
287
+ return Promise.reject(new Error("Analytics tracker configuration is incomplete"));
288
+ }
289
+ const key = `${config.scriptUrl}|${config.websiteId}`;
290
+ const existingPromise = scriptLoads.get(key);
291
+ if (existingPromise) return existingPromise;
292
+ const existing = doc.querySelector(
293
+ `script[data-axcloud-analytics-site="${config.websiteId}"]`
294
+ );
295
+ if (existing && doc.defaultView?.umami) {
296
+ return Promise.resolve();
297
+ }
298
+ const promise = new Promise((resolve, reject) => {
299
+ const script = existing || doc.createElement("script");
300
+ const onLoad = () => resolve();
301
+ const onError = () => reject(new Error("Analytics tracker failed to load"));
302
+ script.addEventListener("load", onLoad, { once: true });
303
+ script.addEventListener("error", onError, { once: true });
304
+ if (!existing) {
305
+ script.src = config.scriptUrl;
306
+ script.defer = true;
307
+ script.dataset.websiteId = config.websiteId;
308
+ script.dataset.axcloudAnalyticsSite = config.websiteId;
309
+ script.dataset.autoTrack = String(config.autoTrack === true);
310
+ if (config.hostUrl) script.dataset.hostUrl = config.hostUrl;
311
+ if (config.domains?.length) script.dataset.domains = config.domains.join(",");
312
+ if (config.respectDoNotTrack !== false) script.dataset.doNotTrack = "true";
313
+ if (config.excludeSearch !== false) script.dataset.excludeSearch = "true";
314
+ if (config.excludeHash !== false) script.dataset.excludeHash = "true";
315
+ doc.head.appendChild(script);
316
+ }
317
+ }).catch((error) => {
318
+ scriptLoads.delete(key);
319
+ throw error;
320
+ });
321
+ scriptLoads.set(key, promise);
322
+ return promise;
323
+ }
324
+ function sendAnalyticsPageView(pathname, options, targetWindow = window) {
325
+ const path = sanitizeAnalyticsPath(pathname, options.normalizePath);
326
+ const umami = targetWindow.umami;
327
+ if (!path || !umami) return false;
328
+ umami.track({ url: path, title: targetWindow.document.title });
329
+ return true;
330
+ }
331
+ function sendAnalyticsEvent(eventName, data, allowedEvents, targetWindow = window) {
332
+ const umami = targetWindow.umami;
333
+ if (!umami || !isAllowedAnalyticsEvent(eventName, allowedEvents)) return false;
334
+ umami.track(eventName, sanitizeAnalyticsEventData(data));
335
+ return true;
336
+ }
337
+ var NAVIGATION_EVENT = "axcloud-sdk:navigation";
338
+ var historySubscriberCount = 0;
339
+ var originalPushState = null;
340
+ var originalReplaceState = null;
341
+ function subscribeToNavigation(callback) {
342
+ if (typeof window === "undefined") return () => void 0;
343
+ if (historySubscriberCount === 0) {
344
+ originalPushState = window.history.pushState.bind(window.history);
345
+ originalReplaceState = window.history.replaceState.bind(window.history);
346
+ window.history.pushState = ((...args) => {
347
+ originalPushState?.(...args);
348
+ window.dispatchEvent(new Event(NAVIGATION_EVENT));
349
+ });
350
+ window.history.replaceState = ((...args) => {
351
+ originalReplaceState?.(...args);
352
+ window.dispatchEvent(new Event(NAVIGATION_EVENT));
353
+ });
354
+ }
355
+ historySubscriberCount += 1;
356
+ window.addEventListener("popstate", callback);
357
+ window.addEventListener(NAVIGATION_EVENT, callback);
358
+ return () => {
359
+ window.removeEventListener("popstate", callback);
360
+ window.removeEventListener(NAVIGATION_EVENT, callback);
361
+ historySubscriberCount = Math.max(0, historySubscriberCount - 1);
362
+ if (historySubscriberCount === 0) {
363
+ if (originalPushState) window.history.pushState = originalPushState;
364
+ if (originalReplaceState) window.history.replaceState = originalReplaceState;
365
+ originalPushState = null;
366
+ originalReplaceState = null;
367
+ }
368
+ };
369
+ }
370
+ function doNotTrackEnabled(config) {
371
+ if (config.respectDoNotTrack === false || typeof navigator === "undefined") return false;
372
+ return navigator.doNotTrack === "1";
373
+ }
374
+ function useAnalyticsRuntime(config) {
375
+ const [enabled, setEnabled] = useState(false);
376
+ const [ready, setReady] = useState(false);
377
+ const publicConfigRef = useRef(null);
378
+ const optionsRef = useRef(config.analytics);
379
+ optionsRef.current = config.analytics;
380
+ const trackPageView = useCallback(
381
+ (pathname) => {
382
+ if (!ready || !optionsRef.current || typeof window === "undefined") return false;
383
+ return sendAnalyticsPageView(pathname || window.location.pathname, optionsRef.current);
384
+ },
385
+ [ready]
386
+ );
387
+ const track = useCallback(
388
+ (eventName, data) => {
389
+ if (!ready || typeof window === "undefined") return false;
390
+ return sendAnalyticsEvent(eventName, data, publicConfigRef.current?.allowedEvents);
391
+ },
392
+ [ready]
393
+ );
394
+ useEffect(() => {
395
+ const options = config.analytics;
396
+ setEnabled(false);
397
+ setReady(false);
398
+ publicConfigRef.current = null;
399
+ if (!options?.enabled || !options.siteKey || typeof window === "undefined") return void 0;
400
+ if (isLocalAnalyticsHostname(window.location.hostname) && !options.trackLocalhost)
401
+ return void 0;
402
+ const controller = new AbortController();
403
+ let cancelled = false;
404
+ let unsubscribe = () => void 0;
405
+ const initialize = async () => {
406
+ try {
407
+ const publicConfig = await fetchAnalyticsPublicConfig({
408
+ apiUrl: config.apiUrl,
409
+ orgId: config.orgId,
410
+ siteKey: options.siteKey,
411
+ stage: config.stage,
412
+ hostname: window.location.hostname,
413
+ signal: controller.signal
414
+ });
415
+ if (cancelled || !publicConfig.enabled || doNotTrackEnabled(publicConfig)) return;
416
+ publicConfigRef.current = publicConfig;
417
+ setEnabled(true);
418
+ await loadAnalyticsScript(publicConfig);
419
+ if (cancelled) return;
420
+ setReady(true);
421
+ if (!publicConfig.autoTrack) {
422
+ const trackCurrentPage = () => {
423
+ sendAnalyticsPageView(window.location.pathname, options);
424
+ };
425
+ trackCurrentPage();
426
+ unsubscribe = subscribeToNavigation(trackCurrentPage);
427
+ }
428
+ } catch (error) {
429
+ if (!cancelled && !(error instanceof Error && error.name === "AbortError")) {
430
+ setEnabled(false);
431
+ setReady(false);
432
+ }
433
+ }
434
+ };
435
+ void initialize();
436
+ return () => {
437
+ cancelled = true;
438
+ controller.abort();
439
+ unsubscribe();
440
+ };
441
+ }, [
442
+ config.analytics?.enabled,
443
+ config.analytics?.siteKey,
444
+ config.analytics?.trackLocalhost,
445
+ config.analytics?.normalizePath,
446
+ config.apiUrl,
447
+ config.orgId,
448
+ config.stage
449
+ ]);
450
+ return useMemo(
451
+ () => ({ enabled, ready, track, trackPageView }),
452
+ [enabled, ready, track, trackPageView]
453
+ );
454
+ }
455
+ function useAnalytics() {
456
+ return useAxCloudContext().analytics;
457
+ }
458
+
459
+ export { AxCloudClient, AxCloudError, createClient, fetchAnalyticsPublicConfig, getClient, isAllowedAnalyticsEvent, isAxCloudError, isLocalAnalyticsHostname, sanitizeAnalyticsEventData, sanitizeAnalyticsPath, useAnalytics, useAnalyticsRuntime };
460
+ //# sourceMappingURL=chunk-F3JPEND3.mjs.map
461
+ //# sourceMappingURL=chunk-F3JPEND3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/errors.ts","../src/core/client.ts","../src/core/analytics.ts","../src/react/analytics.ts"],"names":[],"mappings":"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","file":"chunk-F3JPEND3.mjs","sourcesContent":["/**\n * AxCloud SDK Error Types\n */\n\nexport type AxCloudErrorCode =\n | 'UNAUTHORIZED'\n | 'FORBIDDEN'\n | 'NOT_FOUND'\n | 'VALIDATION_ERROR'\n | 'NETWORK_ERROR'\n | 'TIMEOUT_ERROR'\n | 'SERVER_ERROR'\n | 'UNKNOWN_ERROR';\n\nexport class AxCloudError extends Error {\n readonly code: AxCloudErrorCode;\n readonly status: number;\n readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: AxCloudErrorCode,\n status: number,\n details?: Record<string, unknown>\n ) {\n super(message);\n this.name = 'AxCloudError';\n this.code = code;\n this.status = status;\n this.details = details;\n\n // Maintains proper stack trace for where error was thrown (V8 only)\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor?: typeof AxCloudError) => void;\n };\n if (ErrorWithCapture.captureStackTrace) {\n ErrorWithCapture.captureStackTrace(this, AxCloudError);\n }\n }\n\n static fromResponse(status: number, body?: unknown): AxCloudError {\n const details = typeof body === 'object' ? (body as Record<string, unknown>) : undefined;\n const message =\n (typeof details?.message === 'string' ? details.message : undefined) ||\n (typeof details?.error === 'string' ? details.error : undefined);\n\n switch (status) {\n case 401:\n return new AxCloudError(\n message || 'Authentication required',\n 'UNAUTHORIZED',\n status,\n details\n );\n case 403:\n return new AxCloudError(message || 'Access denied', 'FORBIDDEN', status, details);\n case 404:\n return new AxCloudError(message || 'Resource not found', 'NOT_FOUND', status, details);\n case 422:\n return new AxCloudError(\n message || 'Validation failed',\n 'VALIDATION_ERROR',\n status,\n details\n );\n default:\n if (status >= 500) {\n return new AxCloudError(message || 'Server error', 'SERVER_ERROR', status, details);\n }\n return new AxCloudError(message || 'An error occurred', 'UNKNOWN_ERROR', status, details);\n }\n }\n\n static networkError(originalError?: Error): AxCloudError {\n // Don't include original error details in production to avoid leaking sensitive info\n // Use typeof check to avoid issues in environments where process is not defined\n const isDev = typeof process !== 'undefined' && process.env?.NODE_ENV === 'development';\n const message =\n isDev && originalError?.message ? originalError.message : 'Network request failed';\n\n return new AxCloudError(\n message,\n 'NETWORK_ERROR',\n 0,\n isDev ? { originalError: originalError?.message } : undefined\n );\n }\n\n static timeoutError(timeoutMs: number): AxCloudError {\n return new AxCloudError(`Request timed out after ${timeoutMs}ms`, 'TIMEOUT_ERROR', 0, {\n timeout: timeoutMs,\n });\n }\n}\n\nexport function isAxCloudError(error: unknown): error is AxCloudError {\n return error instanceof AxCloudError;\n}\n","/**\n * AxCloud API Client\n *\n * Fetch wrapper with authentication header injection and error handling.\n */\n\nimport { AxCloudError } from './errors'\n\nexport interface ClientConfig {\n baseUrl: string\n getAccessToken?: () => Promise<string | undefined>\n /** API key for public content endpoints */\n apiKey?: string\n /** Default request timeout in milliseconds (default: 30000) */\n timeout?: number\n}\n\nexport interface RequestOptions extends Omit<RequestInit, 'body'> {\n body?: unknown\n params?: Record<string, string | number | boolean | undefined>\n /** Request timeout in milliseconds (overrides client default) */\n timeout?: number\n}\n\nexport class AxCloudClient {\n private baseUrl: string\n private getAccessToken?: () => Promise<string | undefined>\n private apiKey?: string\n private defaultTimeout: number\n\n constructor(config: ClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, '')\n this.getAccessToken = config.getAccessToken\n this.apiKey = config.apiKey\n this.defaultTimeout = config.timeout ?? 30000\n }\n\n /**\n * Update the access token getter (used when auth state changes)\n */\n setAccessTokenGetter(getter: () => Promise<string | undefined>) {\n this.getAccessToken = getter\n }\n\n /**\n * Build URL with query parameters\n */\n private buildUrl(path: string, params?: Record<string, string | number | boolean | undefined>): string {\n const url = new URL(`${this.baseUrl}${path}`)\n\n if (params) {\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined) {\n url.searchParams.append(key, String(value))\n }\n })\n }\n\n return url.toString()\n }\n\n /**\n * API key should only be sent to public endpoints.\n * This avoids leaking public keys to authenticated/internal routes.\n */\n private shouldAttachApiKey(path: string): boolean {\n const normalized = path.startsWith('/') ? path : `/${path}`\n return (\n normalized.startsWith('/public/') ||\n normalized.startsWith('/api/public/') ||\n normalized.startsWith('/content/public/') ||\n normalized.startsWith('/media/public/') ||\n normalized.startsWith('/documents/public/') ||\n normalized.startsWith('/barnsport/public/') ||\n normalized.startsWith('/api/barnsport/public/')\n )\n }\n\n /**\n * Make an authenticated request\n */\n async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { body, params, headers: customHeaders, timeout, ...restOptions } = options\n\n // Initialize headers as Record<string, string> to avoid type casting\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n }\n\n // Merge custom headers\n if (customHeaders) {\n const customHeadersRecord = customHeaders as Record<string, string>\n Object.assign(headers, customHeadersRecord)\n }\n\n // Add API key header only for public endpoints\n if (this.apiKey && this.shouldAttachApiKey(path)) {\n headers['x-api-key'] = this.apiKey\n }\n\n // Add auth header if we have a token getter\n if (this.getAccessToken) {\n try {\n const token = await this.getAccessToken()\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n } catch (error) {\n // Log in development to help with debugging auth issues\n // Use typeof check to avoid issues in environments where process is not defined\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') {\n console.warn(\n '[AxCloud SDK] Failed to fetch access token:',\n error instanceof Error ? error.message : error\n )\n }\n // Don't throw - allow request to continue (backend will return 401 if needed)\n }\n }\n\n const url = this.buildUrl(path, params)\n\n // Setup AbortController for timeout\n const controller = new AbortController()\n const requestTimeout = timeout ?? this.defaultTimeout\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout)\n\n try {\n const response = await fetch(url, {\n ...restOptions,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n })\n\n // Handle non-JSON responses\n const contentType = response.headers.get('content-type')\n const isJson = contentType?.includes('application/json')\n\n if (!response.ok) {\n const errorBody = isJson ? await response.json().catch(() => null) : null\n throw AxCloudError.fromResponse(response.status, errorBody)\n }\n\n // Return empty object for 204 No Content\n if (response.status === 204) {\n return {} as T\n }\n\n return isJson ? await response.json() : ({} as T)\n } catch (error) {\n if (error instanceof AxCloudError) {\n throw error\n }\n // Handle abort/timeout errors\n if (error instanceof Error && error.name === 'AbortError') {\n throw AxCloudError.timeoutError(requestTimeout)\n }\n throw AxCloudError.networkError(error instanceof Error ? error : undefined)\n } finally {\n clearTimeout(timeoutId)\n }\n }\n\n /**\n * GET request\n */\n get<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T> {\n return this.request<T>(path, { method: 'GET', params })\n }\n\n /**\n * POST request\n */\n post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(path, { method: 'POST', body })\n }\n\n /**\n * PUT request\n */\n put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(path, { method: 'PUT', body })\n }\n\n /**\n * PATCH request\n */\n patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>(path, { method: 'PATCH', body })\n }\n\n /**\n * DELETE request\n */\n delete<T>(path: string): Promise<T> {\n return this.request<T>(path, { method: 'DELETE' })\n }\n}\n\n// Client instance registry - allows multiple providers without SSR issues\n// Uses WeakMap to prevent memory leaks when providers unmount\nconst clientRegistry = new WeakMap<object, AxCloudClient>()\n\n/**\n * Create a client instance associated with a key (typically the provider instance)\n * This allows multiple AxCloudProviders to coexist without conflicts\n */\nexport function createClient(config: ClientConfig, key?: object): AxCloudClient {\n const client = new AxCloudClient(config)\n if (key) {\n clientRegistry.set(key, client)\n }\n return client\n}\n\n/**\n * Get a client instance by key\n * @deprecated Use the client from useAxCloudContext() instead\n */\nexport function getClient(key?: object): AxCloudClient {\n if (key) {\n const client = clientRegistry.get(key)\n if (client) {\n return client\n }\n }\n throw new Error('AxCloud client not found. Make sure AxCloudProvider is mounted and use useAxCloudContext() to get the client.')\n}\n","export type AnalyticsEventValue = string | number | boolean;\nexport type AnalyticsEventData = Record<string, AnalyticsEventValue>;\n\nexport interface AxCloudAnalyticsOptions {\n /** Site key configured in AxCloud, for example \"public-web\". */\n siteKey: string;\n /** Analytics is opt-in and disabled unless this is true. */\n enabled?: boolean;\n /** Allow local collection for explicit development tests. */\n trackLocalhost?: boolean;\n /** Override path normalization. Return null to skip a pageview. */\n normalizePath?: (pathname: string) => string | null;\n}\n\nexport interface AnalyticsPublicConfig {\n enabled: boolean;\n provider?: 'umami';\n websiteId?: string;\n scriptUrl?: string;\n hostUrl?: string;\n domains?: string[];\n autoTrack?: boolean;\n respectDoNotTrack?: boolean;\n excludeSearch?: boolean;\n excludeHash?: boolean;\n allowedEvents?: string[];\n}\n\nexport interface AnalyticsRuntime {\n enabled: boolean;\n ready: boolean;\n track: (eventName: string, data?: AnalyticsEventData) => boolean;\n trackPageView: (pathname?: string) => boolean;\n}\n\ninterface UmamiWindow extends Window {\n umami?: {\n track: (\n event?: string | { url?: string; title?: string },\n data?: AnalyticsEventData\n ) => unknown;\n };\n}\n\nconst EVENT_NAME_PATTERN = /^[a-z][a-z0-9_]{1,63}$/;\nconst PROPERTY_KEY_PATTERN = /^[a-z][a-z0-9_]{0,47}$/;\nconst SENSITIVE_PROPERTY_PATTERN =\n /(^|_)(auth0|email|name|password|query|search|secret|token|trace|user|userid)($|_)/;\nconst EMAIL_VALUE_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst OPAQUE_SEGMENT_PATTERNS = [\n /^[0-9a-f]{8}-[0-9a-f-]{27,}$/i,\n /^(org|user|section|document|content|poll|invitation|invite|trace|chan)[_-][a-z0-9_-]+$/i,\n /^[a-f0-9]{20,}$/i,\n /^[a-z0-9_-]{32,}$/i,\n];\n\nconst scriptLoads = new Map<string, Promise<void>>();\n\nexport function isLocalAnalyticsHostname(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';\n}\n\nexport function sanitizeAnalyticsPath(\n pathname: string,\n customNormalizer?: (pathname: string) => string | null\n): string | null {\n const rawPath = pathname.split(/[?#]/, 1)[0] || '/';\n const normalizedInput = rawPath.startsWith('/') ? rawPath : `/${rawPath}`;\n const custom = customNormalizer?.(normalizedInput);\n if (custom === null) return null;\n const path = custom ?? normalizedInput;\n const cleanPath = path.split(/[?#]/, 1)[0] || '/';\n\n const segments = cleanPath.split('/').map((segment) => {\n if (!segment) return segment;\n let decoded = segment;\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n // Keep malformed path segments encoded and classify them below.\n }\n return OPAQUE_SEGMENT_PATTERNS.some((pattern) => pattern.test(decoded)) ? ':id' : segment;\n });\n\n return segments.join('/') || '/';\n}\n\nexport function sanitizeAnalyticsEventData(\n data: AnalyticsEventData | undefined\n): AnalyticsEventData | undefined {\n if (!data) return undefined;\n const sanitized: AnalyticsEventData = {};\n\n for (const [rawKey, rawValue] of Object.entries(data).slice(0, 20)) {\n const key = rawKey.trim().toLowerCase();\n if (!PROPERTY_KEY_PATTERN.test(key) || SENSITIVE_PROPERTY_PATTERN.test(key)) continue;\n\n if (typeof rawValue === 'string') {\n const value = rawValue.trim();\n if (!value || value.length > 100 || EMAIL_VALUE_PATTERN.test(value)) continue;\n sanitized[key] = value;\n continue;\n }\n if (typeof rawValue === 'number' && Number.isFinite(rawValue)) {\n sanitized[key] = rawValue;\n continue;\n }\n if (typeof rawValue === 'boolean') sanitized[key] = rawValue;\n }\n\n return Object.keys(sanitized).length > 0 ? sanitized : undefined;\n}\n\nexport function isAllowedAnalyticsEvent(\n eventName: string,\n allowedEvents: string[] | undefined\n): boolean {\n return EVENT_NAME_PATTERN.test(eventName) && Boolean(allowedEvents?.includes(eventName));\n}\n\nexport async function fetchAnalyticsPublicConfig(input: {\n apiUrl: string;\n orgId: string;\n siteKey: string;\n stage: string;\n hostname: string;\n signal?: AbortSignal;\n}): Promise<AnalyticsPublicConfig> {\n const baseUrl = input.apiUrl.replace(/\\/$/, '');\n const url = new URL(`${baseUrl}/analytics/public/config`);\n url.searchParams.set('orgId', input.orgId);\n url.searchParams.set('siteKey', input.siteKey);\n url.searchParams.set('stage', input.stage);\n url.searchParams.set('hostname', input.hostname);\n\n const response = await fetch(url, {\n method: 'GET',\n headers: { Accept: 'application/json' },\n signal: input.signal,\n });\n if (!response.ok) throw new Error(`Analytics configuration returned ${response.status}`);\n return response.json() as Promise<AnalyticsPublicConfig>;\n}\n\nexport function loadAnalyticsScript(\n config: AnalyticsPublicConfig,\n doc: Document = document\n): Promise<void> {\n if (!config.enabled || !config.websiteId || !config.scriptUrl) {\n return Promise.reject(new Error('Analytics tracker configuration is incomplete'));\n }\n\n const key = `${config.scriptUrl}|${config.websiteId}`;\n const existingPromise = scriptLoads.get(key);\n if (existingPromise) return existingPromise;\n\n const existing = doc.querySelector<HTMLScriptElement>(\n `script[data-axcloud-analytics-site=\"${config.websiteId}\"]`\n );\n if (existing && (doc.defaultView as UmamiWindow | null)?.umami) {\n return Promise.resolve();\n }\n\n const promise = new Promise<void>((resolve, reject) => {\n const script = existing || doc.createElement('script');\n const onLoad = () => resolve();\n const onError = () => reject(new Error('Analytics tracker failed to load'));\n script.addEventListener('load', onLoad, { once: true });\n script.addEventListener('error', onError, { once: true });\n\n if (!existing) {\n script.src = config.scriptUrl as string;\n script.defer = true;\n script.dataset.websiteId = config.websiteId as string;\n script.dataset.axcloudAnalyticsSite = config.websiteId as string;\n script.dataset.autoTrack = String(config.autoTrack === true);\n if (config.hostUrl) script.dataset.hostUrl = config.hostUrl;\n if (config.domains?.length) script.dataset.domains = config.domains.join(',');\n if (config.respectDoNotTrack !== false) script.dataset.doNotTrack = 'true';\n if (config.excludeSearch !== false) script.dataset.excludeSearch = 'true';\n if (config.excludeHash !== false) script.dataset.excludeHash = 'true';\n doc.head.appendChild(script);\n }\n }).catch((error) => {\n scriptLoads.delete(key);\n throw error;\n });\n\n scriptLoads.set(key, promise);\n return promise;\n}\n\nexport function sendAnalyticsPageView(\n pathname: string,\n options: AxCloudAnalyticsOptions,\n targetWindow: Window = window\n): boolean {\n const path = sanitizeAnalyticsPath(pathname, options.normalizePath);\n const umami = (targetWindow as UmamiWindow).umami;\n if (!path || !umami) return false;\n umami.track({ url: path, title: targetWindow.document.title });\n return true;\n}\n\nexport function sendAnalyticsEvent(\n eventName: string,\n data: AnalyticsEventData | undefined,\n allowedEvents: string[] | undefined,\n targetWindow: Window = window\n): boolean {\n const umami = (targetWindow as UmamiWindow).umami;\n if (!umami || !isAllowedAnalyticsEvent(eventName, allowedEvents)) return false;\n umami.track(eventName, sanitizeAnalyticsEventData(data));\n return true;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { AxCloudConfig } from '../core/types';\nimport { useAxCloudContext } from './context';\nimport {\n fetchAnalyticsPublicConfig,\n isLocalAnalyticsHostname,\n loadAnalyticsScript,\n sendAnalyticsEvent,\n sendAnalyticsPageView,\n type AnalyticsEventData,\n type AnalyticsPublicConfig,\n type AnalyticsRuntime,\n} from '../core/analytics';\n\nconst NAVIGATION_EVENT = 'axcloud-sdk:navigation';\nlet historySubscriberCount = 0;\nlet originalPushState: History['pushState'] | null = null;\nlet originalReplaceState: History['replaceState'] | null = null;\n\nexport type AnalyticsRuntimeConfig = Pick<\n AxCloudConfig,\n 'analytics' | 'apiUrl' | 'orgId' | 'stage'\n>;\n\nfunction subscribeToNavigation(callback: () => void): () => void {\n if (typeof window === 'undefined') return () => undefined;\n\n if (historySubscriberCount === 0) {\n originalPushState = window.history.pushState.bind(window.history);\n originalReplaceState = window.history.replaceState.bind(window.history);\n window.history.pushState = ((...args: Parameters<History['pushState']>) => {\n originalPushState?.(...args);\n window.dispatchEvent(new Event(NAVIGATION_EVENT));\n }) as History['pushState'];\n window.history.replaceState = ((...args: Parameters<History['replaceState']>) => {\n originalReplaceState?.(...args);\n window.dispatchEvent(new Event(NAVIGATION_EVENT));\n }) as History['replaceState'];\n }\n historySubscriberCount += 1;\n window.addEventListener('popstate', callback);\n window.addEventListener(NAVIGATION_EVENT, callback);\n\n return () => {\n window.removeEventListener('popstate', callback);\n window.removeEventListener(NAVIGATION_EVENT, callback);\n historySubscriberCount = Math.max(0, historySubscriberCount - 1);\n if (historySubscriberCount === 0) {\n if (originalPushState) window.history.pushState = originalPushState;\n if (originalReplaceState) window.history.replaceState = originalReplaceState;\n originalPushState = null;\n originalReplaceState = null;\n }\n };\n}\n\nfunction doNotTrackEnabled(config: AnalyticsPublicConfig): boolean {\n if (config.respectDoNotTrack === false || typeof navigator === 'undefined') return false;\n return navigator.doNotTrack === '1';\n}\n\nexport function useAnalyticsRuntime(config: AnalyticsRuntimeConfig): AnalyticsRuntime {\n const [enabled, setEnabled] = useState(false);\n const [ready, setReady] = useState(false);\n const publicConfigRef = useRef<AnalyticsPublicConfig | null>(null);\n const optionsRef = useRef(config.analytics);\n optionsRef.current = config.analytics;\n\n const trackPageView = useCallback(\n (pathname?: string) => {\n if (!ready || !optionsRef.current || typeof window === 'undefined') return false;\n return sendAnalyticsPageView(pathname || window.location.pathname, optionsRef.current);\n },\n [ready]\n );\n\n const track = useCallback(\n (eventName: string, data?: AnalyticsEventData) => {\n if (!ready || typeof window === 'undefined') return false;\n return sendAnalyticsEvent(eventName, data, publicConfigRef.current?.allowedEvents);\n },\n [ready]\n );\n\n useEffect(() => {\n const options = config.analytics;\n setEnabled(false);\n setReady(false);\n publicConfigRef.current = null;\n\n if (!options?.enabled || !options.siteKey || typeof window === 'undefined') return undefined;\n if (isLocalAnalyticsHostname(window.location.hostname) && !options.trackLocalhost)\n return undefined;\n\n const controller = new AbortController();\n let cancelled = false;\n let unsubscribe: () => void = () => undefined;\n\n const initialize = async () => {\n try {\n const publicConfig = await fetchAnalyticsPublicConfig({\n apiUrl: config.apiUrl,\n orgId: config.orgId,\n siteKey: options.siteKey,\n stage: config.stage,\n hostname: window.location.hostname,\n signal: controller.signal,\n });\n if (cancelled || !publicConfig.enabled || doNotTrackEnabled(publicConfig)) return;\n\n publicConfigRef.current = publicConfig;\n setEnabled(true);\n await loadAnalyticsScript(publicConfig);\n if (cancelled) return;\n setReady(true);\n\n if (!publicConfig.autoTrack) {\n const trackCurrentPage = () => {\n sendAnalyticsPageView(window.location.pathname, options);\n };\n trackCurrentPage();\n unsubscribe = subscribeToNavigation(trackCurrentPage);\n }\n } catch (error) {\n if (!cancelled && !(error instanceof Error && error.name === 'AbortError')) {\n setEnabled(false);\n setReady(false);\n }\n }\n };\n\n void initialize();\n return () => {\n cancelled = true;\n controller.abort();\n unsubscribe();\n };\n }, [\n config.analytics?.enabled,\n config.analytics?.siteKey,\n config.analytics?.trackLocalhost,\n config.analytics?.normalizePath,\n config.apiUrl,\n config.orgId,\n config.stage,\n ]);\n\n return useMemo(\n () => ({ enabled, ready, track, trackPageView }),\n [enabled, ready, track, trackPageView]\n );\n}\n\nexport function useAnalytics(): AnalyticsRuntime {\n return useAxCloudContext().analytics;\n}\n"]}