@lovalingo/lovalingo 0.5.22 → 0.5.24
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/utils/api.js +40 -1
- package/package.json +1 -1
package/dist/utils/api.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { warnDebug, errorDebug } from './logger';
|
|
2
2
|
const OK_HTTP_STATUSES = new Set([200, 201]);
|
|
3
|
+
const NOT_FOUND_TITLE_HINTS = /404|not found|page not found|page missing|does not exist|error 404/i;
|
|
3
4
|
function getNavigationResponseStatus() {
|
|
4
5
|
if (typeof performance === "undefined" || typeof performance.getEntriesByType !== "function")
|
|
5
6
|
return null;
|
|
@@ -19,11 +20,43 @@ function isOkHttpStatus(status) {
|
|
|
19
20
|
return true;
|
|
20
21
|
return OK_HTTP_STATUSES.has(status);
|
|
21
22
|
}
|
|
23
|
+
function looksLikeNotFoundDocument() {
|
|
24
|
+
if (typeof document === "undefined")
|
|
25
|
+
return false;
|
|
26
|
+
const title = (document.title || "").toString().trim().toLowerCase();
|
|
27
|
+
if (title && NOT_FOUND_TITLE_HINTS.test(title))
|
|
28
|
+
return true;
|
|
29
|
+
const bodyText = (document.body?.textContent || "").toString().slice(0, 2000).toLowerCase();
|
|
30
|
+
if (!bodyText)
|
|
31
|
+
return false;
|
|
32
|
+
const has404 = /\b404\b/.test(bodyText);
|
|
33
|
+
const hasNotFound = /not found|page not found|page missing|does not exist|error 404/.test(bodyText);
|
|
34
|
+
return has404 && hasNotFound;
|
|
35
|
+
}
|
|
36
|
+
function normalizeApiBase(raw) {
|
|
37
|
+
const input = (raw || "").toString().trim();
|
|
38
|
+
if (!input)
|
|
39
|
+
return "https://cdn.lovalingo.com";
|
|
40
|
+
let base = input.replace(/\/functions\/v1\/?$/i, "").replace(/\/$/, "");
|
|
41
|
+
try {
|
|
42
|
+
const parsed = new URL(base);
|
|
43
|
+
const host = parsed.hostname.toLowerCase();
|
|
44
|
+
// Why: runtime endpoints moved off Supabase Edge Functions; fall back to CDN if a Supabase host is supplied.
|
|
45
|
+
if (host.endsWith(".supabase.co")) {
|
|
46
|
+
warnDebug("LovalingoAPI", `apiBase points to Supabase (${host}); falling back to https://cdn.lovalingo.com`);
|
|
47
|
+
return "https://cdn.lovalingo.com";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Ignore parse errors and keep the raw base.
|
|
52
|
+
}
|
|
53
|
+
return base;
|
|
54
|
+
}
|
|
22
55
|
export class LovalingoAPI {
|
|
23
56
|
constructor(apiKey, apiBase, pathConfig, editKey) {
|
|
24
57
|
this.entitlements = null;
|
|
25
58
|
this.apiKey = apiKey;
|
|
26
|
-
this.apiBase = apiBase;
|
|
59
|
+
this.apiBase = normalizeApiBase(apiBase);
|
|
27
60
|
this.pathConfig = pathConfig;
|
|
28
61
|
this.editKey = editKey;
|
|
29
62
|
}
|
|
@@ -149,6 +182,9 @@ export class LovalingoAPI {
|
|
|
149
182
|
const status = getNavigationResponseStatus();
|
|
150
183
|
if (!isOkHttpStatus(status))
|
|
151
184
|
return;
|
|
185
|
+
// Why: avoid tracking SPA soft-404s (HTTP 200 + "not found" content) so ghost pages don't reappear.
|
|
186
|
+
if (looksLikeNotFoundDocument())
|
|
187
|
+
return;
|
|
152
188
|
const params = new URLSearchParams();
|
|
153
189
|
params.set("key", this.apiKey);
|
|
154
190
|
params.set("path", pathOrUrl);
|
|
@@ -181,6 +217,9 @@ export class LovalingoAPI {
|
|
|
181
217
|
if (!isOkHttpStatus(status)) {
|
|
182
218
|
return { ignored: true, reason: "http_status" };
|
|
183
219
|
}
|
|
220
|
+
if (looksLikeNotFoundDocument()) {
|
|
221
|
+
return { ignored: true, reason: "soft_404" };
|
|
222
|
+
}
|
|
184
223
|
const pathParam = this.buildPathParam(opts?.pathOrUrl);
|
|
185
224
|
const response = await fetch(`${this.apiBase}/functions/v1/misses`, {
|
|
186
225
|
method: "POST",
|
package/package.json
CHANGED