Upload 3 files
Browse files- gss-sdk.js +30 -5
- sdk/demo.html +1 -1
- sdk/gss-sdk.js +9 -5
gss-sdk.js
CHANGED
|
@@ -43,6 +43,8 @@ class GSSClient {
|
|
| 43 |
this.model = opts.model || 'llama-3.1-8b-instant';
|
| 44 |
this.storageKey = opts.storageKey || 'gss_jwt';
|
| 45 |
this._token = null;
|
|
|
|
|
|
|
| 46 |
}
|
| 47 |
|
| 48 |
// ββ JWT management ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -52,9 +54,11 @@ class GSSClient {
|
|
| 52 |
try {
|
| 53 |
const raw = localStorage.getItem(this.storageKey);
|
| 54 |
if (!raw) return null;
|
| 55 |
-
const { token, exp } = JSON.parse(raw);
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
| 58 |
localStorage.removeItem(this.storageKey);
|
| 59 |
} catch { /* ignore */ }
|
| 60 |
return null;
|
|
@@ -83,10 +87,12 @@ class GSSClient {
|
|
| 83 |
throw new Error(`[GSSClient] Lease failed: ${res.status}`);
|
| 84 |
}
|
| 85 |
|
| 86 |
-
const { token } = await res.json();
|
| 87 |
const exp = this._decodeExp(token);
|
| 88 |
-
localStorage.setItem(this.storageKey, JSON.stringify({ token, exp }));
|
| 89 |
this._token = token;
|
|
|
|
|
|
|
| 90 |
return token;
|
| 91 |
}
|
| 92 |
|
|
@@ -167,6 +173,25 @@ class GSSClient {
|
|
| 167 |
this._token = null;
|
| 168 |
return this._lease();
|
| 169 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
}
|
| 171 |
|
| 172 |
// Support both browser global and CommonJS/ESM
|
|
|
|
| 43 |
this.model = opts.model || 'llama-3.1-8b-instant';
|
| 44 |
this.storageKey = opts.storageKey || 'gss_jwt';
|
| 45 |
this._token = null;
|
| 46 |
+
// Start keep-alive sync (only in browser context)
|
| 47 |
+
if (typeof window !== 'undefined') this._startKeepAlive();
|
| 48 |
}
|
| 49 |
|
| 50 |
// ββ JWT management ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 54 |
try {
|
| 55 |
const raw = localStorage.getItem(this.storageKey);
|
| 56 |
if (!raw) return null;
|
| 57 |
+
const { token, exp, hf_space } = JSON.parse(raw);
|
| 58 |
+
if (Date.now() / 1000 < exp - 300) {
|
| 59 |
+
if (hf_space) this.hfEngineUrl = hf_space.replace(/\/$/, '');
|
| 60 |
+
return token;
|
| 61 |
+
}
|
| 62 |
localStorage.removeItem(this.storageKey);
|
| 63 |
} catch { /* ignore */ }
|
| 64 |
return null;
|
|
|
|
| 87 |
throw new Error(`[GSSClient] Lease failed: ${res.status}`);
|
| 88 |
}
|
| 89 |
|
| 90 |
+
const { token, hf_space } = await res.json();
|
| 91 |
const exp = this._decodeExp(token);
|
| 92 |
+
localStorage.setItem(this.storageKey, JSON.stringify({ token, exp, hf_space }));
|
| 93 |
this._token = token;
|
| 94 |
+
// Switch to the assigned HF Space for load balancing
|
| 95 |
+
if (hf_space) this.hfEngineUrl = hf_space.replace(/\/$/, '');
|
| 96 |
return token;
|
| 97 |
}
|
| 98 |
|
|
|
|
| 173 |
this._token = null;
|
| 174 |
return this._lease();
|
| 175 |
}
|
| 176 |
+
|
| 177 |
+
// ββ Keep-alive sync ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 178 |
+
/** Signal Cloudflare to push this subscriber's keys to HF Space.
|
| 179 |
+
* Called automatically every 30 minutes to keep the key pool warm. */
|
| 180 |
+
async _syncKeys() {
|
| 181 |
+
try {
|
| 182 |
+
const token = await this._getToken();
|
| 183 |
+
await fetch(`${this.cfWorkerUrl}/auth/keep-alive`, {
|
| 184 |
+
method: 'POST',
|
| 185 |
+
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
|
| 186 |
+
});
|
| 187 |
+
} catch (_) { /* silent β non-critical */ }
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
_startKeepAlive() {
|
| 191 |
+
// Fire once 5s after page load, then every 30 minutes
|
| 192 |
+
setTimeout(() => this._syncKeys(), 5000);
|
| 193 |
+
setInterval(() => this._syncKeys(), 30 * 60 * 1000);
|
| 194 |
+
}
|
| 195 |
}
|
| 196 |
|
| 197 |
// Support both browser global and CommonJS/ESM
|
sdk/demo.html
CHANGED
|
@@ -155,7 +155,7 @@
|
|
| 155 |
<div class="config">
|
| 156 |
<div>
|
| 157 |
<label>GSS API Key</label>
|
| 158 |
-
<input id="apiKey" type="text" placeholder="gss_..." value="
|
| 159 |
</div>
|
| 160 |
<div class="row2">
|
| 161 |
<div>
|
|
|
|
| 155 |
<div class="config">
|
| 156 |
<div>
|
| 157 |
<label>GSS API Key</label>
|
| 158 |
+
<input id="apiKey" type="text" placeholder="gss_..." value="gss_ZsXcS4qQigXT3DUgOZyKfs0zp1AB5i9T" />
|
| 159 |
</div>
|
| 160 |
<div class="row2">
|
| 161 |
<div>
|
sdk/gss-sdk.js
CHANGED
|
@@ -54,9 +54,11 @@ class GSSClient {
|
|
| 54 |
try {
|
| 55 |
const raw = localStorage.getItem(this.storageKey);
|
| 56 |
if (!raw) return null;
|
| 57 |
-
const { token, exp } = JSON.parse(raw);
|
| 58 |
-
|
| 59 |
-
|
|
|
|
|
|
|
| 60 |
localStorage.removeItem(this.storageKey);
|
| 61 |
} catch { /* ignore */ }
|
| 62 |
return null;
|
|
@@ -85,10 +87,12 @@ class GSSClient {
|
|
| 85 |
throw new Error(`[GSSClient] Lease failed: ${res.status}`);
|
| 86 |
}
|
| 87 |
|
| 88 |
-
const { token } = await res.json();
|
| 89 |
const exp = this._decodeExp(token);
|
| 90 |
-
localStorage.setItem(this.storageKey, JSON.stringify({ token, exp }));
|
| 91 |
this._token = token;
|
|
|
|
|
|
|
| 92 |
return token;
|
| 93 |
}
|
| 94 |
|
|
|
|
| 54 |
try {
|
| 55 |
const raw = localStorage.getItem(this.storageKey);
|
| 56 |
if (!raw) return null;
|
| 57 |
+
const { token, exp, hf_space } = JSON.parse(raw);
|
| 58 |
+
if (Date.now() / 1000 < exp - 300) {
|
| 59 |
+
if (hf_space) this.hfEngineUrl = hf_space.replace(/\/$/, '');
|
| 60 |
+
return token;
|
| 61 |
+
}
|
| 62 |
localStorage.removeItem(this.storageKey);
|
| 63 |
} catch { /* ignore */ }
|
| 64 |
return null;
|
|
|
|
| 87 |
throw new Error(`[GSSClient] Lease failed: ${res.status}`);
|
| 88 |
}
|
| 89 |
|
| 90 |
+
const { token, hf_space } = await res.json();
|
| 91 |
const exp = this._decodeExp(token);
|
| 92 |
+
localStorage.setItem(this.storageKey, JSON.stringify({ token, exp, hf_space }));
|
| 93 |
this._token = token;
|
| 94 |
+
// Switch to the assigned HF Space for load balancing
|
| 95 |
+
if (hf_space) this.hfEngineUrl = hf_space.replace(/\/$/, '');
|
| 96 |
return token;
|
| 97 |
}
|
| 98 |
|