@nexushub/client 0.0.3 → 0.0.6

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.
@@ -3,16 +3,19 @@ import React from 'react';
3
3
 
4
4
  interface MinimalNexusConfig {
5
5
  apiUrl?: string;
6
+ analyticsUrl?: string;
6
7
  apiKey?: string;
7
8
  projectId?: string;
8
9
  }
9
- declare const DEFAULT_API_URL = "https://api.nexushub.com/v1";
10
- declare const DEFAULT_CDN_URL = "https://cdn.nexushub.com";
10
+ declare const DEFAULT_API_URL = "http://localhost:3001";
11
+ declare const DEFAULT_ANALYTICS_URL = "http://localhost:3002";
12
+ declare const LOCAL_NEST_URL = "http://localhost:3001";
13
+ declare const LOCAL_RUST_URL = "http://localhost:3002";
11
14
  declare const getEnvConfig: () => MinimalNexusConfig;
15
+ /**
16
+ * Merges base environment config with manual overrides from the constructor
17
+ */
12
18
  declare const mergeConfigs: (base: MinimalNexusConfig, override: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
13
- declare const hasRequiredConfig: (config: MinimalNexusConfig) => config is MinimalNexusConfig & {
14
- projectId: string;
15
- };
16
19
  declare const getFullConfig: (partialConfig?: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
17
20
  declare const validateConfig: (config: MinimalNexusConfig) => string[];
18
21
 
@@ -395,4 +398,4 @@ declare class BrowserCache {
395
398
 
396
399
  declare const VERSION = "0.0.1";
397
400
 
398
- export { AnalyticsEngine, type AuthContextType, type AuthError, AuthProvider, type AuthState, BrowserCache, type CacheEntry, type CacheMetadata, CacheTags, type CollectionQuery, type CollectionResponse, ContentEngine, type ContentResponse, DEFAULT_API_URL, DEFAULT_CDN_URL, type ErrorResponse, LocalCache, type LoginCredentials, MemoryCache, type MinimalNexusConfig, NexusClient, type NexusConfig, NexusProvider, type RegisterCredentials, type SiteUser, VERSION, createNexusClient, getEnvConfig, getFullConfig, hasRequiredConfig, mergeConfigs, nexus, useNexusAuth, validateConfig };
401
+ export { AnalyticsEngine, type AuthContextType, type AuthError, AuthProvider, type AuthState, BrowserCache, type CacheEntry, type CacheMetadata, CacheTags, type CollectionQuery, type CollectionResponse, ContentEngine, type ContentResponse, DEFAULT_ANALYTICS_URL, DEFAULT_API_URL, type ErrorResponse, LOCAL_NEST_URL, LOCAL_RUST_URL, LocalCache, type LoginCredentials, MemoryCache, type MinimalNexusConfig, NexusClient, type NexusConfig, NexusProvider, type RegisterCredentials, type SiteUser, VERSION, createNexusClient, getEnvConfig, getFullConfig, mergeConfigs, nexus, useNexusAuth, validateConfig };
@@ -3,16 +3,19 @@ import React from 'react';
3
3
 
4
4
  interface MinimalNexusConfig {
5
5
  apiUrl?: string;
6
+ analyticsUrl?: string;
6
7
  apiKey?: string;
7
8
  projectId?: string;
8
9
  }
9
- declare const DEFAULT_API_URL = "https://api.nexushub.com/v1";
10
- declare const DEFAULT_CDN_URL = "https://cdn.nexushub.com";
10
+ declare const DEFAULT_API_URL = "http://localhost:3001";
11
+ declare const DEFAULT_ANALYTICS_URL = "http://localhost:3002";
12
+ declare const LOCAL_NEST_URL = "http://localhost:3001";
13
+ declare const LOCAL_RUST_URL = "http://localhost:3002";
11
14
  declare const getEnvConfig: () => MinimalNexusConfig;
15
+ /**
16
+ * Merges base environment config with manual overrides from the constructor
17
+ */
12
18
  declare const mergeConfigs: (base: MinimalNexusConfig, override: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
13
- declare const hasRequiredConfig: (config: MinimalNexusConfig) => config is MinimalNexusConfig & {
14
- projectId: string;
15
- };
16
19
  declare const getFullConfig: (partialConfig?: Partial<MinimalNexusConfig>) => MinimalNexusConfig;
17
20
  declare const validateConfig: (config: MinimalNexusConfig) => string[];
18
21
 
@@ -395,4 +398,4 @@ declare class BrowserCache {
395
398
 
396
399
  declare const VERSION = "0.0.1";
397
400
 
398
- export { AnalyticsEngine, type AuthContextType, type AuthError, AuthProvider, type AuthState, BrowserCache, type CacheEntry, type CacheMetadata, CacheTags, type CollectionQuery, type CollectionResponse, ContentEngine, type ContentResponse, DEFAULT_API_URL, DEFAULT_CDN_URL, type ErrorResponse, LocalCache, type LoginCredentials, MemoryCache, type MinimalNexusConfig, NexusClient, type NexusConfig, NexusProvider, type RegisterCredentials, type SiteUser, VERSION, createNexusClient, getEnvConfig, getFullConfig, hasRequiredConfig, mergeConfigs, nexus, useNexusAuth, validateConfig };
401
+ export { AnalyticsEngine, type AuthContextType, type AuthError, AuthProvider, type AuthState, BrowserCache, type CacheEntry, type CacheMetadata, CacheTags, type CollectionQuery, type CollectionResponse, ContentEngine, type ContentResponse, DEFAULT_ANALYTICS_URL, DEFAULT_API_URL, type ErrorResponse, LOCAL_NEST_URL, LOCAL_RUST_URL, LocalCache, type LoginCredentials, MemoryCache, type MinimalNexusConfig, NexusClient, type NexusConfig, NexusProvider, type RegisterCredentials, type SiteUser, VERSION, createNexusClient, getEnvConfig, getFullConfig, mergeConfigs, nexus, useNexusAuth, validateConfig };
package/dist/src/index.js CHANGED
@@ -5190,8 +5190,10 @@ __export(src_exports, {
5190
5190
  BrowserCache: () => BrowserCache,
5191
5191
  CacheTags: () => CacheTags,
5192
5192
  ContentEngine: () => ContentEngine,
5193
+ DEFAULT_ANALYTICS_URL: () => DEFAULT_ANALYTICS_URL,
5193
5194
  DEFAULT_API_URL: () => DEFAULT_API_URL,
5194
- DEFAULT_CDN_URL: () => DEFAULT_CDN_URL,
5195
+ LOCAL_NEST_URL: () => LOCAL_NEST_URL,
5196
+ LOCAL_RUST_URL: () => LOCAL_RUST_URL,
5195
5197
  LocalCache: () => LocalCache,
5196
5198
  MemoryCache: () => MemoryCache,
5197
5199
  NexusClient: () => NexusClient,
@@ -5200,7 +5202,6 @@ __export(src_exports, {
5200
5202
  createNexusClient: () => createNexusClient,
5201
5203
  getEnvConfig: () => getEnvConfig,
5202
5204
  getFullConfig: () => getFullConfig,
5203
- hasRequiredConfig: () => hasRequiredConfig,
5204
5205
  mergeConfigs: () => mergeConfigs,
5205
5206
  nexus: () => nexus,
5206
5207
  useNexusAuth: () => useNexusAuth,
@@ -5209,56 +5210,48 @@ __export(src_exports, {
5209
5210
  module.exports = __toCommonJS(src_exports);
5210
5211
 
5211
5212
  // src/config.ts
5212
- var DEFAULT_API_URL = "https://api.nexushub.com/v1";
5213
- var DEFAULT_CDN_URL = "https://cdn.nexushub.com";
5213
+ var DEFAULT_API_URL = "http://localhost:3001";
5214
+ var DEFAULT_ANALYTICS_URL = "http://localhost:3002";
5215
+ var LOCAL_NEST_URL = "http://localhost:3001";
5216
+ var LOCAL_RUST_URL = "http://localhost:3002";
5214
5217
  var hasEnv = () => {
5215
5218
  return typeof process !== "undefined" && typeof process.env !== "undefined" && Object.keys(process.env).length > 0;
5216
5219
  };
5217
5220
  var getEnvConfig = () => {
5218
- if (!hasEnv()) {
5219
- return {
5220
- apiUrl: DEFAULT_API_URL
5221
- };
5222
- }
5223
- const env = process.env;
5224
- const projectId = env.NEXT_PUBLIC_NEXUS_ID ?? env.NEXUS_PROJECT_ID ?? env.NEXUS_PROJECT_ID;
5225
- const apiKey = env.NEXT_PUBLIC_NEXUS_KEY ?? env.NEXUS_API_KEY ?? env.NEXUS_API_KEY;
5226
- const apiUrl = env.NEXT_PUBLIC_NEXUS_API_URL ?? env.NEXUS_API_URL ?? DEFAULT_API_URL;
5221
+ const env = hasEnv() ? process.env : {};
5222
+ const isDev = env.NODE_ENV === "development" || env.NEXT_PUBLIC_NODE_ENV === "development";
5223
+ const projectId = env.NEXT_PUBLIC_NEXUS_ID ?? env.NEXUS_PROJECT_ID;
5224
+ const apiKey = env.NEXT_PUBLIC_NEXUS_KEY ?? env.NEXUS_API_KEY;
5225
+ const apiUrl = env.NEXT_PUBLIC_NEXUS_API_URL ?? env.NEXUS_API_URL ?? (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL);
5226
+ const analyticsUrl = env.NEXT_PUBLIC_NEXUS_ANALYTICS_URL ?? (apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL);
5227
5227
  return {
5228
5228
  projectId,
5229
5229
  apiKey,
5230
- apiUrl
5230
+ apiUrl,
5231
+ analyticsUrl
5231
5232
  };
5232
5233
  };
5233
5234
  var mergeConfigs = (base, override) => {
5235
+ const mergedApiUrl = override.apiUrl || base.apiUrl || DEFAULT_API_URL;
5236
+ const mergedAnalyticsUrl = override.analyticsUrl || base.analyticsUrl || (mergedApiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL);
5234
5237
  return {
5235
5238
  ...base,
5236
5239
  ...override,
5237
- apiUrl: override.apiUrl || base.apiUrl || DEFAULT_API_URL,
5240
+ apiUrl: mergedApiUrl,
5241
+ analyticsUrl: mergedAnalyticsUrl,
5238
5242
  projectId: override.projectId || base.projectId
5239
5243
  };
5240
5244
  };
5241
- var hasRequiredConfig = (config) => {
5242
- return !!config.projectId && !!config.apiUrl;
5243
- };
5244
5245
  var getFullConfig = (partialConfig) => {
5245
5246
  const envConfig = getEnvConfig();
5246
- const merged = mergeConfigs(envConfig, partialConfig || {});
5247
- if (!merged.apiUrl) {
5248
- merged.apiUrl = DEFAULT_API_URL;
5249
- }
5250
- return merged;
5247
+ return mergeConfigs(envConfig, partialConfig || {});
5251
5248
  };
5252
5249
  var validateConfig = (config) => {
5253
5250
  const errors = [];
5254
- if (!config.projectId) {
5255
- errors.push("Missing projectId");
5256
- }
5257
- if (!config.apiUrl) {
5258
- errors.push("Missing apiUrl");
5259
- }
5251
+ if (!config.projectId) errors.push("Missing projectId");
5252
+ if (!config.apiUrl) errors.push("Missing apiUrl");
5260
5253
  if (config.apiUrl && !config.apiUrl.startsWith("http")) {
5261
- errors.push("apiUrl must be a valid URL starting with http:// or https://");
5254
+ errors.push("apiUrl must be a valid URL (http:// or https://)");
5262
5255
  }
5263
5256
  return errors;
5264
5257
  };
@@ -6613,7 +6606,7 @@ var Tracker = class {
6613
6606
  this.isFlushing = false;
6614
6607
  this.config = config;
6615
6608
  const baseUrl = this.config.apiUrl.replace("/v1", "").replace(/\/$/, "");
6616
- this.endpoint = `${baseUrl}:3002/api/collect`;
6609
+ this.endpoint = `${this.config.analyticsUrl}/api/collect`;
6617
6610
  this.circuitBreaker = new CircuitBreaker();
6618
6611
  this.sessionStart = Date.now();
6619
6612
  if (typeof window !== "undefined") {
@@ -6700,7 +6693,7 @@ var Tracker = class {
6700
6693
  method: "POST",
6701
6694
  headers: {
6702
6695
  "Content-Type": "application/json",
6703
- "Authorization": `Bearer ${this.config.apiKey}`
6696
+ Authorization: `Bearer ${this.config.apiKey}`
6704
6697
  },
6705
6698
  body: JSON.stringify(event),
6706
6699
  keepalive: useBeacon
@@ -6836,29 +6829,34 @@ var AnalyticsEngine = class {
6836
6829
  * 4. RESET: Clear local data and (optionally) request GDPR scrub
6837
6830
  */
6838
6831
  reset(performGdprScrub = false) {
6832
+ const config = this.tracker["config"];
6839
6833
  this.tracker.stop();
6840
6834
  localStorage.removeItem("nexus_sid");
6841
6835
  localStorage.removeItem("nexus_vid");
6842
6836
  if (performGdprScrub) {
6843
- const baseUrl = this.tracker["config"].apiUrl.replace("/v1", "").replace(/\/$/, "");
6837
+ const endpoint = `${config.analyticsUrl}/api/privacy/scrub`;
6844
6838
  const userId = this.tracker.visitorId;
6845
- fetch(`${baseUrl}:3002/api/privacy/scrub`, {
6839
+ fetch(endpoint, {
6846
6840
  method: "DELETE",
6847
6841
  headers: {
6848
6842
  "Content-Type": "application/json",
6849
- "Authorization": `Bearer ${this.tracker["config"].apiKey}`
6843
+ Authorization: `Bearer ${config.apiKey}`
6850
6844
  },
6851
6845
  body: JSON.stringify({
6852
- project_id: this.tracker["config"].projectId,
6846
+ project_id: config.projectId,
6853
6847
  user_id: userId
6854
6848
  })
6855
- }).catch(console.error);
6849
+ }).catch((err) => console.error("[NexusHub] Privacy scrub failed:", err));
6856
6850
  }
6857
6851
  window.location.reload();
6858
6852
  }
6859
6853
  // --- E-COMMERCE & CUSTOM ---
6860
6854
  track(eventName, properties = {}) {
6861
- this.tracker.send("custom_event", { event_name: eventName, ...properties }, eventName);
6855
+ this.tracker.send(
6856
+ "custom_event",
6857
+ { event_name: eventName, ...properties },
6858
+ eventName
6859
+ );
6862
6860
  }
6863
6861
  trackPurchase(orderData) {
6864
6862
  this.tracker.send("purchase", {
@@ -6878,8 +6876,8 @@ var AnalyticsEngine = class {
6878
6876
  // --- INTERNAL HELPER ---
6879
6877
  async sendIdentityRequest(type, data) {
6880
6878
  try {
6881
- const baseUrl = this.tracker["config"].apiUrl.replace("/v1", "").replace(/\/$/, "");
6882
- const endpoint = `${baseUrl}:3002/api/${type}`;
6879
+ const config = this.tracker["config"];
6880
+ const endpoint = `${config.analyticsUrl}/api/${type}`;
6883
6881
  const payload = {
6884
6882
  project_id: this.tracker["config"].projectId,
6885
6883
  session_id: this.tracker.getSession(),
@@ -6893,7 +6891,7 @@ var AnalyticsEngine = class {
6893
6891
  method: "POST",
6894
6892
  headers: {
6895
6893
  "Content-Type": "application/json",
6896
- "Authorization": `Bearer ${this.tracker["config"].apiKey}`
6894
+ Authorization: `Bearer ${this.tracker["config"].apiKey}`
6897
6895
  },
6898
6896
  body: JSON.stringify(payload)
6899
6897
  });
@@ -6935,7 +6933,9 @@ var AnalyticsEngine = class {
6935
6933
  }
6936
6934
  };
6937
6935
  window.addEventListener("click", clickHandler, { passive: true });
6938
- this.cleanupFns.push(() => window.removeEventListener("click", clickHandler));
6936
+ this.cleanupFns.push(
6937
+ () => window.removeEventListener("click", clickHandler)
6938
+ );
6939
6939
  }
6940
6940
  setupFormTracking() {
6941
6941
  if (typeof document === "undefined") return;
@@ -6951,10 +6951,13 @@ var AnalyticsEngine = class {
6951
6951
  }
6952
6952
  };
6953
6953
  document.addEventListener("submit", submitHandler, { passive: true });
6954
- this.cleanupFns.push(() => document.removeEventListener("submit", submitHandler));
6954
+ this.cleanupFns.push(
6955
+ () => document.removeEventListener("submit", submitHandler)
6956
+ );
6955
6957
  }
6956
6958
  setupRouteTracking() {
6957
- if (typeof window === "undefined" || typeof window.history === "undefined") return;
6959
+ if (typeof window === "undefined" || typeof window.history === "undefined")
6960
+ return;
6958
6961
  const originalPushState = history.pushState;
6959
6962
  const originalReplaceState = history.replaceState;
6960
6963
  history.pushState = (...args) => {
@@ -6967,7 +6970,9 @@ var AnalyticsEngine = class {
6967
6970
  };
6968
6971
  const popStateHandler = () => this.pageView();
6969
6972
  window.addEventListener("popstate", popStateHandler);
6970
- this.cleanupFns.push(() => window.removeEventListener("popstate", popStateHandler));
6973
+ this.cleanupFns.push(
6974
+ () => window.removeEventListener("popstate", popStateHandler)
6975
+ );
6971
6976
  }
6972
6977
  getSessionId() {
6973
6978
  return this.tracker.getSession();
@@ -7241,8 +7246,10 @@ var VERSION = "0.0.1";
7241
7246
  BrowserCache,
7242
7247
  CacheTags,
7243
7248
  ContentEngine,
7249
+ DEFAULT_ANALYTICS_URL,
7244
7250
  DEFAULT_API_URL,
7245
- DEFAULT_CDN_URL,
7251
+ LOCAL_NEST_URL,
7252
+ LOCAL_RUST_URL,
7246
7253
  LocalCache,
7247
7254
  MemoryCache,
7248
7255
  NexusClient,
@@ -7251,7 +7258,6 @@ var VERSION = "0.0.1";
7251
7258
  createNexusClient,
7252
7259
  getEnvConfig,
7253
7260
  getFullConfig,
7254
- hasRequiredConfig,
7255
7261
  mergeConfigs,
7256
7262
  nexus,
7257
7263
  useNexusAuth,
@@ -5183,56 +5183,48 @@ var require_navigation2 = __commonJS({
5183
5183
  });
5184
5184
 
5185
5185
  // src/config.ts
5186
- var DEFAULT_API_URL = "https://api.nexushub.com/v1";
5187
- var DEFAULT_CDN_URL = "https://cdn.nexushub.com";
5186
+ var DEFAULT_API_URL = "http://localhost:3001";
5187
+ var DEFAULT_ANALYTICS_URL = "http://localhost:3002";
5188
+ var LOCAL_NEST_URL = "http://localhost:3001";
5189
+ var LOCAL_RUST_URL = "http://localhost:3002";
5188
5190
  var hasEnv = () => {
5189
5191
  return typeof process !== "undefined" && typeof process.env !== "undefined" && Object.keys(process.env).length > 0;
5190
5192
  };
5191
5193
  var getEnvConfig = () => {
5192
- if (!hasEnv()) {
5193
- return {
5194
- apiUrl: DEFAULT_API_URL
5195
- };
5196
- }
5197
- const env = process.env;
5198
- const projectId = env.NEXT_PUBLIC_NEXUS_ID ?? env.NEXUS_PROJECT_ID ?? env.NEXUS_PROJECT_ID;
5199
- const apiKey = env.NEXT_PUBLIC_NEXUS_KEY ?? env.NEXUS_API_KEY ?? env.NEXUS_API_KEY;
5200
- const apiUrl = env.NEXT_PUBLIC_NEXUS_API_URL ?? env.NEXUS_API_URL ?? DEFAULT_API_URL;
5194
+ const env = hasEnv() ? process.env : {};
5195
+ const isDev = env.NODE_ENV === "development" || env.NEXT_PUBLIC_NODE_ENV === "development";
5196
+ const projectId = env.NEXT_PUBLIC_NEXUS_ID ?? env.NEXUS_PROJECT_ID;
5197
+ const apiKey = env.NEXT_PUBLIC_NEXUS_KEY ?? env.NEXUS_API_KEY;
5198
+ const apiUrl = env.NEXT_PUBLIC_NEXUS_API_URL ?? env.NEXUS_API_URL ?? (isDev ? LOCAL_NEST_URL : DEFAULT_API_URL);
5199
+ const analyticsUrl = env.NEXT_PUBLIC_NEXUS_ANALYTICS_URL ?? (apiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL);
5201
5200
  return {
5202
5201
  projectId,
5203
5202
  apiKey,
5204
- apiUrl
5203
+ apiUrl,
5204
+ analyticsUrl
5205
5205
  };
5206
5206
  };
5207
5207
  var mergeConfigs = (base, override) => {
5208
+ const mergedApiUrl = override.apiUrl || base.apiUrl || DEFAULT_API_URL;
5209
+ const mergedAnalyticsUrl = override.analyticsUrl || base.analyticsUrl || (mergedApiUrl.includes("localhost") ? LOCAL_RUST_URL : DEFAULT_ANALYTICS_URL);
5208
5210
  return {
5209
5211
  ...base,
5210
5212
  ...override,
5211
- apiUrl: override.apiUrl || base.apiUrl || DEFAULT_API_URL,
5213
+ apiUrl: mergedApiUrl,
5214
+ analyticsUrl: mergedAnalyticsUrl,
5212
5215
  projectId: override.projectId || base.projectId
5213
5216
  };
5214
5217
  };
5215
- var hasRequiredConfig = (config) => {
5216
- return !!config.projectId && !!config.apiUrl;
5217
- };
5218
5218
  var getFullConfig = (partialConfig) => {
5219
5219
  const envConfig = getEnvConfig();
5220
- const merged = mergeConfigs(envConfig, partialConfig || {});
5221
- if (!merged.apiUrl) {
5222
- merged.apiUrl = DEFAULT_API_URL;
5223
- }
5224
- return merged;
5220
+ return mergeConfigs(envConfig, partialConfig || {});
5225
5221
  };
5226
5222
  var validateConfig = (config) => {
5227
5223
  const errors = [];
5228
- if (!config.projectId) {
5229
- errors.push("Missing projectId");
5230
- }
5231
- if (!config.apiUrl) {
5232
- errors.push("Missing apiUrl");
5233
- }
5224
+ if (!config.projectId) errors.push("Missing projectId");
5225
+ if (!config.apiUrl) errors.push("Missing apiUrl");
5234
5226
  if (config.apiUrl && !config.apiUrl.startsWith("http")) {
5235
- errors.push("apiUrl must be a valid URL starting with http:// or https://");
5227
+ errors.push("apiUrl must be a valid URL (http:// or https://)");
5236
5228
  }
5237
5229
  return errors;
5238
5230
  };
@@ -6593,7 +6585,7 @@ var Tracker = class {
6593
6585
  this.isFlushing = false;
6594
6586
  this.config = config;
6595
6587
  const baseUrl = this.config.apiUrl.replace("/v1", "").replace(/\/$/, "");
6596
- this.endpoint = `${baseUrl}:3002/api/collect`;
6588
+ this.endpoint = `${this.config.analyticsUrl}/api/collect`;
6597
6589
  this.circuitBreaker = new CircuitBreaker();
6598
6590
  this.sessionStart = Date.now();
6599
6591
  if (typeof window !== "undefined") {
@@ -6680,7 +6672,7 @@ var Tracker = class {
6680
6672
  method: "POST",
6681
6673
  headers: {
6682
6674
  "Content-Type": "application/json",
6683
- "Authorization": `Bearer ${this.config.apiKey}`
6675
+ Authorization: `Bearer ${this.config.apiKey}`
6684
6676
  },
6685
6677
  body: JSON.stringify(event),
6686
6678
  keepalive: useBeacon
@@ -6816,29 +6808,34 @@ var AnalyticsEngine = class {
6816
6808
  * 4. RESET: Clear local data and (optionally) request GDPR scrub
6817
6809
  */
6818
6810
  reset(performGdprScrub = false) {
6811
+ const config = this.tracker["config"];
6819
6812
  this.tracker.stop();
6820
6813
  localStorage.removeItem("nexus_sid");
6821
6814
  localStorage.removeItem("nexus_vid");
6822
6815
  if (performGdprScrub) {
6823
- const baseUrl = this.tracker["config"].apiUrl.replace("/v1", "").replace(/\/$/, "");
6816
+ const endpoint = `${config.analyticsUrl}/api/privacy/scrub`;
6824
6817
  const userId = this.tracker.visitorId;
6825
- fetch(`${baseUrl}:3002/api/privacy/scrub`, {
6818
+ fetch(endpoint, {
6826
6819
  method: "DELETE",
6827
6820
  headers: {
6828
6821
  "Content-Type": "application/json",
6829
- "Authorization": `Bearer ${this.tracker["config"].apiKey}`
6822
+ Authorization: `Bearer ${config.apiKey}`
6830
6823
  },
6831
6824
  body: JSON.stringify({
6832
- project_id: this.tracker["config"].projectId,
6825
+ project_id: config.projectId,
6833
6826
  user_id: userId
6834
6827
  })
6835
- }).catch(console.error);
6828
+ }).catch((err) => console.error("[NexusHub] Privacy scrub failed:", err));
6836
6829
  }
6837
6830
  window.location.reload();
6838
6831
  }
6839
6832
  // --- E-COMMERCE & CUSTOM ---
6840
6833
  track(eventName, properties = {}) {
6841
- this.tracker.send("custom_event", { event_name: eventName, ...properties }, eventName);
6834
+ this.tracker.send(
6835
+ "custom_event",
6836
+ { event_name: eventName, ...properties },
6837
+ eventName
6838
+ );
6842
6839
  }
6843
6840
  trackPurchase(orderData) {
6844
6841
  this.tracker.send("purchase", {
@@ -6858,8 +6855,8 @@ var AnalyticsEngine = class {
6858
6855
  // --- INTERNAL HELPER ---
6859
6856
  async sendIdentityRequest(type, data) {
6860
6857
  try {
6861
- const baseUrl = this.tracker["config"].apiUrl.replace("/v1", "").replace(/\/$/, "");
6862
- const endpoint = `${baseUrl}:3002/api/${type}`;
6858
+ const config = this.tracker["config"];
6859
+ const endpoint = `${config.analyticsUrl}/api/${type}`;
6863
6860
  const payload = {
6864
6861
  project_id: this.tracker["config"].projectId,
6865
6862
  session_id: this.tracker.getSession(),
@@ -6873,7 +6870,7 @@ var AnalyticsEngine = class {
6873
6870
  method: "POST",
6874
6871
  headers: {
6875
6872
  "Content-Type": "application/json",
6876
- "Authorization": `Bearer ${this.tracker["config"].apiKey}`
6873
+ Authorization: `Bearer ${this.tracker["config"].apiKey}`
6877
6874
  },
6878
6875
  body: JSON.stringify(payload)
6879
6876
  });
@@ -6915,7 +6912,9 @@ var AnalyticsEngine = class {
6915
6912
  }
6916
6913
  };
6917
6914
  window.addEventListener("click", clickHandler, { passive: true });
6918
- this.cleanupFns.push(() => window.removeEventListener("click", clickHandler));
6915
+ this.cleanupFns.push(
6916
+ () => window.removeEventListener("click", clickHandler)
6917
+ );
6919
6918
  }
6920
6919
  setupFormTracking() {
6921
6920
  if (typeof document === "undefined") return;
@@ -6931,10 +6930,13 @@ var AnalyticsEngine = class {
6931
6930
  }
6932
6931
  };
6933
6932
  document.addEventListener("submit", submitHandler, { passive: true });
6934
- this.cleanupFns.push(() => document.removeEventListener("submit", submitHandler));
6933
+ this.cleanupFns.push(
6934
+ () => document.removeEventListener("submit", submitHandler)
6935
+ );
6935
6936
  }
6936
6937
  setupRouteTracking() {
6937
- if (typeof window === "undefined" || typeof window.history === "undefined") return;
6938
+ if (typeof window === "undefined" || typeof window.history === "undefined")
6939
+ return;
6938
6940
  const originalPushState = history.pushState;
6939
6941
  const originalReplaceState = history.replaceState;
6940
6942
  history.pushState = (...args) => {
@@ -6947,7 +6949,9 @@ var AnalyticsEngine = class {
6947
6949
  };
6948
6950
  const popStateHandler = () => this.pageView();
6949
6951
  window.addEventListener("popstate", popStateHandler);
6950
- this.cleanupFns.push(() => window.removeEventListener("popstate", popStateHandler));
6952
+ this.cleanupFns.push(
6953
+ () => window.removeEventListener("popstate", popStateHandler)
6954
+ );
6951
6955
  }
6952
6956
  getSessionId() {
6953
6957
  return this.tracker.getSession();
@@ -7220,8 +7224,10 @@ export {
7220
7224
  BrowserCache,
7221
7225
  CacheTags,
7222
7226
  ContentEngine,
7227
+ DEFAULT_ANALYTICS_URL,
7223
7228
  DEFAULT_API_URL,
7224
- DEFAULT_CDN_URL,
7229
+ LOCAL_NEST_URL,
7230
+ LOCAL_RUST_URL,
7225
7231
  LocalCache,
7226
7232
  MemoryCache,
7227
7233
  NexusClient,
@@ -7230,7 +7236,6 @@ export {
7230
7236
  createNexusClient,
7231
7237
  getEnvConfig,
7232
7238
  getFullConfig,
7233
- hasRequiredConfig,
7234
7239
  mergeConfigs,
7235
7240
  nexus,
7236
7241
  useNexusAuth,
package/dist/tools/cli.js CHANGED
@@ -36,7 +36,9 @@ import_dotenv.default.config({ path: import_path.default.resolve(process.cwd(),
36
36
  var program = new import_commander.Command();
37
37
  program.name("nexus").description("NexusHub CLI - The Developer Toolbelt").version("1.0.0");
38
38
  program.command("init").description("Initialize NexusHub configuration and seed data").action(initProject);
39
- program.command("pull").description("Pull latest content from NexusHub to local cache (Offline Mode)").option("-k, --api-key <key>", "NexusHub API Key").option("-p, --project-id <id>", "NexusHub Project ID").option("-u, --api-url <url>", "NexusHub API URL").option("-o, --output <path>", "Output directory (default: .nexus)").option("-f, --force", "Force overwrite existing cache").action(syncContent);
39
+ program.command("pull").description(
40
+ "Pull latest content from NexusHub to local cache (Offline Mode)"
41
+ ).option("-k, --api-key <key>", "NexusHub API Key").option("-p, --project-id <id>", "NexusHub Project ID").option("-u, --api-url <url>", "NexusHub API URL").option("-o, --output <path>", "Output directory (default: .nexus)").option("-f, --force", "Force overwrite existing cache").action(syncContent);
40
42
  program.command("seed").description("Seed content from local files to NexusHub").option("-i, --input <path>", "Input directory (default: .nexus/seed)").option("-p, --project-id <id>", "NexusHub Project ID").option("-k, --api-key <key>", "NexusHub API Key").option("-u, --api-url <url>", "NexusHub API URL").option("--dry-run", "Validate seed data without uploading").action(seedContent);
41
43
  program.command("deploy").description("Trigger a production deployment").option("-p, --project-id <id>", "NexusHub Project ID").option("-k, --api-key <key>", "NexusHub API Key").option("-u, --api-url <url>", "NexusHub API URL").option("-e, --environment <env>", "Deployment environment", "production").action(triggerDeploy);
42
44
  program.command("status").description("Check project status and content statistics").option("-p, --project-id <id>", "NexusHub Project ID").option("-k, --api-key <key>", "NexusHub API Key").option("-u, --api-url <url>", "NexusHub API URL").action(checkStatus);
@@ -48,7 +50,11 @@ async function getContext() {
48
50
  const apiUrl = process.env.NEXUS_API_URL || "https://api.nexushub.com/v1";
49
51
  if (!apiKey || !projectId) {
50
52
  console.error(import_chalk.default.red("\n\u274C Missing Configuration"));
51
- console.log(import_chalk.default.gray("Please set NEXUS_API_KEY and NEXUS_PROJECT_ID in your .env file."));
53
+ console.log(
54
+ import_chalk.default.gray(
55
+ "Please set NEXUS_API_KEY and NEXUS_PROJECT_ID in your .env file."
56
+ )
57
+ );
52
58
  process.exit(1);
53
59
  }
54
60
  return { apiKey, projectId, apiUrl };
@@ -59,7 +65,7 @@ async function fetchWithAuth(url, apiKey, timeout = 3e4) {
59
65
  try {
60
66
  const response = await (0, import_node_fetch.default)(url, {
61
67
  headers: {
62
- "Authorization": `Bearer ${apiKey}`,
68
+ Authorization: `Bearer ${apiKey}`,
63
69
  "Content-Type": "application/json",
64
70
  "User-Agent": "NexusHub-CLI/1.0.0"
65
71
  },
@@ -101,7 +107,12 @@ async function fetchCollections(baseUrl, apiKey, projectId) {
101
107
  const itemsData = itemsRes;
102
108
  result[collection.slug || collection.id] = itemsData.data || itemsData.items || [];
103
109
  } catch (error) {
104
- console.warn(import_chalk.default.yellow(`\u26A0\uFE0F Failed to fetch collection ${collection.id}:`, error instanceof Error ? error.message : String(error)));
110
+ console.warn(
111
+ import_chalk.default.yellow(
112
+ `\u26A0\uFE0F Failed to fetch collection ${collection.id}:`,
113
+ error instanceof Error ? error.message : String(error)
114
+ )
115
+ );
105
116
  }
106
117
  })
107
118
  );
@@ -163,9 +174,17 @@ async function initProject() {
163
174
  copyright: "\xA9 2024 My Site"
164
175
  }
165
176
  };
166
- await fs.writeJson(import_path.default.join(seedDir, "pages.json"), examplePages, { spaces: 2 });
167
- await fs.writeJson(import_path.default.join(collectionsDir, "blog_posts.json"), exampleCollection, { spaces: 2 });
168
- await fs.writeJson(import_path.default.join(seedDir, "globals.json"), exampleGlobals, { spaces: 2 });
177
+ await fs.writeJson(import_path.default.join(seedDir, "pages.json"), examplePages, {
178
+ spaces: 2
179
+ });
180
+ await fs.writeJson(
181
+ import_path.default.join(collectionsDir, "blog_posts.json"),
182
+ exampleCollection,
183
+ { spaces: 2 }
184
+ );
185
+ await fs.writeJson(import_path.default.join(seedDir, "globals.json"), exampleGlobals, {
186
+ spaces: 2
187
+ });
169
188
  const gitignorePath = import_path.default.join(nexusDir, ".gitignore");
170
189
  await fs.writeFile(gitignorePath, "cache.json\n");
171
190
  const readmePath = import_path.default.join(nexusDir, "README.md");
@@ -208,7 +227,9 @@ This directory contains seed data for your NexusHub project.
208
227
  console.log(import_chalk.default.gray(" NEXUS_PROJECT_ID=your_project_id_here"));
209
228
  console.log(import_chalk.default.gray(" 3. Run `npx nexus seed` to upload content"));
210
229
  } catch (error) {
211
- console.error(import_chalk.default.red(`\u274C Failed to initialize project: ${error.message}`));
230
+ console.error(
231
+ import_chalk.default.red(`\u274C Failed to initialize project: ${error.message}`)
232
+ );
212
233
  process.exit(1);
213
234
  }
214
235
  }
@@ -220,22 +241,32 @@ async function syncContent(options) {
220
241
  const outputDir = options.output || ".nexus";
221
242
  if (!apiKey || !projectId) {
222
243
  console.error(import_chalk.default.red("\u274C Missing API Key or Project ID"));
223
- console.log(import_chalk.default.gray("Set NEXUS_API_KEY and NEXUS_PROJECT_ID in .env or use --api-key and --project-id flags"));
244
+ console.log(
245
+ import_chalk.default.gray(
246
+ "Set NEXUS_API_KEY and NEXUS_PROJECT_ID in .env or use --api-key and --project-id flags"
247
+ )
248
+ );
224
249
  process.exit(1);
225
250
  }
226
- const spinner = (0, import_ora.default)(`Fetching content for project: ${import_chalk.default.green(projectId)}...`).start();
251
+ const spinner = (0, import_ora.default)(
252
+ `Fetching content for project: ${import_chalk.default.green(projectId)}...`
253
+ ).start();
227
254
  try {
228
255
  const cacheDir = import_path.default.join(process.cwd(), outputDir);
229
256
  const cacheFile = import_path.default.join(cacheDir, "cache.json");
230
257
  if (await fs.pathExists(cacheFile) && !options.force) {
231
258
  spinner.stop();
232
- console.log(import_chalk.default.yellow("\u26A0\uFE0F Cache file already exists. Use --force to overwrite."));
259
+ console.log(
260
+ import_chalk.default.yellow(
261
+ "\u26A0\uFE0F Cache file already exists. Use --force to overwrite."
262
+ )
263
+ );
233
264
  process.exit(0);
234
265
  }
235
266
  const [pages, collections, globals] = await Promise.all([
236
267
  fetchWithAuth(`${apiUrl}/content/${projectId}/pages`, apiKey),
237
268
  fetchCollections(`${apiUrl}/content/${projectId}`, apiKey, projectId),
238
- fetchWithAuth(`${apiUrl}/project/${projectId}/globals`, apiKey)
269
+ fetchWithAuth(`${apiUrl}/projects/${projectId}/globals`, apiKey)
239
270
  ]);
240
271
  const cacheData = {
241
272
  pages: pages.data || pages,
@@ -256,7 +287,9 @@ async function syncContent(options) {
256
287
  spinner.succeed(import_chalk.default.green("Content synced successfully!"));
257
288
  console.log(import_chalk.default.gray(` \u{1F4C1} Saved to: ${cacheFile}`));
258
289
  console.log(import_chalk.default.gray(` \u{1F4CA} Pages: ${cacheData.meta.count.pages}`));
259
- console.log(import_chalk.default.gray(` \u{1F4DA} Collections: ${cacheData.meta.count.collections}`));
290
+ console.log(
291
+ import_chalk.default.gray(` \u{1F4DA} Collections: ${cacheData.meta.count.collections}`)
292
+ );
260
293
  console.log(import_chalk.default.yellow(` \u26A1 Mode: Offline / Local Cache Enabled`));
261
294
  } catch (error) {
262
295
  spinner.fail(import_chalk.default.red("Failed to sync content"));
@@ -264,7 +297,9 @@ async function syncContent(options) {
264
297
  if (error.message.includes("401") || error.message.includes("403")) {
265
298
  console.log(import_chalk.default.yellow(" \u{1F511} Check your API key and permissions"));
266
299
  } else if (error.message.includes("404")) {
267
- console.log(import_chalk.default.yellow(" \u{1F50D} Project not found. Check your project ID"));
300
+ console.log(
301
+ import_chalk.default.yellow(" \u{1F50D} Project not found. Check your project ID")
302
+ );
268
303
  }
269
304
  process.exit(1);
270
305
  }
@@ -285,7 +320,9 @@ async function seedContent(options) {
285
320
  console.error(import_chalk.default.red(`\u274C Seed directory not found: ${seedPath}`));
286
321
  console.log(import_chalk.default.gray("Create a seed directory with your content files:"));
287
322
  console.log(import_chalk.default.gray(" mkdir -p .nexus/seed"));
288
- console.log(import_chalk.default.gray(" # Add pages.json, collections/ folder, globals.json"));
323
+ console.log(
324
+ import_chalk.default.gray(" # Add pages.json, collections/ folder, globals.json")
325
+ );
289
326
  process.exit(1);
290
327
  }
291
328
  const spinner = (0, import_ora.default)("Validating seed data...").start();
@@ -307,7 +344,12 @@ async function seedContent(options) {
307
344
  if (await fs.pathExists(collectionsDir)) {
308
345
  if (!dryRun) {
309
346
  spinner.text = "Seeding collections...";
310
- const counts = await seedCollections(collectionsDir, apiUrl, projectId, apiKey);
347
+ const counts = await seedCollections(
348
+ collectionsDir,
349
+ apiUrl,
350
+ projectId,
351
+ apiKey
352
+ );
311
353
  collectionCount = counts.collections;
312
354
  itemCount = counts.items;
313
355
  } else {
@@ -343,7 +385,7 @@ async function seedPages(pages, apiUrl, projectId, apiKey) {
343
385
  const response = await (0, import_node_fetch.default)(`${apiUrl}/content/${projectId}/pages`, {
344
386
  method: "POST",
345
387
  headers: {
346
- "Authorization": `Bearer ${apiKey}`,
388
+ Authorization: `Bearer ${apiKey}`,
347
389
  "Content-Type": "application/json"
348
390
  },
349
391
  body: JSON.stringify(page)
@@ -376,14 +418,16 @@ async function seedCollections(collectionsDir, apiUrl, projectId, apiKey) {
376
418
  const filePath = import_path.default.join(collectionsDir, file);
377
419
  const items = await fs.readJson(filePath);
378
420
  if (!Array.isArray(items)) {
379
- console.warn(import_chalk.default.yellow(` \u26A0\uFE0F ${file} does not contain a valid array of items`));
421
+ console.warn(
422
+ import_chalk.default.yellow(` \u26A0\uFE0F ${file} does not contain a valid array of items`)
423
+ );
380
424
  continue;
381
425
  }
382
426
  try {
383
427
  await (0, import_node_fetch.default)(`${apiUrl}/content/${projectId}/collections`, {
384
428
  method: "POST",
385
429
  headers: {
386
- "Authorization": `Bearer ${apiKey}`,
430
+ Authorization: `Bearer ${apiKey}`,
387
431
  "Content-Type": "application/json"
388
432
  },
389
433
  body: JSON.stringify({
@@ -395,40 +439,57 @@ async function seedCollections(collectionsDir, apiUrl, projectId, apiKey) {
395
439
  let itemCount = 0;
396
440
  for (const item of items) {
397
441
  try {
398
- await (0, import_node_fetch.default)(`${apiUrl}/content/${projectId}/collections/${collectionName}/items`, {
399
- method: "POST",
400
- headers: {
401
- "Authorization": `Bearer ${apiKey}`,
402
- "Content-Type": "application/json"
403
- },
404
- body: JSON.stringify(item)
405
- });
442
+ await (0, import_node_fetch.default)(
443
+ `${apiUrl}/content/${projectId}/collections/${collectionName}/items`,
444
+ {
445
+ method: "POST",
446
+ headers: {
447
+ Authorization: `Bearer ${apiKey}`,
448
+ "Content-Type": "application/json"
449
+ },
450
+ body: JSON.stringify(item)
451
+ }
452
+ );
406
453
  itemCount++;
407
454
  } catch (error) {
408
- console.warn(import_chalk.default.yellow(` Failed to create item in ${collectionName}: ${error instanceof Error ? error.message : String(error)}`));
455
+ console.warn(
456
+ import_chalk.default.yellow(
457
+ ` Failed to create item in ${collectionName}: ${error instanceof Error ? error.message : String(error)}`
458
+ )
459
+ );
409
460
  }
410
461
  }
411
- console.log(import_chalk.default.gray(` \u2705 Created collection ${collectionName} with ${itemCount} items`));
462
+ console.log(
463
+ import_chalk.default.gray(
464
+ ` \u2705 Created collection ${collectionName} with ${itemCount} items`
465
+ )
466
+ );
412
467
  totalItems += itemCount;
413
468
  } catch (error) {
414
- console.warn(import_chalk.default.yellow(` \u274C Failed to create collection ${collectionName}: ${error.message}`));
469
+ console.warn(
470
+ import_chalk.default.yellow(
471
+ ` \u274C Failed to create collection ${collectionName}: ${error.message}`
472
+ )
473
+ );
415
474
  }
416
475
  }
417
476
  return { collections: jsonFiles.length, items: totalItems };
418
477
  }
419
478
  async function seedGlobals(globals, apiUrl, projectId, apiKey) {
420
479
  try {
421
- await (0, import_node_fetch.default)(`${apiUrl}/project/${projectId}/globals`, {
480
+ await (0, import_node_fetch.default)(`${apiUrl}/projects/${projectId}/globals`, {
422
481
  method: "PUT",
423
482
  headers: {
424
- "Authorization": `Bearer ${apiKey}`,
483
+ Authorization: `Bearer ${apiKey}`,
425
484
  "Content-Type": "application/json"
426
485
  },
427
486
  body: JSON.stringify(globals)
428
487
  });
429
488
  console.log(import_chalk.default.gray(" \u2705 Created globals"));
430
489
  } catch (error) {
431
- console.warn(import_chalk.default.yellow(` \u274C Failed to create globals: ${error.message}`));
490
+ console.warn(
491
+ import_chalk.default.yellow(` \u274C Failed to create globals: ${error.message}`)
492
+ );
432
493
  }
433
494
  }
434
495
  async function triggerDeploy(options) {
@@ -446,7 +507,7 @@ async function triggerDeploy(options) {
446
507
  const response = await (0, import_node_fetch.default)(`${apiUrl}/projects/${projectId}/deploy`, {
447
508
  method: "POST",
448
509
  headers: {
449
- "Authorization": `Bearer ${apiKey}`,
510
+ Authorization: `Bearer ${apiKey}`,
450
511
  "Content-Type": "application/json"
451
512
  },
452
513
  body: JSON.stringify({
@@ -460,7 +521,9 @@ async function triggerDeploy(options) {
460
521
  spinner.succeed(import_chalk.default.green("Deployment triggered successfully!"));
461
522
  console.log(import_chalk.default.gray(` \u{1F517} Deployment ID: ${data.deploymentId}`));
462
523
  console.log(import_chalk.default.gray(` \u{1F30D} Environment: ${environment}`));
463
- console.log(import_chalk.default.gray(` \u23F0 Started at: ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`));
524
+ console.log(
525
+ import_chalk.default.gray(` \u23F0 Started at: ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`)
526
+ );
464
527
  } else {
465
528
  throw new Error(`API Error ${response.status}: ${response.statusText}`);
466
529
  }
@@ -483,7 +546,7 @@ async function checkStatus(options) {
483
546
  try {
484
547
  const response = await (0, import_node_fetch.default)(`${apiUrl}/projects/${projectId}/status`, {
485
548
  headers: {
486
- "Authorization": `Bearer ${apiKey}`,
549
+ Authorization: `Bearer ${apiKey}`,
487
550
  "Content-Type": "application/json"
488
551
  }
489
552
  });
@@ -495,7 +558,11 @@ async function checkStatus(options) {
495
558
  console.log(import_chalk.default.gray(` \u{1F4C4} Pages: ${data.stats.pages}`));
496
559
  console.log(import_chalk.default.gray(` \u{1F4DA} Collections: ${data.stats.collections}`));
497
560
  console.log(import_chalk.default.gray(` \u{1F465} Users: ${data.stats.users}`));
498
- console.log(import_chalk.default.gray(` \u{1F552} Last Updated: ${new Date(data.project.updatedAt).toLocaleString()}`));
561
+ console.log(
562
+ import_chalk.default.gray(
563
+ ` \u{1F552} Last Updated: ${new Date(data.project.updatedAt).toLocaleString()}`
564
+ )
565
+ );
499
566
  } else {
500
567
  throw new Error(`API Error ${response.status}: ${response.statusText}`);
501
568
  }
@@ -510,7 +577,7 @@ async function generateTypes(options) {
510
577
  const spinner = (0, import_ora.default)("Fetching Content Schema...").start();
511
578
  try {
512
579
  const response = await (0, import_node_fetch.default)(`${apiUrl}/content/${projectId}/schema`, {
513
- headers: { "Authorization": `Bearer ${apiKey}` }
580
+ headers: { Authorization: `Bearer ${apiKey}` }
514
581
  });
515
582
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
516
583
  const schema = await response.json();
@@ -550,7 +617,11 @@ async function generateTypes(options) {
550
617
  await fs.writeFile(outputPath, typeDefs);
551
618
  spinner.succeed(import_chalk.default.green(`Types generated at ${options.output}`));
552
619
  if (collections.length > 0) {
553
- console.log(import_chalk.default.gray(` \u2728 You can now use: nexus.getCollection<${formatInterfaceName(collections[0].slug)}>('${collections[0].slug}')`));
620
+ console.log(
621
+ import_chalk.default.gray(
622
+ ` \u2728 You can now use: nexus.getCollection<${formatInterfaceName(collections[0].slug)}>('${collections[0].slug}')`
623
+ )
624
+ );
554
625
  }
555
626
  } catch (error) {
556
627
  spinner.fail(import_chalk.default.red("Failed to generate types"));
@@ -13,7 +13,9 @@ dotenv.config({ path: path.resolve(process.cwd(), ".env") });
13
13
  var program = new Command();
14
14
  program.name("nexus").description("NexusHub CLI - The Developer Toolbelt").version("1.0.0");
15
15
  program.command("init").description("Initialize NexusHub configuration and seed data").action(initProject);
16
- program.command("pull").description("Pull latest content from NexusHub to local cache (Offline Mode)").option("-k, --api-key <key>", "NexusHub API Key").option("-p, --project-id <id>", "NexusHub Project ID").option("-u, --api-url <url>", "NexusHub API URL").option("-o, --output <path>", "Output directory (default: .nexus)").option("-f, --force", "Force overwrite existing cache").action(syncContent);
16
+ program.command("pull").description(
17
+ "Pull latest content from NexusHub to local cache (Offline Mode)"
18
+ ).option("-k, --api-key <key>", "NexusHub API Key").option("-p, --project-id <id>", "NexusHub Project ID").option("-u, --api-url <url>", "NexusHub API URL").option("-o, --output <path>", "Output directory (default: .nexus)").option("-f, --force", "Force overwrite existing cache").action(syncContent);
17
19
  program.command("seed").description("Seed content from local files to NexusHub").option("-i, --input <path>", "Input directory (default: .nexus/seed)").option("-p, --project-id <id>", "NexusHub Project ID").option("-k, --api-key <key>", "NexusHub API Key").option("-u, --api-url <url>", "NexusHub API URL").option("--dry-run", "Validate seed data without uploading").action(seedContent);
18
20
  program.command("deploy").description("Trigger a production deployment").option("-p, --project-id <id>", "NexusHub Project ID").option("-k, --api-key <key>", "NexusHub API Key").option("-u, --api-url <url>", "NexusHub API URL").option("-e, --environment <env>", "Deployment environment", "production").action(triggerDeploy);
19
21
  program.command("status").description("Check project status and content statistics").option("-p, --project-id <id>", "NexusHub Project ID").option("-k, --api-key <key>", "NexusHub API Key").option("-u, --api-url <url>", "NexusHub API URL").action(checkStatus);
@@ -25,7 +27,11 @@ async function getContext() {
25
27
  const apiUrl = process.env.NEXUS_API_URL || "https://api.nexushub.com/v1";
26
28
  if (!apiKey || !projectId) {
27
29
  console.error(chalk.red("\n\u274C Missing Configuration"));
28
- console.log(chalk.gray("Please set NEXUS_API_KEY and NEXUS_PROJECT_ID in your .env file."));
30
+ console.log(
31
+ chalk.gray(
32
+ "Please set NEXUS_API_KEY and NEXUS_PROJECT_ID in your .env file."
33
+ )
34
+ );
29
35
  process.exit(1);
30
36
  }
31
37
  return { apiKey, projectId, apiUrl };
@@ -36,7 +42,7 @@ async function fetchWithAuth(url, apiKey, timeout = 3e4) {
36
42
  try {
37
43
  const response = await fetch(url, {
38
44
  headers: {
39
- "Authorization": `Bearer ${apiKey}`,
45
+ Authorization: `Bearer ${apiKey}`,
40
46
  "Content-Type": "application/json",
41
47
  "User-Agent": "NexusHub-CLI/1.0.0"
42
48
  },
@@ -78,7 +84,12 @@ async function fetchCollections(baseUrl, apiKey, projectId) {
78
84
  const itemsData = itemsRes;
79
85
  result[collection.slug || collection.id] = itemsData.data || itemsData.items || [];
80
86
  } catch (error) {
81
- console.warn(chalk.yellow(`\u26A0\uFE0F Failed to fetch collection ${collection.id}:`, error instanceof Error ? error.message : String(error)));
87
+ console.warn(
88
+ chalk.yellow(
89
+ `\u26A0\uFE0F Failed to fetch collection ${collection.id}:`,
90
+ error instanceof Error ? error.message : String(error)
91
+ )
92
+ );
82
93
  }
83
94
  })
84
95
  );
@@ -140,9 +151,17 @@ async function initProject() {
140
151
  copyright: "\xA9 2024 My Site"
141
152
  }
142
153
  };
143
- await fs.writeJson(path.join(seedDir, "pages.json"), examplePages, { spaces: 2 });
144
- await fs.writeJson(path.join(collectionsDir, "blog_posts.json"), exampleCollection, { spaces: 2 });
145
- await fs.writeJson(path.join(seedDir, "globals.json"), exampleGlobals, { spaces: 2 });
154
+ await fs.writeJson(path.join(seedDir, "pages.json"), examplePages, {
155
+ spaces: 2
156
+ });
157
+ await fs.writeJson(
158
+ path.join(collectionsDir, "blog_posts.json"),
159
+ exampleCollection,
160
+ { spaces: 2 }
161
+ );
162
+ await fs.writeJson(path.join(seedDir, "globals.json"), exampleGlobals, {
163
+ spaces: 2
164
+ });
146
165
  const gitignorePath = path.join(nexusDir, ".gitignore");
147
166
  await fs.writeFile(gitignorePath, "cache.json\n");
148
167
  const readmePath = path.join(nexusDir, "README.md");
@@ -185,7 +204,9 @@ This directory contains seed data for your NexusHub project.
185
204
  console.log(chalk.gray(" NEXUS_PROJECT_ID=your_project_id_here"));
186
205
  console.log(chalk.gray(" 3. Run `npx nexus seed` to upload content"));
187
206
  } catch (error) {
188
- console.error(chalk.red(`\u274C Failed to initialize project: ${error.message}`));
207
+ console.error(
208
+ chalk.red(`\u274C Failed to initialize project: ${error.message}`)
209
+ );
189
210
  process.exit(1);
190
211
  }
191
212
  }
@@ -197,22 +218,32 @@ async function syncContent(options) {
197
218
  const outputDir = options.output || ".nexus";
198
219
  if (!apiKey || !projectId) {
199
220
  console.error(chalk.red("\u274C Missing API Key or Project ID"));
200
- console.log(chalk.gray("Set NEXUS_API_KEY and NEXUS_PROJECT_ID in .env or use --api-key and --project-id flags"));
221
+ console.log(
222
+ chalk.gray(
223
+ "Set NEXUS_API_KEY and NEXUS_PROJECT_ID in .env or use --api-key and --project-id flags"
224
+ )
225
+ );
201
226
  process.exit(1);
202
227
  }
203
- const spinner = ora(`Fetching content for project: ${chalk.green(projectId)}...`).start();
228
+ const spinner = ora(
229
+ `Fetching content for project: ${chalk.green(projectId)}...`
230
+ ).start();
204
231
  try {
205
232
  const cacheDir = path.join(process.cwd(), outputDir);
206
233
  const cacheFile = path.join(cacheDir, "cache.json");
207
234
  if (await fs.pathExists(cacheFile) && !options.force) {
208
235
  spinner.stop();
209
- console.log(chalk.yellow("\u26A0\uFE0F Cache file already exists. Use --force to overwrite."));
236
+ console.log(
237
+ chalk.yellow(
238
+ "\u26A0\uFE0F Cache file already exists. Use --force to overwrite."
239
+ )
240
+ );
210
241
  process.exit(0);
211
242
  }
212
243
  const [pages, collections, globals] = await Promise.all([
213
244
  fetchWithAuth(`${apiUrl}/content/${projectId}/pages`, apiKey),
214
245
  fetchCollections(`${apiUrl}/content/${projectId}`, apiKey, projectId),
215
- fetchWithAuth(`${apiUrl}/project/${projectId}/globals`, apiKey)
246
+ fetchWithAuth(`${apiUrl}/projects/${projectId}/globals`, apiKey)
216
247
  ]);
217
248
  const cacheData = {
218
249
  pages: pages.data || pages,
@@ -233,7 +264,9 @@ async function syncContent(options) {
233
264
  spinner.succeed(chalk.green("Content synced successfully!"));
234
265
  console.log(chalk.gray(` \u{1F4C1} Saved to: ${cacheFile}`));
235
266
  console.log(chalk.gray(` \u{1F4CA} Pages: ${cacheData.meta.count.pages}`));
236
- console.log(chalk.gray(` \u{1F4DA} Collections: ${cacheData.meta.count.collections}`));
267
+ console.log(
268
+ chalk.gray(` \u{1F4DA} Collections: ${cacheData.meta.count.collections}`)
269
+ );
237
270
  console.log(chalk.yellow(` \u26A1 Mode: Offline / Local Cache Enabled`));
238
271
  } catch (error) {
239
272
  spinner.fail(chalk.red("Failed to sync content"));
@@ -241,7 +274,9 @@ async function syncContent(options) {
241
274
  if (error.message.includes("401") || error.message.includes("403")) {
242
275
  console.log(chalk.yellow(" \u{1F511} Check your API key and permissions"));
243
276
  } else if (error.message.includes("404")) {
244
- console.log(chalk.yellow(" \u{1F50D} Project not found. Check your project ID"));
277
+ console.log(
278
+ chalk.yellow(" \u{1F50D} Project not found. Check your project ID")
279
+ );
245
280
  }
246
281
  process.exit(1);
247
282
  }
@@ -262,7 +297,9 @@ async function seedContent(options) {
262
297
  console.error(chalk.red(`\u274C Seed directory not found: ${seedPath}`));
263
298
  console.log(chalk.gray("Create a seed directory with your content files:"));
264
299
  console.log(chalk.gray(" mkdir -p .nexus/seed"));
265
- console.log(chalk.gray(" # Add pages.json, collections/ folder, globals.json"));
300
+ console.log(
301
+ chalk.gray(" # Add pages.json, collections/ folder, globals.json")
302
+ );
266
303
  process.exit(1);
267
304
  }
268
305
  const spinner = ora("Validating seed data...").start();
@@ -284,7 +321,12 @@ async function seedContent(options) {
284
321
  if (await fs.pathExists(collectionsDir)) {
285
322
  if (!dryRun) {
286
323
  spinner.text = "Seeding collections...";
287
- const counts = await seedCollections(collectionsDir, apiUrl, projectId, apiKey);
324
+ const counts = await seedCollections(
325
+ collectionsDir,
326
+ apiUrl,
327
+ projectId,
328
+ apiKey
329
+ );
288
330
  collectionCount = counts.collections;
289
331
  itemCount = counts.items;
290
332
  } else {
@@ -320,7 +362,7 @@ async function seedPages(pages, apiUrl, projectId, apiKey) {
320
362
  const response = await fetch(`${apiUrl}/content/${projectId}/pages`, {
321
363
  method: "POST",
322
364
  headers: {
323
- "Authorization": `Bearer ${apiKey}`,
365
+ Authorization: `Bearer ${apiKey}`,
324
366
  "Content-Type": "application/json"
325
367
  },
326
368
  body: JSON.stringify(page)
@@ -353,14 +395,16 @@ async function seedCollections(collectionsDir, apiUrl, projectId, apiKey) {
353
395
  const filePath = path.join(collectionsDir, file);
354
396
  const items = await fs.readJson(filePath);
355
397
  if (!Array.isArray(items)) {
356
- console.warn(chalk.yellow(` \u26A0\uFE0F ${file} does not contain a valid array of items`));
398
+ console.warn(
399
+ chalk.yellow(` \u26A0\uFE0F ${file} does not contain a valid array of items`)
400
+ );
357
401
  continue;
358
402
  }
359
403
  try {
360
404
  await fetch(`${apiUrl}/content/${projectId}/collections`, {
361
405
  method: "POST",
362
406
  headers: {
363
- "Authorization": `Bearer ${apiKey}`,
407
+ Authorization: `Bearer ${apiKey}`,
364
408
  "Content-Type": "application/json"
365
409
  },
366
410
  body: JSON.stringify({
@@ -372,40 +416,57 @@ async function seedCollections(collectionsDir, apiUrl, projectId, apiKey) {
372
416
  let itemCount = 0;
373
417
  for (const item of items) {
374
418
  try {
375
- await fetch(`${apiUrl}/content/${projectId}/collections/${collectionName}/items`, {
376
- method: "POST",
377
- headers: {
378
- "Authorization": `Bearer ${apiKey}`,
379
- "Content-Type": "application/json"
380
- },
381
- body: JSON.stringify(item)
382
- });
419
+ await fetch(
420
+ `${apiUrl}/content/${projectId}/collections/${collectionName}/items`,
421
+ {
422
+ method: "POST",
423
+ headers: {
424
+ Authorization: `Bearer ${apiKey}`,
425
+ "Content-Type": "application/json"
426
+ },
427
+ body: JSON.stringify(item)
428
+ }
429
+ );
383
430
  itemCount++;
384
431
  } catch (error) {
385
- console.warn(chalk.yellow(` Failed to create item in ${collectionName}: ${error instanceof Error ? error.message : String(error)}`));
432
+ console.warn(
433
+ chalk.yellow(
434
+ ` Failed to create item in ${collectionName}: ${error instanceof Error ? error.message : String(error)}`
435
+ )
436
+ );
386
437
  }
387
438
  }
388
- console.log(chalk.gray(` \u2705 Created collection ${collectionName} with ${itemCount} items`));
439
+ console.log(
440
+ chalk.gray(
441
+ ` \u2705 Created collection ${collectionName} with ${itemCount} items`
442
+ )
443
+ );
389
444
  totalItems += itemCount;
390
445
  } catch (error) {
391
- console.warn(chalk.yellow(` \u274C Failed to create collection ${collectionName}: ${error.message}`));
446
+ console.warn(
447
+ chalk.yellow(
448
+ ` \u274C Failed to create collection ${collectionName}: ${error.message}`
449
+ )
450
+ );
392
451
  }
393
452
  }
394
453
  return { collections: jsonFiles.length, items: totalItems };
395
454
  }
396
455
  async function seedGlobals(globals, apiUrl, projectId, apiKey) {
397
456
  try {
398
- await fetch(`${apiUrl}/project/${projectId}/globals`, {
457
+ await fetch(`${apiUrl}/projects/${projectId}/globals`, {
399
458
  method: "PUT",
400
459
  headers: {
401
- "Authorization": `Bearer ${apiKey}`,
460
+ Authorization: `Bearer ${apiKey}`,
402
461
  "Content-Type": "application/json"
403
462
  },
404
463
  body: JSON.stringify(globals)
405
464
  });
406
465
  console.log(chalk.gray(" \u2705 Created globals"));
407
466
  } catch (error) {
408
- console.warn(chalk.yellow(` \u274C Failed to create globals: ${error.message}`));
467
+ console.warn(
468
+ chalk.yellow(` \u274C Failed to create globals: ${error.message}`)
469
+ );
409
470
  }
410
471
  }
411
472
  async function triggerDeploy(options) {
@@ -423,7 +484,7 @@ async function triggerDeploy(options) {
423
484
  const response = await fetch(`${apiUrl}/projects/${projectId}/deploy`, {
424
485
  method: "POST",
425
486
  headers: {
426
- "Authorization": `Bearer ${apiKey}`,
487
+ Authorization: `Bearer ${apiKey}`,
427
488
  "Content-Type": "application/json"
428
489
  },
429
490
  body: JSON.stringify({
@@ -437,7 +498,9 @@ async function triggerDeploy(options) {
437
498
  spinner.succeed(chalk.green("Deployment triggered successfully!"));
438
499
  console.log(chalk.gray(` \u{1F517} Deployment ID: ${data.deploymentId}`));
439
500
  console.log(chalk.gray(` \u{1F30D} Environment: ${environment}`));
440
- console.log(chalk.gray(` \u23F0 Started at: ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`));
501
+ console.log(
502
+ chalk.gray(` \u23F0 Started at: ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`)
503
+ );
441
504
  } else {
442
505
  throw new Error(`API Error ${response.status}: ${response.statusText}`);
443
506
  }
@@ -460,7 +523,7 @@ async function checkStatus(options) {
460
523
  try {
461
524
  const response = await fetch(`${apiUrl}/projects/${projectId}/status`, {
462
525
  headers: {
463
- "Authorization": `Bearer ${apiKey}`,
526
+ Authorization: `Bearer ${apiKey}`,
464
527
  "Content-Type": "application/json"
465
528
  }
466
529
  });
@@ -472,7 +535,11 @@ async function checkStatus(options) {
472
535
  console.log(chalk.gray(` \u{1F4C4} Pages: ${data.stats.pages}`));
473
536
  console.log(chalk.gray(` \u{1F4DA} Collections: ${data.stats.collections}`));
474
537
  console.log(chalk.gray(` \u{1F465} Users: ${data.stats.users}`));
475
- console.log(chalk.gray(` \u{1F552} Last Updated: ${new Date(data.project.updatedAt).toLocaleString()}`));
538
+ console.log(
539
+ chalk.gray(
540
+ ` \u{1F552} Last Updated: ${new Date(data.project.updatedAt).toLocaleString()}`
541
+ )
542
+ );
476
543
  } else {
477
544
  throw new Error(`API Error ${response.status}: ${response.statusText}`);
478
545
  }
@@ -487,7 +554,7 @@ async function generateTypes(options) {
487
554
  const spinner = ora("Fetching Content Schema...").start();
488
555
  try {
489
556
  const response = await fetch(`${apiUrl}/content/${projectId}/schema`, {
490
- headers: { "Authorization": `Bearer ${apiKey}` }
557
+ headers: { Authorization: `Bearer ${apiKey}` }
491
558
  });
492
559
  if (!response.ok) throw new Error(`API Error: ${response.statusText}`);
493
560
  const schema = await response.json();
@@ -527,7 +594,11 @@ async function generateTypes(options) {
527
594
  await fs.writeFile(outputPath, typeDefs);
528
595
  spinner.succeed(chalk.green(`Types generated at ${options.output}`));
529
596
  if (collections.length > 0) {
530
- console.log(chalk.gray(` \u2728 You can now use: nexus.getCollection<${formatInterfaceName(collections[0].slug)}>('${collections[0].slug}')`));
597
+ console.log(
598
+ chalk.gray(
599
+ ` \u2728 You can now use: nexus.getCollection<${formatInterfaceName(collections[0].slug)}>('${collections[0].slug}')`
600
+ )
601
+ );
531
602
  }
532
603
  } catch (error) {
533
604
  spinner.fail(chalk.red("Failed to generate types"));
package/package.json CHANGED
@@ -1,19 +1,27 @@
1
1
  {
2
2
  "name": "@nexushub/client",
3
3
  "private": false,
4
- "version": "0.0.3",
4
+ "version": "0.0.6",
5
5
  "description": "The God-Tier NexusHub SDK",
6
6
  "main": "dist/src/index.js",
7
7
  "types": "dist/src/index.d.ts",
8
+ "module": "./dist/src/index.mjs",
8
9
  "bin": {
9
- "nexus": "./dist/cli.js"
10
+ "nexus": "dist/tools/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/src/index.d.ts",
15
+ "import": "./dist/src/index.mjs",
16
+ "require": "./dist/src/index.js"
17
+ }
10
18
  },
11
19
  "files": [
12
20
  "dist",
13
21
  "README.md"
14
22
  ],
15
23
  "scripts": {
16
- "build": "tsup src/index.ts tools/cli.ts --format esm,cjs --dts --clean",
24
+ "build": "tsup src/index.ts tools/cli.ts --format esm,cjs --dts --clean && chmod +x ./dist/tools/cli.js",
17
25
  "dev": "tsup src/index.ts tools/cli.ts --format esm,cjs --dts --watch",
18
26
  "test": "jest",
19
27
  "test:coverage": "jest --coverage",