@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 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 env = hasEnv() ? process.env : {};
11
- const isDev = env.NODE_ENV === "development" || env.NEXT_PUBLIC_NODE_ENV === "development";
12
- const projectId = _nullishCoalesce(env.NEXT_PUBLIC_NEXUS_ID, () => ( env.NEXUS_PROJECT_ID));
13
- const apiKey = _nullishCoalesce(env.NEXT_PUBLIC_NEXUS_KEY, () => ( env.NEXUS_API_KEY));
14
- const apiUrl = _nullishCoalesce(_nullishCoalesce(env.NEXT_PUBLIC_NEXUS_API_URL, () => ( env.NEXUS_API_URL)), () => ( (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL)));
15
- const analyticsUrl = _nullishCoalesce(env.NEXT_PUBLIC_NEXUS_ANALYTICS_URL, () => ( (apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL)));
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((time) => time > windowStart).length;
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(`[NexusHub] \u{1F50C} Circuit Breaker OPEN. Pausing network requests.`);
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', _13 => _13.include, 'optionalAccess', _14 => _14.length])) {
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', _15 => _15.fields, 'optionalAccess', _16 => _16.length])) {
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', _17 => _17.include, 'optionalAccess', _18 => _18.length])) {
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', _19 => _19.collections, 'optionalAccess', _20 => _20.length])) {
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', _21 => _21.fields, 'optionalAccess', _22 => _22.length])) {
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', _23 => _23.close, 'call', _24 => _24()]);
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', _25 => _25.close, 'call', _26 => _26()]);
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
- project_id: this.config.projectId,
1465
- session_id: this.sessionId,
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
- user_agent: window.navigator.userAgent,
1470
- screen_width: window.screen.width,
1471
- screen_height: window.screen.height,
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
- event_type: eventType,
1475
- event_name: eventName,
1476
- event_data: data,
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
- hardware_concurrency: entropy.hardware_concurrency,
1483
- device_memory: entropy.device_memory,
1484
- pixel_ratio: entropy.pixel_ratio,
1485
- canvas_fingerprint: entropy.canvas_hash,
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
- visitor_id_local: this.visitorId
1489
- // Hint for stitching
1494
+ visitorIdLocal: this.visitorId
1490
1495
  },
1491
- client_timestamp: (/* @__PURE__ */ new Date()).toISOString()
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', _27 => _27.url]) || window.location.href,
1614
- title: _optionalChain([data, 'optionalAccess', _28 => _28.title])
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
- project_id: this.tracker["config"].projectId,
1710
- session_id: this.tracker.getSession(),
1711
- visitor_id: this.tracker.visitorId,
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', _29 => _29.innerText, 'optionalAccess', _30 => _30.substring, 'call', _31 => _31(0, 50)]),
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', _32 => _32.innerText, 'optionalAccess', _33 => _33.substring, 'call', _34 => _34(0, 50)]),
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', _35 => _35.debug]) || false,
1826
- cacheStrategy: _optionalChain([config, 'optionalAccess', _36 => _36.cacheStrategy]) || "memory",
1827
- revalidateTime: _optionalChain([config, 'optionalAccess', _37 => _37.revalidateTime]) || 60,
1828
- timeout: _optionalChain([config, 'optionalAccess', _38 => _38.timeout]) || 1e4,
1829
- retries: _optionalChain([config, 'optionalAccess', _39 => _39.retries]) || 3,
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`, { method: "POST", headers: getHeaders(config) });
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, AuthContext.Provider, { value: {
1997
- user,
1998
- isLoading,
1999
- error,
2000
- isAuthenticated: !!user,
2001
- login,
2002
- register,
2003
- logout,
2004
- updateProfile,
2005
- requestPasswordReset
2006
- }, children });
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
- // Note: We do NOT send the Master API Key here.
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 env = hasEnv() ? process.env : {};
11
- const isDev = env.NODE_ENV === "development" || env.NEXT_PUBLIC_NODE_ENV === "development";
12
- const projectId = env.NEXT_PUBLIC_NEXUS_ID ?? env.NEXUS_PROJECT_ID;
13
- const apiKey = env.NEXT_PUBLIC_NEXUS_KEY ?? env.NEXUS_API_KEY;
14
- const apiUrl = env.NEXT_PUBLIC_NEXUS_API_URL ?? env.NEXUS_API_URL ?? (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL);
15
- const analyticsUrl = env.NEXT_PUBLIC_NEXUS_ANALYTICS_URL ?? (apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL);
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((time) => time > windowStart).length;
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(`[NexusHub] \u{1F50C} Circuit Breaker OPEN. Pausing network requests.`);
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
- project_id: this.config.projectId,
1465
- session_id: this.sessionId,
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
- user_agent: window.navigator.userAgent,
1470
- screen_width: window.screen.width,
1471
- screen_height: window.screen.height,
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
- event_type: eventType,
1475
- event_name: eventName,
1476
- event_data: data,
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
- hardware_concurrency: entropy.hardware_concurrency,
1483
- device_memory: entropy.device_memory,
1484
- pixel_ratio: entropy.pixel_ratio,
1485
- canvas_fingerprint: entropy.canvas_hash,
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
- visitor_id_local: this.visitorId
1489
- // Hint for stitching
1494
+ visitorIdLocal: this.visitorId
1490
1495
  },
1491
- client_timestamp: (/* @__PURE__ */ new Date()).toISOString()
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
- project_id: this.tracker["config"].projectId,
1710
- session_id: this.tracker.getSession(),
1711
- visitor_id: this.tracker.visitorId,
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 { createContext, useContext, useEffect, useState, useCallback } from "react";
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`, { method: "POST", headers: getHeaders(config) });
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(AuthContext.Provider, { value: {
1997
- user,
1998
- isLoading,
1999
- error,
2000
- isAuthenticated: !!user,
2001
- login,
2002
- register,
2003
- logout,
2004
- updateProfile,
2005
- requestPasswordReset
2006
- }, children });
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
- // Note: We do NOT send the Master API Key here.
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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexushub/client",
3
3
  "private": false,
4
- "version": "0.1.1",
4
+ "version": "0.1.3",
5
5
  "description": "The God-Tier NexusHub SDK",
6
6
  "type": "module",
7
7
  "main": "./dist/index.cjs",