@crediball/react 0.3.6 → 0.3.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/fetchWatcher.d.ts +15 -9
- package/dist/fetchWatcher.js +29 -37
- package/package.json +1 -1
package/dist/fetchWatcher.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Patches window.fetch at module-import time — before any React component
|
|
3
|
+
* mounts and before any AI SDK can capture the fetch reference. This is the
|
|
4
|
+
* key difference from installing the patch in a useEffect: by the time a
|
|
5
|
+
* useEffect runs, the Vercel AI SDK (and others) may have already resolved
|
|
6
|
+
* their fetch reference and bypass the patch entirely.
|
|
6
7
|
*
|
|
7
|
-
* Handles
|
|
8
|
-
* 1. HTTP 402 — regular JSON
|
|
9
|
-
* 2. HTTP 200
|
|
10
|
-
*
|
|
8
|
+
* Handles three credit-error surfaces:
|
|
9
|
+
* 1. HTTP 402 with { code: "insufficient_credits" } — regular JSON routes.
|
|
10
|
+
* 2. HTTP 200 streaming body containing "insufficient_credits" — SSE, ndjson,
|
|
11
|
+
* or Vercel AI SDK data-stream (text/plain) routes.
|
|
12
|
+
* 3. Manual call to notifyInsufficientCredits() from any error handler.
|
|
11
13
|
*/
|
|
12
14
|
type Listener = () => void;
|
|
13
15
|
/**
|
|
14
16
|
* Subscribe to insufficient-credits events detected in window.fetch.
|
|
15
|
-
* Returns an unsubscribe function
|
|
17
|
+
* Returns an unsubscribe function for use in useEffect cleanup.
|
|
18
|
+
*
|
|
19
|
+
* The fetch patch is installed at module load time regardless of whether
|
|
20
|
+
* anyone calls this function. This exists for components that need a direct
|
|
21
|
+
* callback rather than the global DOM event.
|
|
16
22
|
*/
|
|
17
23
|
export declare function subscribeFetchWatcher(listener: Listener): () => void;
|
|
18
24
|
export {};
|
package/dist/fetchWatcher.js
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Patches window.fetch at module-import time — before any React component
|
|
3
|
+
* mounts and before any AI SDK can capture the fetch reference. This is the
|
|
4
|
+
* key difference from installing the patch in a useEffect: by the time a
|
|
5
|
+
* useEffect runs, the Vercel AI SDK (and others) may have already resolved
|
|
6
|
+
* their fetch reference and bypass the patch entirely.
|
|
6
7
|
*
|
|
7
|
-
* Handles
|
|
8
|
-
* 1. HTTP 402 — regular JSON
|
|
9
|
-
* 2. HTTP 200
|
|
10
|
-
*
|
|
8
|
+
* Handles three credit-error surfaces:
|
|
9
|
+
* 1. HTTP 402 with { code: "insufficient_credits" } — regular JSON routes.
|
|
10
|
+
* 2. HTTP 200 streaming body containing "insufficient_credits" — SSE, ndjson,
|
|
11
|
+
* or Vercel AI SDK data-stream (text/plain) routes.
|
|
12
|
+
* 3. Manual call to notifyInsufficientCredits() from any error handler.
|
|
11
13
|
*/
|
|
12
14
|
import { notifyInsufficientCredits } from "./creditEvent";
|
|
13
|
-
let _original = null;
|
|
14
15
|
const _listeners = new Set();
|
|
15
16
|
function fire() {
|
|
16
|
-
// Dispatch the global event so ALL mounted paywall instances react,
|
|
17
|
-
// plus any manual subscribeInsufficientCredits() listeners.
|
|
18
17
|
notifyInsufficientCredits();
|
|
19
|
-
// Also call per-instance listeners registered via subscribeFetchWatcher
|
|
20
|
-
// (kept for backwards compatibility with direct watcher subscribers).
|
|
21
18
|
_listeners.forEach((fn) => fn());
|
|
22
19
|
}
|
|
20
|
+
function isStreamingContentType(ct) {
|
|
21
|
+
return (ct.includes("text/event-stream") ||
|
|
22
|
+
ct.includes("ndjson") ||
|
|
23
|
+
// Vercel AI SDK uses text/plain for its data-stream protocol
|
|
24
|
+
ct.includes("text/plain"));
|
|
25
|
+
}
|
|
23
26
|
/**
|
|
24
27
|
* Tee the streaming response body and scan each chunk for the
|
|
25
28
|
* `insufficient_credits` signal. Returns a new Response whose body is the
|
|
@@ -54,10 +57,11 @@ function watchStream(res) {
|
|
|
54
57
|
headers: res.headers,
|
|
55
58
|
});
|
|
56
59
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
// ── Install patch immediately at module load time ─────────────────────────
|
|
61
|
+
// Running here (not in a useEffect) ensures the patch is in place before any
|
|
62
|
+
// SDK or framework code captures the window.fetch reference.
|
|
63
|
+
if (typeof window !== "undefined") {
|
|
64
|
+
const _original = window.fetch;
|
|
61
65
|
window.fetch = async (...args) => {
|
|
62
66
|
const res = await _original(...args);
|
|
63
67
|
if (res.status === 402) {
|
|
@@ -72,43 +76,31 @@ function install() {
|
|
|
72
76
|
}
|
|
73
77
|
})
|
|
74
78
|
.catch(() => {
|
|
75
|
-
// Non-JSON 402 — fire anyway
|
|
76
|
-
// almost certainly a credit shortage. Set watchFetch=false and call
|
|
77
|
-
// trigger() manually if your app uses 402 for other purposes.
|
|
79
|
+
// Non-JSON 402 — fire anyway.
|
|
78
80
|
fire();
|
|
79
81
|
});
|
|
80
82
|
return res;
|
|
81
83
|
}
|
|
82
|
-
// Watch streaming responses for embedded credit errors (HTTP 200 with
|
|
83
|
-
// text/event-stream or ndjson — the common AI streaming pattern).
|
|
84
84
|
if (res.body) {
|
|
85
85
|
const ct = res.headers.get("content-type") ?? "";
|
|
86
|
-
if (
|
|
86
|
+
if (isStreamingContentType(ct)) {
|
|
87
87
|
return watchStream(res);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
return res;
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
function uninstall() {
|
|
94
|
-
if (typeof window === "undefined" || _original === null)
|
|
95
|
-
return;
|
|
96
|
-
window.fetch = _original;
|
|
97
|
-
_original = null;
|
|
98
|
-
}
|
|
99
93
|
/**
|
|
100
94
|
* Subscribe to insufficient-credits events detected in window.fetch.
|
|
101
|
-
* Returns an unsubscribe function
|
|
95
|
+
* Returns an unsubscribe function for use in useEffect cleanup.
|
|
96
|
+
*
|
|
97
|
+
* The fetch patch is installed at module load time regardless of whether
|
|
98
|
+
* anyone calls this function. This exists for components that need a direct
|
|
99
|
+
* callback rather than the global DOM event.
|
|
102
100
|
*/
|
|
103
101
|
export function subscribeFetchWatcher(listener) {
|
|
104
102
|
if (typeof window === "undefined")
|
|
105
103
|
return () => { };
|
|
106
|
-
if (_listeners.size === 0)
|
|
107
|
-
install();
|
|
108
104
|
_listeners.add(listener);
|
|
109
|
-
return () =>
|
|
110
|
-
_listeners.delete(listener);
|
|
111
|
-
if (_listeners.size === 0)
|
|
112
|
-
uninstall();
|
|
113
|
-
};
|
|
105
|
+
return () => _listeners.delete(listener);
|
|
114
106
|
}
|
package/package.json
CHANGED