@nexushub/client 0.1.1 → 0.1.3
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.cjs +88 -66
- package/dist/index.d.cts +1 -4
- package/dist/index.d.ts +1 -4
- package/dist/index.js +73 -51
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3,16 +3,19 @@ var DEFAULT_API_URL = "http://localhost:3001";
|
|
|
3
3
|
var DEFAULT_ANALYTICS_URL = "http://localhost:3002";
|
|
4
4
|
var LOCAL_NEST_URL = "http://localhost:3001";
|
|
5
5
|
var LOCAL_RUST_URL = "http://localhost:3002";
|
|
6
|
-
var hasEnv = () => {
|
|
7
|
-
return typeof process !== "undefined" && typeof process.env !== "undefined" && Object.keys(process.env).length > 0;
|
|
8
|
-
};
|
|
9
6
|
var getEnvConfig = () => {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
7
|
+
const NEXT_PUBLIC_ID = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_ID : void 0;
|
|
8
|
+
const NEXT_PUBLIC_KEY = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_KEY : void 0;
|
|
9
|
+
const NEXT_PUBLIC_URL = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_API_URL : void 0;
|
|
10
|
+
const NODE_ID = typeof process !== "undefined" ? process.env.NEXUS_PROJECT_ID : void 0;
|
|
11
|
+
const NODE_KEY = typeof process !== "undefined" ? process.env.NEXUS_API_KEY : void 0;
|
|
12
|
+
const NODE_URL = typeof process !== "undefined" ? process.env.NEXUS_API_URL : void 0;
|
|
13
|
+
const NODE_ENV = typeof process !== "undefined" ? process.env.NODE_ENV : "production";
|
|
14
|
+
const isDev = NODE_ENV === "development" || typeof window !== "undefined" && window.location.hostname === "localhost";
|
|
15
|
+
const projectId = _nullishCoalesce(NEXT_PUBLIC_ID, () => ( NODE_ID));
|
|
16
|
+
const apiKey = _nullishCoalesce(NEXT_PUBLIC_KEY, () => ( NODE_KEY));
|
|
17
|
+
const apiUrl = _nullishCoalesce(_nullishCoalesce(NEXT_PUBLIC_URL, () => ( NODE_URL)), () => ( (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL)));
|
|
18
|
+
const analyticsUrl = apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL;
|
|
16
19
|
return {
|
|
17
20
|
projectId,
|
|
18
21
|
apiKey,
|
|
@@ -28,7 +31,8 @@ var mergeConfigs = (base, override) => {
|
|
|
28
31
|
...override,
|
|
29
32
|
apiUrl: mergedApiUrl,
|
|
30
33
|
analyticsUrl: mergedAnalyticsUrl,
|
|
31
|
-
projectId: override.projectId || base.projectId
|
|
34
|
+
projectId: override.projectId || base.projectId,
|
|
35
|
+
apiKey: override.apiKey || base.apiKey
|
|
32
36
|
};
|
|
33
37
|
};
|
|
34
38
|
var getFullConfig = (partialConfig) => {
|
|
@@ -39,9 +43,6 @@ var validateConfig = (config) => {
|
|
|
39
43
|
const errors = [];
|
|
40
44
|
if (!config.projectId) errors.push("Missing projectId");
|
|
41
45
|
if (!config.apiUrl) errors.push("Missing apiUrl");
|
|
42
|
-
if (config.apiUrl && !config.apiUrl.startsWith("http")) {
|
|
43
|
-
errors.push("apiUrl must be a valid URL (http:// or https://)");
|
|
44
|
-
}
|
|
45
46
|
return errors;
|
|
46
47
|
};
|
|
47
48
|
|
|
@@ -364,7 +365,9 @@ var RateLimiter = class {
|
|
|
364
365
|
getStats() {
|
|
365
366
|
const now = Date.now();
|
|
366
367
|
const windowStart = now - this.config.timeWindow;
|
|
367
|
-
const currentRequests = this.requests.filter(
|
|
368
|
+
const currentRequests = this.requests.filter(
|
|
369
|
+
(time) => time > windowStart
|
|
370
|
+
).length;
|
|
368
371
|
return {
|
|
369
372
|
currentRequests,
|
|
370
373
|
limit: this.config.maxRequests
|
|
@@ -445,10 +448,15 @@ var CircuitBreaker = class {
|
|
|
445
448
|
if (this.failures >= this.failureThreshold) {
|
|
446
449
|
this.state = 1 /* OPEN */;
|
|
447
450
|
if (process.env.NODE_ENV === "development") {
|
|
448
|
-
console.warn(
|
|
451
|
+
console.warn(
|
|
452
|
+
`[NexusHub] \u{1F50C} Circuit Breaker OPEN. Pausing network requests.`
|
|
453
|
+
);
|
|
449
454
|
}
|
|
450
455
|
}
|
|
451
456
|
}
|
|
457
|
+
isIgnorableError(error) {
|
|
458
|
+
return _optionalChain([error, 'optionalAccess', _13 => _13.status]) === 401 || _optionalChain([error, 'optionalAccess', _14 => _14.status]) === 404;
|
|
459
|
+
}
|
|
452
460
|
};
|
|
453
461
|
var RequestBatcher = class {
|
|
454
462
|
constructor(batchWindow = 10, maxBatchSize = 20) {
|
|
@@ -526,10 +534,10 @@ function buildQueryString(query) {
|
|
|
526
534
|
if (query.sort) params.append("sort", query.sort);
|
|
527
535
|
if (query.order) params.append("order", query.order);
|
|
528
536
|
if (query.search) params.append("search", query.search);
|
|
529
|
-
if (_optionalChain([query, 'access',
|
|
537
|
+
if (_optionalChain([query, 'access', _15 => _15.include, 'optionalAccess', _16 => _16.length])) {
|
|
530
538
|
params.append("include", query.include.join(","));
|
|
531
539
|
}
|
|
532
|
-
if (_optionalChain([query, 'access',
|
|
540
|
+
if (_optionalChain([query, 'access', _17 => _17.fields, 'optionalAccess', _18 => _18.length])) {
|
|
533
541
|
params.append("fields", query.fields.join(","));
|
|
534
542
|
}
|
|
535
543
|
if (query.filter) {
|
|
@@ -811,7 +819,7 @@ var ContentEngine = class {
|
|
|
811
819
|
}
|
|
812
820
|
return this.requestBatcher.schedule(cacheKey, async () => {
|
|
813
821
|
const params = new URLSearchParams();
|
|
814
|
-
if (_optionalChain([options, 'access',
|
|
822
|
+
if (_optionalChain([options, 'access', _19 => _19.include, 'optionalAccess', _20 => _20.length])) {
|
|
815
823
|
params.append("include", options.include.join(","));
|
|
816
824
|
}
|
|
817
825
|
const url = `${this.config.apiUrl}/content/${this.config.projectId}/collection/${collectionId}/${itemId}?${params}`;
|
|
@@ -844,10 +852,10 @@ var ContentEngine = class {
|
|
|
844
852
|
q: query,
|
|
845
853
|
limit: (options.limit || 20).toString()
|
|
846
854
|
});
|
|
847
|
-
if (_optionalChain([options, 'access',
|
|
855
|
+
if (_optionalChain([options, 'access', _21 => _21.collections, 'optionalAccess', _22 => _22.length])) {
|
|
848
856
|
params.append("collections", options.collections.join(","));
|
|
849
857
|
}
|
|
850
|
-
if (_optionalChain([options, 'access',
|
|
858
|
+
if (_optionalChain([options, 'access', _23 => _23.fields, 'optionalAccess', _24 => _24.length])) {
|
|
851
859
|
params.append("fields", options.fields.join(","));
|
|
852
860
|
}
|
|
853
861
|
const url = `${this.config.apiUrl}/content/${this.config.projectId}/search?${params}`;
|
|
@@ -908,7 +916,7 @@ var ContentEngine = class {
|
|
|
908
916
|
}
|
|
909
917
|
};
|
|
910
918
|
eventSource.onerror = () => {
|
|
911
|
-
_optionalChain([eventSource, 'optionalAccess',
|
|
919
|
+
_optionalChain([eventSource, 'optionalAccess', _25 => _25.close, 'call', _26 => _26()]);
|
|
912
920
|
if (isClosed) return;
|
|
913
921
|
const timeout = Math.min(1e3 * Math.pow(2, retryCount), 1e4);
|
|
914
922
|
retryCount++;
|
|
@@ -921,7 +929,7 @@ var ContentEngine = class {
|
|
|
921
929
|
connect();
|
|
922
930
|
return () => {
|
|
923
931
|
isClosed = true;
|
|
924
|
-
_optionalChain([eventSource, 'optionalAccess',
|
|
932
|
+
_optionalChain([eventSource, 'optionalAccess', _27 => _27.close, 'call', _28 => _28()]);
|
|
925
933
|
};
|
|
926
934
|
}
|
|
927
935
|
// --- CACHE MANAGEMENT ---
|
|
@@ -1461,34 +1469,31 @@ var Tracker = class {
|
|
|
1461
1469
|
const entropy = await getDeviceEntropy();
|
|
1462
1470
|
const perfMetrics = vitalsCollector.getMetricsSnapshot();
|
|
1463
1471
|
const payload = {
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
// We send this, Rust verifies it
|
|
1472
|
+
projectId: this.config.projectId,
|
|
1473
|
+
sessionId: this.sessionId,
|
|
1467
1474
|
url: window.location.href,
|
|
1468
1475
|
referrer: document.referrer,
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1476
|
+
userAgent: window.navigator.userAgent,
|
|
1477
|
+
screenWidth: window.screen.width,
|
|
1478
|
+
screenHeight: window.screen.height,
|
|
1472
1479
|
language: window.navigator.language,
|
|
1473
1480
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
// 3. Attach Performance Data (Rust: Option<PerformanceMetrics>)
|
|
1481
|
+
eventType,
|
|
1482
|
+
eventName,
|
|
1483
|
+
eventData: data,
|
|
1478
1484
|
performance: perfMetrics || void 0,
|
|
1479
|
-
// 4. Attach Hardware Signals for Anomaly Detection (Rust: DeviceData)
|
|
1480
1485
|
context: {
|
|
1481
1486
|
device: {
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1487
|
+
hardwareConcurrency: entropy.hardware_concurrency,
|
|
1488
|
+
// Match Rust sub-struct too if needed
|
|
1489
|
+
deviceMemory: entropy.device_memory,
|
|
1490
|
+
pixelRatio: entropy.pixel_ratio,
|
|
1491
|
+
canvasFingerprint: entropy.canvas_hash,
|
|
1486
1492
|
platform: entropy.platform
|
|
1487
1493
|
},
|
|
1488
|
-
|
|
1489
|
-
// Hint for stitching
|
|
1494
|
+
visitorIdLocal: this.visitorId
|
|
1490
1495
|
},
|
|
1491
|
-
|
|
1496
|
+
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1492
1497
|
};
|
|
1493
1498
|
await eventStorage.enqueue(payload);
|
|
1494
1499
|
const count = await eventStorage.count();
|
|
@@ -1610,8 +1615,8 @@ var AnalyticsEngine = class {
|
|
|
1610
1615
|
navigator.share = (data) => {
|
|
1611
1616
|
this.tracker.send("social_share", {
|
|
1612
1617
|
method: "native_share_menu",
|
|
1613
|
-
url: _optionalChain([data, 'optionalAccess',
|
|
1614
|
-
title: _optionalChain([data, 'optionalAccess',
|
|
1618
|
+
url: _optionalChain([data, 'optionalAccess', _29 => _29.url]) || window.location.href,
|
|
1619
|
+
title: _optionalChain([data, 'optionalAccess', _30 => _30.title])
|
|
1615
1620
|
});
|
|
1616
1621
|
return originalShare.apply(navigator, [data]);
|
|
1617
1622
|
};
|
|
@@ -1706,9 +1711,9 @@ var AnalyticsEngine = class {
|
|
|
1706
1711
|
const config = this.tracker["config"];
|
|
1707
1712
|
const endpoint = `${config.analyticsUrl}/api/${type}`;
|
|
1708
1713
|
const payload = {
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1714
|
+
projectId: config.projectId,
|
|
1715
|
+
sessionId: this.tracker.getSession(),
|
|
1716
|
+
visitorId: this.tracker.visitorId,
|
|
1712
1717
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1713
1718
|
...data
|
|
1714
1719
|
};
|
|
@@ -1742,7 +1747,7 @@ var AnalyticsEngine = class {
|
|
|
1742
1747
|
this.tracker.send("click", {
|
|
1743
1748
|
element_type: "link",
|
|
1744
1749
|
href: link.href,
|
|
1745
|
-
text: _optionalChain([link, 'access',
|
|
1750
|
+
text: _optionalChain([link, 'access', _31 => _31.innerText, 'optionalAccess', _32 => _32.substring, 'call', _33 => _33(0, 50)]),
|
|
1746
1751
|
id: link.id,
|
|
1747
1752
|
classes: link.className,
|
|
1748
1753
|
dataset: { ...link.dataset }
|
|
@@ -1752,7 +1757,7 @@ var AnalyticsEngine = class {
|
|
|
1752
1757
|
if (button) {
|
|
1753
1758
|
this.tracker.send("click", {
|
|
1754
1759
|
element_type: "button",
|
|
1755
|
-
text: _optionalChain([button, 'access',
|
|
1760
|
+
text: _optionalChain([button, 'access', _34 => _34.innerText, 'optionalAccess', _35 => _35.substring, 'call', _36 => _36(0, 50)]),
|
|
1756
1761
|
id: button.id,
|
|
1757
1762
|
classes: button.className,
|
|
1758
1763
|
coordinates: { x: e.clientX, y: e.clientY }
|
|
@@ -1822,11 +1827,11 @@ var NexusClient = class {
|
|
|
1822
1827
|
constructor(config) {
|
|
1823
1828
|
const fullConfig = getFullConfig(config);
|
|
1824
1829
|
this.config = {
|
|
1825
|
-
debug: _optionalChain([config, 'optionalAccess',
|
|
1826
|
-
cacheStrategy: _optionalChain([config, 'optionalAccess',
|
|
1827
|
-
revalidateTime: _optionalChain([config, 'optionalAccess',
|
|
1828
|
-
timeout: _optionalChain([config, 'optionalAccess',
|
|
1829
|
-
retries: _optionalChain([config, 'optionalAccess',
|
|
1830
|
+
debug: _optionalChain([config, 'optionalAccess', _37 => _37.debug]) || false,
|
|
1831
|
+
cacheStrategy: _optionalChain([config, 'optionalAccess', _38 => _38.cacheStrategy]) || "memory",
|
|
1832
|
+
revalidateTime: _optionalChain([config, 'optionalAccess', _39 => _39.revalidateTime]) || 60,
|
|
1833
|
+
timeout: _optionalChain([config, 'optionalAccess', _40 => _40.timeout]) || 1e4,
|
|
1834
|
+
retries: _optionalChain([config, 'optionalAccess', _41 => _41.retries]) || 3,
|
|
1830
1835
|
...fullConfig
|
|
1831
1836
|
};
|
|
1832
1837
|
this.content = new ContentEngine(this.config);
|
|
@@ -1861,6 +1866,12 @@ var _navigation = require('next/navigation');
|
|
|
1861
1866
|
|
|
1862
1867
|
// src/auth/context.tsx
|
|
1863
1868
|
|
|
1869
|
+
|
|
1870
|
+
|
|
1871
|
+
|
|
1872
|
+
|
|
1873
|
+
|
|
1874
|
+
|
|
1864
1875
|
var _jsxruntime = require('react/jsx-runtime');
|
|
1865
1876
|
var AuthContext = _react.createContext.call(void 0, null);
|
|
1866
1877
|
var AuthProvider = ({
|
|
@@ -1956,7 +1967,10 @@ var AuthProvider = ({
|
|
|
1956
1967
|
const logout = async () => {
|
|
1957
1968
|
setIsLoading(true);
|
|
1958
1969
|
try {
|
|
1959
|
-
await fetch(`${AUTH_BASE}/logout`, {
|
|
1970
|
+
await fetch(`${AUTH_BASE}/logout`, {
|
|
1971
|
+
method: "POST",
|
|
1972
|
+
headers: getHeaders(config)
|
|
1973
|
+
});
|
|
1960
1974
|
} catch (e) {
|
|
1961
1975
|
console.warn("Logout network error", e);
|
|
1962
1976
|
} finally {
|
|
@@ -1993,17 +2007,23 @@ var AuthProvider = ({
|
|
|
1993
2007
|
});
|
|
1994
2008
|
if (!res.ok) throw await parseError(res);
|
|
1995
2009
|
};
|
|
1996
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2010
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2011
|
+
AuthContext.Provider,
|
|
2012
|
+
{
|
|
2013
|
+
value: {
|
|
2014
|
+
user,
|
|
2015
|
+
isLoading,
|
|
2016
|
+
error,
|
|
2017
|
+
isAuthenticated: !!user,
|
|
2018
|
+
login,
|
|
2019
|
+
register,
|
|
2020
|
+
logout,
|
|
2021
|
+
updateProfile,
|
|
2022
|
+
requestPasswordReset
|
|
2023
|
+
},
|
|
2024
|
+
children
|
|
2025
|
+
}
|
|
2026
|
+
);
|
|
2007
2027
|
};
|
|
2008
2028
|
var useNexusAuth = () => {
|
|
2009
2029
|
const context = _react.useContext.call(void 0, AuthContext);
|
|
@@ -2015,8 +2035,10 @@ var useNexusAuth = () => {
|
|
|
2015
2035
|
function getHeaders(config) {
|
|
2016
2036
|
return {
|
|
2017
2037
|
"Content-Type": "application/json",
|
|
2018
|
-
"x-nexus-project": config.projectId
|
|
2019
|
-
|
|
2038
|
+
"x-nexus-project": config.projectId,
|
|
2039
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
2040
|
+
// 👈 CRITICAL: Send the nx_pk_ key
|
|
2041
|
+
// Note: We do NOT send the Master API Key here.
|
|
2020
2042
|
// This is client-side. The backend uses Cookies or public tokens.
|
|
2021
2043
|
};
|
|
2022
2044
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -13,9 +13,6 @@ declare const DEFAULT_ANALYTICS_URL = "http://localhost:3002";
|
|
|
13
13
|
declare const LOCAL_NEST_URL = "http://localhost:3001";
|
|
14
14
|
declare const LOCAL_RUST_URL = "http://localhost:3002";
|
|
15
15
|
declare const getEnvConfig: () => MinimalNexusConfig;
|
|
16
|
-
/**
|
|
17
|
-
* Merges base environment config with manual overrides from the constructor
|
|
18
|
-
*/
|
|
19
16
|
declare const mergeConfigs: (base: MinimalNexusConfig, override: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
|
|
20
17
|
declare const getFullConfig: (partialConfig?: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
|
|
21
18
|
declare const validateConfig: (config: MinimalNexusConfig) => string[];
|
|
@@ -328,7 +325,7 @@ interface AuthContextType extends AuthState {
|
|
|
328
325
|
requestPasswordReset: (email: string) => Promise<void>;
|
|
329
326
|
}
|
|
330
327
|
|
|
331
|
-
declare const AuthProvider: ({ children, config }: {
|
|
328
|
+
declare const AuthProvider: ({ children, config, }: {
|
|
332
329
|
children: React.ReactNode;
|
|
333
330
|
config: NexusConfig;
|
|
334
331
|
}) => react_jsx_runtime.JSX.Element;
|
package/dist/index.d.ts
CHANGED
|
@@ -13,9 +13,6 @@ declare const DEFAULT_ANALYTICS_URL = "http://localhost:3002";
|
|
|
13
13
|
declare const LOCAL_NEST_URL = "http://localhost:3001";
|
|
14
14
|
declare const LOCAL_RUST_URL = "http://localhost:3002";
|
|
15
15
|
declare const getEnvConfig: () => MinimalNexusConfig;
|
|
16
|
-
/**
|
|
17
|
-
* Merges base environment config with manual overrides from the constructor
|
|
18
|
-
*/
|
|
19
16
|
declare const mergeConfigs: (base: MinimalNexusConfig, override: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
|
|
20
17
|
declare const getFullConfig: (partialConfig?: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
|
|
21
18
|
declare const validateConfig: (config: MinimalNexusConfig) => string[];
|
|
@@ -328,7 +325,7 @@ interface AuthContextType extends AuthState {
|
|
|
328
325
|
requestPasswordReset: (email: string) => Promise<void>;
|
|
329
326
|
}
|
|
330
327
|
|
|
331
|
-
declare const AuthProvider: ({ children, config }: {
|
|
328
|
+
declare const AuthProvider: ({ children, config, }: {
|
|
332
329
|
children: React.ReactNode;
|
|
333
330
|
config: NexusConfig;
|
|
334
331
|
}) => react_jsx_runtime.JSX.Element;
|
package/dist/index.js
CHANGED
|
@@ -3,16 +3,19 @@ var DEFAULT_API_URL = "http://localhost:3001";
|
|
|
3
3
|
var DEFAULT_ANALYTICS_URL = "http://localhost:3002";
|
|
4
4
|
var LOCAL_NEST_URL = "http://localhost:3001";
|
|
5
5
|
var LOCAL_RUST_URL = "http://localhost:3002";
|
|
6
|
-
var hasEnv = () => {
|
|
7
|
-
return typeof process !== "undefined" && typeof process.env !== "undefined" && Object.keys(process.env).length > 0;
|
|
8
|
-
};
|
|
9
6
|
var getEnvConfig = () => {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
7
|
+
const NEXT_PUBLIC_ID = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_ID : void 0;
|
|
8
|
+
const NEXT_PUBLIC_KEY = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_KEY : void 0;
|
|
9
|
+
const NEXT_PUBLIC_URL = typeof process !== "undefined" ? process.env.NEXT_PUBLIC_NEXUS_API_URL : void 0;
|
|
10
|
+
const NODE_ID = typeof process !== "undefined" ? process.env.NEXUS_PROJECT_ID : void 0;
|
|
11
|
+
const NODE_KEY = typeof process !== "undefined" ? process.env.NEXUS_API_KEY : void 0;
|
|
12
|
+
const NODE_URL = typeof process !== "undefined" ? process.env.NEXUS_API_URL : void 0;
|
|
13
|
+
const NODE_ENV = typeof process !== "undefined" ? process.env.NODE_ENV : "production";
|
|
14
|
+
const isDev = NODE_ENV === "development" || typeof window !== "undefined" && window.location.hostname === "localhost";
|
|
15
|
+
const projectId = NEXT_PUBLIC_ID ?? NODE_ID;
|
|
16
|
+
const apiKey = NEXT_PUBLIC_KEY ?? NODE_KEY;
|
|
17
|
+
const apiUrl = NEXT_PUBLIC_URL ?? NODE_URL ?? (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL);
|
|
18
|
+
const analyticsUrl = apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL;
|
|
16
19
|
return {
|
|
17
20
|
projectId,
|
|
18
21
|
apiKey,
|
|
@@ -28,7 +31,8 @@ var mergeConfigs = (base, override) => {
|
|
|
28
31
|
...override,
|
|
29
32
|
apiUrl: mergedApiUrl,
|
|
30
33
|
analyticsUrl: mergedAnalyticsUrl,
|
|
31
|
-
projectId: override.projectId || base.projectId
|
|
34
|
+
projectId: override.projectId || base.projectId,
|
|
35
|
+
apiKey: override.apiKey || base.apiKey
|
|
32
36
|
};
|
|
33
37
|
};
|
|
34
38
|
var getFullConfig = (partialConfig) => {
|
|
@@ -39,9 +43,6 @@ var validateConfig = (config) => {
|
|
|
39
43
|
const errors = [];
|
|
40
44
|
if (!config.projectId) errors.push("Missing projectId");
|
|
41
45
|
if (!config.apiUrl) errors.push("Missing apiUrl");
|
|
42
|
-
if (config.apiUrl && !config.apiUrl.startsWith("http")) {
|
|
43
|
-
errors.push("apiUrl must be a valid URL (http:// or https://)");
|
|
44
|
-
}
|
|
45
46
|
return errors;
|
|
46
47
|
};
|
|
47
48
|
|
|
@@ -364,7 +365,9 @@ var RateLimiter = class {
|
|
|
364
365
|
getStats() {
|
|
365
366
|
const now = Date.now();
|
|
366
367
|
const windowStart = now - this.config.timeWindow;
|
|
367
|
-
const currentRequests = this.requests.filter(
|
|
368
|
+
const currentRequests = this.requests.filter(
|
|
369
|
+
(time) => time > windowStart
|
|
370
|
+
).length;
|
|
368
371
|
return {
|
|
369
372
|
currentRequests,
|
|
370
373
|
limit: this.config.maxRequests
|
|
@@ -445,10 +448,15 @@ var CircuitBreaker = class {
|
|
|
445
448
|
if (this.failures >= this.failureThreshold) {
|
|
446
449
|
this.state = 1 /* OPEN */;
|
|
447
450
|
if (process.env.NODE_ENV === "development") {
|
|
448
|
-
console.warn(
|
|
451
|
+
console.warn(
|
|
452
|
+
`[NexusHub] \u{1F50C} Circuit Breaker OPEN. Pausing network requests.`
|
|
453
|
+
);
|
|
449
454
|
}
|
|
450
455
|
}
|
|
451
456
|
}
|
|
457
|
+
isIgnorableError(error) {
|
|
458
|
+
return error?.status === 401 || error?.status === 404;
|
|
459
|
+
}
|
|
452
460
|
};
|
|
453
461
|
var RequestBatcher = class {
|
|
454
462
|
constructor(batchWindow = 10, maxBatchSize = 20) {
|
|
@@ -1461,34 +1469,31 @@ var Tracker = class {
|
|
|
1461
1469
|
const entropy = await getDeviceEntropy();
|
|
1462
1470
|
const perfMetrics = vitalsCollector.getMetricsSnapshot();
|
|
1463
1471
|
const payload = {
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
// We send this, Rust verifies it
|
|
1472
|
+
projectId: this.config.projectId,
|
|
1473
|
+
sessionId: this.sessionId,
|
|
1467
1474
|
url: window.location.href,
|
|
1468
1475
|
referrer: document.referrer,
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1476
|
+
userAgent: window.navigator.userAgent,
|
|
1477
|
+
screenWidth: window.screen.width,
|
|
1478
|
+
screenHeight: window.screen.height,
|
|
1472
1479
|
language: window.navigator.language,
|
|
1473
1480
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
// 3. Attach Performance Data (Rust: Option<PerformanceMetrics>)
|
|
1481
|
+
eventType,
|
|
1482
|
+
eventName,
|
|
1483
|
+
eventData: data,
|
|
1478
1484
|
performance: perfMetrics || void 0,
|
|
1479
|
-
// 4. Attach Hardware Signals for Anomaly Detection (Rust: DeviceData)
|
|
1480
1485
|
context: {
|
|
1481
1486
|
device: {
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1487
|
+
hardwareConcurrency: entropy.hardware_concurrency,
|
|
1488
|
+
// Match Rust sub-struct too if needed
|
|
1489
|
+
deviceMemory: entropy.device_memory,
|
|
1490
|
+
pixelRatio: entropy.pixel_ratio,
|
|
1491
|
+
canvasFingerprint: entropy.canvas_hash,
|
|
1486
1492
|
platform: entropy.platform
|
|
1487
1493
|
},
|
|
1488
|
-
|
|
1489
|
-
// Hint for stitching
|
|
1494
|
+
visitorIdLocal: this.visitorId
|
|
1490
1495
|
},
|
|
1491
|
-
|
|
1496
|
+
clientTimestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1492
1497
|
};
|
|
1493
1498
|
await eventStorage.enqueue(payload);
|
|
1494
1499
|
const count = await eventStorage.count();
|
|
@@ -1706,9 +1711,9 @@ var AnalyticsEngine = class {
|
|
|
1706
1711
|
const config = this.tracker["config"];
|
|
1707
1712
|
const endpoint = `${config.analyticsUrl}/api/${type}`;
|
|
1708
1713
|
const payload = {
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1714
|
+
projectId: config.projectId,
|
|
1715
|
+
sessionId: this.tracker.getSession(),
|
|
1716
|
+
visitorId: this.tracker.visitorId,
|
|
1712
1717
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1713
1718
|
...data
|
|
1714
1719
|
};
|
|
@@ -1860,7 +1865,13 @@ import React2, { createContext as createContext2, useEffect as useEffect2, useRe
|
|
|
1860
1865
|
import { usePathname, useSearchParams } from "next/navigation";
|
|
1861
1866
|
|
|
1862
1867
|
// src/auth/context.tsx
|
|
1863
|
-
import {
|
|
1868
|
+
import {
|
|
1869
|
+
createContext,
|
|
1870
|
+
useContext,
|
|
1871
|
+
useEffect,
|
|
1872
|
+
useState,
|
|
1873
|
+
useCallback
|
|
1874
|
+
} from "react";
|
|
1864
1875
|
import { jsx } from "react/jsx-runtime";
|
|
1865
1876
|
var AuthContext = createContext(null);
|
|
1866
1877
|
var AuthProvider = ({
|
|
@@ -1956,7 +1967,10 @@ var AuthProvider = ({
|
|
|
1956
1967
|
const logout = async () => {
|
|
1957
1968
|
setIsLoading(true);
|
|
1958
1969
|
try {
|
|
1959
|
-
await fetch(`${AUTH_BASE}/logout`, {
|
|
1970
|
+
await fetch(`${AUTH_BASE}/logout`, {
|
|
1971
|
+
method: "POST",
|
|
1972
|
+
headers: getHeaders(config)
|
|
1973
|
+
});
|
|
1960
1974
|
} catch (e) {
|
|
1961
1975
|
console.warn("Logout network error", e);
|
|
1962
1976
|
} finally {
|
|
@@ -1993,17 +2007,23 @@ var AuthProvider = ({
|
|
|
1993
2007
|
});
|
|
1994
2008
|
if (!res.ok) throw await parseError(res);
|
|
1995
2009
|
};
|
|
1996
|
-
return /* @__PURE__ */ jsx(
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2010
|
+
return /* @__PURE__ */ jsx(
|
|
2011
|
+
AuthContext.Provider,
|
|
2012
|
+
{
|
|
2013
|
+
value: {
|
|
2014
|
+
user,
|
|
2015
|
+
isLoading,
|
|
2016
|
+
error,
|
|
2017
|
+
isAuthenticated: !!user,
|
|
2018
|
+
login,
|
|
2019
|
+
register,
|
|
2020
|
+
logout,
|
|
2021
|
+
updateProfile,
|
|
2022
|
+
requestPasswordReset
|
|
2023
|
+
},
|
|
2024
|
+
children
|
|
2025
|
+
}
|
|
2026
|
+
);
|
|
2007
2027
|
};
|
|
2008
2028
|
var useNexusAuth = () => {
|
|
2009
2029
|
const context = useContext(AuthContext);
|
|
@@ -2015,8 +2035,10 @@ var useNexusAuth = () => {
|
|
|
2015
2035
|
function getHeaders(config) {
|
|
2016
2036
|
return {
|
|
2017
2037
|
"Content-Type": "application/json",
|
|
2018
|
-
"x-nexus-project": config.projectId
|
|
2019
|
-
|
|
2038
|
+
"x-nexus-project": config.projectId,
|
|
2039
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
2040
|
+
// 👈 CRITICAL: Send the nx_pk_ key
|
|
2041
|
+
// Note: We do NOT send the Master API Key here.
|
|
2020
2042
|
// This is client-side. The backend uses Cookies or public tokens.
|
|
2021
2043
|
};
|
|
2022
2044
|
}
|