opencode-pollinations-plugin 5.6.0-beta.1 → 5.6.0-beta.13
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/debug_check.js +36 -0
- package/dist/index.js +5 -1
- package/dist/server/commands.d.ts +6 -0
- package/dist/server/commands.js +77 -1
- package/dist/server/generate-config.js +5 -5
- package/dist/server/index.js +35 -8
- package/dist/server/quota.js +5 -6
- package/dist/test-require.js +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as https from 'https';
|
|
2
|
+
|
|
3
|
+
function checkEndpoint(ep, key) {
|
|
4
|
+
return new Promise((resolve) => {
|
|
5
|
+
console.log(`Checking ${ep}...`);
|
|
6
|
+
const req = https.request({
|
|
7
|
+
hostname: 'gen.pollinations.ai',
|
|
8
|
+
path: ep,
|
|
9
|
+
method: 'GET',
|
|
10
|
+
headers: { 'Authorization': `Bearer ${key}` }
|
|
11
|
+
}, (res) => {
|
|
12
|
+
console.log(`Status Code: ${res.statusCode}`);
|
|
13
|
+
let data = '';
|
|
14
|
+
res.on('data', chunk => data += chunk);
|
|
15
|
+
res.on('end', () => {
|
|
16
|
+
console.log(`Headers:`, res.headers);
|
|
17
|
+
console.log(`Body Full: ${data}`);
|
|
18
|
+
if (res.statusCode === 200) resolve({ ok: true, body: data });
|
|
19
|
+
else resolve({ ok: false, status: res.statusCode, body: data });
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
req.on('error', (e) => {
|
|
23
|
+
console.log(`Error: ${e.message}`);
|
|
24
|
+
resolve({ ok: false, status: e.message || 'Error' });
|
|
25
|
+
});
|
|
26
|
+
req.setTimeout(10000, () => req.destroy());
|
|
27
|
+
req.end();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const KEY = "plln_sk_F7a4RcBG4AVCeBSo6lnS36EKwm0nPn1O";
|
|
32
|
+
|
|
33
|
+
(async () => {
|
|
34
|
+
const res = await checkEndpoint('/account/profile', KEY);
|
|
35
|
+
console.log('Result:', res);
|
|
36
|
+
})();
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import { handleChatCompletion } from './server/proxy.js';
|
|
|
6
6
|
import { createToastHooks, setGlobalClient } from './server/toast.js';
|
|
7
7
|
import { createStatusHooks } from './server/status.js';
|
|
8
8
|
import { createCommandHooks } from './server/commands.js';
|
|
9
|
+
import { createRequire } from 'module';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
9
11
|
const LOG_FILE = '/tmp/opencode_pollinations_v4.log';
|
|
10
12
|
function log(msg) {
|
|
11
13
|
try {
|
|
@@ -94,9 +96,11 @@ export const PollinationsPlugin = async (ctx) => {
|
|
|
94
96
|
}
|
|
95
97
|
if (!config.provider)
|
|
96
98
|
config.provider = {};
|
|
99
|
+
// Dynamic Provider Name
|
|
100
|
+
const version = require('../package.json').version;
|
|
97
101
|
config.provider['pollinations'] = {
|
|
98
102
|
id: 'pollinations',
|
|
99
|
-
name:
|
|
103
|
+
name: `Pollinations AI (v${version})`,
|
|
100
104
|
options: { baseURL: localBaseUrl },
|
|
101
105
|
models: modelsObj
|
|
102
106
|
};
|
package/dist/server/commands.js
CHANGED
|
@@ -1,8 +1,60 @@
|
|
|
1
|
+
import * as https from 'https';
|
|
1
2
|
import { loadConfig, saveConfig } from './config.js';
|
|
2
3
|
import { getQuotaStatus } from './quota.js';
|
|
3
4
|
import { emitStatusToast } from './toast.js';
|
|
4
5
|
import { getDetailedUsage } from './pollinations-api.js';
|
|
5
6
|
import { generatePollinationsConfig } from './generate-config.js';
|
|
7
|
+
function checkEndpoint(ep, key) {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
const req = https.request({
|
|
10
|
+
hostname: 'gen.pollinations.ai',
|
|
11
|
+
path: ep,
|
|
12
|
+
method: 'GET',
|
|
13
|
+
headers: {
|
|
14
|
+
'Authorization': `Bearer ${key}`,
|
|
15
|
+
'User-Agent': 'Pollinations-Plugin/5.6.0' // Identify cleanly
|
|
16
|
+
}
|
|
17
|
+
}, (res) => {
|
|
18
|
+
const isJson = res.headers['content-type']?.includes('application/json');
|
|
19
|
+
let data = '';
|
|
20
|
+
res.on('data', chunk => data += chunk);
|
|
21
|
+
res.on('end', () => {
|
|
22
|
+
if (res.statusCode === 200 && isJson) {
|
|
23
|
+
// Double Check Check Body for Logical Errors masked as 200
|
|
24
|
+
try {
|
|
25
|
+
const json = JSON.parse(data);
|
|
26
|
+
if (json.error || json.success === false) {
|
|
27
|
+
resolve({ ok: false, reason: "API Logical Error", status: 200 });
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
resolve({ ok: true });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
resolve({ ok: false, reason: "Invalid JSON", status: 200 });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
resolve({ ok: false, status: res.statusCode, reason: isJson ? "API Error" : "Not JSON (Cloudflare?)" });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
req.on('error', (e) => resolve({ ok: false, status: e.message || 'Error' }));
|
|
43
|
+
req.setTimeout(10000, () => req.destroy()); // 10s Timeout
|
|
44
|
+
req.end();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export async function checkKeyPermissions(key) {
|
|
48
|
+
// SEQUENTIAL CHECK (Avoid Rate Limits on Key Verification)
|
|
49
|
+
const endpoints = ['/account/profile', '/account/balance', '/account/usage'];
|
|
50
|
+
for (const ep of endpoints) {
|
|
51
|
+
const res = await checkEndpoint(ep, key);
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
return { ok: false, reason: `${ep} (${res.status})` };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { ok: true };
|
|
57
|
+
}
|
|
6
58
|
// === CONSTANTS & PRICING ===
|
|
7
59
|
const TIER_LIMITS = {
|
|
8
60
|
spore: { pollen: 1, emoji: '🦠' },
|
|
@@ -230,10 +282,34 @@ async function handleConnectCommand(args) {
|
|
|
230
282
|
const masked = key.substring(0, 6) + '...';
|
|
231
283
|
// Count Paid Only models found
|
|
232
284
|
const diamondCount = enterpriseModels.filter(m => m.name.includes('💎')).length;
|
|
285
|
+
// CHECK RESTRICTIONS: Strict Check (Usage + Profile + Balance)
|
|
286
|
+
let forcedModeMsg = "";
|
|
287
|
+
let isLimited = false;
|
|
288
|
+
let limitReason = "";
|
|
289
|
+
try {
|
|
290
|
+
// Strict Probe: Must be able to read ALL accounting data
|
|
291
|
+
const check = await checkKeyPermissions(key);
|
|
292
|
+
if (!check.ok) {
|
|
293
|
+
isLimited = true;
|
|
294
|
+
limitReason = check.reason || "Unknown";
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (e) {
|
|
298
|
+
isLimited = true;
|
|
299
|
+
limitReason = e.message;
|
|
300
|
+
}
|
|
301
|
+
// If Limited -> FORCE MANUAL
|
|
302
|
+
if (isLimited) {
|
|
303
|
+
saveConfig({ apiKey: key, mode: 'manual', keyHasAccessToProfile: false });
|
|
304
|
+
forcedModeMsg = `\n⚠️ **Clé Limitée** (Echec: ${limitReason}) -> Mode **MANUEL** forcé.\n*Requis pour mode Auto: Profile, Balance & Usage.*`;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
saveConfig({ apiKey: key, keyHasAccessToProfile: true }); // Let user keep current mode or default
|
|
308
|
+
}
|
|
233
309
|
emitStatusToast('success', `Clé Valide! (${enterpriseModels.length} modèles Pro débloqués)`, 'Pollinations Config');
|
|
234
310
|
return {
|
|
235
311
|
handled: true,
|
|
236
|
-
response: `✅ **Connexion Réussie!**\n- Clé: \`${masked}\`\n-
|
|
312
|
+
response: `✅ **Connexion Réussie!**\n- Clé: \`${masked}\`\n- Modèles Débloqués: ${enterpriseModels.length} (dont ${diamondCount} 💎 Paid)${forcedModeMsg}`
|
|
237
313
|
};
|
|
238
314
|
}
|
|
239
315
|
else {
|
|
@@ -85,11 +85,11 @@ export async function generatePollinationsConfig(forceApiKey, forceStrict = fals
|
|
|
85
85
|
log(`[ConfigGen] Force-injecting free/gemini.`);
|
|
86
86
|
modelsOutput.push({ id: "free/gemini", name: "[Free] Gemini Flash (Force)", object: "model", variants: {} });
|
|
87
87
|
}
|
|
88
|
-
// ALIAS for
|
|
89
|
-
const hasGeminiAlias = modelsOutput.find(m => m.id === 'pollinations/free/gemini');
|
|
90
|
-
if (!hasGeminiAlias) {
|
|
91
|
-
|
|
92
|
-
}
|
|
88
|
+
// ALIAS Removed for Clean Config
|
|
89
|
+
// const hasGeminiAlias = modelsOutput.find(m => m.id === 'pollinations/free/gemini');
|
|
90
|
+
// if (!hasGeminiAlias) {
|
|
91
|
+
// modelsOutput.push({ id: "pollinations/free/gemini", name: "[Free] Gemini Flash (Alias)", object: "model", variants: {} });
|
|
92
|
+
// }
|
|
93
93
|
// 2. ENTERPRISE UNIVERSE
|
|
94
94
|
if (effectiveKey && effectiveKey.length > 5 && effectiveKey !== 'dummy') {
|
|
95
95
|
try {
|
package/dist/server/index.js
CHANGED
|
@@ -145,12 +145,39 @@ process.on('exit', (code) => {
|
|
|
145
145
|
}
|
|
146
146
|
catch (e) { }
|
|
147
147
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
// STARTUP CHECK: Re-validate Key (in case of upgrade/config drift)
|
|
149
|
+
import { checkKeyPermissions } from './commands.js';
|
|
150
|
+
(async () => {
|
|
151
|
+
const config = loadConfig();
|
|
152
|
+
if (config.apiKey) {
|
|
153
|
+
try {
|
|
154
|
+
console.log('Pollinations Plugin: Verifying API Key on startup...');
|
|
155
|
+
const check = await checkKeyPermissions(config.apiKey);
|
|
156
|
+
if (!check.ok) {
|
|
157
|
+
console.warn(`Pollinations Plugin: Limited Key Detected on Startup (${check.reason}). Enforcing Manual Mode.`);
|
|
158
|
+
saveConfig({
|
|
159
|
+
apiKey: config.apiKey,
|
|
160
|
+
mode: 'manual',
|
|
161
|
+
keyHasAccessToProfile: false
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
if (config.keyHasAccessToProfile === false) {
|
|
166
|
+
saveConfig({ apiKey: config.apiKey, keyHasAccessToProfile: true });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
console.error('Pollinations Plugin: Startup Check Failed:', e);
|
|
172
|
+
}
|
|
153
173
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
});
|
|
174
|
+
server.listen(PORT, '127.0.0.1', () => {
|
|
175
|
+
const url = `http://127.0.0.1:${PORT}`;
|
|
176
|
+
log(`[SERVER] Started V3 Phase 3 (Auth Enabled) on port ${PORT}`);
|
|
177
|
+
try {
|
|
178
|
+
fs.appendFileSync(LIFE_LOG, `[${new Date().toISOString()}] [LISTEN] PID:${process.pid} Listening on ${PORT}\n`);
|
|
179
|
+
}
|
|
180
|
+
catch (e) { }
|
|
181
|
+
console.log(`POLLINATIONS_V3_URL=${url}`);
|
|
182
|
+
});
|
|
183
|
+
})();
|
package/dist/server/quota.js
CHANGED
|
@@ -44,12 +44,11 @@ export async function getQuotaStatus(forceRefresh = false) {
|
|
|
44
44
|
}
|
|
45
45
|
try {
|
|
46
46
|
logQuota("Fetching Quota Data...");
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
]);
|
|
47
|
+
// SEQUENTIAL FETCH (Avoid Rate Limits)
|
|
48
|
+
// We fetch one by one. If one fails, we catch and return fallback.
|
|
49
|
+
const profileRes = await fetchAPI('/account/profile', config.apiKey);
|
|
50
|
+
const balanceRes = await fetchAPI('/account/balance', config.apiKey);
|
|
51
|
+
const usageRes = await fetchAPI('/account/usage', config.apiKey);
|
|
53
52
|
logQuota(`Fetch Success. Tier: ${profileRes.tier}, Balance: ${balanceRes.balance}`);
|
|
54
53
|
const profile = profileRes;
|
|
55
54
|
const balance = balanceRes.balance;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
try {
|
|
4
|
+
const pkg = require('../package.json');
|
|
5
|
+
console.log("SUCCESS: Loaded version " + pkg.version);
|
|
6
|
+
} catch (e) {
|
|
7
|
+
console.error("FAILURE:", e.message);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-pollinations-plugin",
|
|
3
3
|
"displayName": "Pollinations AI (V5.1)",
|
|
4
|
-
"version": "5.6.0-beta.
|
|
4
|
+
"version": "5.6.0-beta.13",
|
|
5
5
|
"description": "Native Pollinations.ai Provider Plugin for OpenCode",
|
|
6
6
|
"publisher": "pollinations",
|
|
7
7
|
"repository": {
|