iobroker.ai-usage 0.2.0 → 0.3.0
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 +76 -15
- package/admin/custom/assets/Components-Bq1fGAd7.js +1 -0
- package/admin/custom/assets/ConfigPanel-DGMF4_qT.js +1 -0
- package/admin/custom/assets/{_virtual_mf-localSharedImportMap___mfe_internal__AiUsageComponentSet__mf_owner__1-CXmnAfNY.js → _virtual_mf-localSharedImportMap___mfe_internal__AiUsageComponentSet__mf_owner__1-DKcsNxEw.js} +1 -1
- package/admin/custom/assets/{_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DwHNIjSR.js → _virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DzPBJWNQ.js} +1 -1
- package/admin/custom/assets/{_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-qu1s07FY.js → _virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-DEdJInQG.js} +3 -3
- package/admin/custom/assets/{_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-C8-GjKo4.js → _virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-CFn_lBXc.js} +1 -1
- package/admin/custom/assets/{_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__prebuild___mf_0_iobroker_mf_1_gui_mf_2_components__prebuild__-CQxWwR2r.js → _virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__prebuild___mf_0_iobroker_mf_1_gui_mf_2_components__prebuild__-DeLUTSLT.js} +1 -1
- package/admin/custom/assets/{hostInit-RHMRa462.js → hostInit-DoGxgbHj.js} +1 -1
- package/admin/custom/assets/index-CKngiVu3.js +1 -0
- package/admin/custom/assets/{lib-ByF76TCN.js → lib-MY71LxhX.js} +1 -1
- package/admin/custom/assets/{mf-entry-bootstrap-0-e070fa3e.js → mf-entry-bootstrap-0-eec08a33.js} +2 -2
- package/admin/custom/assets/virtualExposes-Dc9myzsk.js +1 -0
- package/admin/custom/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__AiUsageComponentSet__customComponents_js-l7jtElkM.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__AiUsageComponentSet__customComponents_js-CP4YA3u3.js} +1 -1
- package/admin/custom/assets/virtual_mf-exposes-ssr___mfe_internal__AiUsageComponentSet__customComponents_js-DlNU_Z38.js +2 -0
- package/admin/custom/assets/{virtual_mf-exposes___mfe_internal__AiUsageComponentSet__customComponents_js-BZ-CVpVo.js → virtual_mf-exposes___mfe_internal__AiUsageComponentSet__customComponents_js-CEfffc0D.js} +2 -2
- package/admin/custom/customComponents.js +1 -1
- package/admin/custom/i18n/de.json +24 -15
- package/admin/custom/i18n/en.json +25 -16
- package/admin/custom/i18n/es.json +25 -16
- package/admin/custom/i18n/fr.json +25 -16
- package/admin/custom/i18n/it.json +25 -16
- package/admin/custom/i18n/nl.json +25 -16
- package/admin/custom/i18n/pl.json +25 -16
- package/admin/custom/i18n/pt.json +25 -16
- package/admin/custom/i18n/ru.json +25 -16
- package/admin/custom/i18n/uk.json +25 -16
- package/admin/custom/i18n/zh-cn.json +25 -16
- package/admin/custom/mf-manifest.json +1 -1
- package/build/lib/http.js +29 -0
- package/build/lib/http.js.map +2 -2
- package/build/lib/jwt.js +59 -0
- package/build/lib/jwt.js.map +7 -0
- package/build/lib/poll-engine.js +14 -0
- package/build/lib/poll-engine.js.map +2 -2
- package/build/lib/provider.js.map +2 -2
- package/build/lib/providers/chatgpt-auth.js +125 -0
- package/build/lib/providers/chatgpt-auth.js.map +7 -0
- package/build/lib/providers/chatgpt-sub.js +121 -0
- package/build/lib/providers/chatgpt-sub.js.map +7 -0
- package/build/lib/providers/claude-auth.js.map +2 -2
- package/build/lib/providers/claude-sub.js.map +2 -2
- package/build/lib/providers/gemini-auth.js +135 -0
- package/build/lib/providers/gemini-auth.js.map +7 -0
- package/build/lib/providers/gemini-sub.js +147 -0
- package/build/lib/providers/gemini-sub.js.map +7 -0
- package/build/lib/pure-helpers.js +38 -6
- package/build/lib/pure-helpers.js.map +2 -2
- package/build/lib/sign-in.js +38 -0
- package/build/lib/sign-in.js.map +7 -0
- package/build/main.js +283 -151
- package/build/main.js.map +2 -2
- package/io-package.json +28 -12
- package/package.json +1 -1
- package/admin/custom/assets/Components-Bd545388.js +0 -1
- package/admin/custom/assets/ConfigPanel-qivVprTj.js +0 -1
- package/admin/custom/assets/index-B0J1NbOp.js +0 -1
- package/admin/custom/assets/virtualExposes-BZWQ_oUV.js +0 -1
- package/admin/custom/assets/virtual_mf-exposes-ssr___mfe_internal__AiUsageComponentSet__customComponents_js-CRK-nAdE.js +0 -2
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"aiu_storedTitle": "Account IA",
|
|
3
|
+
"aiu_storedHint": "Attiva ciò che vuoi monitorare. Gli abbonamenti accedono con il tuo account; le voci sotto provengono dall'archivio centrale delle credenziali (Impostazioni → Credenziali).",
|
|
4
|
+
"aiu_capClaude": "Abbonamento — accedi una volta con il tuo account Claude",
|
|
5
|
+
"aiu_capChatgpt": "Abbonamento — accedi una volta con il tuo account ChatGPT",
|
|
6
|
+
"aiu_capGemini": "Abbonamento — accedi una volta con il tuo account Google",
|
|
7
|
+
"aiu_storedKey": "Chiave salvata",
|
|
8
|
+
"aiu_provider": "Fornitore",
|
|
9
|
+
"aiu_warnAt": "Avvisa da %",
|
|
3
10
|
"aiu_signedIn": "Accesso effettuato",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
11
|
+
"aiu_signOut": "Disconnetti",
|
|
12
|
+
"aiu_startSignIn": "Accedi",
|
|
13
|
+
"aiu_claudeStep1": "1. Apri la pagina di accesso ed entra con il tuo account Claude.",
|
|
14
|
+
"aiu_claudeStep2": "2. Copia il codice mostrato e riscattalo qui.",
|
|
15
|
+
"aiu_codeLabel": "Codice",
|
|
16
|
+
"aiu_googleStep1": "1. Apri la pagina di accesso ed entra con il tuo account Google.",
|
|
17
|
+
"aiu_googleStep2": "2. Copia l'INTERO indirizzo dalla barra degli indirizzi e incollalo qui.",
|
|
18
|
+
"aiu_googleErrorPageHint": "Il browser mostrerà poi una pagina di errore («sito non raggiungibile») — è corretto così. Google invia il risultato al tuo computer, dove nessuno è in ascolto. Nell'indirizzo il risultato c'è comunque — ed è proprio quello che serve qui.",
|
|
19
|
+
"aiu_addressLabel": "Indirizzo dal browser",
|
|
20
|
+
"aiu_deviceStep1": "1. Apri la pagina OpenAI e digita questo codice:",
|
|
21
|
+
"aiu_copyCode": "Copia codice",
|
|
22
|
+
"aiu_openPage": "Apri pagina",
|
|
23
|
+
"aiu_deviceWaiting": "In attesa della tua conferma — questa scheda si aggiorna da sola.",
|
|
9
24
|
"aiu_openSignIn": "Apri pagina di accesso",
|
|
10
25
|
"aiu_copyLink": "Copia link",
|
|
11
|
-
"aiu_codeLabel": "Codice",
|
|
12
26
|
"aiu_redeem": "Riscatta",
|
|
13
|
-
"
|
|
14
|
-
"aiu_signInFailed": "Accesso non riuscito",
|
|
27
|
+
"aiu_saveFirst": "Salva prima le impostazioni — poi l'accesso può iniziare.",
|
|
15
28
|
"aiu_instanceNotRunning": "L'istanza non è in esecuzione — avviala per accedere.",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"aiu_unsupported": "Nessuna interrogazione dei consumi disponibile",
|
|
20
|
-
"aiu_provider": "Fornitore",
|
|
21
|
-
"aiu_warnAt": "Avvisa da %",
|
|
22
|
-
"aiu_claudeCaption": "Abbonamento — accede con il tuo account Claude invece di una chiave"
|
|
29
|
+
"aiu_noAnswer": "l'istanza non ha risposto",
|
|
30
|
+
"aiu_noCredentials": "Nessuna credenziale IA salvata — aggiungila in Impostazioni → Credenziali.",
|
|
31
|
+
"aiu_adminKeyHint": "Questo account richiede una chiave di AMMINISTRAZIONE della tua organizzazione, non quella dell'assistente IA. Gli account personali senza organizzazione non forniscono rapporti di utilizzo."
|
|
23
32
|
}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"aiu_storedTitle": "AI-accounts",
|
|
3
|
+
"aiu_storedHint": "Schakel in wat u wilt bewaken. Abonnementen melden zich aan met uw eigen account; de vermeldingen daaronder komen uit de centrale opslag van toegangsgegevens (Instellingen → Toegangsgegevens).",
|
|
4
|
+
"aiu_capClaude": "Abonnement — meld u eenmalig aan met uw Claude-account",
|
|
5
|
+
"aiu_capChatgpt": "Abonnement — meld u eenmalig aan met uw ChatGPT-account",
|
|
6
|
+
"aiu_capGemini": "Abonnement — meld u eenmalig aan met uw Google-account",
|
|
7
|
+
"aiu_storedKey": "Opgeslagen sleutel",
|
|
8
|
+
"aiu_provider": "Aanbieder",
|
|
9
|
+
"aiu_warnAt": "Waarschuwen vanaf %",
|
|
3
10
|
"aiu_signedIn": "Aangemeld",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
11
|
+
"aiu_signOut": "Afmelden",
|
|
12
|
+
"aiu_startSignIn": "Aanmelden",
|
|
13
|
+
"aiu_claudeStep1": "1. Open de aanmeldpagina en log in met uw Claude-account.",
|
|
14
|
+
"aiu_claudeStep2": "2. Kopieer de getoonde code en wissel die hier in.",
|
|
15
|
+
"aiu_codeLabel": "Code",
|
|
16
|
+
"aiu_googleStep1": "1. Open de aanmeldpagina en log in met uw Google-account.",
|
|
17
|
+
"aiu_googleStep2": "2. Kopieer het VOLLEDIGE adres uit de adresbalk en plak het hier.",
|
|
18
|
+
"aiu_googleErrorPageHint": "Uw browser toont daarna een foutpagina («site kan niet worden bereikt») — dat hoort zo. Google stuurt het resultaat naar uw eigen computer, waar niets luistert. In de adresbalk staat het resultaat wél — en dat is wat hier nodig is.",
|
|
19
|
+
"aiu_addressLabel": "Adres uit de browser",
|
|
20
|
+
"aiu_deviceStep1": "1. Open de OpenAI-pagina en typ deze code in:",
|
|
21
|
+
"aiu_copyCode": "Code kopiëren",
|
|
22
|
+
"aiu_openPage": "Pagina openen",
|
|
23
|
+
"aiu_deviceWaiting": "Wachten op uw bevestiging — deze kaart werkt zichzelf bij.",
|
|
9
24
|
"aiu_openSignIn": "Aanmeldpagina openen",
|
|
10
25
|
"aiu_copyLink": "Link kopiëren",
|
|
11
|
-
"aiu_codeLabel": "Code",
|
|
12
26
|
"aiu_redeem": "Inwisselen",
|
|
13
|
-
"
|
|
14
|
-
"aiu_signInFailed": "Aanmelden mislukt",
|
|
27
|
+
"aiu_saveFirst": "Sla eerst de instellingen op — daarna kan het aanmelden starten.",
|
|
15
28
|
"aiu_instanceNotRunning": "De instantie draait niet — start deze om aan te melden.",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"aiu_unsupported": "Geen verbruiksopvraging beschikbaar",
|
|
20
|
-
"aiu_provider": "Aanbieder",
|
|
21
|
-
"aiu_warnAt": "Waarschuwen vanaf %",
|
|
22
|
-
"aiu_claudeCaption": "Abonnement — meldt zich aan met uw Claude-account in plaats van een sleutel"
|
|
29
|
+
"aiu_noAnswer": "de instantie antwoordde niet",
|
|
30
|
+
"aiu_noCredentials": "Nog geen AI-toegangsgegevens opgeslagen — voeg ze toe via Instellingen → Toegangsgegevens.",
|
|
31
|
+
"aiu_adminKeyHint": "Dit account heeft een BEHEER-sleutel van uw organisatie nodig, niet die van de AI-assistent. Persoonlijke accounts zonder organisatie leveren geen verbruiksrapporten."
|
|
23
32
|
}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"aiu_storedTitle": "Konta AI",
|
|
3
|
+
"aiu_storedHint": "Włącz to, co ma być monitorowane. Subskrypcje logują się Twoim kontem; pozycje poniżej pochodzą z centralnego magazynu danych dostępu (Ustawienia → Dane dostępu).",
|
|
4
|
+
"aiu_capClaude": "Subskrypcja — zaloguj się raz kontem Claude",
|
|
5
|
+
"aiu_capChatgpt": "Subskrypcja — zaloguj się raz kontem ChatGPT",
|
|
6
|
+
"aiu_capGemini": "Subskrypcja — zaloguj się raz kontem Google",
|
|
7
|
+
"aiu_storedKey": "Zapisany klucz",
|
|
8
|
+
"aiu_provider": "Dostawca",
|
|
9
|
+
"aiu_warnAt": "Ostrzegaj od %",
|
|
3
10
|
"aiu_signedIn": "Zalogowano",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
11
|
+
"aiu_signOut": "Wyloguj",
|
|
12
|
+
"aiu_startSignIn": "Zaloguj",
|
|
13
|
+
"aiu_claudeStep1": "1. Otwórz stronę logowania i zaloguj się kontem Claude.",
|
|
14
|
+
"aiu_claudeStep2": "2. Skopiuj pokazany kod i zrealizuj go tutaj.",
|
|
15
|
+
"aiu_codeLabel": "Kod",
|
|
16
|
+
"aiu_googleStep1": "1. Otwórz stronę logowania i zaloguj się kontem Google.",
|
|
17
|
+
"aiu_googleStep2": "2. Skopiuj CAŁY adres z paska adresu i wklej go tutaj.",
|
|
18
|
+
"aiu_googleErrorPageHint": "Przeglądarka pokaże potem stronę błędu («nie można otworzyć strony») — tak ma być. Google wysyła wynik na Twój komputer, gdzie nic nie nasłuchuje. W pasku adresu wynik jednak jest — i właśnie on jest tu potrzebny.",
|
|
19
|
+
"aiu_addressLabel": "Adres z przeglądarki",
|
|
20
|
+
"aiu_deviceStep1": "1. Otwórz stronę OpenAI i wpisz ten kod:",
|
|
21
|
+
"aiu_copyCode": "Kopiuj kod",
|
|
22
|
+
"aiu_openPage": "Otwórz stronę",
|
|
23
|
+
"aiu_deviceWaiting": "Czekam na potwierdzenie — ta karta odświeży się sama.",
|
|
9
24
|
"aiu_openSignIn": "Otwórz stronę logowania",
|
|
10
25
|
"aiu_copyLink": "Kopiuj link",
|
|
11
|
-
"aiu_codeLabel": "Kod",
|
|
12
26
|
"aiu_redeem": "Zrealizuj",
|
|
13
|
-
"
|
|
14
|
-
"aiu_signInFailed": "Logowanie nie powiodło się",
|
|
27
|
+
"aiu_saveFirst": "Najpierw zapisz ustawienia — potem można rozpocząć logowanie.",
|
|
15
28
|
"aiu_instanceNotRunning": "Instancja nie działa — uruchom ją, aby się zalogować.",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"aiu_unsupported": "Zapytanie o zużycie niedostępne",
|
|
20
|
-
"aiu_provider": "Dostawca",
|
|
21
|
-
"aiu_warnAt": "Ostrzegaj od %",
|
|
22
|
-
"aiu_claudeCaption": "Subskrypcja — loguje się kontem Claude zamiast klucza"
|
|
29
|
+
"aiu_noAnswer": "instancja nie odpowiedziała",
|
|
30
|
+
"aiu_noCredentials": "Brak zapisanych danych dostępu AI — dodaj je w Ustawienia → Dane dostępu.",
|
|
31
|
+
"aiu_adminKeyHint": "To konto wymaga klucza ADMINISTRACYJNEGO organizacji, a nie klucza asystenta AI. Konta osobiste bez organizacji nie dostarczają raportów zużycia."
|
|
23
32
|
}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"aiu_storedTitle": "Contas de IA",
|
|
3
|
+
"aiu_storedHint": "Ative o que deseja monitorizar. As assinaturas iniciam sessão com a sua conta; as entradas abaixo vêm do armazenamento central de credenciais (Definições → Credenciais).",
|
|
4
|
+
"aiu_capClaude": "Assinatura — inicie sessão uma vez com a sua conta Claude",
|
|
5
|
+
"aiu_capChatgpt": "Assinatura — inicie sessão uma vez com a sua conta ChatGPT",
|
|
6
|
+
"aiu_capGemini": "Assinatura — inicie sessão uma vez com a sua conta Google",
|
|
7
|
+
"aiu_storedKey": "Chave guardada",
|
|
8
|
+
"aiu_provider": "Fornecedor",
|
|
9
|
+
"aiu_warnAt": "Avisar a partir de %",
|
|
3
10
|
"aiu_signedIn": "Sessão iniciada",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
11
|
+
"aiu_signOut": "Terminar sessão",
|
|
12
|
+
"aiu_startSignIn": "Iniciar sessão",
|
|
13
|
+
"aiu_claudeStep1": "1. Abra a página de início de sessão e entre com a sua conta Claude.",
|
|
14
|
+
"aiu_claudeStep2": "2. Copie o código mostrado e resgate-o aqui.",
|
|
15
|
+
"aiu_codeLabel": "Código",
|
|
16
|
+
"aiu_googleStep1": "1. Abra a página de início de sessão e entre com a sua conta Google.",
|
|
17
|
+
"aiu_googleStep2": "2. Copie o endereço COMPLETO da barra de endereços e cole-o aqui.",
|
|
18
|
+
"aiu_googleErrorPageHint": "O navegador mostrará depois uma página de erro («não é possível aceder») — isso é esperado. A Google envia o resultado para o seu computador, onde nada está à escuta. O endereço contém na mesma o resultado — e é isso que é preciso aqui.",
|
|
19
|
+
"aiu_addressLabel": "Endereço do navegador",
|
|
20
|
+
"aiu_deviceStep1": "1. Abra a página da OpenAI e introduza este código:",
|
|
21
|
+
"aiu_copyCode": "Copiar código",
|
|
22
|
+
"aiu_openPage": "Abrir página",
|
|
23
|
+
"aiu_deviceWaiting": "À espera da sua confirmação — este cartão atualiza-se sozinho.",
|
|
9
24
|
"aiu_openSignIn": "Abrir página de início de sessão",
|
|
10
25
|
"aiu_copyLink": "Copiar link",
|
|
11
|
-
"aiu_codeLabel": "Código",
|
|
12
26
|
"aiu_redeem": "Resgatar",
|
|
13
|
-
"
|
|
14
|
-
"aiu_signInFailed": "Falha no início de sessão",
|
|
27
|
+
"aiu_saveFirst": "Guarde primeiro as definições — depois o início de sessão pode começar.",
|
|
15
28
|
"aiu_instanceNotRunning": "A instância não está em execução — inicie-a para entrar.",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"aiu_unsupported": "Consulta de uso indisponível",
|
|
20
|
-
"aiu_provider": "Fornecedor",
|
|
21
|
-
"aiu_warnAt": "Avisar a partir de %",
|
|
22
|
-
"aiu_claudeCaption": "Assinatura — inicia sessão com a sua conta Claude em vez de uma chave"
|
|
29
|
+
"aiu_noAnswer": "a instância não respondeu",
|
|
30
|
+
"aiu_noCredentials": "Ainda não há credenciais de IA guardadas — adicione-as em Definições → Credenciais.",
|
|
31
|
+
"aiu_adminKeyHint": "Esta conta precisa de uma chave de ADMINISTRAÇÃO da organização, não da chave do assistente de IA. Contas pessoais sem organização não fornecem relatórios de uso."
|
|
23
32
|
}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"aiu_storedTitle": "Аккаунты ИИ",
|
|
3
|
+
"aiu_storedHint": "Включите то, что нужно отслеживать. Подписки входят под вашим аккаунтом; записи ниже — из центрального хранилища учётных данных (Настройки → Учётные данные).",
|
|
4
|
+
"aiu_capClaude": "Подписка — один раз войдите со своим аккаунтом Claude",
|
|
5
|
+
"aiu_capChatgpt": "Подписка — один раз войдите со своим аккаунтом ChatGPT",
|
|
6
|
+
"aiu_capGemini": "Подписка — один раз войдите со своим аккаунтом Google",
|
|
7
|
+
"aiu_storedKey": "Сохранённый ключ",
|
|
8
|
+
"aiu_provider": "Провайдер",
|
|
9
|
+
"aiu_warnAt": "Предупреждать с %",
|
|
3
10
|
"aiu_signedIn": "Вход выполнен",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
11
|
+
"aiu_signOut": "Выйти",
|
|
12
|
+
"aiu_startSignIn": "Войти",
|
|
13
|
+
"aiu_claudeStep1": "1. Откройте страницу входа и войдите со своим аккаунтом Claude.",
|
|
14
|
+
"aiu_claudeStep2": "2. Скопируйте показанный код и активируйте его здесь.",
|
|
15
|
+
"aiu_codeLabel": "Код",
|
|
16
|
+
"aiu_googleStep1": "1. Откройте страницу входа и войдите со своим аккаунтом Google.",
|
|
17
|
+
"aiu_googleStep2": "2. Скопируйте ВЕСЬ адрес из адресной строки браузера и вставьте сюда.",
|
|
18
|
+
"aiu_googleErrorPageHint": "Затем браузер покажет страницу ошибки («не удаётся открыть сайт») — так и должно быть. Google отправляет результат на ваш компьютер, где его никто не ждёт. Но в адресной строке результат входа есть — именно он здесь и нужен.",
|
|
19
|
+
"aiu_addressLabel": "Адрес из браузера",
|
|
20
|
+
"aiu_deviceStep1": "1. Откройте страницу OpenAI и введите этот код:",
|
|
21
|
+
"aiu_copyCode": "Копировать код",
|
|
22
|
+
"aiu_openPage": "Открыть страницу",
|
|
23
|
+
"aiu_deviceWaiting": "Ожидание подтверждения — карточка обновится сама.",
|
|
9
24
|
"aiu_openSignIn": "Открыть страницу входа",
|
|
10
25
|
"aiu_copyLink": "Копировать ссылку",
|
|
11
|
-
"aiu_codeLabel": "Код",
|
|
12
26
|
"aiu_redeem": "Активировать",
|
|
13
|
-
"
|
|
14
|
-
"aiu_signInFailed": "Ошибка входа",
|
|
27
|
+
"aiu_saveFirst": "Сначала сохраните настройки — затем можно начать вход.",
|
|
15
28
|
"aiu_instanceNotRunning": "Экземпляр не запущен — запустите его для входа.",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"aiu_unsupported": "Запрос расхода недоступен",
|
|
20
|
-
"aiu_provider": "Провайдер",
|
|
21
|
-
"aiu_warnAt": "Предупреждать с %",
|
|
22
|
-
"aiu_claudeCaption": "Подписка — вход через ваш аккаунт Claude вместо ключа"
|
|
29
|
+
"aiu_noAnswer": "экземпляр не ответил",
|
|
30
|
+
"aiu_noCredentials": "Данные доступа ИИ ещё не сохранены — добавьте их: Настройки → Учётные данные.",
|
|
31
|
+
"aiu_adminKeyHint": "Этому аккаунту нужен АДМИНИСТРАТИВНЫЙ ключ организации, а не ключ ИИ-ассистента. Личные аккаунты без организации не выдают отчёты о расходе."
|
|
23
32
|
}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"aiu_storedTitle": "Акаунти ШІ",
|
|
3
|
+
"aiu_storedHint": "Увімкніть те, що треба відстежувати. Підписки входять під вашим акаунтом; записи нижче — з центрального сховища даних доступу (Налаштування → Дані доступу).",
|
|
4
|
+
"aiu_capClaude": "Підписка — увійдіть один раз акаунтом Claude",
|
|
5
|
+
"aiu_capChatgpt": "Підписка — увійдіть один раз акаунтом ChatGPT",
|
|
6
|
+
"aiu_capGemini": "Підписка — увійдіть один раз акаунтом Google",
|
|
7
|
+
"aiu_storedKey": "Збережений ключ",
|
|
8
|
+
"aiu_provider": "Постачальник",
|
|
9
|
+
"aiu_warnAt": "Попереджати від %",
|
|
3
10
|
"aiu_signedIn": "Вхід виконано",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
11
|
+
"aiu_signOut": "Вийти",
|
|
12
|
+
"aiu_startSignIn": "Увійти",
|
|
13
|
+
"aiu_claudeStep1": "1. Відкрийте сторінку входу та увійдіть акаунтом Claude.",
|
|
14
|
+
"aiu_claudeStep2": "2. Скопіюйте показаний код і активуйте його тут.",
|
|
15
|
+
"aiu_codeLabel": "Код",
|
|
16
|
+
"aiu_googleStep1": "1. Відкрийте сторінку входу та увійдіть акаунтом Google.",
|
|
17
|
+
"aiu_googleStep2": "2. Скопіюйте ВЕСЬ адрес з адресного рядка та вставте сюди.",
|
|
18
|
+
"aiu_googleErrorPageHint": "Далі браузер покаже сторінку помилки («сайт недоступний») — так і має бути. Google надсилає результат на ваш комп'ютер, де ніхто не слухає. В адресному рядку результат усе одно є — саме він тут і потрібен.",
|
|
19
|
+
"aiu_addressLabel": "Адреса з браузера",
|
|
20
|
+
"aiu_deviceStep1": "1. Відкрийте сторінку OpenAI та введіть цей код:",
|
|
21
|
+
"aiu_copyCode": "Копіювати код",
|
|
22
|
+
"aiu_openPage": "Відкрити сторінку",
|
|
23
|
+
"aiu_deviceWaiting": "Очікую підтвердження — картка оновиться сама.",
|
|
9
24
|
"aiu_openSignIn": "Відкрити сторінку входу",
|
|
10
25
|
"aiu_copyLink": "Копіювати посилання",
|
|
11
|
-
"aiu_codeLabel": "Код",
|
|
12
26
|
"aiu_redeem": "Активувати",
|
|
13
|
-
"
|
|
14
|
-
"aiu_signInFailed": "Помилка входу",
|
|
27
|
+
"aiu_saveFirst": "Спочатку збережіть налаштування — потім можна починати вхід.",
|
|
15
28
|
"aiu_instanceNotRunning": "Екземпляр не запущено — запустіть його для входу.",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"aiu_unsupported": "Запит використання недоступний",
|
|
20
|
-
"aiu_provider": "Постачальник",
|
|
21
|
-
"aiu_warnAt": "Попереджати від %",
|
|
22
|
-
"aiu_claudeCaption": "Підписка — вхід через ваш акаунт Claude замість ключа"
|
|
29
|
+
"aiu_noAnswer": "екземпляр не відповів",
|
|
30
|
+
"aiu_noCredentials": "Ще немає збережених даних доступу ШІ — додайте їх у Налаштування → Дані доступу.",
|
|
31
|
+
"aiu_adminKeyHint": "Цей акаунт потребує АДМІНІСТРАТИВНОГО ключа організації, а не ключа ШІ-асистента. Особисті акаунти без організації не дають звітів про використання."
|
|
23
32
|
}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"aiu_storedTitle": "AI 账户",
|
|
3
|
+
"aiu_storedHint": "开启需要监控的项目。订阅使用您自己的账户登录;下方条目来自管理界面的中央凭据存储(设置 → 凭据)。",
|
|
4
|
+
"aiu_capClaude": "订阅——使用您的 Claude 账户登录一次",
|
|
5
|
+
"aiu_capChatgpt": "订阅——使用您的 ChatGPT 账户登录一次",
|
|
6
|
+
"aiu_capGemini": "订阅——使用您的 Google 账户登录一次",
|
|
7
|
+
"aiu_storedKey": "已保存的密钥",
|
|
8
|
+
"aiu_provider": "提供商",
|
|
9
|
+
"aiu_warnAt": "警告阈值 %",
|
|
3
10
|
"aiu_signedIn": "已登录",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
11
|
+
"aiu_signOut": "退出登录",
|
|
12
|
+
"aiu_startSignIn": "登录",
|
|
13
|
+
"aiu_claudeStep1": "1. 打开登录页面并使用您的 Claude 账户登录。",
|
|
14
|
+
"aiu_claudeStep2": "2. 复制页面显示的代码并在此兑换。",
|
|
15
|
+
"aiu_codeLabel": "代码",
|
|
16
|
+
"aiu_googleStep1": "1. 打开登录页面并使用您的 Google 账户登录。",
|
|
17
|
+
"aiu_googleStep2": "2. 复制浏览器地址栏中的完整地址并粘贴到这里。",
|
|
18
|
+
"aiu_googleErrorPageHint": "随后浏览器会显示错误页面(无法访问此网站)——这是正常的。Google 把结果发送到您自己的电脑,而那里没有程序在接收。地址栏中仍然包含登录结果——这正是此处需要的。",
|
|
19
|
+
"aiu_addressLabel": "来自浏览器的地址",
|
|
20
|
+
"aiu_deviceStep1": "1. 打开 OpenAI 页面并输入此代码:",
|
|
21
|
+
"aiu_copyCode": "复制代码",
|
|
22
|
+
"aiu_openPage": "打开页面",
|
|
23
|
+
"aiu_deviceWaiting": "正在等待您的确认——完成后此卡片会自动更新。",
|
|
9
24
|
"aiu_openSignIn": "打开登录页面",
|
|
10
25
|
"aiu_copyLink": "复制链接",
|
|
11
|
-
"aiu_codeLabel": "代码",
|
|
12
26
|
"aiu_redeem": "兑换",
|
|
13
|
-
"
|
|
14
|
-
"aiu_signInFailed": "登录失败",
|
|
27
|
+
"aiu_saveFirst": "请先保存设置——之后即可开始登录。",
|
|
15
28
|
"aiu_instanceNotRunning": "实例未运行——请启动后再登录。",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"aiu_unsupported": "无可用的用量查询",
|
|
20
|
-
"aiu_provider": "提供商",
|
|
21
|
-
"aiu_warnAt": "警告阈值 %",
|
|
22
|
-
"aiu_claudeCaption": "订阅——使用您的 Claude 账户登录,无需密钥"
|
|
29
|
+
"aiu_noAnswer": "实例没有响应",
|
|
30
|
+
"aiu_noCredentials": "尚未保存任何 AI 凭据——请在 设置 → 凭据 中添加。",
|
|
31
|
+
"aiu_adminKeyHint": "此账户需要您所在组织的管理密钥,而不是管理界面 AI 助手使用的密钥。没有组织的个人账户无法提供用量报告。"
|
|
23
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"id":"AiUsageComponentSet","name":"AiUsageComponentSet","metaData":{"name":"AiUsageComponentSet","type":"app","buildInfo":{"buildVersion":"1.0.0","buildName":"AiUsageComponentSet"},"remoteEntry":{"name":"customComponents.js","path":"","type":"module"},"ssrRemoteEntry":{"name":"customComponents.ssr.js","path":"","type":"module"},"types":{"path":"","name":"","zip":"@mf-types.zip","api":"@mf-types.d.ts"},"globalName":"AiUsageComponentSet","pluginVersion":"0.2.5","publicPath":"auto"},"shared":[{"id":"AiUsageComponentSet:@iobroker/gui-components","name":"@iobroker/gui-components","version":"10.1.0","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__prebuild___mf_0_iobroker_mf_1_gui_mf_2_components__prebuild__-
|
|
1
|
+
{"id":"AiUsageComponentSet","name":"AiUsageComponentSet","metaData":{"name":"AiUsageComponentSet","type":"app","buildInfo":{"buildVersion":"1.0.0","buildName":"AiUsageComponentSet"},"remoteEntry":{"name":"customComponents.js","path":"","type":"module"},"ssrRemoteEntry":{"name":"customComponents.ssr.js","path":"","type":"module"},"types":{"path":"","name":"","zip":"@mf-types.zip","api":"@mf-types.d.ts"},"globalName":"AiUsageComponentSet","pluginVersion":"0.2.5","publicPath":"auto"},"shared":[{"id":"AiUsageComponentSet:@iobroker/gui-components","name":"@iobroker/gui-components","version":"10.1.0","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__prebuild___mf_0_iobroker_mf_1_gui_mf_2_components__prebuild__-DeLUTSLT.js"]},"css":{"async":[],"sync":[]}}},{"id":"AiUsageComponentSet:@iobroker/json-config","name":"@iobroker/json-config","version":"9.0.22","singleton":true,"requiredVersion":"*","assets":{"js":{"async":["assets/lib-MY71LxhX.js"],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-DEdJInQG.js"]},"css":{"async":[],"sync":[]}}},{"id":"AiUsageComponentSet:@mui/icons-material","name":"@mui/icons-material","version":"9.3.1","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DzPBJWNQ.js"]},"css":{"async":[],"sync":[]}}},{"id":"AiUsageComponentSet:@mui/material","name":"@mui/material","version":"9.3.1","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DzPBJWNQ.js"]},"css":{"async":[],"sync":[]}}},{"id":"AiUsageComponentSet:react","name":"react","version":"19.2.8","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DzPBJWNQ.js"]},"css":{"async":[],"sync":[]}}},{"id":"AiUsageComponentSet:react-dom","name":"react-dom","version":"19.2.8","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DzPBJWNQ.js"]},"css":{"async":[],"sync":[]}}},{"id":"AiUsageComponentSet:react/jsx-runtime","name":"react/jsx-runtime","version":"19.2.8","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DzPBJWNQ.js"]},"css":{"async":[],"sync":[]}}},{"id":"AiUsageComponentSet:react-dom/client","name":"react-dom/client","version":"19.2.8","singleton":true,"requiredVersion":"*","assets":{"js":{"async":[],"sync":["assets/_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-CFn_lBXc.js"]},"css":{"async":[],"sync":[]}}}],"remotes":[],"exposes":[{"id":"AiUsageComponentSet:Components","name":"Components","assets":{"js":{"async":["assets/lib-MY71LxhX.js"],"sync":["assets/Components-Bq1fGAd7.js"]},"css":{"async":[],"sync":[]}},"path":"./Components"}]}
|
package/build/lib/http.js
CHANGED
|
@@ -19,6 +19,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var http_exports = {};
|
|
20
20
|
__export(http_exports, {
|
|
21
21
|
getJson: () => getJson,
|
|
22
|
+
postForm: () => postForm,
|
|
22
23
|
postJson: () => postJson
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(http_exports);
|
|
@@ -73,9 +74,37 @@ async function postJson(url, body) {
|
|
|
73
74
|
throw new import_provider.FetchError("network", "invalid JSON response");
|
|
74
75
|
}
|
|
75
76
|
}
|
|
77
|
+
async function postForm(url, form, headers = {}) {
|
|
78
|
+
let response;
|
|
79
|
+
try {
|
|
80
|
+
response = await fetch(url, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded", ...headers },
|
|
83
|
+
body: new URLSearchParams(form).toString(),
|
|
84
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
85
|
+
});
|
|
86
|
+
} catch (e) {
|
|
87
|
+
throw new import_provider.FetchError("network", e instanceof Error ? e.message : String(e));
|
|
88
|
+
}
|
|
89
|
+
if (response.status === 400 || response.status === 401 || response.status === 403) {
|
|
90
|
+
throw new import_provider.FetchError("auth", `HTTP ${response.status}`);
|
|
91
|
+
}
|
|
92
|
+
if (response.status === 429) {
|
|
93
|
+
throw new import_provider.FetchError("rate-limit", "HTTP 429");
|
|
94
|
+
}
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new import_provider.FetchError("network", `HTTP ${response.status}`);
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
return await response.json();
|
|
100
|
+
} catch (e) {
|
|
101
|
+
throw new import_provider.FetchError("network", `invalid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
76
104
|
// Annotate the CommonJS export names for ESM import in node:
|
|
77
105
|
0 && (module.exports = {
|
|
78
106
|
getJson,
|
|
107
|
+
postForm,
|
|
79
108
|
postJson
|
|
80
109
|
});
|
|
81
110
|
//# sourceMappingURL=http.js.map
|
package/build/lib/http.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/http.ts"],
|
|
4
|
-
"sourcesContent": ["import { FetchError } from \"./provider\";\n\n/** Per-request timeout (ms). */\nconst REQUEST_TIMEOUT_MS = 15000;\n\n/** The JSON-GET seam the provider modules use \u2014 injectable for tests. */\nexport type JsonFetch = (url: string, headers: Record<string, string>) => Promise<unknown>;\n\n/**\n * GET a JSON document with the shared failure classification: 401/403 become an\n * auth error, 429 a rate-limit error, everything else (bad status, network throw,\n * timeout, invalid JSON) a network error \u2014 the classes the poll engine acts on.\n *\n * @param url the request URL\n * @param headers request headers (Authorization etc.)\n * @returns the parsed JSON body\n */\nexport async function getJson(url: string, headers: Record<string, string>): Promise<unknown> {\n let response: Response;\n try {\n response = await fetch(url, { headers, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });\n } catch (e) {\n throw new FetchError(\"network\", e instanceof Error ? e.message : String(e));\n }\n if (response.status === 401 || response.status === 403) {\n throw new FetchError(\"auth\", `HTTP ${response.status}`);\n }\n if (response.status === 429) {\n throw new FetchError(\"rate-limit\", \"HTTP 429\");\n }\n if (!response.ok) {\n throw new FetchError(\"network\", `HTTP ${response.status}`);\n }\n try {\n return await response.json();\n } catch {\n throw new FetchError(\"network\", \"invalid JSON response\");\n }\n}\n\n/**\n * POST a JSON document with the same failure classification as {@link getJson}.\n *\n * @param url the request URL\n * @param body the JSON body\n * @returns the parsed JSON response\n */\nexport async function postJson(url: string, body: Record<string, unknown>): Promise<unknown> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n } catch (e) {\n throw new FetchError(\"network\", e instanceof Error ? e.message : String(e));\n }\n if (response.status === 401 || response.status === 403 || response.status === 400) {\n throw new FetchError(\"auth\", `HTTP ${response.status}`);\n }\n if (response.status === 429) {\n throw new FetchError(\"rate-limit\", \"HTTP 429\");\n }\n if (!response.ok) {\n throw new FetchError(\"network\", `HTTP ${response.status}`);\n }\n try {\n return await response.json();\n } catch {\n throw new FetchError(\"network\", \"invalid JSON response\");\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAA2B;AAG3B,MAAM,qBAAqB;AAc3B,eAAsB,QAAQ,KAAa,SAAmD;AAC5F,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,KAAK,EAAE,SAAS,QAAQ,YAAY,QAAQ,kBAAkB,EAAE,CAAC;AAAA,EAC1F,SAAS,GAAG;AACV,UAAM,IAAI,2BAAW,WAAW,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,EAC5E;AACA,MAAI,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACtD,UAAM,IAAI,2BAAW,QAAQ,QAAQ,SAAS,MAAM,EAAE;AAAA,EACxD;AACA,MAAI,SAAS,WAAW,KAAK;AAC3B,UAAM,IAAI,2BAAW,cAAc,UAAU;AAAA,EAC/C;AACA,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,2BAAW,WAAW,QAAQ,SAAS,MAAM,EAAE;AAAA,EAC3D;AACA,MAAI;AACF,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B,QAAQ;AACN,UAAM,IAAI,2BAAW,WAAW,uBAAuB;AAAA,EACzD;AACF;AASA,eAAsB,SAAS,KAAa,MAAiD;AAC3F,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,KAAK;AAAA,MAC1B,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,MACzB,QAAQ,YAAY,QAAQ,kBAAkB;AAAA,IAChD,CAAC;AAAA,EACH,SAAS,GAAG;AACV,UAAM,IAAI,2BAAW,WAAW,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,EAC5E;AACA,MAAI,SAAS,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS,WAAW,KAAK;AACjF,UAAM,IAAI,2BAAW,QAAQ,QAAQ,SAAS,MAAM,EAAE;AAAA,EACxD;AACA,MAAI,SAAS,WAAW,KAAK;AAC3B,UAAM,IAAI,2BAAW,cAAc,UAAU;AAAA,EAC/C;AACA,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,2BAAW,WAAW,QAAQ,SAAS,MAAM,EAAE;AAAA,EAC3D;AACA,MAAI;AACF,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B,QAAQ;AACN,UAAM,IAAI,2BAAW,WAAW,uBAAuB;AAAA,EACzD;AACF;",
|
|
4
|
+
"sourcesContent": ["import { FetchError } from \"./provider\";\n\n/** Per-request timeout (ms). */\nconst REQUEST_TIMEOUT_MS = 15000;\n\n/** The JSON-GET seam the provider modules use \u2014 injectable for tests. */\nexport type JsonFetch = (url: string, headers: Record<string, string>) => Promise<unknown>;\n\n/**\n * GET a JSON document with the shared failure classification: 401/403 become an\n * auth error, 429 a rate-limit error, everything else (bad status, network throw,\n * timeout, invalid JSON) a network error \u2014 the classes the poll engine acts on.\n *\n * @param url the request URL\n * @param headers request headers (Authorization etc.)\n * @returns the parsed JSON body\n */\nexport async function getJson(url: string, headers: Record<string, string>): Promise<unknown> {\n let response: Response;\n try {\n response = await fetch(url, { headers, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });\n } catch (e) {\n throw new FetchError(\"network\", e instanceof Error ? e.message : String(e));\n }\n if (response.status === 401 || response.status === 403) {\n throw new FetchError(\"auth\", `HTTP ${response.status}`);\n }\n if (response.status === 429) {\n throw new FetchError(\"rate-limit\", \"HTTP 429\");\n }\n if (!response.ok) {\n throw new FetchError(\"network\", `HTTP ${response.status}`);\n }\n try {\n return await response.json();\n } catch {\n throw new FetchError(\"network\", \"invalid JSON response\");\n }\n}\n\n/**\n * POST a JSON document with the same failure classification as {@link getJson}.\n *\n * @param url the request URL\n * @param body the JSON body\n * @returns the parsed JSON response\n */\nexport async function postJson(url: string, body: Record<string, unknown>): Promise<unknown> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n } catch (e) {\n throw new FetchError(\"network\", e instanceof Error ? e.message : String(e));\n }\n if (response.status === 401 || response.status === 403 || response.status === 400) {\n throw new FetchError(\"auth\", `HTTP ${response.status}`);\n }\n if (response.status === 429) {\n throw new FetchError(\"rate-limit\", \"HTTP 429\");\n }\n if (!response.ok) {\n throw new FetchError(\"network\", `HTTP ${response.status}`);\n }\n try {\n return await response.json();\n } catch {\n throw new FetchError(\"network\", \"invalid JSON response\");\n }\n}\n\n/**\n * POST a form-encoded body and return the parsed JSON answer.\n *\n * OAuth code redemption uses form encoding while token refresh often uses JSON \u2014\n * ChatGPT/Codex needs BOTH, so the two shapes are separate helpers rather than one\n * guessing wrapper.\n *\n * @param url the request URL\n * @param form the form fields\n * @param headers extra headers\n * @returns the parsed JSON body\n */\nexport async function postForm(\n url: string,\n form: Record<string, string>,\n headers: Record<string, string> = {},\n): Promise<unknown> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\", ...headers },\n body: new URLSearchParams(form).toString(),\n signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n });\n } catch (e) {\n throw new FetchError(\"network\", e instanceof Error ? e.message : String(e));\n }\n if (response.status === 400 || response.status === 401 || response.status === 403) {\n throw new FetchError(\"auth\", `HTTP ${response.status}`);\n }\n if (response.status === 429) {\n throw new FetchError(\"rate-limit\", \"HTTP 429\");\n }\n if (!response.ok) {\n throw new FetchError(\"network\", `HTTP ${response.status}`);\n }\n try {\n return await response.json();\n } catch (e) {\n throw new FetchError(\"network\", `invalid JSON: ${e instanceof Error ? e.message : String(e)}`);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/lib/jwt.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var jwt_exports = {};
|
|
20
|
+
__export(jwt_exports, {
|
|
21
|
+
chatgptAccountId: () => chatgptAccountId,
|
|
22
|
+
jwtClaims: () => jwtClaims,
|
|
23
|
+
jwtExpiry: () => jwtExpiry
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(jwt_exports);
|
|
26
|
+
function jwtClaims(token) {
|
|
27
|
+
const parts = token.split(".");
|
|
28
|
+
if (parts.length !== 3) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const json = Buffer.from(parts[1].replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8");
|
|
33
|
+
const parsed = JSON.parse(json);
|
|
34
|
+
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function jwtExpiry(token, fallbackMs, now) {
|
|
40
|
+
var _a;
|
|
41
|
+
const exp = (_a = jwtClaims(token)) == null ? void 0 : _a.exp;
|
|
42
|
+
return typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : now + fallbackMs;
|
|
43
|
+
}
|
|
44
|
+
function chatgptAccountId(idToken) {
|
|
45
|
+
var _a;
|
|
46
|
+
const auth = (_a = jwtClaims(idToken)) == null ? void 0 : _a["https://api.openai.com/auth"];
|
|
47
|
+
if (typeof auth !== "object" || auth === null) {
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
const value = auth.chatgpt_account_id;
|
|
51
|
+
return typeof value === "string" && value ? value : void 0;
|
|
52
|
+
}
|
|
53
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
54
|
+
0 && (module.exports = {
|
|
55
|
+
chatgptAccountId,
|
|
56
|
+
jwtClaims,
|
|
57
|
+
jwtExpiry
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=jwt.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/jwt.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Read claims out of a JWT we RECEIVED \u2014 no signature check.\n *\n * We are the token's holder, not its verifier: the provider validates it on every\n * call. All we need is metadata the token carries because the responses do not:\n * the expiry (ChatGPT's refresh answer has no `expires_in`) and the ChatGPT account\n * id (which lives in a namespaced claim, not in any profile endpoint).\n *\n * @param token the compact JWT\n * @returns the payload as a record, or null when it is not a readable JWT\n */\nexport function jwtClaims(token: string): Record<string, unknown> | null {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n return null;\n }\n try {\n const json = Buffer.from(parts[1].replace(/-/g, \"+\").replace(/_/g, \"/\"), \"base64\").toString(\"utf8\");\n const parsed: unknown = JSON.parse(json);\n return typeof parsed === \"object\" && parsed !== null ? (parsed as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * The absolute expiry of an access token, in ms since epoch.\n *\n * @param token the access token\n * @param fallbackMs how long to assume when the token carries no `exp`\n * @param now current time in ms\n * @returns the expiry timestamp\n */\nexport function jwtExpiry(token: string, fallbackMs: number, now: number): number {\n const exp = jwtClaims(token)?.exp;\n return typeof exp === \"number\" && Number.isFinite(exp) ? exp * 1000 : now + fallbackMs;\n}\n\n/**\n * The ChatGPT account id, carried in a namespaced claim of the id token.\n *\n * @param idToken the id token from the OAuth exchange\n * @returns the account id, or undefined\n */\nexport function chatgptAccountId(idToken: string): string | undefined {\n const auth = jwtClaims(idToken)?.[\"https://api.openai.com/auth\"];\n if (typeof auth !== \"object\" || auth === null) {\n return undefined;\n }\n const value = (auth as Record<string, unknown>).chatgpt_account_id;\n return typeof value === \"string\" && value ? value : undefined;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWO,SAAS,UAAU,OAA+C;AACvE,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,OAAO,OAAO,KAAK,MAAM,CAAC,EAAE,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,GAAG,QAAQ,EAAE,SAAS,MAAM;AAClG,UAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,WAAO,OAAO,WAAW,YAAY,WAAW,OAAQ,SAAqC;AAAA,EAC/F,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAUO,SAAS,UAAU,OAAe,YAAoB,KAAqB;AAjClF;AAkCE,QAAM,OAAM,eAAU,KAAK,MAAf,mBAAkB;AAC9B,SAAO,OAAO,QAAQ,YAAY,OAAO,SAAS,GAAG,IAAI,MAAM,MAAO,MAAM;AAC9E;AAQO,SAAS,iBAAiB,SAAqC;AA5CtE;AA6CE,QAAM,QAAO,eAAU,OAAO,MAAjB,mBAAqB;AAClC,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,WAAO;AAAA,EACT;AACA,QAAM,QAAS,KAAiC;AAChD,SAAO,OAAO,UAAU,YAAY,QAAQ,QAAQ;AACtD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/build/lib/poll-engine.js
CHANGED
|
@@ -87,6 +87,20 @@ class PollEngine {
|
|
|
87
87
|
get accountIds() {
|
|
88
88
|
return this.runtimes.map((runtime) => runtime.config.id);
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Poll one account immediately, by id. Used after a successful sign-in: waiting
|
|
92
|
+
* up to a full interval there reads as "the sign-in did not work".
|
|
93
|
+
*
|
|
94
|
+
* @param accountId the account's object id
|
|
95
|
+
*/
|
|
96
|
+
async pollNow(accountId) {
|
|
97
|
+
const runtime = this.runtimes.find((entry) => entry.config.id === accountId);
|
|
98
|
+
if (runtime) {
|
|
99
|
+
runtime.authNotified = false;
|
|
100
|
+
runtime.skipUntil = 0;
|
|
101
|
+
await this.pollAccount(runtime);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
90
104
|
/**
|
|
91
105
|
* Poll one account now (also used by the staggered first run).
|
|
92
106
|
*
|