@jeffreycao/copilot-api 2.3.0 → 2.3.3
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/{auth-CMjIc9P5.js → auth-BbYtl2YO.js} +2 -2
- package/dist/{auth-CMjIc9P5.js.map → auth-BbYtl2YO.js.map} +1 -1
- package/dist/auth-rIQFsqw4.js +2 -0
- package/dist/main.js +2 -2
- package/dist/{models-BWz0NqC_.js → models-hA7oPkkI.js} +2 -2
- package/dist/{models-BWz0NqC_.js.map → models-hA7oPkkI.js.map} +1 -1
- package/dist/{server-B7mWm6lt.js → server-oZS_bQYn.js} +16 -13
- package/dist/server-oZS_bQYn.js.map +1 -0
- package/dist/{start-30t65upk.js → start-DDx8cKiL.js} +5 -5
- package/dist/{start-30t65upk.js.map → start-DDx8cKiL.js.map} +1 -1
- package/dist/{token-CzyAtvCM.js → token-DUG-1XmB.js} +13 -9
- package/dist/{token-CzyAtvCM.js.map → token-DUG-1XmB.js.map} +1 -1
- package/package.json +1 -1
- package/pages/index.html +167 -23
- package/dist/auth-Dc_46FWA.js +0 -2
- package/dist/server-B7mWm6lt.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@jeffreycao/copilot-api",
|
|
4
|
-
"version": "2.3.
|
|
4
|
+
"version": "2.3.3",
|
|
5
5
|
"description": "GitHub Copilot, OpenAI Codex, OpenCode Go, and third-party AI provider gateway with OpenAI and Anthropic API compatibility.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"github-copilot",
|
package/pages/index.html
CHANGED
|
@@ -407,12 +407,12 @@
|
|
|
407
407
|
/>
|
|
408
408
|
</div>
|
|
409
409
|
<div>
|
|
410
|
-
<label for="x-api-key" class="field-label">
|
|
410
|
+
<label for="x-api-key" class="field-label">Auth credential</label>
|
|
411
411
|
<input
|
|
412
412
|
type="password"
|
|
413
413
|
id="x-api-key"
|
|
414
414
|
class="input-control input-focus"
|
|
415
|
-
placeholder="
|
|
415
|
+
placeholder="x-api-key or Authorization Bearer"
|
|
416
416
|
autocomplete="off"
|
|
417
417
|
spellcheck="false"
|
|
418
418
|
/>
|
|
@@ -433,6 +433,9 @@
|
|
|
433
433
|
<span>Refresh</span>
|
|
434
434
|
</button>
|
|
435
435
|
</form>
|
|
436
|
+
<p class="mt-2 text-xs" style="color: var(--color-gray);">
|
|
437
|
+
Credentials are remembered per endpoint origin and are not sent to other endpoints.
|
|
438
|
+
</p>
|
|
436
439
|
</header>
|
|
437
440
|
|
|
438
441
|
<main id="content-area" class="content-area"></main>
|
|
@@ -464,7 +467,8 @@
|
|
|
464
467
|
const DEFAULT_TOKEN_USAGE_EVENTS_PAGE_SIZE = 20;
|
|
465
468
|
const ALL_METRICS_VALUE = "__all__";
|
|
466
469
|
const ALL_MODELS_VALUE = "__all__";
|
|
467
|
-
const
|
|
470
|
+
const LEGACY_API_KEY_STORAGE_KEY = "copilot-api.usage-viewer.x-api-key";
|
|
471
|
+
const CREDENTIAL_STORAGE_PREFIX = "copilot-api.usage-viewer.credential.";
|
|
468
472
|
const VALID_PERIODS = new Set(["day", "week", "month"]);
|
|
469
473
|
const EMPTY_TOKEN_USAGE_TOTALS = {
|
|
470
474
|
cache_creation_input_tokens: 0,
|
|
@@ -545,33 +549,156 @@
|
|
|
545
549
|
return normalized;
|
|
546
550
|
}
|
|
547
551
|
|
|
548
|
-
function
|
|
552
|
+
function getEndpointOrigin(endpoint) {
|
|
553
|
+
if (!endpoint) {
|
|
554
|
+
return "";
|
|
555
|
+
}
|
|
549
556
|
try {
|
|
550
|
-
return
|
|
557
|
+
return new URL(endpoint, window.location.href).origin;
|
|
551
558
|
} catch (error) {
|
|
552
|
-
console.warn("Could not
|
|
559
|
+
console.warn("Could not parse endpoint URL:", getErrorMessage(error));
|
|
553
560
|
return "";
|
|
554
561
|
}
|
|
555
562
|
}
|
|
556
563
|
|
|
557
|
-
function
|
|
564
|
+
function getCredentialStorageKey(endpoint) {
|
|
565
|
+
const origin = getEndpointOrigin(endpoint);
|
|
566
|
+
return origin ? `${CREDENTIAL_STORAGE_PREFIX}${origin}` : "";
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function readStoredApiKey(endpoint) {
|
|
570
|
+
const storageKey = getCredentialStorageKey(endpoint);
|
|
571
|
+
if (!storageKey) {
|
|
572
|
+
return "";
|
|
573
|
+
}
|
|
558
574
|
try {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
575
|
+
return window.localStorage.getItem(storageKey) || "";
|
|
576
|
+
} catch (error) {
|
|
577
|
+
console.warn(
|
|
578
|
+
"Could not read stored credential:",
|
|
579
|
+
getErrorMessage(error)
|
|
580
|
+
);
|
|
581
|
+
return "";
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function writeStoredApiKey(endpoint, value) {
|
|
586
|
+
const storageKey = getCredentialStorageKey(endpoint);
|
|
587
|
+
if (!storageKey) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
try {
|
|
591
|
+
window.localStorage.setItem(storageKey, value);
|
|
565
592
|
} catch (error) {
|
|
566
|
-
console.warn(
|
|
593
|
+
console.warn(
|
|
594
|
+
"Could not store credential:",
|
|
595
|
+
getErrorMessage(error)
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function removeStoredApiKey(endpoint) {
|
|
601
|
+
const storageKey = getCredentialStorageKey(endpoint);
|
|
602
|
+
if (!storageKey) {
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
try {
|
|
606
|
+
window.localStorage.removeItem(storageKey);
|
|
607
|
+
} catch (error) {
|
|
608
|
+
console.warn(
|
|
609
|
+
"Could not remove stored credential:",
|
|
610
|
+
getErrorMessage(error)
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function removeLegacyStoredApiKey() {
|
|
616
|
+
try {
|
|
617
|
+
window.localStorage.removeItem(LEGACY_API_KEY_STORAGE_KEY);
|
|
618
|
+
} catch (error) {
|
|
619
|
+
console.warn(
|
|
620
|
+
"Could not remove legacy credential:",
|
|
621
|
+
getErrorMessage(error)
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function migrateLegacyApiKey(endpoint) {
|
|
627
|
+
const storageKey = getCredentialStorageKey(endpoint);
|
|
628
|
+
if (storageKey && getEndpointOrigin(endpoint) === window.location.origin) {
|
|
629
|
+
try {
|
|
630
|
+
const legacyValue = window.localStorage.getItem(
|
|
631
|
+
LEGACY_API_KEY_STORAGE_KEY
|
|
632
|
+
);
|
|
633
|
+
if (legacyValue && !window.localStorage.getItem(storageKey)) {
|
|
634
|
+
window.localStorage.setItem(storageKey, legacyValue);
|
|
635
|
+
}
|
|
636
|
+
} catch (error) {
|
|
637
|
+
console.warn(
|
|
638
|
+
"Could not migrate legacy credential:",
|
|
639
|
+
getErrorMessage(error)
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
removeLegacyStoredApiKey();
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function loadStoredApiKey(endpoint) {
|
|
647
|
+
return readStoredApiKey(endpoint);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function storeApiKey(value, endpoint) {
|
|
651
|
+
const trimmed = value.trim();
|
|
652
|
+
if (trimmed) {
|
|
653
|
+
writeStoredApiKey(endpoint, trimmed);
|
|
654
|
+
} else {
|
|
655
|
+
removeStoredApiKey(endpoint);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function parseCredential(value) {
|
|
660
|
+
const trimmed = value.trim();
|
|
661
|
+
if (!trimmed) {
|
|
662
|
+
return null;
|
|
567
663
|
}
|
|
664
|
+
|
|
665
|
+
const authorizationMatch = trimmed.match(
|
|
666
|
+
/^authorization\s*:\s*bearer\s+(.+)$/i
|
|
667
|
+
);
|
|
668
|
+
if (authorizationMatch) {
|
|
669
|
+
return {
|
|
670
|
+
header: "authorization",
|
|
671
|
+
value: `Bearer ${authorizationMatch[1].trim()}`,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const bearerMatch = trimmed.match(/^bearer\s+(.+)$/i);
|
|
676
|
+
if (bearerMatch) {
|
|
677
|
+
return {
|
|
678
|
+
header: "authorization",
|
|
679
|
+
value: `Bearer ${bearerMatch[1].trim()}`,
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const xApiKeyMatch = trimmed.match(/^x-api-key\s*:\s*(.+)$/i);
|
|
684
|
+
if (xApiKeyMatch) {
|
|
685
|
+
return {
|
|
686
|
+
header: "x-api-key",
|
|
687
|
+
value: xApiKeyMatch[1].trim(),
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
return {
|
|
692
|
+
header: "x-api-key",
|
|
693
|
+
value: trimmed,
|
|
694
|
+
};
|
|
568
695
|
}
|
|
569
696
|
|
|
570
697
|
function buildRequestHeaders() {
|
|
571
698
|
const headers = {};
|
|
572
|
-
const
|
|
573
|
-
if (
|
|
574
|
-
headers[
|
|
699
|
+
const credential = parseCredential(apiKeyInput.value);
|
|
700
|
+
if (credential) {
|
|
701
|
+
headers[credential.header] = credential.value;
|
|
575
702
|
}
|
|
576
703
|
return headers;
|
|
577
704
|
}
|
|
@@ -2001,7 +2128,8 @@
|
|
|
2001
2128
|
*/
|
|
2002
2129
|
function handleFormSubmit(event) {
|
|
2003
2130
|
event.preventDefault();
|
|
2004
|
-
|
|
2131
|
+
syncEndpointCredential();
|
|
2132
|
+
storeApiKey(apiKeyInput.value, endpointUrlInput.value.trim());
|
|
2005
2133
|
syncUrlState();
|
|
2006
2134
|
void fetchData();
|
|
2007
2135
|
}
|
|
@@ -2074,6 +2202,18 @@
|
|
|
2074
2202
|
render();
|
|
2075
2203
|
}
|
|
2076
2204
|
|
|
2205
|
+
let currentEndpointOrigin = "";
|
|
2206
|
+
|
|
2207
|
+
function syncEndpointCredential() {
|
|
2208
|
+
const endpoint = endpointUrlInput.value.trim();
|
|
2209
|
+
const endpointOrigin = getEndpointOrigin(endpoint);
|
|
2210
|
+
if (endpointOrigin === currentEndpointOrigin) {
|
|
2211
|
+
return;
|
|
2212
|
+
}
|
|
2213
|
+
apiKeyInput.value = loadStoredApiKey(endpoint);
|
|
2214
|
+
currentEndpointOrigin = endpointOrigin;
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2077
2217
|
/**
|
|
2078
2218
|
* Initializes the application.
|
|
2079
2219
|
*/
|
|
@@ -2081,25 +2221,29 @@
|
|
|
2081
2221
|
endpointForm.addEventListener("submit", handleFormSubmit);
|
|
2082
2222
|
tokenUsagePeriodSelect.addEventListener("change", handlePeriodChange);
|
|
2083
2223
|
apiKeyInput.addEventListener("input", () => {
|
|
2084
|
-
storeApiKey(
|
|
2224
|
+
storeApiKey(
|
|
2225
|
+
apiKeyInput.value,
|
|
2226
|
+
endpointUrlInput.value.trim()
|
|
2227
|
+
);
|
|
2085
2228
|
});
|
|
2229
|
+
endpointUrlInput.addEventListener("change", syncEndpointCredential);
|
|
2086
2230
|
contentArea.addEventListener("click", handleContentAreaClick);
|
|
2087
2231
|
contentArea.addEventListener("change", handleContentAreaChange);
|
|
2088
2232
|
|
|
2089
|
-
apiKeyInput.value = loadStoredApiKey();
|
|
2090
|
-
|
|
2091
2233
|
const urlParams = new URLSearchParams(window.location.search);
|
|
2092
2234
|
const periodFromUrl = normalizePeriod(urlParams.get("period"));
|
|
2093
2235
|
const endpointFromUrl = urlParams.get("endpoint");
|
|
2236
|
+
const initialEndpoint = endpointFromUrl || DEFAULT_ENDPOINT;
|
|
2094
2237
|
|
|
2095
2238
|
state.tokenUsagePeriod = periodFromUrl;
|
|
2096
2239
|
tokenUsagePeriodSelect.value = periodFromUrl;
|
|
2240
|
+
endpointUrlInput.value = initialEndpoint;
|
|
2241
|
+
migrateLegacyApiKey(initialEndpoint);
|
|
2242
|
+
syncEndpointCredential();
|
|
2097
2243
|
|
|
2098
2244
|
if (endpointFromUrl) {
|
|
2099
|
-
endpointUrlInput.value = endpointFromUrl;
|
|
2100
2245
|
void fetchData();
|
|
2101
2246
|
} else {
|
|
2102
|
-
endpointUrlInput.value = DEFAULT_ENDPOINT;
|
|
2103
2247
|
render();
|
|
2104
2248
|
}
|
|
2105
2249
|
}
|
package/dist/auth-Dc_46FWA.js
DELETED