@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/cli.cjs +209 -123
- package/dist/index.cjs +76 -20
- package/dist/index.d.cts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +76 -20
- package/dist/react.cjs +76 -20
- package/dist/react.d.cts +20 -0
- package/dist/react.d.ts +20 -0
- package/dist/react.js +76 -20
- package/package.json +1 -1
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
891
|
-
|
|
892
|
-
|
|
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: {
|
|
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
|
-
|
|
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
|