@nexushub/client 0.7.8 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -535,7 +535,7 @@ var ContentEngine = class {
535
535
  });
536
536
  this.requestBatcher = new RequestBatcher(20, 50);
537
537
  this.circuitBreaker = new CircuitBreaker();
538
- this.defaultRevalidate = config.revalidateTime || false;
538
+ this.defaultRevalidate = config.revalidateTime ?? false;
539
539
  this.cacheStrategy = config.cacheStrategy || "memory";
540
540
  if (!this.isServer) {
541
541
  window.addEventListener("beforeunload", this.cleanup.bind(this));
@@ -799,7 +799,10 @@ var ContentEngine = class {
799
799
  method: "GET",
800
800
  headers: this.getHeaders(),
801
801
  tags: fetchTags,
802
- revalidate: options.revalidate || this.defaultRevalidate
802
+ // ?? not || — see the constructor comment on defaultRevalidate for
803
+ // why: an explicit `revalidate: 0` on this call must not be
804
+ // discarded in favor of the engine's default.
805
+ revalidate: options.revalidate ?? this.defaultRevalidate
803
806
  });
804
807
  if (!res.ok) {
805
808
  throw new Error(`API Error ${res.status}: ${res.statusText}`);
@@ -807,7 +810,7 @@ var ContentEngine = class {
807
810
  const json = await res.json();
808
811
  const data = json.data || json;
809
812
  this.writeCache(cacheKey, data, {
810
- revalidate: options.revalidate || this.defaultRevalidate,
813
+ revalidate: options.revalidate ?? this.defaultRevalidate,
811
814
  tags: fetchTags
812
815
  });
813
816
  return data;
@@ -851,19 +854,49 @@ var ContentEngine = class {
851
854
  }
852
855
  /**
853
856
  * Robust Real-time Subscriptions (SSE) with Auto-Reconnect
857
+ *
858
+ * ⚠️ SCOPE — READ BEFORE RELYING ON THIS FOR "instant" UPDATES:
859
+ * This connects from the BROWSER TAB it's called in, and on message it
860
+ * only clears THIS SDK INSTANCE's in-memory `memoryCache` (via
861
+ * invalidateCache below) in THAT browser tab's JS heap. In a typical
862
+ * Next.js deployment — and Cloudflare specifically, which is stateless
863
+ * per-request at the edge — that is a different process/isolate than the
864
+ * one that will render the NEXT server request for this content. So:
865
+ * - ✅ Useful for: a client component that reads from `nexus.content`
866
+ * directly in the browser and re-renders in place without a page
867
+ * navigation (e.g. a live-updating dashboard widget).
868
+ * - ❌ NOT sufficient for: "user A edits content in the CMS, user B's
869
+ * already-loaded page updates" via a server-rendered page. That
870
+ * requires the backend's /api/revalidate webhook (see
871
+ * content.service.ts `pingNextRevalidateWebhook`) to have actually
872
+ * cleared the *server's* Data Cache, so the NEXT navigation or
873
+ * server request picks up fresh data. This SSE channel does not
874
+ * replace that — it's a complementary, browser-local optimization.
875
+ * If your symptom was "stale content after editing," fix the webhook
876
+ * wiring first; treat this method as an enhancement layered on top.
854
877
  */
855
878
  subscribeToUpdates(callback) {
856
879
  if (this.isServer || typeof EventSource === "undefined") {
857
- console.warn("[NexusHub] EventSource not supported in this environment");
880
+ if (this.config.debug) {
881
+ console.warn(
882
+ "[NexusHub] subscribeToUpdates() called in a non-browser environment (server render or SSR pass) \u2014 this is expected and safely skipped; EventSource only makes sense client-side."
883
+ );
884
+ }
858
885
  return () => {
859
886
  };
860
887
  }
888
+ if (!this.config.apiKey) {
889
+ console.warn(
890
+ "[NexusHub] subscribeToUpdates(): no apiKey configured, the SSE connection will likely be rejected by the backend. Set NEXT_PUBLIC_NEXUS_KEY."
891
+ );
892
+ }
861
893
  let eventSource = null;
862
894
  let retryCount = 0;
863
895
  let isClosed = false;
896
+ const MAX_RETRY_DELAY_MS = 3e4;
864
897
  const connect = () => {
865
898
  if (isClosed) return;
866
- const url = `${this.config.apiUrl}/content/${this.config.projectId}/updates?key=${this.config.apiKey}`;
899
+ const url = `${this.config.apiUrl}/content/${this.config.projectId}/updates?key=${this.config.apiKey ?? ""}`;
867
900
  eventSource = new EventSource(url);
868
901
  eventSource.onopen = () => {
869
902
  retryCount = 0;
@@ -871,27 +904,40 @@ var ContentEngine = class {
871
904
  console.log("[NexusHub] \u{1F7E2} Real-time stream connected");
872
905
  };
873
906
  eventSource.onmessage = (event) => {
907
+ let data;
874
908
  try {
875
- const data = JSON.parse(event.data);
876
- if (data.type === "content.updated" && data.slug) {
877
- this.invalidateCache([CacheTags.content(data.slug)]);
878
- }
879
- if (data.type === "collection.updated") {
880
- this.invalidateCache([CacheTags.collection(data.collectionId)]);
881
- }
882
- callback(data);
909
+ data = JSON.parse(event.data);
883
910
  } catch (e) {
884
911
  console.error("[NexusHub] SSE Parse Error", e);
912
+ return;
913
+ }
914
+ if (!data || typeof data.type !== "string") {
915
+ return;
885
916
  }
917
+ if (data.type === "content.updated" && data.slug) {
918
+ this.invalidateCache([CacheTags.content(data.slug)]);
919
+ }
920
+ if (data.type === "collection.updated" && data.collectionId) {
921
+ this.invalidateCache([CacheTags.collection(data.collectionId)]);
922
+ }
923
+ if (data.type === "schema.updated") {
924
+ this.clearCache();
925
+ }
926
+ callback(data);
886
927
  };
887
928
  eventSource.onerror = () => {
888
929
  eventSource?.close();
889
930
  if (isClosed) return;
890
- const timeout = Math.min(1e3 * Math.pow(2, retryCount), 1e4);
891
- retryCount++;
892
- console.warn(
893
- `[NexusHub] \u{1F534} Stream disconnected. Reconnecting in ${timeout}ms...`
931
+ const timeout = Math.min(
932
+ 1e3 * Math.pow(2, retryCount),
933
+ MAX_RETRY_DELAY_MS
894
934
  );
935
+ retryCount++;
936
+ if (this.config.debug) {
937
+ console.warn(
938
+ `[NexusHub] \u{1F534} Stream disconnected. Reconnecting in ${timeout}ms...`
939
+ );
940
+ }
895
941
  setTimeout(connect, timeout);
896
942
  };
897
943
  };
@@ -1116,8 +1162,11 @@ var ContentEngine = class {
1116
1162
  const controller = new AbortController();
1117
1163
  const id = setTimeout(() => controller.abort(), timeout);
1118
1164
  const nextConfig = this.isServer ? {
1119
- cache: "force-cache",
1120
- next: { tags, revalidate: revalidate === false ? false : revalidate }
1165
+ cache: revalidate === 0 ? "no-store" : "force-cache",
1166
+ next: {
1167
+ tags,
1168
+ revalidate: revalidate === false ? false : revalidate
1169
+ }
1121
1170
  } : {};
1122
1171
  try {
1123
1172
  const response = await fetch(url, {
@@ -2140,13 +2189,20 @@ function getSelector(el, depth = 0) {
2140
2189
  }
2141
2190
 
2142
2191
  // src/client.ts
2192
+ var DEFAULT_REVALIDATE_SECONDS = 60;
2143
2193
  var NexusClient = class {
2144
2194
  constructor(config) {
2145
2195
  const fullConfig = getFullConfig(config);
2146
2196
  this.config = {
2147
2197
  debug: config?.debug ?? false,
2148
2198
  cacheStrategy: config?.cacheStrategy ?? "memory",
2149
- revalidateTime: config?.revalidateTime ?? false,
2199
+ // Only fall through to the safe default when revalidateTime is
2200
+ // genuinely *unset* (undefined). An explicit `false` from the caller
2201
+ // is a deliberate "never revalidate" choice and must be respected,
2202
+ // not silently upgraded — `??` (not `||`) is required here so that
2203
+ // `0` (revalidate on every request) also passes through untouched
2204
+ // instead of being treated as falsy.
2205
+ revalidateTime: config?.revalidateTime ?? DEFAULT_REVALIDATE_SECONDS,
2150
2206
  timeout: config?.timeout ?? 1e4,
2151
2207
  retries: config?.retries ?? 3,
2152
2208
  ...fullConfig
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexushub/client",
3
3
  "private": false,
4
- "version": "0.7.8",
4
+ "version": "0.8.0",
5
5
  "description": "The God-Tier NexusHub SDK",
6
6
  "type": "module",
7
7
  "main": "./dist/index.cjs",