@moguiyu/dsh-tavily 0.1.3 → 0.1.5
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/lib/client.js +88 -74
- package/package.json +1 -1
- package/src/client.js +88 -74
- package/src/index.js +1 -1
package/lib/client.js
CHANGED
|
@@ -144,10 +144,6 @@ window.__ModuleLoader__.load({
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
const hasPending = Object.values(removing).some(Boolean)
|
|
148
|
-
|| Object.values(replacing).some(Boolean)
|
|
149
|
-
|| adds.some((item) => item.value.trim().length > 0)
|
|
150
|
-
|
|
151
147
|
const saveStrategy = async (next) => {
|
|
152
148
|
setBusy(true)
|
|
153
149
|
setNotice(null)
|
|
@@ -168,29 +164,69 @@ window.__ModuleLoader__.load({
|
|
|
168
164
|
}
|
|
169
165
|
}
|
|
170
166
|
|
|
171
|
-
const
|
|
167
|
+
const saveAdd = async (item) => {
|
|
168
|
+
const value = item.value.trim()
|
|
169
|
+
if (!value) return
|
|
172
170
|
setBusy(true)
|
|
173
171
|
setNotice(null)
|
|
174
172
|
try {
|
|
175
|
-
const addValues = adds.map((item) => item.value.trim()).filter((value) => value.length > 0)
|
|
176
|
-
const removeMasked = [
|
|
177
|
-
...Object.keys(removing).filter((masked) => removing[masked] === true),
|
|
178
|
-
...Object.keys(replacing).filter((masked) => replacing[masked] === true)
|
|
179
|
-
]
|
|
180
173
|
const response = await fetch('/api/tavily-manager', {
|
|
181
174
|
method: 'POST',
|
|
182
175
|
headers: { 'content-type': 'application/json' },
|
|
183
|
-
body: JSON.stringify({ add:
|
|
176
|
+
body: JSON.stringify({ add: [value], remove: [], strategy })
|
|
184
177
|
})
|
|
185
178
|
const data = await response.json()
|
|
186
179
|
if (!data.ok) { setNotice({ error: data.error || 'Save failed' }); return }
|
|
187
|
-
setNotice({ ok: '
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
180
|
+
setNotice({ ok: 'Key saved.' })
|
|
181
|
+
setAdds((current) => current.filter((entry) => entry.id !== item.id))
|
|
182
|
+
await refresh()
|
|
183
|
+
} catch (error) {
|
|
184
|
+
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
185
|
+
} finally {
|
|
186
|
+
setBusy(false)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const saveRemove = async (masked) => {
|
|
191
|
+
setBusy(true)
|
|
192
|
+
setNotice(null)
|
|
193
|
+
try {
|
|
194
|
+
const response = await fetch('/api/tavily-manager', {
|
|
195
|
+
method: 'POST',
|
|
196
|
+
headers: { 'content-type': 'application/json' },
|
|
197
|
+
body: JSON.stringify({ add: [], remove: [masked], strategy })
|
|
198
|
+
})
|
|
199
|
+
const data = await response.json()
|
|
200
|
+
if (!data.ok) { setNotice({ error: data.error || 'Delete failed' }); return }
|
|
201
|
+
setNotice({ ok: 'Key removed.' })
|
|
202
|
+
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
203
|
+
setRemoving((current) => Object.assign({}, current, { [masked]: false }))
|
|
204
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
205
|
+
await refresh()
|
|
206
|
+
} catch (error) {
|
|
207
|
+
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
208
|
+
} finally {
|
|
209
|
+
setBusy(false)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const saveReplace = async (masked) => {
|
|
214
|
+
const value = typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim() : ''
|
|
215
|
+
if (!value) return
|
|
216
|
+
setBusy(true)
|
|
217
|
+
setNotice(null)
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetch('/api/tavily-manager', {
|
|
220
|
+
method: 'POST',
|
|
221
|
+
headers: { 'content-type': 'application/json' },
|
|
222
|
+
body: JSON.stringify({ add: [value], remove: [masked], strategy })
|
|
223
|
+
})
|
|
224
|
+
const data = await response.json()
|
|
225
|
+
if (!data.ok) { setNotice({ error: data.error || 'Update failed' }); return }
|
|
226
|
+
setNotice({ ok: 'Key updated.' })
|
|
227
|
+
setReplacing((current) => Object.assign({}, current, { [masked]: false }))
|
|
228
|
+
setReplaceDrafts((current) => Object.assign({}, current, { [masked]: '' }))
|
|
229
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
194
230
|
await refresh()
|
|
195
231
|
} catch (error) {
|
|
196
232
|
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
@@ -226,6 +262,7 @@ window.__ModuleLoader__.load({
|
|
|
226
262
|
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
227
263
|
setRemoving((current) => Object.assign({}, current, { [masked]: true }))
|
|
228
264
|
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
265
|
+
saveRemove(masked)
|
|
229
266
|
}
|
|
230
267
|
|
|
231
268
|
const restore = (masked) => {
|
|
@@ -291,16 +328,21 @@ window.__ModuleLoader__.load({
|
|
|
291
328
|
react.createElement('thead', null,
|
|
292
329
|
react.createElement('tr', null,
|
|
293
330
|
react.createElement('th', { style: headStyle }, 'Key'),
|
|
331
|
+
react.createElement('th', { style: headStyle }, 'Usage'),
|
|
294
332
|
react.createElement('th', { style: headStyle }, 'Saved'),
|
|
295
333
|
react.createElement('th', { style: headStyle }, 'Actions')
|
|
296
334
|
)
|
|
297
335
|
),
|
|
298
336
|
react.createElement('tbody', null,
|
|
299
|
-
(server !== null ? server.keys : []).map((key) => {
|
|
337
|
+
(server !== null ? server.keys : []).map((key, index) => {
|
|
300
338
|
const masked = key.masked
|
|
301
339
|
const isRemoved = removing[masked] === true
|
|
302
340
|
const isReplacing = replacing[masked] === true
|
|
303
341
|
const isRevealed = typeof revealed[masked] === 'string'
|
|
342
|
+
const usageRow = usage !== null && usage.ok === true ? usage.perKey[index] : null
|
|
343
|
+
const pct = usageRow && usageRow.ok && usageRow.planLimit != null && usageRow.planLimit > 0 && usageRow.planUsage != null
|
|
344
|
+
? Math.min(100, Math.round((usageRow.planUsage / usageRow.planLimit) * 100))
|
|
345
|
+
: null
|
|
304
346
|
return react.createElement('tr', { key: masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)', opacity: isRemoved ? 0.45 : 1 } },
|
|
305
347
|
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) },
|
|
306
348
|
isReplacing
|
|
@@ -319,11 +361,14 @@ window.__ModuleLoader__.load({
|
|
|
319
361
|
})
|
|
320
362
|
)
|
|
321
363
|
),
|
|
364
|
+
react.createElement('td', { style: cellStyle },
|
|
365
|
+
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (usageRow && usageRow.ok && usageRow.planUsage != null ? String(usageRow.planUsage) : '—') })
|
|
366
|
+
),
|
|
322
367
|
react.createElement('td', { style: Object.assign({}, cellStyle, { color: 'var(--dsw-alias-label-tertiary)', whiteSpace: 'nowrap' }) }, formatDate(key.savedAt)),
|
|
323
368
|
react.createElement('td', { style: cellStyle },
|
|
324
369
|
isReplacing
|
|
325
370
|
? react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
326
|
-
react.createElement(IconButton, { icon: 'check', title: '
|
|
371
|
+
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveReplace(masked), disabled: busy || (typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim().length === 0 : true) }),
|
|
327
372
|
react.createElement(IconButton, { icon: 'close', title: 'Cancel', onClick: () => cancelReplace(masked), disabled: busy })
|
|
328
373
|
)
|
|
329
374
|
: react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
@@ -348,73 +393,42 @@ window.__ModuleLoader__.load({
|
|
|
348
393
|
placeholder: 'New key value',
|
|
349
394
|
value: item.value,
|
|
350
395
|
onChange: (event) => setAdds((current) => current.map((entry) => entry.id === item.id ? Object.assign({}, entry, { value: event.target.value }) : entry)),
|
|
396
|
+
onKeyDown: (event) => { if (event.key === 'Enter') saveAdd(item) },
|
|
351
397
|
disabled: busy
|
|
352
398
|
})
|
|
353
399
|
),
|
|
354
400
|
react.createElement('td', { style: cellStyle }, '—'),
|
|
401
|
+
react.createElement('td', { style: cellStyle }, '—'),
|
|
355
402
|
react.createElement('td', { style: cellStyle },
|
|
356
|
-
react.createElement(
|
|
403
|
+
react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
404
|
+
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveAdd(item), disabled: busy || item.value.trim().length === 0 }),
|
|
405
|
+
react.createElement(IconButton, { icon: 'trash', title: 'Remove', danger: true, onClick: () => setAdds((current) => current.filter((entry) => entry.id !== item.id)), disabled: busy })
|
|
406
|
+
)
|
|
357
407
|
)
|
|
358
408
|
))
|
|
359
409
|
)
|
|
360
410
|
),
|
|
361
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
362
|
-
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key')
|
|
363
|
-
|
|
364
|
-
react.createElement('div', { style: { border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 12, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
365
|
-
react.createElement('label', { style: { fontWeight: 500, fontSize: 13 } }, 'Key usage strategy'),
|
|
366
|
-
react.createElement('select', {
|
|
367
|
-
style: { maxWidth: 280, height: 32, border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)', padding: '0 10px', fontSize: 13 },
|
|
368
|
-
value: strategy,
|
|
369
|
-
onChange: (event) => saveStrategy(event.target.value),
|
|
370
|
-
disabled: busy
|
|
371
|
-
}, STRATEGIES.map((option) => react.createElement('option', { key: option.id, value: option.id }, option.label))),
|
|
372
|
-
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)' } },
|
|
373
|
-
(STRATEGIES.find((option) => option.id === strategy) || STRATEGIES[0]).hint + ' The strategy is saved immediately when you select it; the first key then becomes primary for web_search.'
|
|
374
|
-
)
|
|
375
|
-
),
|
|
376
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
377
|
-
react.createElement('button', { type: 'button', style: Object.assign({}, btn, { height: 32, background: 'var(--dsw-alias-button-primary-fill)', color: 'var(--dsw-alias-label-primary-foreground)' }), onClick: save, disabled: busy || !hasPending }, 'Save key changes'),
|
|
378
|
-
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
411
|
+
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' } },
|
|
412
|
+
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key'),
|
|
413
|
+
react.createElement('button', { type: 'button', style: btn, onClick: refresh, disabled: busy }, 'Refresh usage')
|
|
379
414
|
),
|
|
380
|
-
react.createElement('div', { style: {
|
|
381
|
-
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8,
|
|
382
|
-
react.createElement('
|
|
383
|
-
react.createElement('
|
|
415
|
+
react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 6 } },
|
|
416
|
+
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
|
|
417
|
+
react.createElement('label', { style: { fontWeight: 500, fontSize: 13 } }, 'Key usage strategy'),
|
|
418
|
+
react.createElement('select', {
|
|
419
|
+
style: { maxWidth: 280, height: 32, border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)', padding: '0 10px', fontSize: 13 },
|
|
420
|
+
value: strategy,
|
|
421
|
+
onChange: (event) => saveStrategy(event.target.value),
|
|
422
|
+
disabled: busy
|
|
423
|
+
}, STRATEGIES.map((option) => react.createElement('option', { key: option.id, value: option.id }, option.label))),
|
|
424
|
+
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
384
425
|
),
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
usage !== null && usage.ok === true && react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
388
|
-
react.createElement('div', { style: { fontSize: 13 } },
|
|
389
|
-
usage.totals.keys + ' key(s) (' + usage.totals.okKeys + ' readable)' + (usage.totals.planLimit !== null ? ' · plan usage ' + usage.totals.planUsage + ' / ' + usage.totals.planLimit : '')
|
|
390
|
-
),
|
|
391
|
-
react.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13 } },
|
|
392
|
-
react.createElement('thead', null,
|
|
393
|
-
react.createElement('tr', null,
|
|
394
|
-
react.createElement('th', { style: headStyle }, 'API Key'),
|
|
395
|
-
react.createElement('th', { style: headStyle }, 'Usage')
|
|
396
|
-
)
|
|
397
|
-
),
|
|
398
|
-
react.createElement('tbody', null,
|
|
399
|
-
(server !== null ? server.keys : []).map((key, index) => {
|
|
400
|
-
const row = usage.perKey[index]
|
|
401
|
-
const pct = row && row.ok && row.planLimit != null && row.planLimit > 0 && row.planUsage != null
|
|
402
|
-
? Math.min(100, Math.round((row.planUsage / row.planLimit) * 100))
|
|
403
|
-
: null
|
|
404
|
-
return react.createElement('tr', { key: key.masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)' } },
|
|
405
|
-
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) }, key.masked),
|
|
406
|
-
react.createElement('td', { style: cellStyle },
|
|
407
|
-
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (row && row.ok && row.planUsage != null ? String(row.planUsage) : '—') })
|
|
408
|
-
)
|
|
409
|
-
)
|
|
410
|
-
})
|
|
411
|
-
)
|
|
412
|
-
)
|
|
426
|
+
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)' } },
|
|
427
|
+
(STRATEGIES.find((option) => option.id === strategy) || STRATEGIES[0]).hint + ' Saved immediately when selected; the first key then becomes primary for web_search.'
|
|
413
428
|
)
|
|
414
429
|
),
|
|
415
|
-
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-
|
|
416
|
-
|
|
417
|
-
)
|
|
430
|
+
usageError !== null && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usageError)),
|
|
431
|
+
usage !== null && usage.ok === false && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usage.error))
|
|
418
432
|
)
|
|
419
433
|
)
|
|
420
434
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moguiyu/dsh-tavily",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Tavily Search for DSH: multiple API keys, rotation/failover, usage gauge, settings card, and web_search toggle in one plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
package/src/client.js
CHANGED
|
@@ -149,10 +149,6 @@ export function factory(require) {
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
const hasPending = Object.values(removing).some(Boolean)
|
|
153
|
-
|| Object.values(replacing).some(Boolean)
|
|
154
|
-
|| adds.some((item) => item.value.trim().length > 0)
|
|
155
|
-
|
|
156
152
|
const saveStrategy = async (next) => {
|
|
157
153
|
setBusy(true)
|
|
158
154
|
setNotice(null)
|
|
@@ -173,29 +169,69 @@ export function factory(require) {
|
|
|
173
169
|
}
|
|
174
170
|
}
|
|
175
171
|
|
|
176
|
-
const
|
|
172
|
+
const saveAdd = async (item) => {
|
|
173
|
+
const value = item.value.trim()
|
|
174
|
+
if (!value) return
|
|
177
175
|
setBusy(true)
|
|
178
176
|
setNotice(null)
|
|
179
177
|
try {
|
|
180
|
-
const addValues = adds.map((item) => item.value.trim()).filter((value) => value.length > 0)
|
|
181
|
-
const removeMasked = [
|
|
182
|
-
...Object.keys(removing).filter((masked) => removing[masked] === true),
|
|
183
|
-
...Object.keys(replacing).filter((masked) => replacing[masked] === true)
|
|
184
|
-
]
|
|
185
178
|
const response = await fetch('/api/tavily-manager', {
|
|
186
179
|
method: 'POST',
|
|
187
180
|
headers: { 'content-type': 'application/json' },
|
|
188
|
-
body: JSON.stringify({ add:
|
|
181
|
+
body: JSON.stringify({ add: [value], remove: [], strategy })
|
|
189
182
|
})
|
|
190
183
|
const data = await response.json()
|
|
191
184
|
if (!data.ok) { setNotice({ error: data.error || 'Save failed' }); return }
|
|
192
|
-
setNotice({ ok: '
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
185
|
+
setNotice({ ok: 'Key saved.' })
|
|
186
|
+
setAdds((current) => current.filter((entry) => entry.id !== item.id))
|
|
187
|
+
await refresh()
|
|
188
|
+
} catch (error) {
|
|
189
|
+
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
190
|
+
} finally {
|
|
191
|
+
setBusy(false)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const saveRemove = async (masked) => {
|
|
196
|
+
setBusy(true)
|
|
197
|
+
setNotice(null)
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch('/api/tavily-manager', {
|
|
200
|
+
method: 'POST',
|
|
201
|
+
headers: { 'content-type': 'application/json' },
|
|
202
|
+
body: JSON.stringify({ add: [], remove: [masked], strategy })
|
|
203
|
+
})
|
|
204
|
+
const data = await response.json()
|
|
205
|
+
if (!data.ok) { setNotice({ error: data.error || 'Delete failed' }); return }
|
|
206
|
+
setNotice({ ok: 'Key removed.' })
|
|
207
|
+
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
208
|
+
setRemoving((current) => Object.assign({}, current, { [masked]: false }))
|
|
209
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
210
|
+
await refresh()
|
|
211
|
+
} catch (error) {
|
|
212
|
+
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
213
|
+
} finally {
|
|
214
|
+
setBusy(false)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const saveReplace = async (masked) => {
|
|
219
|
+
const value = typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim() : ''
|
|
220
|
+
if (!value) return
|
|
221
|
+
setBusy(true)
|
|
222
|
+
setNotice(null)
|
|
223
|
+
try {
|
|
224
|
+
const response = await fetch('/api/tavily-manager', {
|
|
225
|
+
method: 'POST',
|
|
226
|
+
headers: { 'content-type': 'application/json' },
|
|
227
|
+
body: JSON.stringify({ add: [value], remove: [masked], strategy })
|
|
228
|
+
})
|
|
229
|
+
const data = await response.json()
|
|
230
|
+
if (!data.ok) { setNotice({ error: data.error || 'Update failed' }); return }
|
|
231
|
+
setNotice({ ok: 'Key updated.' })
|
|
232
|
+
setReplacing((current) => Object.assign({}, current, { [masked]: false }))
|
|
233
|
+
setReplaceDrafts((current) => Object.assign({}, current, { [masked]: '' }))
|
|
234
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
199
235
|
await refresh()
|
|
200
236
|
} catch (error) {
|
|
201
237
|
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
@@ -231,6 +267,7 @@ export function factory(require) {
|
|
|
231
267
|
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
232
268
|
setRemoving((current) => Object.assign({}, current, { [masked]: true }))
|
|
233
269
|
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
270
|
+
saveRemove(masked)
|
|
234
271
|
}
|
|
235
272
|
|
|
236
273
|
const restore = (masked) => {
|
|
@@ -296,16 +333,21 @@ export function factory(require) {
|
|
|
296
333
|
react.createElement('thead', null,
|
|
297
334
|
react.createElement('tr', null,
|
|
298
335
|
react.createElement('th', { style: headStyle }, 'Key'),
|
|
336
|
+
react.createElement('th', { style: headStyle }, 'Usage'),
|
|
299
337
|
react.createElement('th', { style: headStyle }, 'Saved'),
|
|
300
338
|
react.createElement('th', { style: headStyle }, 'Actions')
|
|
301
339
|
)
|
|
302
340
|
),
|
|
303
341
|
react.createElement('tbody', null,
|
|
304
|
-
(server !== null ? server.keys : []).map((key) => {
|
|
342
|
+
(server !== null ? server.keys : []).map((key, index) => {
|
|
305
343
|
const masked = key.masked
|
|
306
344
|
const isRemoved = removing[masked] === true
|
|
307
345
|
const isReplacing = replacing[masked] === true
|
|
308
346
|
const isRevealed = typeof revealed[masked] === 'string'
|
|
347
|
+
const usageRow = usage !== null && usage.ok === true ? usage.perKey[index] : null
|
|
348
|
+
const pct = usageRow && usageRow.ok && usageRow.planLimit != null && usageRow.planLimit > 0 && usageRow.planUsage != null
|
|
349
|
+
? Math.min(100, Math.round((usageRow.planUsage / usageRow.planLimit) * 100))
|
|
350
|
+
: null
|
|
309
351
|
return react.createElement('tr', { key: masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)', opacity: isRemoved ? 0.45 : 1 } },
|
|
310
352
|
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) },
|
|
311
353
|
isReplacing
|
|
@@ -324,11 +366,14 @@ export function factory(require) {
|
|
|
324
366
|
})
|
|
325
367
|
)
|
|
326
368
|
),
|
|
369
|
+
react.createElement('td', { style: cellStyle },
|
|
370
|
+
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (usageRow && usageRow.ok && usageRow.planUsage != null ? String(usageRow.planUsage) : '—') })
|
|
371
|
+
),
|
|
327
372
|
react.createElement('td', { style: Object.assign({}, cellStyle, { color: 'var(--dsw-alias-label-tertiary)', whiteSpace: 'nowrap' }) }, formatDate(key.savedAt)),
|
|
328
373
|
react.createElement('td', { style: cellStyle },
|
|
329
374
|
isReplacing
|
|
330
375
|
? react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
331
|
-
react.createElement(IconButton, { icon: 'check', title: '
|
|
376
|
+
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveReplace(masked), disabled: busy || (typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim().length === 0 : true) }),
|
|
332
377
|
react.createElement(IconButton, { icon: 'close', title: 'Cancel', onClick: () => cancelReplace(masked), disabled: busy })
|
|
333
378
|
)
|
|
334
379
|
: react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
@@ -353,73 +398,42 @@ export function factory(require) {
|
|
|
353
398
|
placeholder: 'New key value',
|
|
354
399
|
value: item.value,
|
|
355
400
|
onChange: (event) => setAdds((current) => current.map((entry) => entry.id === item.id ? Object.assign({}, entry, { value: event.target.value }) : entry)),
|
|
401
|
+
onKeyDown: (event) => { if (event.key === 'Enter') saveAdd(item) },
|
|
356
402
|
disabled: busy
|
|
357
403
|
})
|
|
358
404
|
),
|
|
359
405
|
react.createElement('td', { style: cellStyle }, '—'),
|
|
406
|
+
react.createElement('td', { style: cellStyle }, '—'),
|
|
360
407
|
react.createElement('td', { style: cellStyle },
|
|
361
|
-
react.createElement(
|
|
408
|
+
react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
409
|
+
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveAdd(item), disabled: busy || item.value.trim().length === 0 }),
|
|
410
|
+
react.createElement(IconButton, { icon: 'trash', title: 'Remove', danger: true, onClick: () => setAdds((current) => current.filter((entry) => entry.id !== item.id)), disabled: busy })
|
|
411
|
+
)
|
|
362
412
|
)
|
|
363
413
|
))
|
|
364
414
|
)
|
|
365
415
|
),
|
|
366
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
367
|
-
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key')
|
|
368
|
-
|
|
369
|
-
react.createElement('div', { style: { border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 12, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
370
|
-
react.createElement('label', { style: { fontWeight: 500, fontSize: 13 } }, 'Key usage strategy'),
|
|
371
|
-
react.createElement('select', {
|
|
372
|
-
style: { maxWidth: 280, height: 32, border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)', padding: '0 10px', fontSize: 13 },
|
|
373
|
-
value: strategy,
|
|
374
|
-
onChange: (event) => saveStrategy(event.target.value),
|
|
375
|
-
disabled: busy
|
|
376
|
-
}, STRATEGIES.map((option) => react.createElement('option', { key: option.id, value: option.id }, option.label))),
|
|
377
|
-
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)' } },
|
|
378
|
-
(STRATEGIES.find((option) => option.id === strategy) || STRATEGIES[0]).hint + ' The strategy is saved immediately when you select it; the first key then becomes primary for web_search.'
|
|
379
|
-
)
|
|
380
|
-
),
|
|
381
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
382
|
-
react.createElement('button', { type: 'button', style: Object.assign({}, btn, { height: 32, background: 'var(--dsw-alias-button-primary-fill)', color: 'var(--dsw-alias-label-primary-foreground)' }), onClick: save, disabled: busy || !hasPending }, 'Save key changes'),
|
|
383
|
-
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
416
|
+
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' } },
|
|
417
|
+
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key'),
|
|
418
|
+
react.createElement('button', { type: 'button', style: btn, onClick: refresh, disabled: busy }, 'Refresh usage')
|
|
384
419
|
),
|
|
385
|
-
react.createElement('div', { style: {
|
|
386
|
-
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8,
|
|
387
|
-
react.createElement('
|
|
388
|
-
react.createElement('
|
|
420
|
+
react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 6 } },
|
|
421
|
+
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
|
|
422
|
+
react.createElement('label', { style: { fontWeight: 500, fontSize: 13 } }, 'Key usage strategy'),
|
|
423
|
+
react.createElement('select', {
|
|
424
|
+
style: { maxWidth: 280, height: 32, border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)', padding: '0 10px', fontSize: 13 },
|
|
425
|
+
value: strategy,
|
|
426
|
+
onChange: (event) => saveStrategy(event.target.value),
|
|
427
|
+
disabled: busy
|
|
428
|
+
}, STRATEGIES.map((option) => react.createElement('option', { key: option.id, value: option.id }, option.label))),
|
|
429
|
+
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
389
430
|
),
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
usage !== null && usage.ok === true && react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
393
|
-
react.createElement('div', { style: { fontSize: 13 } },
|
|
394
|
-
usage.totals.keys + ' key(s) (' + usage.totals.okKeys + ' readable)' + (usage.totals.planLimit !== null ? ' · plan usage ' + usage.totals.planUsage + ' / ' + usage.totals.planLimit : '')
|
|
395
|
-
),
|
|
396
|
-
react.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13 } },
|
|
397
|
-
react.createElement('thead', null,
|
|
398
|
-
react.createElement('tr', null,
|
|
399
|
-
react.createElement('th', { style: headStyle }, 'API Key'),
|
|
400
|
-
react.createElement('th', { style: headStyle }, 'Usage')
|
|
401
|
-
)
|
|
402
|
-
),
|
|
403
|
-
react.createElement('tbody', null,
|
|
404
|
-
(server !== null ? server.keys : []).map((key, index) => {
|
|
405
|
-
const row = usage.perKey[index]
|
|
406
|
-
const pct = row && row.ok && row.planLimit != null && row.planLimit > 0 && row.planUsage != null
|
|
407
|
-
? Math.min(100, Math.round((row.planUsage / row.planLimit) * 100))
|
|
408
|
-
: null
|
|
409
|
-
return react.createElement('tr', { key: key.masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)' } },
|
|
410
|
-
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) }, key.masked),
|
|
411
|
-
react.createElement('td', { style: cellStyle },
|
|
412
|
-
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (row && row.ok && row.planUsage != null ? String(row.planUsage) : '—') })
|
|
413
|
-
)
|
|
414
|
-
)
|
|
415
|
-
})
|
|
416
|
-
)
|
|
417
|
-
)
|
|
431
|
+
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)' } },
|
|
432
|
+
(STRATEGIES.find((option) => option.id === strategy) || STRATEGIES[0]).hint + ' Saved immediately when selected; the first key then becomes primary for web_search.'
|
|
418
433
|
)
|
|
419
434
|
),
|
|
420
|
-
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-
|
|
421
|
-
|
|
422
|
-
)
|
|
435
|
+
usageError !== null && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usageError)),
|
|
436
|
+
usage !== null && usage.ok === false && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usage.error))
|
|
423
437
|
)
|
|
424
438
|
)
|
|
425
439
|
)
|
package/src/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { readFileSync, writeFileSync } from 'node:fs'
|
|
|
6
6
|
import { join } from 'node:path'
|
|
7
7
|
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
|
8
8
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
9
|
-
import { STRATEGIES, maskValue, parseKeyList, orderKeys, readJsonFile } from './lib.js'
|
|
9
|
+
import { STRATEGIES, isValidStrategy, maskValue, parseKeyList, orderKeys, readJsonFile } from './lib.js'
|
|
10
10
|
|
|
11
11
|
export const name = 'dsh-tavily'
|
|
12
12
|
|