@nexushub/client 1.1.6 → 1.1.7
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 +191 -287
- package/dist/index.d.cts +68 -112
- package/dist/index.d.ts +68 -112
- package/dist/index.js +191 -287
- package/dist/react.cjs +206 -302
- package/dist/react.d.cts +12 -48
- package/dist/react.d.ts +12 -48
- package/dist/react.js +191 -287
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -829,14 +829,13 @@ var ContentEngine = class {
|
|
|
829
829
|
this.localCache = new LocalCacheProxy();
|
|
830
830
|
this.memoryCache = new MemoryCache({
|
|
831
831
|
maxSize: 500,
|
|
832
|
-
ttl:
|
|
833
|
-
// 5 minutes
|
|
832
|
+
ttl: 60 * 1e3
|
|
834
833
|
});
|
|
835
834
|
if (!this.isServer) {
|
|
836
835
|
this.browserCache = new BrowserCache(config.projectId);
|
|
837
836
|
}
|
|
838
837
|
this.rateLimiter = new RateLimiter({
|
|
839
|
-
maxRequests: config.debug ?
|
|
838
|
+
maxRequests: config.debug ? 200 : 100,
|
|
840
839
|
timeWindow: 6e4
|
|
841
840
|
});
|
|
842
841
|
this.backoff = new ExponentialBackoff({
|
|
@@ -853,15 +852,11 @@ var ContentEngine = class {
|
|
|
853
852
|
window.addEventListener("beforeunload", this.cleanup.bind(this));
|
|
854
853
|
}
|
|
855
854
|
}
|
|
856
|
-
/** Update runtime configuration without exposing internal mutation. */
|
|
857
855
|
updateConfig(config) {
|
|
858
856
|
this.config = config;
|
|
859
857
|
this.defaultRevalidate = _nullishCoalesce(config.revalidateTime, () => ( false));
|
|
860
858
|
this.cacheStrategy = config.cacheStrategy || "memory";
|
|
861
859
|
}
|
|
862
|
-
/**
|
|
863
|
-
* Fetch a Single Page with full strategy pipeline
|
|
864
|
-
*/
|
|
865
860
|
async getPage(slug, options = {}) {
|
|
866
861
|
const { result, duration } = _chunkOP3LNZPCcjs.measurePerformance.call(void 0,
|
|
867
862
|
`getPage("${slug}")`,
|
|
@@ -883,66 +878,66 @@ var ContentEngine = class {
|
|
|
883
878
|
includeMetadata = false
|
|
884
879
|
} = options;
|
|
885
880
|
const cacheKey = `page:${slug}`;
|
|
886
|
-
|
|
887
|
-
cacheKey
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
881
|
+
if (!this.isServer && !forceRefresh && this.cacheStrategy === "memory") {
|
|
882
|
+
const cached = this.memoryCache.get(cacheKey);
|
|
883
|
+
if (cached && this.isCacheValid(cached.metadata)) {
|
|
884
|
+
return includeMetadata ? cached : cached.data;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
if (!forceRefresh && process.env.NODE_ENV === "development") {
|
|
888
|
+
try {
|
|
889
|
+
const local = await this.localCache.getPage(slug);
|
|
890
|
+
if (local) {
|
|
891
|
+
return includeMetadata ? {
|
|
892
|
+
data: local,
|
|
893
|
+
metadata: {
|
|
894
|
+
timestamp: Date.now(),
|
|
895
|
+
expiresAt: Infinity,
|
|
896
|
+
tags: []
|
|
897
|
+
}
|
|
898
|
+
} : local;
|
|
899
|
+
}
|
|
900
|
+
} catch (e6) {
|
|
901
|
+
}
|
|
894
902
|
}
|
|
895
903
|
if (this.circuitBreaker.isOpen()) {
|
|
896
|
-
throw new Error(
|
|
904
|
+
throw new Error("[NexusHub] Circuit open. API is unavailable.");
|
|
897
905
|
}
|
|
898
906
|
try {
|
|
899
907
|
await this.rateLimiter.checkLimit();
|
|
900
|
-
const data = await this.backoff.execute(
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
},
|
|
910
|
-
(attempt, delay, error) => {
|
|
911
|
-
if (this.config.debug) {
|
|
912
|
-
console.log(
|
|
913
|
-
`[NexusHub] \u{1F504} Retry ${attempt} for '${slug}' after ${delay}ms: ${error.message}`
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
);
|
|
908
|
+
const data = await this.backoff.execute(async () => {
|
|
909
|
+
return this.fetchPage(
|
|
910
|
+
slug,
|
|
911
|
+
cacheKey,
|
|
912
|
+
tags,
|
|
913
|
+
revalidate,
|
|
914
|
+
forceRefresh
|
|
915
|
+
);
|
|
916
|
+
});
|
|
918
917
|
this.circuitBreaker.recordSuccess();
|
|
919
918
|
return includeMetadata ? data : data.data;
|
|
920
919
|
} catch (error) {
|
|
921
920
|
this.circuitBreaker.recordFailure();
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
921
|
+
if (process.env.NODE_ENV === "development") {
|
|
922
|
+
try {
|
|
923
|
+
const local = await this.localCache.getPage(slug);
|
|
924
|
+
if (local) {
|
|
925
|
+
return includeMetadata ? {
|
|
926
|
+
data: local,
|
|
927
|
+
metadata: {
|
|
928
|
+
timestamp: Date.now(),
|
|
929
|
+
expiresAt: Infinity,
|
|
930
|
+
tags: []
|
|
931
|
+
}
|
|
932
|
+
} : local;
|
|
933
|
+
}
|
|
934
|
+
} catch (e7) {
|
|
935
|
+
}
|
|
926
936
|
}
|
|
927
937
|
throw this.normalizeError(error, `Failed to fetch page '${slug}'`);
|
|
928
938
|
}
|
|
929
939
|
}
|
|
930
|
-
/**
|
|
931
|
-
* Fetch a Collection (Optimized)
|
|
932
|
-
*/
|
|
933
940
|
async getCollection(collectionId, query = {}, options = {}) {
|
|
934
|
-
const { result, duration } = _chunkOP3LNZPCcjs.measurePerformance.call(void 0,
|
|
935
|
-
`getCollection("${collectionId}")`,
|
|
936
|
-
() => this._getCollection(collectionId, query, options)
|
|
937
|
-
);
|
|
938
|
-
if (this.config.debug && duration > 100) {
|
|
939
|
-
console.warn(
|
|
940
|
-
`[NexusHub] \u26A0\uFE0F getCollection("${collectionId}") took ${duration.toFixed(2)}ms`
|
|
941
|
-
);
|
|
942
|
-
}
|
|
943
|
-
return result;
|
|
944
|
-
}
|
|
945
|
-
async _getCollection(collectionId, query = {}, options = {}) {
|
|
946
941
|
const normalizedQuery = _chunkOP3LNZPCcjs.normalizeQuery.call(void 0, query);
|
|
947
942
|
const {
|
|
948
943
|
revalidate = this.defaultRevalidate,
|
|
@@ -952,20 +947,13 @@ var ContentEngine = class {
|
|
|
952
947
|
} = options;
|
|
953
948
|
const queryString = _chunkOP3LNZPCcjs.buildQueryString.call(void 0, normalizedQuery);
|
|
954
949
|
const cacheKey = `collection:${collectionId}:${queryString}`;
|
|
955
|
-
|
|
956
|
-
cacheKey
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
);
|
|
960
|
-
if (cached) {
|
|
961
|
-
if (this.config.debug) {
|
|
962
|
-
console.log(
|
|
963
|
-
`[NexusHub] \u26A1 Served collection '${collectionId}' from memory cache.`
|
|
964
|
-
);
|
|
950
|
+
if (!this.isServer && !forceRefresh && this.cacheStrategy === "memory") {
|
|
951
|
+
const cached = this.memoryCache.get(cacheKey);
|
|
952
|
+
if (cached && this.isCacheValid(cached.metadata)) {
|
|
953
|
+
return includeMetadata ? cached : cached.data;
|
|
965
954
|
}
|
|
966
|
-
return includeMetadata ? cached : cached.data;
|
|
967
955
|
}
|
|
968
|
-
if (!forceRefresh) {
|
|
956
|
+
if (!forceRefresh && process.env.NODE_ENV === "development") {
|
|
969
957
|
try {
|
|
970
958
|
const localCollection = await this.localCache.getCollection(collectionId);
|
|
971
959
|
if (localCollection) {
|
|
@@ -973,21 +961,14 @@ var ContentEngine = class {
|
|
|
973
961
|
localCollection,
|
|
974
962
|
normalizedQuery
|
|
975
963
|
);
|
|
976
|
-
if (this.config.debug) {
|
|
977
|
-
console.log(
|
|
978
|
-
`[NexusHub] \u{1F4C1} Compiled collection '${collectionId}' from local offline binaries.`
|
|
979
|
-
);
|
|
980
|
-
}
|
|
981
|
-
this.memoryCache.set(cacheKey, result, {
|
|
982
|
-
tags: [...tags, CacheTags.collection(collectionId)],
|
|
983
|
-
revalidate: revalidate === false ? void 0 : revalidate
|
|
984
|
-
});
|
|
985
964
|
return result;
|
|
986
965
|
}
|
|
987
|
-
} catch (
|
|
966
|
+
} catch (e8) {
|
|
988
967
|
}
|
|
989
968
|
}
|
|
990
|
-
if (this.circuitBreaker.isOpen())
|
|
969
|
+
if (this.circuitBreaker.isOpen()) {
|
|
970
|
+
throw new Error("[NexusHub] Circuit open. API is unavailable.");
|
|
971
|
+
}
|
|
991
972
|
try {
|
|
992
973
|
await this.rateLimiter.checkLimit();
|
|
993
974
|
const result = await this.backoff.execute(async () => {
|
|
@@ -996,19 +977,25 @@ var ContentEngine = class {
|
|
|
996
977
|
normalizedQuery,
|
|
997
978
|
cacheKey,
|
|
998
979
|
tags,
|
|
999
|
-
revalidate
|
|
980
|
+
revalidate,
|
|
981
|
+
forceRefresh
|
|
1000
982
|
);
|
|
1001
983
|
});
|
|
1002
984
|
this.circuitBreaker.recordSuccess();
|
|
1003
985
|
return includeMetadata ? result : result.data;
|
|
1004
986
|
} catch (error) {
|
|
1005
987
|
this.circuitBreaker.recordFailure();
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
988
|
+
if (process.env.NODE_ENV === "development") {
|
|
989
|
+
try {
|
|
990
|
+
const localCollection = await this.localCache.getCollection(collectionId);
|
|
991
|
+
if (localCollection) {
|
|
992
|
+
return this.applyLocalQuery(
|
|
993
|
+
localCollection,
|
|
994
|
+
normalizedQuery
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
} catch (e9) {
|
|
998
|
+
}
|
|
1012
999
|
}
|
|
1013
1000
|
throw this.normalizeError(
|
|
1014
1001
|
error,
|
|
@@ -1016,9 +1003,6 @@ var ContentEngine = class {
|
|
|
1016
1003
|
);
|
|
1017
1004
|
}
|
|
1018
1005
|
}
|
|
1019
|
-
/**
|
|
1020
|
-
* Fetch Global Settings
|
|
1021
|
-
*/
|
|
1022
1006
|
async getGlobals(options = {}) {
|
|
1023
1007
|
const {
|
|
1024
1008
|
include = [],
|
|
@@ -1026,31 +1010,19 @@ var ContentEngine = class {
|
|
|
1026
1010
|
forceRefresh = false
|
|
1027
1011
|
} = options;
|
|
1028
1012
|
const cacheKey = `globals:${include.join(",")}`;
|
|
1029
|
-
if (!forceRefresh && this.cacheStrategy === "memory") {
|
|
1013
|
+
if (!this.isServer && !forceRefresh && this.cacheStrategy === "memory") {
|
|
1030
1014
|
const cached = this.memoryCache.get(cacheKey);
|
|
1031
1015
|
if (cached && this.isCacheValid(cached.metadata)) {
|
|
1032
|
-
if (this.config.debug)
|
|
1033
|
-
console.log("[NexusHub] \u26A1 Served globals from memory cache.");
|
|
1034
1016
|
return cached.data;
|
|
1035
1017
|
}
|
|
1036
1018
|
}
|
|
1037
|
-
if (!forceRefresh &&
|
|
1038
|
-
const cached = this.browserCache.get(cacheKey);
|
|
1039
|
-
if (cached) {
|
|
1040
|
-
return cached;
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
if (!forceRefresh) {
|
|
1019
|
+
if (!forceRefresh && process.env.NODE_ENV === "development") {
|
|
1044
1020
|
try {
|
|
1045
1021
|
const localGlobals = await this.localCache.getGlobals();
|
|
1046
1022
|
if (localGlobals) {
|
|
1047
|
-
this.memoryCache.set(cacheKey, localGlobals, {
|
|
1048
|
-
tags: [CacheTags.global],
|
|
1049
|
-
revalidate: revalidate === false ? void 0 : revalidate
|
|
1050
|
-
});
|
|
1051
1023
|
return localGlobals;
|
|
1052
1024
|
}
|
|
1053
|
-
} catch (
|
|
1025
|
+
} catch (e10) {
|
|
1054
1026
|
}
|
|
1055
1027
|
}
|
|
1056
1028
|
try {
|
|
@@ -1066,80 +1038,79 @@ var ContentEngine = class {
|
|
|
1066
1038
|
method: "GET",
|
|
1067
1039
|
headers: this.getHeaders(),
|
|
1068
1040
|
tags: fetchTags,
|
|
1069
|
-
revalidate
|
|
1041
|
+
revalidate,
|
|
1042
|
+
forceRefresh
|
|
1070
1043
|
});
|
|
1071
1044
|
if (!res.ok) {
|
|
1072
|
-
if (res.status === 408) {
|
|
1073
|
-
throw new Error("Request timeout");
|
|
1074
|
-
}
|
|
1075
1045
|
throw new Error(`API Error ${res.status}: ${res.statusText}`);
|
|
1076
1046
|
}
|
|
1077
1047
|
const json = await res.json();
|
|
1078
1048
|
const data = json.data || json;
|
|
1079
|
-
this.
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1049
|
+
if (!this.isServer) {
|
|
1050
|
+
this.writeCache(cacheKey, data, {
|
|
1051
|
+
revalidate,
|
|
1052
|
+
tags: fetchTags
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1083
1055
|
return data;
|
|
1084
1056
|
} catch (error) {
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1057
|
+
if (process.env.NODE_ENV === "development") {
|
|
1058
|
+
try {
|
|
1059
|
+
const localGlobals = await this.localCache.getGlobals();
|
|
1060
|
+
if (localGlobals) {
|
|
1061
|
+
return localGlobals;
|
|
1062
|
+
}
|
|
1063
|
+
} catch (e11) {
|
|
1064
|
+
}
|
|
1089
1065
|
}
|
|
1090
1066
|
throw this.normalizeError(error, "Failed to fetch globals");
|
|
1091
1067
|
}
|
|
1092
1068
|
}
|
|
1093
|
-
/**
|
|
1094
|
-
* Get a single item from a collection (Uses Request Batching)
|
|
1095
|
-
*/
|
|
1096
1069
|
async getItem(collectionId, itemId, options = {}) {
|
|
1070
|
+
const { forceRefresh = false } = options;
|
|
1097
1071
|
const cacheKey = `item:${collectionId}:${itemId}`;
|
|
1098
|
-
if (this.cacheStrategy === "memory") {
|
|
1072
|
+
if (!this.isServer && !forceRefresh && this.cacheStrategy === "memory") {
|
|
1099
1073
|
const cached = this.memoryCache.get(cacheKey);
|
|
1100
1074
|
if (cached && this.isCacheValid(cached.metadata)) {
|
|
1101
|
-
if (this.config.debug) {
|
|
1102
|
-
console.log(`[NexusHub] \u26A1 Served item '${itemId}' from cache.`);
|
|
1103
|
-
}
|
|
1104
1075
|
return cached.data;
|
|
1105
1076
|
}
|
|
1106
1077
|
}
|
|
1107
|
-
return this.requestBatcher.schedule(
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
params
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
const fetchTags = [
|
|
1114
|
-
CacheTags.project(this.config.projectId),
|
|
1115
|
-
CacheTags.collection(collectionId),
|
|
1116
|
-
`item_${itemId}`,
|
|
1117
|
-
...options.tags || []
|
|
1118
|
-
];
|
|
1119
|
-
const res = await this.fetchWithTimeout(url, {
|
|
1120
|
-
method: "GET",
|
|
1121
|
-
headers: this.getHeaders(),
|
|
1122
|
-
tags: fetchTags,
|
|
1123
|
-
revalidate: _nullishCoalesce(options.revalidate, () => ( this.defaultRevalidate))
|
|
1124
|
-
});
|
|
1125
|
-
if (!res.ok) {
|
|
1126
|
-
if (res.status === 408) {
|
|
1127
|
-
throw new Error("Request timeout");
|
|
1078
|
+
return this.requestBatcher.schedule(
|
|
1079
|
+
forceRefresh ? `${cacheKey}:refresh:${Date.now()}` : cacheKey,
|
|
1080
|
+
async () => {
|
|
1081
|
+
const params = new URLSearchParams();
|
|
1082
|
+
if (_optionalChain([options, 'access', _17 => _17.include, 'optionalAccess', _18 => _18.length])) {
|
|
1083
|
+
params.append("include", options.include.join(","));
|
|
1128
1084
|
}
|
|
1129
|
-
|
|
1085
|
+
const url = `${this.config.apiUrl}/content/${this.config.projectId}/collection/${collectionId}/${itemId}?${params}`;
|
|
1086
|
+
const fetchTags = [
|
|
1087
|
+
CacheTags.project(this.config.projectId),
|
|
1088
|
+
CacheTags.collection(collectionId),
|
|
1089
|
+
`item_${itemId}`,
|
|
1090
|
+
...options.tags || []
|
|
1091
|
+
];
|
|
1092
|
+
const res = await this.fetchWithTimeout(url, {
|
|
1093
|
+
method: "GET",
|
|
1094
|
+
headers: this.getHeaders(),
|
|
1095
|
+
tags: fetchTags,
|
|
1096
|
+
revalidate: _nullishCoalesce(options.revalidate, () => ( this.defaultRevalidate)),
|
|
1097
|
+
forceRefresh
|
|
1098
|
+
});
|
|
1099
|
+
if (!res.ok) {
|
|
1100
|
+
throw new Error(`API Error ${res.status}: ${res.statusText}`);
|
|
1101
|
+
}
|
|
1102
|
+
const json = await res.json();
|
|
1103
|
+
const data = json.data || json;
|
|
1104
|
+
if (!this.isServer) {
|
|
1105
|
+
this.writeCache(cacheKey, data, {
|
|
1106
|
+
revalidate: _nullishCoalesce(options.revalidate, () => ( this.defaultRevalidate)),
|
|
1107
|
+
tags: fetchTags
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
return data;
|
|
1130
1111
|
}
|
|
1131
|
-
|
|
1132
|
-
const data = json.data || json;
|
|
1133
|
-
this.writeCache(cacheKey, data, {
|
|
1134
|
-
revalidate: _nullishCoalesce(options.revalidate, () => ( this.defaultRevalidate)),
|
|
1135
|
-
tags: fetchTags
|
|
1136
|
-
});
|
|
1137
|
-
return data;
|
|
1138
|
-
});
|
|
1112
|
+
);
|
|
1139
1113
|
}
|
|
1140
|
-
/**
|
|
1141
|
-
* Search across collections
|
|
1142
|
-
*/
|
|
1143
1114
|
async search(query, options = {}) {
|
|
1144
1115
|
const params = new URLSearchParams({
|
|
1145
1116
|
q: query,
|
|
@@ -1152,65 +1123,61 @@ var ContentEngine = class {
|
|
|
1152
1123
|
params.append("fields", options.fields.join(","));
|
|
1153
1124
|
}
|
|
1154
1125
|
const url = `${this.config.apiUrl}/content/${this.config.projectId}/search?${params}`;
|
|
1126
|
+
const fetchTags = [
|
|
1127
|
+
CacheTags.project(this.config.projectId),
|
|
1128
|
+
...(options.collections || []).map(
|
|
1129
|
+
(collection) => CacheTags.collection(collection)
|
|
1130
|
+
)
|
|
1131
|
+
];
|
|
1155
1132
|
const res = await this.fetchWithTimeout(url, {
|
|
1156
1133
|
method: "GET",
|
|
1157
|
-
headers: this.getHeaders()
|
|
1134
|
+
headers: this.getHeaders(),
|
|
1135
|
+
tags: fetchTags,
|
|
1136
|
+
revalidate: _nullishCoalesce(options.revalidate, () => ( this.defaultRevalidate)),
|
|
1137
|
+
forceRefresh: _nullishCoalesce(options.forceRefresh, () => ( false))
|
|
1158
1138
|
});
|
|
1159
1139
|
if (!res.ok) {
|
|
1160
|
-
if (res.status === 408) {
|
|
1161
|
-
throw new Error("Request timeout");
|
|
1162
|
-
}
|
|
1163
1140
|
throw new Error(`API Error ${res.status}: ${res.statusText}`);
|
|
1164
1141
|
}
|
|
1165
1142
|
return await res.json();
|
|
1166
1143
|
}
|
|
1167
|
-
/**
|
|
1168
|
-
* Prefetch content
|
|
1169
|
-
*/
|
|
1170
1144
|
async prefetch(urls) {
|
|
1171
1145
|
if (typeof window !== "undefined" && "requestIdleCallback" in window) {
|
|
1172
1146
|
requestIdleCallback(async () => {
|
|
1173
1147
|
await Promise.allSettled(
|
|
1174
|
-
urls.map(
|
|
1148
|
+
urls.map(
|
|
1149
|
+
(url) => fetch(url, {
|
|
1150
|
+
priority: "low"
|
|
1151
|
+
})
|
|
1152
|
+
)
|
|
1175
1153
|
);
|
|
1176
1154
|
});
|
|
1177
1155
|
}
|
|
1178
1156
|
}
|
|
1179
|
-
/**
|
|
1180
|
-
* Robust Real-time Subscriptions (SSE) with Auto-Reconnect
|
|
1181
|
-
*/
|
|
1182
1157
|
subscribeToUpdates(callback) {
|
|
1183
1158
|
if (this.isServer || typeof EventSource === "undefined") {
|
|
1184
|
-
if (this.config.debug) {
|
|
1185
|
-
console.warn(
|
|
1186
|
-
"[NexusHub] subscribeToUpdates() called in a non-browser environment."
|
|
1187
|
-
);
|
|
1188
|
-
}
|
|
1189
1159
|
return () => {
|
|
1190
1160
|
};
|
|
1191
1161
|
}
|
|
1192
1162
|
if (!this.config.apiKey) {
|
|
1193
|
-
|
|
1163
|
+
return () => {
|
|
1164
|
+
};
|
|
1194
1165
|
}
|
|
1195
1166
|
let eventSource = null;
|
|
1196
1167
|
let retryCount = 0;
|
|
1197
1168
|
let isClosed = false;
|
|
1198
|
-
const MAX_RETRY_DELAY_MS = 3e4;
|
|
1199
1169
|
const connect = () => {
|
|
1200
1170
|
if (isClosed) return;
|
|
1201
1171
|
const url = `${this.config.apiUrl}/content/${this.config.projectId}/updates?key=${_nullishCoalesce(this.config.apiKey, () => ( ""))}`;
|
|
1202
1172
|
eventSource = new EventSource(url);
|
|
1203
1173
|
eventSource.onopen = () => {
|
|
1204
1174
|
retryCount = 0;
|
|
1205
|
-
if (this.config.debug)
|
|
1206
|
-
console.log("[NexusHub] \u{1F7E2} Real-time stream connected");
|
|
1207
1175
|
};
|
|
1208
1176
|
eventSource.onmessage = (event) => {
|
|
1209
1177
|
let data;
|
|
1210
1178
|
try {
|
|
1211
1179
|
data = JSON.parse(event.data);
|
|
1212
|
-
} catch (
|
|
1213
|
-
console.error("[NexusHub] SSE Parse Error", e);
|
|
1180
|
+
} catch (e12) {
|
|
1214
1181
|
return;
|
|
1215
1182
|
}
|
|
1216
1183
|
if (!data || typeof data.type !== "string") {
|
|
@@ -1222,6 +1189,9 @@ var ContentEngine = class {
|
|
|
1222
1189
|
if (data.type === "collection.updated" && data.collectionId) {
|
|
1223
1190
|
this.invalidateCache([CacheTags.collection(data.collectionId)]);
|
|
1224
1191
|
}
|
|
1192
|
+
if (data.type === "globals.updated") {
|
|
1193
|
+
this.invalidateCache([CacheTags.global]);
|
|
1194
|
+
}
|
|
1225
1195
|
if (data.type === "schema.updated") {
|
|
1226
1196
|
this.clearCache();
|
|
1227
1197
|
}
|
|
@@ -1230,16 +1200,8 @@ var ContentEngine = class {
|
|
|
1230
1200
|
eventSource.onerror = () => {
|
|
1231
1201
|
_optionalChain([eventSource, 'optionalAccess', _23 => _23.close, 'call', _24 => _24()]);
|
|
1232
1202
|
if (isClosed) return;
|
|
1233
|
-
const timeout = Math.min(
|
|
1234
|
-
1e3 * Math.pow(2, retryCount),
|
|
1235
|
-
MAX_RETRY_DELAY_MS
|
|
1236
|
-
);
|
|
1203
|
+
const timeout = Math.min(1e3 * Math.pow(2, retryCount), 3e4);
|
|
1237
1204
|
retryCount++;
|
|
1238
|
-
if (this.config.debug) {
|
|
1239
|
-
console.warn(
|
|
1240
|
-
`[NexusHub] \u{1F534} Stream disconnected. Reconnecting in ${timeout}ms...`
|
|
1241
|
-
);
|
|
1242
|
-
}
|
|
1243
1205
|
setTimeout(connect, timeout);
|
|
1244
1206
|
};
|
|
1245
1207
|
};
|
|
@@ -1249,70 +1211,19 @@ var ContentEngine = class {
|
|
|
1249
1211
|
_optionalChain([eventSource, 'optionalAccess', _25 => _25.close, 'call', _26 => _26()]);
|
|
1250
1212
|
};
|
|
1251
1213
|
}
|
|
1252
|
-
// --- CACHE MANAGEMENT ---
|
|
1253
|
-
async checkCaches(key, forceRefresh, includeMetadata) {
|
|
1254
|
-
if (forceRefresh) return null;
|
|
1255
|
-
if (this.cacheStrategy === "memory") {
|
|
1256
|
-
const cached = this.memoryCache.get(key);
|
|
1257
|
-
if (cached && this.isCacheValid(cached.metadata)) {
|
|
1258
|
-
return cached;
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
if (!this.isServer && this.cacheStrategy === "localStorage" && this.browserCache) {
|
|
1262
|
-
const cached = this.browserCache.get(key);
|
|
1263
|
-
if (cached) {
|
|
1264
|
-
return {
|
|
1265
|
-
data: cached,
|
|
1266
|
-
metadata: {
|
|
1267
|
-
timestamp: 0,
|
|
1268
|
-
expiresAt: Infinity,
|
|
1269
|
-
tags: [],
|
|
1270
|
-
etag: void 0
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
if (key.startsWith("page:")) {
|
|
1276
|
-
const slug = key.split(":")[1];
|
|
1277
|
-
try {
|
|
1278
|
-
const local = await this.localCache.getPage(slug);
|
|
1279
|
-
if (local && (process.env.NODE_ENV === "development" || !this.config.apiKey)) {
|
|
1280
|
-
return {
|
|
1281
|
-
data: local,
|
|
1282
|
-
metadata: {
|
|
1283
|
-
timestamp: Date.now(),
|
|
1284
|
-
expiresAt: Infinity,
|
|
1285
|
-
tags: [
|
|
1286
|
-
CacheTags.content(slug),
|
|
1287
|
-
CacheTags.project(this.config.projectId)
|
|
1288
|
-
],
|
|
1289
|
-
etag: void 0
|
|
1290
|
-
}
|
|
1291
|
-
};
|
|
1292
|
-
}
|
|
1293
|
-
} catch (e8) {
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
return null;
|
|
1297
|
-
}
|
|
1298
1214
|
writeCache(key, data, options) {
|
|
1299
|
-
const
|
|
1215
|
+
const ttlSeconds = options.revalidate === false ? 60 : Math.max(1, options.revalidate);
|
|
1300
1216
|
if (this.cacheStrategy === "memory") {
|
|
1301
1217
|
this.memoryCache.set(key, data, {
|
|
1302
1218
|
tags: options.tags,
|
|
1303
|
-
|
|
1219
|
+
ttl: ttlSeconds * 1e3
|
|
1304
1220
|
});
|
|
1305
1221
|
}
|
|
1306
|
-
if (!this.isServer && this.cacheStrategy === "localStorage" && this.browserCache) {
|
|
1307
|
-
this.browserCache.set(key, data, numericRevalidate * 1e3);
|
|
1308
|
-
}
|
|
1309
1222
|
}
|
|
1310
1223
|
invalidateCache(tags) {
|
|
1311
1224
|
this.memoryCache.invalidateByTags(tags);
|
|
1312
|
-
if (this.
|
|
1313
|
-
|
|
1314
|
-
`[NexusHub] \u267B\uFE0F Invalidated cache for tags: ${tags.join(", ")}`
|
|
1315
|
-
);
|
|
1225
|
+
if (this.browserCache) {
|
|
1226
|
+
this.browserCache.clear();
|
|
1316
1227
|
}
|
|
1317
1228
|
}
|
|
1318
1229
|
clearCache() {
|
|
@@ -1320,24 +1231,17 @@ var ContentEngine = class {
|
|
|
1320
1231
|
if (this.browserCache) {
|
|
1321
1232
|
this.browserCache.clear();
|
|
1322
1233
|
}
|
|
1323
|
-
if (this.config.debug) {
|
|
1324
|
-
console.log("[NexusHub] \u{1F9F9} Cleared all caches");
|
|
1325
|
-
}
|
|
1326
1234
|
}
|
|
1327
1235
|
getCacheStats() {
|
|
1328
|
-
|
|
1236
|
+
return {
|
|
1329
1237
|
memory: this.memoryCache.getStats(),
|
|
1330
|
-
local: {
|
|
1238
|
+
local: {
|
|
1239
|
+
loaded: this.localCache.isLoaded()
|
|
1240
|
+
}
|
|
1331
1241
|
};
|
|
1332
|
-
if (this.browserCache) {
|
|
1333
|
-
stats.browser = { size: 0 };
|
|
1334
|
-
}
|
|
1335
|
-
return stats;
|
|
1336
1242
|
}
|
|
1337
|
-
// --- REQUEST METHODS ---
|
|
1338
1243
|
async fetchPage(slug, cacheKey, tags, revalidate, forceRefresh) {
|
|
1339
1244
|
const url = `${this.config.apiUrl}/content/${this.config.projectId}/page/${slug}`;
|
|
1340
|
-
const expiresAt = revalidate === false ? Infinity : Date.now() + revalidate * 1e3;
|
|
1341
1245
|
const fetchTags = [
|
|
1342
1246
|
CacheTags.project(this.config.projectId),
|
|
1343
1247
|
CacheTags.content(slug),
|
|
@@ -1347,13 +1251,12 @@ var ContentEngine = class {
|
|
|
1347
1251
|
method: "GET",
|
|
1348
1252
|
headers: this.getHeaders(),
|
|
1349
1253
|
tags: fetchTags,
|
|
1350
|
-
revalidate
|
|
1254
|
+
revalidate,
|
|
1255
|
+
forceRefresh
|
|
1351
1256
|
});
|
|
1352
1257
|
if (!res.ok) {
|
|
1353
1258
|
if (res.status === 404) {
|
|
1354
|
-
throw new Error(
|
|
1355
|
-
`Page '${slug}' not found. Check your Dashboard or Seed data.`
|
|
1356
|
-
);
|
|
1259
|
+
throw new Error(`Page '${slug}' not found.`);
|
|
1357
1260
|
}
|
|
1358
1261
|
if (res.status === 408) {
|
|
1359
1262
|
throw new Error("Request timeout");
|
|
@@ -1367,17 +1270,19 @@ var ContentEngine = class {
|
|
|
1367
1270
|
metadata: {
|
|
1368
1271
|
timestamp: Date.now(),
|
|
1369
1272
|
etag: etag || void 0,
|
|
1370
|
-
expiresAt,
|
|
1273
|
+
expiresAt: revalidate === false ? Infinity : Date.now() + revalidate * 1e3,
|
|
1371
1274
|
tags: fetchTags
|
|
1372
1275
|
}
|
|
1373
1276
|
};
|
|
1374
|
-
this.
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1277
|
+
if (!this.isServer) {
|
|
1278
|
+
this.writeCache(cacheKey, cacheEntry.data, {
|
|
1279
|
+
revalidate,
|
|
1280
|
+
tags: fetchTags
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1378
1283
|
return cacheEntry;
|
|
1379
1284
|
}
|
|
1380
|
-
async fetchCollection(collectionId, query, cacheKey, tags, revalidate) {
|
|
1285
|
+
async fetchCollection(collectionId, query, cacheKey, tags, revalidate, forceRefresh) {
|
|
1381
1286
|
const params = _chunkOP3LNZPCcjs.buildQueryString.call(void 0, query);
|
|
1382
1287
|
const url = `${this.config.apiUrl}/content/${this.config.projectId}/collection/${collectionId}?${params}`;
|
|
1383
1288
|
const fetchTags = [
|
|
@@ -1389,7 +1294,8 @@ var ContentEngine = class {
|
|
|
1389
1294
|
method: "GET",
|
|
1390
1295
|
headers: this.getHeaders(),
|
|
1391
1296
|
tags: fetchTags,
|
|
1392
|
-
revalidate
|
|
1297
|
+
revalidate,
|
|
1298
|
+
forceRefresh
|
|
1393
1299
|
});
|
|
1394
1300
|
if (!res.ok) {
|
|
1395
1301
|
if (res.status === 408) {
|
|
@@ -1399,23 +1305,23 @@ var ContentEngine = class {
|
|
|
1399
1305
|
}
|
|
1400
1306
|
const json = await res.json();
|
|
1401
1307
|
const etag = res.headers.get("etag");
|
|
1402
|
-
const expiresAt = revalidate === false ? Infinity : Date.now() + revalidate * 1e3;
|
|
1403
1308
|
const cacheEntry = {
|
|
1404
1309
|
data: json,
|
|
1405
1310
|
metadata: {
|
|
1406
1311
|
timestamp: Date.now(),
|
|
1407
1312
|
etag: etag || void 0,
|
|
1408
|
-
expiresAt,
|
|
1313
|
+
expiresAt: revalidate === false ? Infinity : Date.now() + revalidate * 1e3,
|
|
1409
1314
|
tags: fetchTags
|
|
1410
1315
|
}
|
|
1411
1316
|
};
|
|
1412
|
-
this.
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1317
|
+
if (!this.isServer) {
|
|
1318
|
+
this.writeCache(cacheKey, cacheEntry.data, {
|
|
1319
|
+
revalidate,
|
|
1320
|
+
tags: fetchTags
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1416
1323
|
return cacheEntry;
|
|
1417
1324
|
}
|
|
1418
|
-
// --- HELPER METHODS ---
|
|
1419
1325
|
applyLocalQuery(items, query) {
|
|
1420
1326
|
let filtered = [...items];
|
|
1421
1327
|
if (query.search) {
|
|
@@ -1428,7 +1334,9 @@ var ContentEngine = class {
|
|
|
1428
1334
|
filtered = filtered.filter((item) => {
|
|
1429
1335
|
return Object.entries(query.filter).every(([key, value]) => {
|
|
1430
1336
|
const itemValue = item[key];
|
|
1431
|
-
if (itemValue === void 0)
|
|
1337
|
+
if (itemValue === void 0) {
|
|
1338
|
+
return false;
|
|
1339
|
+
}
|
|
1432
1340
|
if (Array.isArray(value)) {
|
|
1433
1341
|
return value.includes(itemValue);
|
|
1434
1342
|
}
|
|
@@ -1441,8 +1349,12 @@ var ContentEngine = class {
|
|
|
1441
1349
|
const aVal = a[query.sort];
|
|
1442
1350
|
const bVal = b[query.sort];
|
|
1443
1351
|
const order = query.order === "asc" ? 1 : -1;
|
|
1444
|
-
if (aVal < bVal)
|
|
1445
|
-
|
|
1352
|
+
if (aVal < bVal) {
|
|
1353
|
+
return -1 * order;
|
|
1354
|
+
}
|
|
1355
|
+
if (aVal > bVal) {
|
|
1356
|
+
return 1 * order;
|
|
1357
|
+
}
|
|
1446
1358
|
return 0;
|
|
1447
1359
|
});
|
|
1448
1360
|
}
|
|
@@ -1466,15 +1378,18 @@ var ContentEngine = class {
|
|
|
1466
1378
|
timeout = this.config.timeout || 1e4,
|
|
1467
1379
|
tags = [],
|
|
1468
1380
|
revalidate,
|
|
1381
|
+
forceRefresh = false,
|
|
1469
1382
|
...fetchOptions
|
|
1470
1383
|
} = options;
|
|
1471
1384
|
const controller = new AbortController();
|
|
1472
1385
|
const id = setTimeout(() => controller.abort(), timeout);
|
|
1473
1386
|
const nextConfig = this.isServer ? {
|
|
1474
|
-
cache: revalidate === 0 ? "no-store" : "force-cache",
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1387
|
+
cache: forceRefresh || revalidate === 0 ? "no-store" : "force-cache",
|
|
1388
|
+
...forceRefresh ? {} : {
|
|
1389
|
+
next: {
|
|
1390
|
+
tags,
|
|
1391
|
+
revalidate: revalidate === false ? false : revalidate
|
|
1392
|
+
}
|
|
1478
1393
|
}
|
|
1479
1394
|
} : {};
|
|
1480
1395
|
try {
|
|
@@ -1493,9 +1408,9 @@ var ContentEngine = class {
|
|
|
1493
1408
|
getHeaders() {
|
|
1494
1409
|
const headers = {
|
|
1495
1410
|
"Content-Type": "application/json",
|
|
1496
|
-
"X-
|
|
1497
|
-
"X-
|
|
1498
|
-
"X-
|
|
1411
|
+
"X-GN-Apex-Client": `gnapex-sdk/${_nullishCoalesce(this.config.sdkVersion, () => ( "1.1.6"))}`,
|
|
1412
|
+
"X-GN-Apex-Request-ID": typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : `nx_${Date.now()}_${Math.random().toString(36).slice(2)}`,
|
|
1413
|
+
"X-GN-Apex-Project": this.config.projectId
|
|
1499
1414
|
};
|
|
1500
1415
|
if (this.config.apiKey) {
|
|
1501
1416
|
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
@@ -1505,10 +1420,6 @@ var ContentEngine = class {
|
|
|
1505
1420
|
isCacheValid(metadata) {
|
|
1506
1421
|
return Date.now() < metadata.expiresAt;
|
|
1507
1422
|
}
|
|
1508
|
-
/**
|
|
1509
|
-
* 🛡️ FIX: Normalizes timeout errors (AbortError, 408, or Timeout messages)
|
|
1510
|
-
* into clean, standardized "Request timeout" errors.
|
|
1511
|
-
*/
|
|
1512
1423
|
normalizeError(error, context) {
|
|
1513
1424
|
if (error instanceof Error) {
|
|
1514
1425
|
const msg = error.message.toLowerCase();
|
|
@@ -1523,14 +1434,7 @@ var ContentEngine = class {
|
|
|
1523
1434
|
}
|
|
1524
1435
|
return new Error(`${context}: ${String(error)}`);
|
|
1525
1436
|
}
|
|
1526
|
-
cancelRequests() {
|
|
1527
|
-
if (this.abortController) {
|
|
1528
|
-
this.abortController.abort();
|
|
1529
|
-
this.abortController = new AbortController();
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
1437
|
cleanup() {
|
|
1533
|
-
this.cancelRequests();
|
|
1534
1438
|
if (!this.isServer) {
|
|
1535
1439
|
window.removeEventListener("beforeunload", this.cleanup.bind(this));
|
|
1536
1440
|
}
|
|
@@ -1581,7 +1485,7 @@ var generateCanvasHash = async () => {
|
|
|
1581
1485
|
hash = hash & hash;
|
|
1582
1486
|
}
|
|
1583
1487
|
return hash.toString(16);
|
|
1584
|
-
} catch (
|
|
1488
|
+
} catch (e13) {
|
|
1585
1489
|
return "";
|
|
1586
1490
|
}
|
|
1587
1491
|
};
|
|
@@ -1812,20 +1716,20 @@ var eventStorage = new EventStorage();
|
|
|
1812
1716
|
var safeGetItem = (key) => {
|
|
1813
1717
|
try {
|
|
1814
1718
|
return localStorage.getItem(key);
|
|
1815
|
-
} catch (
|
|
1719
|
+
} catch (e14) {
|
|
1816
1720
|
return null;
|
|
1817
1721
|
}
|
|
1818
1722
|
};
|
|
1819
1723
|
var safeSetItem = (key, value) => {
|
|
1820
1724
|
try {
|
|
1821
1725
|
localStorage.setItem(key, value);
|
|
1822
|
-
} catch (
|
|
1726
|
+
} catch (e15) {
|
|
1823
1727
|
}
|
|
1824
1728
|
};
|
|
1825
1729
|
var safeRemoveItem = (key) => {
|
|
1826
1730
|
try {
|
|
1827
1731
|
localStorage.removeItem(key);
|
|
1828
|
-
} catch (
|
|
1732
|
+
} catch (e16) {
|
|
1829
1733
|
}
|
|
1830
1734
|
};
|
|
1831
1735
|
var generateUUID = () => {
|
|
@@ -1958,7 +1862,7 @@ var Tracker = class {
|
|
|
1958
1862
|
keepalive: useBeacon
|
|
1959
1863
|
}
|
|
1960
1864
|
);
|
|
1961
|
-
} catch (
|
|
1865
|
+
} catch (e17) {
|
|
1962
1866
|
response = void 0;
|
|
1963
1867
|
}
|
|
1964
1868
|
if (!response || response.status === 404 || response.status === 405) {
|
|
@@ -2037,7 +1941,7 @@ function extractUtmParams(url) {
|
|
|
2037
1941
|
if (val) result[key] = val;
|
|
2038
1942
|
});
|
|
2039
1943
|
return result;
|
|
2040
|
-
} catch (
|
|
1944
|
+
} catch (e18) {
|
|
2041
1945
|
return {};
|
|
2042
1946
|
}
|
|
2043
1947
|
}
|
|
@@ -2046,7 +1950,7 @@ function extractUtmParams(url) {
|
|
|
2046
1950
|
var safeRemoveItem2 = (key) => {
|
|
2047
1951
|
try {
|
|
2048
1952
|
localStorage.removeItem(key);
|
|
2049
|
-
} catch (
|
|
1953
|
+
} catch (e19) {
|
|
2050
1954
|
}
|
|
2051
1955
|
};
|
|
2052
1956
|
var AnalyticsEngine = class {
|
|
@@ -2265,7 +2169,7 @@ var AnalyticsEngine = class {
|
|
|
2265
2169
|
"outbound_click"
|
|
2266
2170
|
);
|
|
2267
2171
|
}
|
|
2268
|
-
} catch (
|
|
2172
|
+
} catch (e20) {
|
|
2269
2173
|
}
|
|
2270
2174
|
};
|
|
2271
2175
|
window.addEventListener("click", outboundHandler, { passive: true });
|
|
@@ -2522,7 +2426,7 @@ var NexusEventBus = class {
|
|
|
2522
2426
|
_optionalChain([this, 'access', _49 => _49.listeners, 'access', _50 => _50.get, 'call', _51 => _51(event), 'optionalAccess', _52 => _52.forEach, 'call', _53 => _53((l) => {
|
|
2523
2427
|
try {
|
|
2524
2428
|
l(payload);
|
|
2525
|
-
} catch (
|
|
2429
|
+
} catch (e21) {
|
|
2526
2430
|
}
|
|
2527
2431
|
})]);
|
|
2528
2432
|
}
|
|
@@ -2622,7 +2526,7 @@ var NexusHttpClient = class {
|
|
|
2622
2526
|
let details;
|
|
2623
2527
|
try {
|
|
2624
2528
|
details = await response.clone().json();
|
|
2625
|
-
} catch (
|
|
2529
|
+
} catch (e22) {
|
|
2626
2530
|
}
|
|
2627
2531
|
const code = response.status === 404 ? "NOT_FOUND" : response.status === 429 ? "RATE_LIMITED" : "HTTP_ERROR";
|
|
2628
2532
|
const err = new NexusError(
|
|
@@ -2979,7 +2883,7 @@ async function parseError(res) {
|
|
|
2979
2883
|
code: json.code || "UNKNOWN_ERROR",
|
|
2980
2884
|
message: json.message || "An error occurred during authentication"
|
|
2981
2885
|
};
|
|
2982
|
-
} catch (
|
|
2886
|
+
} catch (e23) {
|
|
2983
2887
|
return {
|
|
2984
2888
|
status: res.status,
|
|
2985
2889
|
code: "NETWORK_ERROR",
|
|
@@ -3136,7 +3040,7 @@ var NexusProvider = ({
|
|
|
3136
3040
|
try {
|
|
3137
3041
|
const pushClient = new NexusPushClient(nexus.getConfig());
|
|
3138
3042
|
await pushClient.requestSubscription("/sw.js");
|
|
3139
|
-
} catch (
|
|
3043
|
+
} catch (e24) {
|
|
3140
3044
|
}
|
|
3141
3045
|
}
|
|
3142
3046
|
}).catch((err) => {
|
|
@@ -3578,7 +3482,7 @@ function NexusCode({
|
|
|
3578
3482
|
textArea.select();
|
|
3579
3483
|
try {
|
|
3580
3484
|
document.execCommand("copy");
|
|
3581
|
-
} catch (
|
|
3485
|
+
} catch (e25) {
|
|
3582
3486
|
}
|
|
3583
3487
|
textArea.remove();
|
|
3584
3488
|
}
|