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
package/build/main.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/main.ts"],
|
|
4
|
-
"sourcesContent": ["import * as utils from \"@iobroker/adapter-core\";\nimport { Credentials } from \"@iobroker/adapter-core\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { postJson } from \"./lib/http\";\nimport { PollEngine } from \"./lib/poll-engine\";\nimport { clampPollInterval, parseAccounts, sanitizeId, validAccountIds, type AccountConfig } from \"./lib/pure-helpers\";\nimport type { UsageProvider } from \"./lib/provider\";\nimport {\n buildAuthorizeUrl,\n exchangeCode,\n generatePkce,\n type PkcePair,\n type TokenSet,\n} from \"./lib/providers/claude-auth\";\nimport { anthropicApiProvider } from \"./lib/providers/anthropic-api\";\nimport { claudeSubProvider, type TokenStore } from \"./lib/providers/claude-sub\";\nimport { deepSeekProvider } from \"./lib/providers/deepseek\";\nimport { openAiProvider } from \"./lib/providers/openai\";\nimport { openRouterProvider } from \"./lib/providers/openrouter\";\n\n/** A cancellable handle: interval or timeout \u2014 the engine treats them uniformly. */\ntype TimerHandle =\n | { kind: \"interval\"; handle: ioBroker.Interval | undefined }\n | { kind: \"timeout\"; handle: ioBroker.Timeout | undefined };\n\n/**\n * AI Usage adapter \u2014 polls the usage/limit/cost sources of configured AI accounts\n * (Claude subscription, OpenRouter, DeepSeek, OpenAI API, Anthropic API) and\n * mirrors them into read-only states. Orchestration lives in the\n * fully unit-tested {@link PollEngine}; this class only wires ioBroker IO to it.\n */\nexport class AiUsageAdapter extends utils.Adapter {\n private engine: PollEngine | null = null;\n /** Pending Claude sign-in attempts, keyed by account id (PKCE lives only in memory). */\n private readonly pendingClaudeAuth = new Map<string, PkcePair>();\n\n /**\n * @param options the adapter options\n */\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({ ...options, name: \"ai-usage\" });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"message\", this.onMessage.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n }\n\n /**\n * Handle admin messages \u2014 the guided Claude subscription sign-in.\n *\n * @param obj the message\n */\n private async onMessage(obj: ioBroker.Message): Promise<void> {\n try {\n switch (obj.command) {\n case \"claudeAuthStart\": {\n // Regenerate the sign-in link for one account (invalidates the previous one).\n const accountId = this.claudeAccountIdFrom(obj.message);\n if (!accountId) {\n this.respond(obj, { error: \"Save the settings with a Claude subscription account first\" });\n return;\n }\n const url = await this.publishClaudeSignInUrl(accountId);\n this.respond(obj, { url });\n return;\n }\n case \"claudeAuthCode\": {\n const accountId = this.claudeAccountIdFrom(obj.message);\n const code =\n typeof (obj.message as { code?: unknown })?.code === \"string\" ? (obj.message as { code: string }).code : \"\";\n const pkce = accountId ? this.pendingClaudeAuth.get(accountId) : undefined;\n if (!accountId || !pkce) {\n this.respond(obj, { error: \"Save the settings with a Claude subscription account first\" });\n return;\n }\n if (!code.trim()) {\n this.respond(obj, { error: \"Paste the code from the Anthropic page first\" });\n return;\n }\n try {\n const tokens = await exchangeCode(code, pkce, postJson, Date.now());\n await this.claudeTokenStore(accountId).save(tokens);\n this.pendingClaudeAuth.delete(accountId);\n await this.setClaudeAuthStates(accountId, \"\", true);\n this.respond(obj, { result: \"ok\" });\n } catch (e) {\n this.respond(obj, { error: `Sign-in failed: ${e instanceof Error ? e.message : String(e)}` });\n }\n return;\n }\n default:\n // Always answer, or the caller's callback would dangle until timeout.\n this.respond(obj, { error: `Unknown command: ${obj.command}` });\n }\n } catch (e) {\n this.log.error(`onMessage failed: ${e instanceof Error ? e.message : String(e)}`);\n this.respond(obj, { error: \"internal error \u2014 see log\" });\n }\n }\n\n /**\n * Send a message response, when the caller expects one.\n *\n * @param obj the request message\n * @param response the response payload\n */\n private respond(obj: ioBroker.Message, response: unknown): void {\n if (obj.callback) {\n this.sendTo(obj.from, obj.command, response, obj.callback);\n }\n }\n\n /**\n * Resolve the account id for a Claude sign-in message: the given name must match\n * a claude-sub row of the accounts table.\n *\n * @param message the message payload ({ account })\n * @returns the id-safe account id, or undefined\n */\n private claudeAccountIdFrom(message: unknown): string | undefined {\n const name =\n typeof (message as { account?: unknown })?.account === \"string\" ? (message as { account: string }).account : \"\";\n const id = sanitizeId(name);\n if (!id) {\n return undefined;\n }\n const accounts = parseAccounts(this.config.accounts);\n return accounts.some(account => account.id === id && account.provider === \"claude-sub\") ? id : undefined;\n }\n\n /**\n * Create the `auth.<id>` states of one Claude account and publish a FRESH\n * sign-in link (the adapter owns the secret; the link stays valid until it is\n * regenerated or redeemed \u2014 the admin card only displays it).\n *\n * @param accountId the id-safe account id\n * @returns the sign-in URL\n */\n private async publishClaudeSignInUrl(accountId: string): Promise<string> {\n const pkce = generatePkce();\n this.pendingClaudeAuth.set(accountId, pkce);\n const url = buildAuthorizeUrl(pkce);\n await this.setClaudeAuthStates(accountId, url, false);\n return url;\n }\n\n /**\n * Create (once) and write the two `auth.<id>` states of one Claude account.\n *\n * @param accountId the id-safe account id\n * @param url the current sign-in URL (\"\" when signed in)\n * @param signedIn whether a usable sign-in exists\n */\n private async setClaudeAuthStates(accountId: string, url: string, signedIn: boolean): Promise<void> {\n await this.extendObject(\"auth\", {\n type: \"folder\",\n common: { name: { en: \"Sign-in\", de: \"Anmeldung\" } },\n native: {},\n });\n await this.extendObject(`auth.${accountId}`, {\n type: \"channel\",\n common: { name: accountId },\n native: {},\n });\n await this.extendObject(`auth.${accountId}.signInUrl`, {\n type: \"state\",\n common: {\n name: { en: \"Sign-in link\", de: \"Anmelde-Link\" },\n type: \"string\",\n role: \"url\",\n read: true,\n write: false,\n def: \"\",\n },\n native: {},\n });\n await this.extendObject(`auth.${accountId}.signedIn`, {\n type: \"state\",\n common: {\n name: { en: \"Signed in\", de: \"Angemeldet\" },\n type: \"boolean\",\n role: \"indicator\",\n read: true,\n write: false,\n def: false,\n },\n native: {},\n });\n await this.setState(`auth.${accountId}.signInUrl`, { val: url, ack: true });\n await this.setState(`auth.${accountId}.signedIn`, { val: signedIn, ack: true });\n }\n\n /**\n * Prepare the guided sign-in of every Claude subscription account: publish the\n * live status, and for accounts without a usable sign-in a stable sign-in link.\n *\n * @param accounts the validated account configs\n */\n private async prepareClaudeAuth(accounts: AccountConfig[]): Promise<void> {\n const claudeAccounts = accounts.filter(a => a.provider === \"claude-sub\");\n // Remove sign-in channels of accounts that are gone (the account cleanup only\n // handles top-level account trees, not the shared auth folder).\n try {\n const wanted = new Set(claudeAccounts.map(a => a.id));\n const objects = await this.getAdapterObjectsAsync();\n const stale = new Set<string>();\n for (const id of Object.keys(objects)) {\n const relative = id.substring(this.namespace.length + 1);\n const [root, child] = relative.split(\".\");\n if (root === \"auth\" && child && !wanted.has(child)) {\n stale.add(child);\n }\n }\n for (const child of stale) {\n await this.delObjectAsync(`auth.${child}`, { recursive: true });\n }\n } catch {\n // cleanup only \u2014 never block startup\n }\n for (const account of claudeAccounts) {\n try {\n const tokens = await this.claudeTokenStore(account.id).load();\n if (tokens) {\n await this.setClaudeAuthStates(account.id, \"\", true);\n } else {\n await this.publishClaudeSignInUrl(account.id);\n }\n } catch (e) {\n this.log.warn(`${account.name}: cannot prepare sign-in (${e instanceof Error ? e.message : String(e)})`);\n }\n }\n }\n\n /**\n * The persistent token storage for one Claude account: an encrypted JSON file in\n * the instance data directory (a `native` write would restart the instance).\n *\n * @param accountId the id-safe account id\n * @returns the store\n */\n private claudeTokenStore(accountId: string): TokenStore {\n const dir = utils.getAbsoluteInstanceDataDir(this);\n const file = join(dir, `claude-tokens-${accountId}.json`);\n return {\n load: async (): Promise<TokenSet | null> => {\n try {\n const encrypted = await readFile(file, \"utf8\");\n const parsed = JSON.parse(this.decrypt(encrypted)) as Partial<TokenSet>;\n if (typeof parsed.accessToken !== \"string\" || typeof parsed.refreshToken !== \"string\") {\n return null;\n }\n return {\n accessToken: parsed.accessToken,\n refreshToken: parsed.refreshToken,\n expiresAt: Number(parsed.expiresAt) || 0,\n };\n } catch {\n return null; // never signed in (or unreadable) \u2014 the provider reports auth-required\n }\n },\n save: async (tokens: TokenSet): Promise<void> => {\n await mkdir(dir, { recursive: true });\n await writeFile(file, this.encrypt(JSON.stringify(tokens)), \"utf8\");\n },\n };\n }\n\n /** Validate the configuration, clean up stale account trees and start the engine. */\n private async onReady(): Promise<void> {\n try {\n const accounts = parseAccounts(this.config.accounts);\n const interval = clampPollInterval(this.config.pollInterval);\n await this.cleanupStaleAccounts();\n await this.prepareClaudeAuth(accounts);\n if (accounts.length === 0) {\n this.log.info(\"No AI accounts configured \u2014 add accounts in the instance settings\");\n await this.setState(\"info.connection\", { val: false, ack: true });\n return;\n }\n const providers = new Map<string, UsageProvider>();\n for (const account of accounts) {\n const provider = await this.makeProvider(account);\n if (provider) {\n providers.set(account.id, provider);\n }\n }\n this.engine = new PollEngine(accounts, providers, interval, {\n upsertObject: async def => {\n await this.extendObject(def.id, { type: def.type, common: def.common as ioBroker.ObjectCommon, native: {} });\n },\n setState: (id, value) => {\n void this.setState(id, { val: value, ack: true }).catch(() => {\n /* states DB going down \u2014 never crash the poll loop */\n });\n },\n schedule: (cb, ms): TimerHandle => ({ kind: \"interval\", handle: this.setInterval(cb, ms) }),\n scheduleOnce: (cb, ms): TimerHandle => ({ kind: \"timeout\", handle: this.setTimeout(cb, ms) }),\n cancel: handle => {\n const timer = handle as TimerHandle;\n if (timer.kind === \"interval\") {\n this.clearInterval(timer.handle);\n } else {\n this.clearTimeout(timer.handle);\n }\n },\n now: () => Date.now(),\n log: {\n debug: m => this.log.debug(m),\n info: m => this.log.info(m),\n warn: m => this.log.warn(m),\n error: m => this.log.error(m),\n },\n notify: this.config.notifications\n ? (_account, message) =>\n void this.registerNotification(\"ai-usage\", \"userActionRequired\", message).catch(e =>\n this.log.debug(`Could not raise notification: ${e instanceof Error ? e.message : String(e)}`),\n )\n : undefined,\n });\n await this.engine.start();\n this.log.info(`Monitoring ${providers.size} of ${accounts.length} AI account(s), polling every ${interval} s`);\n } catch (e) {\n this.log.error(`Startup failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n /**\n * Build the provider for one account, resolving its credential from the central\n * storage. Accounts whose provider is not implemented yet, or whose credential\n * cannot be read, are skipped (the engine logs the skip).\n *\n * @param account the validated account config\n * @returns the provider, or undefined to skip the account\n */\n private async makeProvider(account: AccountConfig): Promise<UsageProvider | undefined> {\n switch (account.provider) {\n case \"claude-sub\":\n return claudeSubProvider(this.claudeTokenStore(account.id), undefined, postJson);\n case \"openrouter\": {\n const key = await this.resolveKey(account);\n return key ? openRouterProvider(key) : undefined;\n }\n case \"deepseek\": {\n const key = await this.resolveKey(account);\n return key ? deepSeekProvider(key) : undefined;\n }\n case \"openai\": {\n const key = await this.resolveKey(account);\n return key ? openAiProvider(key) : undefined;\n }\n case \"anthropic-api\": {\n const key = await this.resolveKey(account);\n return key ? anthropicApiProvider(key) : undefined;\n }\n default:\n return undefined;\n }\n }\n\n /**\n * Read and decrypt a key-form credential from the central credential storage.\n *\n * @param account the account whose credential to resolve\n * @returns the key, or undefined (with a log line) when it cannot be read\n */\n private async resolveKey(account: AccountConfig): Promise<string | undefined> {\n if (!account.credentialId) {\n this.log.warn(`${account.name}: no credential selected \u2014 pick one in the instance settings`);\n return undefined;\n }\n try {\n const credential = await Credentials.getCredentials(this, account.credentialId);\n const values = credential.values as { key?: unknown; password?: unknown };\n const key = typeof values.key === \"string\" && values.key ? values.key : undefined;\n if (!key) {\n this.log.warn(`${account.name}: credential ${account.credentialId} carries no API key`);\n }\n return key;\n } catch (e) {\n this.log.warn(\n `${account.name}: cannot read credential ${account.credentialId} (${e instanceof Error ? e.message : String(e)})`,\n );\n return undefined;\n }\n }\n\n /**\n * Delete the object trees of accounts that are no longer in the table. Disabled\n * rows keep their tree (they are only paused); an EMPTY table deletes nothing \u2014\n * the guard against wiping everything through an accidental clear.\n */\n private async cleanupStaleAccounts(): Promise<void> {\n const keepIds = validAccountIds(this.config.accounts);\n if (keepIds.length === 0) {\n return;\n }\n const keep = new Set([...keepIds, \"info\", \"total\", \"auth\"]);\n try {\n const objects = await this.getAdapterObjectsAsync();\n const roots = new Set<string>();\n for (const id of Object.keys(objects)) {\n const relative = id.substring(this.namespace.length + 1);\n const root = relative.split(\".\")[0];\n if (root && !keep.has(root)) {\n roots.add(root);\n }\n }\n for (const root of roots) {\n this.log.info(`Removing objects of no longer configured account \"${root}\"`);\n await this.delObjectAsync(root, { recursive: true });\n }\n } catch (e) {\n this.log.warn(`Cleanup of stale accounts failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n /**\n * Tear down synchronously \u2014 no async/await here, else the controller kills the\n * process before cleanup finishes.\n *\n * @param callback invoked when cleanup is done\n */\n private onUnload(callback: () => void): void {\n try {\n this.engine?.stop();\n this.engine = null;\n void this.setState(\"info.connection\", { val: false, ack: true });\n } catch {\n // never block shutdown\n }\n callback();\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new AiUsageAdapter(options);\n} else {\n (() => new AiUsageAdapter())();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import * as utils from \"@iobroker/adapter-core\";\nimport { Credentials } from \"@iobroker/adapter-core\";\nimport { mkdir, readFile, rename, unlink, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { postForm, postJson } from \"./lib/http\";\nimport { PollEngine } from \"./lib/poll-engine\";\nimport {\n clampPollInterval,\n parseAccounts,\n SUBSCRIPTION_IDS,\n validAccountIds,\n type AccountConfig,\n} from \"./lib/pure-helpers\";\nimport type { TokenSet, TokenStore, UsageProvider } from \"./lib/provider\";\nimport { SIGN_IN_FLOWS, attemptExpired, type SignInState } from \"./lib/sign-in\";\nimport { buildAuthorizeUrl, exchangeCode, generatePkce, type PkcePair } from \"./lib/providers/claude-auth\";\nimport { claudeSubProvider } from \"./lib/providers/claude-sub\";\nimport {\n exchangeDeviceCode,\n pollDeviceCode,\n startDeviceCode,\n type DeviceCodeStart,\n} from \"./lib/providers/chatgpt-auth\";\nimport { chatgptSubProvider } from \"./lib/providers/chatgpt-sub\";\nimport {\n buildGeminiAuthorizeUrl,\n exchangeGeminiCode,\n extractGeminiCode,\n generateGeminiPkce,\n type GeminiPkce,\n} from \"./lib/providers/gemini-auth\";\nimport { geminiSubProvider } from \"./lib/providers/gemini-sub\";\nimport { anthropicApiProvider } from \"./lib/providers/anthropic-api\";\nimport { deepSeekProvider } from \"./lib/providers/deepseek\";\nimport { openAiProvider } from \"./lib/providers/openai\";\nimport { openRouterProvider } from \"./lib/providers/openrouter\";\n\n/** A cancellable handle: interval or timeout \u2014 the engine treats them uniformly. */\ntype TimerHandle =\n | { kind: \"interval\"; handle: ioBroker.Interval | undefined }\n | { kind: \"timeout\"; handle: ioBroker.Timeout | undefined };\n\n/** One running sign-in attempt (secrets live in memory only, never on disk). */\ntype Attempt =\n | { flow: \"paste-code\"; pkce: PkcePair; url: string; expiresAt: number }\n | { flow: \"paste-url\"; pkce: GeminiPkce; url: string; expiresAt: number }\n | { flow: \"device-code\"; start: DeviceCodeStart };\n\n/**\n * AI Usage adapter \u2014 reads usage windows, credits and costs of AI accounts into\n * read-only states. Three subscriptions sign in with the user's own account\n * (Claude, ChatGPT, Google), the other accounts use a key from the admin's central\n * credential storage. Orchestration lives in the unit-tested {@link PollEngine};\n * this class wires ioBroker IO, the sign-in flows and the token files to it.\n */\nexport class AiUsageAdapter extends utils.Adapter {\n private engine: PollEngine | null = null;\n /** Running sign-in attempts, keyed by provider kind. */\n private readonly attempts = new Map<string, Attempt>();\n /** Last failure reason per provider, shown in the admin row. */\n private readonly signInErrors = new Map<string, string>();\n /** Device-code pollers, so they can be stopped on unload. */\n private readonly devicePollers = new Map<string, TimerHandle>();\n\n /**\n * @param options the adapter options\n */\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({ ...options, name: \"ai-usage\" });\n this.on(\"ready\", this.onReady.bind(this));\n this.on(\"message\", this.onMessage.bind(this));\n this.on(\"unload\", this.onUnload.bind(this));\n }\n\n // ---------------------------------------------------------------- sign-in\n\n /**\n * Handle admin messages: the three sign-in flows plus their status.\n *\n * @param obj the message\n */\n private async onMessage(obj: ioBroker.Message): Promise<void> {\n try {\n const provider = this.providerFrom(obj.message);\n switch (obj.command) {\n case \"signInStart\":\n this.respond(obj, provider ? await this.startSignIn(provider) : { error: \"unknown provider\" });\n return;\n case \"signInSubmit\":\n this.respond(obj, provider ? await this.submitSignIn(provider, obj.message) : { error: \"unknown provider\" });\n return;\n case \"signInStatus\":\n this.respond(obj, provider ? await this.signInState(provider) : { error: \"unknown provider\" });\n return;\n case \"signOut\":\n this.respond(obj, provider ? await this.signOut(provider) : { error: \"unknown provider\" });\n return;\n default:\n // Always answer, or the caller's callback dangles until timeout.\n this.respond(obj, { error: `Unknown command: ${obj.command}` });\n }\n } catch (e) {\n this.log.error(`onMessage failed: ${e instanceof Error ? e.message : String(e)}`);\n this.respond(obj, { error: \"internal error \u2014 see log\" });\n }\n }\n\n /**\n * Send a message response, when the caller expects one.\n *\n * @param obj the request message\n * @param response the response payload\n */\n private respond(obj: ioBroker.Message, response: unknown): void {\n if (obj.callback) {\n this.sendTo(obj.from, obj.command, response, obj.callback);\n }\n }\n\n /**\n * The provider kind named in a message, if it is a subscription we know.\n *\n * @param message the message payload ({ provider })\n * @returns the provider kind, or undefined\n */\n private providerFrom(message: unknown): string | undefined {\n const value =\n typeof (message as { provider?: unknown })?.provider === \"string\"\n ? (message as { provider: string }).provider\n : \"\";\n return SIGN_IN_FLOWS[value] ? value : undefined;\n }\n\n /**\n * Begin a sign-in: build the link (Claude/Google) or fetch a device code (ChatGPT).\n *\n * @param provider the subscription kind\n * @returns what the admin panel has to show\n */\n private async startSignIn(provider: string): Promise<SignInState | { error: string }> {\n this.signInErrors.delete(provider);\n this.stopDevicePoller(provider);\n const flow = SIGN_IN_FLOWS[provider];\n const now = Date.now();\n try {\n if (flow === \"paste-code\") {\n const pkce = generatePkce();\n const url = buildAuthorizeUrl(pkce);\n this.attempts.set(provider, { flow, pkce, url, expiresAt: now + 15 * 60_000 });\n return { status: \"awaiting-paste\", url, flow };\n }\n if (flow === \"paste-url\") {\n const pkce = generateGeminiPkce();\n const url = buildGeminiAuthorizeUrl(pkce);\n this.attempts.set(provider, { flow, pkce, url, expiresAt: now + 15 * 60_000 });\n return { status: \"awaiting-paste\", url, flow };\n }\n const start = await startDeviceCode(postJson, now);\n this.attempts.set(provider, { flow: \"device-code\", start });\n this.armDevicePoller(provider, start);\n return {\n status: \"awaiting-device\",\n userCode: start.userCode,\n verificationUrl: \"https://auth.openai.com/codex/device\",\n expiresAt: start.expiresAt,\n };\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.signInErrors.set(provider, reason);\n return { status: \"failed\", reason };\n }\n }\n\n /**\n * Finish a paste-based sign-in (Claude code, Google address).\n *\n * @param provider the subscription kind\n * @param message the message payload ({ value })\n * @returns the resulting state\n */\n private async submitSignIn(provider: string, message: unknown): Promise<SignInState> {\n const attempt = this.attempts.get(provider);\n const value =\n typeof (message as { value?: unknown })?.value === \"string\" ? (message as { value: string }).value.trim() : \"\";\n if (!attempt || attempt.flow === \"device-code\") {\n return { status: \"failed\", reason: \"start the sign-in first\" };\n }\n if (!value) {\n return { status: \"failed\", reason: \"nothing pasted\" };\n }\n try {\n const now = Date.now();\n const tokens =\n attempt.flow === \"paste-code\"\n ? await exchangeCode(value, attempt.pkce, postJson, now)\n : await exchangeGeminiCode(extractGeminiCode(value, attempt.pkce.state), attempt.pkce, postForm, now);\n await this.finishSignIn(provider, tokens);\n return { status: \"signed-in\" };\n } catch (e) {\n const reason = e instanceof Error ? e.message : String(e);\n this.signInErrors.set(provider, reason);\n return { status: \"failed\", reason };\n }\n }\n\n /**\n * Store fresh tokens, mark the account signed in and poll it right away \u2014 waiting\n * up to a full interval after a successful sign-in reads as \"it did not work\".\n *\n * @param provider the subscription kind\n * @param tokens the token set\n */\n private async finishSignIn(provider: string, tokens: TokenSet): Promise<void> {\n await this.tokenStore(provider).save(tokens);\n this.attempts.delete(provider);\n this.signInErrors.delete(provider);\n this.stopDevicePoller(provider);\n const id = SUBSCRIPTION_IDS[provider];\n if (id) {\n await this.setSignedInState(id, true);\n await this.engine?.pollNow(id);\n }\n this.log.info(`${provider}: signed in`);\n }\n\n /**\n * Poll the device-code endpoint until the user confirmed, the window closed or\n * the adapter stops. The handle lives in memory only \u2014 a restart mid-flow just\n * means the user starts again, which is cheaper than persisting a 15-minute secret.\n *\n * @param provider the subscription kind\n * @param start the device-code handle\n */\n private armDevicePoller(provider: string, start: DeviceCodeStart): void {\n const tick = async (): Promise<void> => {\n try {\n if (attemptExpired(start.expiresAt, Date.now())) {\n this.stopDevicePoller(provider);\n this.attempts.delete(provider);\n this.signInErrors.set(provider, \"the code expired \u2014 start the sign-in again\");\n return;\n }\n const result = await pollDeviceCode(start, postJson);\n if (result.status === \"ready\") {\n this.stopDevicePoller(provider);\n const tokens = await exchangeDeviceCode(result.code, result.codeVerifier, postForm, Date.now());\n await this.finishSignIn(provider, tokens);\n }\n } catch (e) {\n this.stopDevicePoller(provider);\n this.attempts.delete(provider);\n this.signInErrors.set(provider, e instanceof Error ? e.message : String(e));\n }\n };\n this.devicePollers.set(provider, {\n kind: \"interval\",\n handle: this.setInterval(() => void tick(), Math.max(start.intervalSec, 1) * 1000),\n });\n }\n\n /**\n * Stop a running device-code poller.\n *\n * @param provider the subscription kind\n */\n private stopDevicePoller(provider: string): void {\n const handle = this.devicePollers.get(provider);\n if (handle?.kind === \"interval\") {\n this.clearInterval(handle.handle);\n }\n this.devicePollers.delete(provider);\n }\n\n /**\n * The current sign-in state of one subscription, for the admin row.\n *\n * @param provider the subscription kind\n * @returns the state\n */\n private async signInState(provider: string): Promise<SignInState> {\n const failure = this.signInErrors.get(provider);\n const attempt = this.attempts.get(provider);\n if (attempt?.flow === \"device-code\") {\n return {\n status: \"awaiting-device\",\n userCode: attempt.start.userCode,\n verificationUrl: \"https://auth.openai.com/codex/device\",\n expiresAt: attempt.start.expiresAt,\n };\n }\n if (attempt) {\n return { status: \"awaiting-paste\", url: attempt.url, flow: attempt.flow };\n }\n if (failure) {\n return { status: \"failed\", reason: failure };\n }\n return (await this.tokenStore(provider).load()) ? { status: \"signed-in\" } : { status: \"signed-out\" };\n }\n\n /**\n * Forget the tokens of one subscription.\n *\n * @param provider the subscription kind\n * @returns the resulting state\n */\n private async signOut(provider: string): Promise<SignInState> {\n await this.tokenStore(provider).clear();\n this.attempts.delete(provider);\n this.signInErrors.delete(provider);\n this.stopDevicePoller(provider);\n const id = SUBSCRIPTION_IDS[provider];\n if (id) {\n await this.setSignedInState(id, false);\n }\n return { status: \"signed-out\" };\n }\n\n // ------------------------------------------------------------ token files\n\n /**\n * Where one subscription's tokens live: an encrypted file in the instance data\n * directory, named after the PROVIDER. Keying by provider (not by account name)\n * keeps a sign-in alive when an account is renamed \u2014 the previous scheme lost it.\n *\n * @param provider the subscription kind\n * @returns the store\n */\n private tokenStore(provider: string): TokenStore {\n const dir = utils.getAbsoluteInstanceDataDir(this);\n const file = join(dir, `tokens-${provider}.json`);\n return {\n load: async (): Promise<TokenSet | null> => {\n try {\n const parsed = JSON.parse(this.decrypt(await readFile(file, \"utf8\"))) as Partial<TokenSet>;\n if (typeof parsed.accessToken !== \"string\" || typeof parsed.refreshToken !== \"string\") {\n return null;\n }\n return {\n accessToken: parsed.accessToken,\n refreshToken: parsed.refreshToken,\n expiresAt: Number(parsed.expiresAt) || 0,\n accountRef: typeof parsed.accountRef === \"string\" ? parsed.accountRef : undefined,\n };\n } catch {\n return null; // never signed in (or unreadable) \u2014 the provider reports auth-required\n }\n },\n save: async (tokens: TokenSet): Promise<void> => {\n await mkdir(dir, { recursive: true });\n await writeFile(file, this.encrypt(JSON.stringify(tokens)), \"utf8\");\n },\n clear: async (): Promise<void> => {\n await unlink(file).catch(() => {\n /* already gone */\n });\n },\n };\n }\n\n /**\n * Carry a sign-in from the pre-0.3.0 layout over: tokens used to be stored per\n * ACCOUNT NAME (`claude-tokens-<name>.json`). Without this the rename to fixed\n * account ids would silently sign the user out.\n */\n private async migrateTokenFiles(): Promise<void> {\n const dir = utils.getAbsoluteInstanceDataDir(this);\n const target = join(dir, \"tokens-claude-sub.json\");\n try {\n await readFile(target, \"utf8\");\n return; // already migrated\n } catch {\n // not there yet \u2014 look for an old file\n }\n for (const legacy of [\"claude-tokens-Claude.json\", \"claude-tokens-claude.json\"]) {\n try {\n await rename(join(dir, legacy), target);\n this.log.info(\"Carried the existing Claude sign-in over to the new layout\");\n return;\n } catch {\n // try the next candidate\n }\n }\n }\n\n // ------------------------------------------------------------- life cycle\n\n /** Validate the configuration, clean up stale objects and start the engine. */\n private async onReady(): Promise<void> {\n try {\n const accounts = parseAccounts(this.config.accounts);\n const interval = clampPollInterval(this.config.pollInterval);\n await this.migrateTokenFiles();\n await this.cleanupStaleObjects();\n if (accounts.length === 0) {\n this.log.info(\"No AI accounts configured \u2014 add accounts in the instance settings\");\n await this.setState(\"info.connection\", { val: false, ack: true });\n return;\n }\n const providers = new Map<string, UsageProvider>();\n for (const account of accounts) {\n const provider = await this.makeProvider(account);\n if (provider) {\n providers.set(account.id, provider);\n }\n }\n this.engine = new PollEngine(accounts, providers, interval, {\n upsertObject: async def => {\n await this.extendObject(def.id, { type: def.type, common: def.common as ioBroker.ObjectCommon, native: {} });\n },\n setState: (id, value) => {\n void this.setState(id, { val: value, ack: true }).catch(() => {\n /* states DB going down \u2014 never crash the poll loop */\n });\n },\n schedule: (cb, ms): TimerHandle => ({ kind: \"interval\", handle: this.setInterval(cb, ms) }),\n scheduleOnce: (cb, ms): TimerHandle => ({ kind: \"timeout\", handle: this.setTimeout(cb, ms) }),\n cancel: handle => {\n const timer = handle as TimerHandle;\n if (timer.kind === \"interval\") {\n this.clearInterval(timer.handle);\n } else {\n this.clearTimeout(timer.handle);\n }\n },\n now: () => Date.now(),\n log: {\n debug: m => this.log.debug(m),\n info: m => this.log.info(m),\n warn: m => this.log.warn(m),\n error: m => this.log.error(m),\n },\n notify: this.config.notifications\n ? (_account, message) =>\n void this.registerNotification(\"ai-usage\", \"userActionRequired\", message).catch(e =>\n this.log.debug(`Could not raise notification: ${e instanceof Error ? e.message : String(e)}`),\n )\n : undefined,\n });\n await this.engine.start();\n await this.publishSignedInStates(accounts);\n this.log.info(`Monitoring ${providers.size} of ${accounts.length} AI account(s), polling every ${interval} s`);\n } catch (e) {\n this.log.error(`Startup failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n /**\n * Build the provider for one account.\n *\n * @param account the validated account config\n * @returns the provider, or undefined to skip the account\n */\n private async makeProvider(account: AccountConfig): Promise<UsageProvider | undefined> {\n switch (account.provider) {\n case \"claude-sub\":\n return claudeSubProvider(this.tokenStore(account.provider), undefined, postJson);\n case \"chatgpt-sub\":\n return chatgptSubProvider(this.tokenStore(account.provider), undefined, postJson);\n case \"gemini-sub\":\n return geminiSubProvider(this.tokenStore(account.provider), postJson, postForm);\n case \"openrouter\": {\n const key = await this.resolveKey(account);\n return key ? openRouterProvider(key) : undefined;\n }\n case \"deepseek\": {\n const key = await this.resolveKey(account);\n return key ? deepSeekProvider(key) : undefined;\n }\n case \"openai\": {\n const key = await this.resolveKey(account);\n return key ? openAiProvider(key) : undefined;\n }\n case \"anthropic-api\": {\n const key = await this.resolveKey(account);\n return key ? anthropicApiProvider(key) : undefined;\n }\n default:\n return undefined;\n }\n }\n\n /**\n * Read and decrypt a key-form credential from the central credential storage.\n *\n * @param account the account whose credential to resolve\n * @returns the key, or undefined (with a log line) when it cannot be read\n */\n private async resolveKey(account: AccountConfig): Promise<string | undefined> {\n if (!account.credentialId) {\n this.log.warn(`${account.name}: no credential selected \u2014 pick one in the instance settings`);\n return undefined;\n }\n try {\n const credential = await Credentials.getCredentials(this, account.credentialId);\n const values = credential.values as { key?: unknown };\n const key = typeof values.key === \"string\" && values.key ? values.key : undefined;\n if (!key) {\n this.log.warn(`${account.name}: credential ${account.credentialId} carries no API key`);\n }\n return key;\n } catch (e) {\n this.log.warn(\n `${account.name}: cannot read credential ${account.credentialId} (${e instanceof Error ? e.message : String(e)})`,\n );\n return undefined;\n }\n }\n\n /**\n * Create and write `<account>.info.signedIn` for every subscription in the table.\n *\n * @param accounts the configured accounts\n */\n private async publishSignedInStates(accounts: readonly AccountConfig[]): Promise<void> {\n for (const account of accounts) {\n if (!SIGN_IN_FLOWS[account.provider]) {\n continue;\n }\n const tokens = await this.tokenStore(account.provider).load();\n await this.setSignedInState(account.id, !!tokens);\n }\n }\n\n /**\n * Write the sign-in indicator INSIDE the account node \u2014 the pre-0.3.0 layout kept\n * a second `auth.<name>` branch, which showed every subscription twice in the tree.\n *\n * @param accountId the account's object id\n * @param signedIn whether a usable sign-in exists\n */\n private async setSignedInState(accountId: string, signedIn: boolean): Promise<void> {\n await this.extendObject(`${accountId}.info.signedIn`, {\n type: \"state\",\n common: {\n name: { en: \"Signed in\", de: \"Angemeldet\" },\n type: \"boolean\",\n role: \"indicator\",\n read: true,\n write: false,\n def: false,\n },\n native: {},\n });\n await this.setState(`${accountId}.info.signedIn`, { val: signedIn, ack: true });\n }\n\n /**\n * Delete object trees that no longer belong to a configured account, plus the\n * `auth` branch of the pre-0.3.0 layout. An EMPTY table deletes nothing \u2014 the\n * guard against wiping everything through an accidental clear.\n */\n private async cleanupStaleObjects(): Promise<void> {\n const keepIds = validAccountIds(this.config.accounts);\n if (keepIds.length === 0) {\n return;\n }\n const keep = new Set([...keepIds, \"info\", \"total\"]);\n try {\n const objects = await this.getAdapterObjectsAsync();\n const roots = new Set<string>();\n for (const id of Object.keys(objects)) {\n const root = id.substring(this.namespace.length + 1).split(\".\")[0];\n if (root && !keep.has(root)) {\n roots.add(root);\n }\n }\n for (const root of roots) {\n this.log.info(\n root === \"auth\"\n ? \"Removing the old sign-in branch \u2014 the sign-in state now lives inside each account\"\n : `Removing objects of no longer configured account \"${root}\"`,\n );\n await this.delObjectAsync(root, { recursive: true });\n }\n } catch (e) {\n this.log.warn(`Cleanup of stale objects failed: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n /**\n * Tear down synchronously \u2014 no async/await here, else the controller kills the\n * process before cleanup finishes.\n *\n * @param callback invoked when cleanup is done\n */\n private onUnload(callback: () => void): void {\n try {\n for (const provider of [...this.devicePollers.keys()]) {\n this.stopDevicePoller(provider);\n }\n this.engine?.stop();\n this.engine = null;\n void this.setState(\"info.connection\", { val: false, ack: true });\n } catch {\n // never block shutdown\n }\n callback();\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new AiUsageAdapter(options);\n} else {\n (() => new AiUsageAdapter())();\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "ai-usage",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.3.0": {
|
|
7
|
+
"en": "Three subscriptions instead of one: Claude, ChatGPT and Google/Gemini each with their own guided sign-in; ChatGPT and Gemini could not be tested on a live account yet",
|
|
8
|
+
"de": "Drei Abos statt einem: Claude, ChatGPT und Google/Gemini mit je eigener geführter Anmeldung; ChatGPT und Gemini konnten noch an keinem echten Konto getestet werden",
|
|
9
|
+
"ru": "Три подписки вместо одной: Claude, ChatGPT и Google/Gemini, у каждой свой пошаговый вход; ChatGPT и Gemini пока не проверены на реальном аккаунте",
|
|
10
|
+
"pt": "Três subscrições em vez de uma: Claude, ChatGPT e Google/Gemini, cada uma com o seu início de sessão guiado; ChatGPT e Gemini ainda não foram testados numa conta real",
|
|
11
|
+
"nl": "Drie abonnementen in plaats van één: Claude, ChatGPT en Google/Gemini, elk met een eigen begeleide aanmelding; ChatGPT en Gemini zijn nog niet op een echt account getest",
|
|
12
|
+
"fr": "Trois abonnements au lieu d'un : Claude, ChatGPT et Google/Gemini, chacun avec sa connexion guidée ; ChatGPT et Gemini n'ont pas encore été testés sur un compte réel",
|
|
13
|
+
"it": "Tre abbonamenti invece di uno: Claude, ChatGPT e Google/Gemini, ognuno con il proprio accesso guidato; ChatGPT e Gemini non sono ancora stati testati su un account reale",
|
|
14
|
+
"es": "Tres suscripciones en lugar de una: Claude, ChatGPT y Google/Gemini, cada una con su inicio de sesión guiado; ChatGPT y Gemini aún no se han probado en una cuenta real",
|
|
15
|
+
"pl": "Trzy subskrypcje zamiast jednej: Claude, ChatGPT i Google/Gemini, każda z własnym prowadzonym logowaniem; ChatGPT i Gemini nie zostały jeszcze sprawdzone na prawdziwym koncie",
|
|
16
|
+
"uk": "Три підписки замість однієї: Claude, ChatGPT і Google/Gemini, кожна зі своїм покроковим входом; ChatGPT і Gemini ще не перевірені на справжньому обліковому записі",
|
|
17
|
+
"zh-cn": "三个订阅而不是一个:Claude、ChatGPT 和 Google/Gemini 各有自己的引导式登录;ChatGPT 和 Gemini 尚未在真实账户上测试"
|
|
18
|
+
},
|
|
6
19
|
"0.2.0": {
|
|
7
20
|
"en": "Completely new settings page: your stored AI credentials as simple on/off switches, and a reliable guided Claude sign-in",
|
|
8
21
|
"de": "Komplett neue Einstellungs-Seite: gespeicherte KI-Zugänge als einfache An/Aus-Schalter und eine zuverlässige geführte Claude-Anmeldung",
|
|
@@ -44,17 +57,17 @@
|
|
|
44
57
|
"zh-cn": "AI Usage"
|
|
45
58
|
},
|
|
46
59
|
"desc": {
|
|
47
|
-
"en": "Monitors usage, limits and costs of AI accounts (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
48
|
-
"de": "Überwacht Verbrauch, Limits und Kosten von KI-Konten (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
49
|
-
"ru": "Отслеживает использование, лимиты и расходы аккаунтов ИИ (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
50
|
-
"pt": "Monitora uso, limites e custos de contas de IA (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
51
|
-
"nl": "Bewaakt verbruik, limieten en kosten van AI-accounts (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
52
|
-
"fr": "Surveille l'utilisation, les limites et les coûts des comptes IA (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
53
|
-
"it": "Monitora utilizzo, limiti e costi degli account IA (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
54
|
-
"es": "Supervisa el uso, los límites y los costes de las cuentas de IA (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
55
|
-
"pl": "Monitoruje zużycie, limity i koszty kont AI (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
56
|
-
"uk": "Відстежує використання, ліміти та витрати акаунтів ШІ (Claude, OpenAI, OpenRouter, DeepSeek)",
|
|
57
|
-
"zh-cn": "监控 AI 账户的使用量、限额和费用(Claude、OpenAI、OpenRouter、DeepSeek)"
|
|
60
|
+
"en": "Monitors usage, limits and costs of AI accounts (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
61
|
+
"de": "Überwacht Verbrauch, Limits und Kosten von KI-Konten (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
62
|
+
"ru": "Отслеживает использование, лимиты и расходы аккаунтов ИИ (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
63
|
+
"pt": "Monitora uso, limites e custos de contas de IA (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
64
|
+
"nl": "Bewaakt verbruik, limieten en kosten van AI-accounts (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
65
|
+
"fr": "Surveille l'utilisation, les limites et les coûts des comptes IA (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
66
|
+
"it": "Monitora utilizzo, limiti e costi degli account IA (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
67
|
+
"es": "Supervisa el uso, los límites y los costes de las cuentas de IA (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
68
|
+
"pl": "Monitoruje zużycie, limity i koszty kont AI (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
69
|
+
"uk": "Відстежує використання, ліміти та витрати акаунтів ШІ (Claude, ChatGPT, Gemini, OpenAI, Anthropic, OpenRouter, DeepSeek)",
|
|
70
|
+
"zh-cn": "监控 AI 账户的使用量、限额和费用(Claude、ChatGPT、Gemini、OpenAI、Anthropic、OpenRouter、DeepSeek)"
|
|
58
71
|
},
|
|
59
72
|
"keywords": [
|
|
60
73
|
"ai",
|
|
@@ -62,7 +75,10 @@
|
|
|
62
75
|
"limits",
|
|
63
76
|
"costs",
|
|
64
77
|
"claude",
|
|
78
|
+
"chatgpt",
|
|
79
|
+
"gemini",
|
|
65
80
|
"openai",
|
|
81
|
+
"anthropic",
|
|
66
82
|
"openrouter",
|
|
67
83
|
"deepseek",
|
|
68
84
|
"monitoring"
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./ConfigPanel-qivVprTj.js";var t={ConfigPanel:e};export{t as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_json_mf_2_config__loadShare__.js-qu1s07FY.js";import{Br as t,Dr as n,Er as r,Fi as i,Ha as a,Hi as o,Or as s,Ti as c,Tr as l,Va as u,Xr as d,_o as f,ai as p,ei as m,ga as h,ii as g,in as _,kr as v,li as y,ni as b,oi as x}from"./_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DwHNIjSR.js";f();var S=`Claude`,C={openrouter:`OpenRouter`,deepseek:`DeepSeek`,openai:`OpenAI`,"anthropic-api":`Anthropic`};function w(e,t){let n=`${e} ${t}`.toLowerCase();return n.includes(`gemini`)?`unsupported`:n.includes(`anthropic`)?`anthropic-api`:n.includes(`chatgpt`)||n.includes(`openai`)?`openai`:n.includes(`deepseek`)?`deepseek`:n.includes(`openrouter`)||n.includes(`router`)?`openrouter`:null}var T=class extends e{constructor(e){super(e),h(this,`urlId`,``),h(this,`connId`,``),h(this,`onUrl`,(e,t)=>{this.setState({claudeUrl:typeof(t==null?void 0:t.val)==`string`?t.val:``})}),h(this,`onConn`,(e,t)=>{this.setState({claudeSignedIn:(t==null?void 0:t.val)===!0})}),this.state={...this.state,credentials:[],credentialsLoaded:!1,claudeUrl:``,claudeSignedIn:!1,code:``,busy:!1,message:null,providerChoice:{}}}async componentDidMount(){var e;(e=super.componentDidMount)==null||e.call(this);let t=this.props.oContext,n=`${t.adapterName}.${t.instance}`;this.urlId=`${n}.auth.${S}.signInUrl`,this.connId=`${n}.auth.${S}.signedIn`;try{let e=await t.socket.getObjectViewSystem(`config`,`system.credentials.`,`system.credentials.香`),n=Object.values(e||{}).filter(e=>{var t;return!!e&&((t=e.native)==null?void 0:t.type)===`ai`}).map(e=>{var t,n;let r=e._id.substring(19),i=(t=e.common)==null?void 0:t.name,a=typeof i==`string`?i:(i==null?void 0:i.en)||Object.values(i||{})[0]||r;return{id:e._id,suffix:r,name:a,icon:typeof((n=e.common)==null?void 0:n.icon)==`string`?e.common.icon:void 0,guess:w(r,a)}}).sort((e,t)=>e.name.localeCompare(t.name));this.setState({credentials:n,credentialsLoaded:!0})}catch{this.setState({credentialsLoaded:!0})}try{let[e,n]=await Promise.all([t.socket.getState(this.urlId),t.socket.getState(this.connId)]);this.setState({claudeUrl:typeof(e==null?void 0:e.val)==`string`?e.val:``,claudeSignedIn:(n==null?void 0:n.val)===!0}),await t.socket.subscribeState(this.urlId,this.onUrl),await t.socket.subscribeState(this.connId,this.onConn)}catch{}}componentWillUnmount(){var e,t;let n=(e=this.props.oContext)==null?void 0:e.socket;n&&this.urlId&&(n.unsubscribeState(this.urlId,this.onUrl),n.unsubscribeState(this.connId,this.onConn)),(t=super.componentWillUnmount)==null||t.call(this)}accounts(){let t=e.getValue(this.props.data,`accounts`);return Array.isArray(t)?t:[]}commit(e){this.onChange(`accounts`,e)}claudeEnabled(){return this.accounts().some(e=>e.provider===`claude-sub`)}toggleClaude(e){let t=this.accounts().filter(e=>e.provider!==`claude-sub`);e&&t.unshift({name:S,provider:`claude-sub`,credentialId:``,warnThreshold:80,enabled:!0}),this.commit(t)}toggleCredential(e,t){let n=this.accounts().filter(t=>t.credentialId!==e.id);if(t){let t=e.guess&&e.guess!==`unsupported`?e.guess:this.state.providerChoice[e.id];if(!t)return;n.push({name:e.name,provider:t,credentialId:e.id,warnThreshold:80,enabled:!0})}this.commit(n)}setThreshold(e,t){let n=Math.min(100,Math.max(10,Math.round(Number(t))||80));this.commit(this.accounts().map(t=>(e?t.credentialId===e:t.provider===`claude-sub`)?{...t,warnThreshold:n}:t))}async redeemCode(){let e=this.props.oContext;this.setState({busy:!0,message:null});try{let t=await e.socket.sendTo(`${e.adapterName}.${e.instance}`,`claudeAuthCode`,{account:S,code:this.state.code});(t==null?void 0:t.result)===`ok`?this.setState({busy:!1,code:``,message:{ok:!0,text:_.t(`aiu_signInDone`)}}):this.setState({busy:!1,message:{ok:!1,text:(t==null?void 0:t.error)||_.t(`aiu_signInFailed`)}})}catch{this.setState({busy:!1,message:{ok:!1,text:_.t(`aiu_instanceNotRunning`)}})}}async newLink(){let e=this.props.oContext;this.setState({busy:!0,message:null});try{await e.socket.sendTo(`${e.adapterName}.${e.instance}`,`claudeAuthStart`,{account:S}),this.setState({busy:!1})}catch{this.setState({busy:!1,message:{ok:!1,text:_.t(`aiu_instanceNotRunning`)}})}}renderThreshold(e,t){return u(d,{size:`small`,type:`number`,label:_.t(`aiu_warnAt`),defaultValue:t.warnThreshold||80,onBlur:t=>this.setThreshold(e,t.target.value),slotProps:{htmlInput:{min:10,max:100,style:{width:60}},inputLabel:{shrink:!0}},sx:{ml:`auto`}},`${e}-threshold`)}renderClaudeRow(){let e=this.claudeEnabled(),n=this.accounts().find(e=>e.provider===`claude-sub`);return a(b,{children:[a(b,{sx:{display:`flex`,alignItems:`center`,gap:1.5,py:1,borderBottom:1,borderColor:`divider`},children:[u(o,{sx:{width:28,height:28,bgcolor:`transparent`},children:u(l,{fontSize:`small`,color:`primary`})}),a(b,{sx:{minWidth:160},children:[u(m,{children:_.t(`aiu_claudeTitle`)}),u(m,{variant:`caption`,sx:{opacity:.7},children:_.t(`aiu_claudeCaption`)})]}),e&&n?this.renderThreshold(``,n):null,u(t,{checked:e,onChange:e=>this.toggleClaude(e.target.checked),sx:{ml:e?0:`auto`}})]}),e?u(b,{sx:{pl:6,py:1.5,borderBottom:1,borderColor:`divider`},children:this.renderClaudeAuth()}):null]},`claude-sub`)}renderClaudeAuth(){return this.state.claudeSignedIn?a(b,{sx:{display:`flex`,alignItems:`center`,gap:1,flexWrap:`wrap`},children:[u(v,{color:`success`}),u(m,{sx:{color:`success.main`},children:_.t(`aiu_signedIn`)}),u(g,{size:`small`,startIcon:u(r,{}),disabled:this.state.busy,onClick:()=>void this.newLink(),children:_.t(`aiu_signInAgain`)})]}):this.state.claudeUrl?a(b,{sx:{display:`flex`,flexDirection:`column`,gap:1.5},children:[u(m,{variant:`body2`,children:_.t(`aiu_step1`)}),a(b,{sx:{display:`flex`,gap:1,flexWrap:`wrap`},children:[u(g,{variant:`contained`,startIcon:u(n,{}),href:this.state.claudeUrl,target:`_blank`,rel:`noopener noreferrer`,children:_.t(`aiu_openSignIn`)}),u(g,{variant:`outlined`,startIcon:u(s,{}),onClick:()=>{var e;(e=navigator.clipboard)==null||e.writeText(this.state.claudeUrl)},children:_.t(`aiu_copyLink`)})]}),u(m,{variant:`body2`,children:_.t(`aiu_step2`)}),a(b,{sx:{display:`flex`,gap:1,alignItems:`center`,flexWrap:`wrap`},children:[u(d,{size:`small`,label:_.t(`aiu_codeLabel`),value:this.state.code,onChange:e=>this.setState({code:e.target.value}),sx:{minWidth:320}}),u(g,{variant:`contained`,disabled:!this.state.code.trim()||this.state.busy||!this.props.alive,onClick:()=>void this.redeemCode(),children:this.state.busy?u(y,{size:20}):_.t(`aiu_redeem`)})]}),this.props.alive?null:u(c,{severity:`warning`,children:_.t(`aiu_instanceNotRunning`)}),this.state.message?u(c,{severity:this.state.message.ok?`success`:`error`,children:this.state.message.text}):null]}):u(c,{severity:`info`,children:this.props.changed?_.t(`aiu_saveFirst`):_.t(`aiu_waitingForLink`)})}renderCredentialRow(e){let n=this.accounts().find(t=>t.credentialId===e.id),r=e.guess===`unsupported`,s=e.guess===null&&!n,c=(n==null?void 0:n.provider)||e.guess!==`unsupported`&&e.guess||this.state.providerChoice[e.id]||``;return a(b,{sx:{display:`flex`,alignItems:`center`,gap:1.5,py:1,borderBottom:1,borderColor:`divider`},children:[u(o,{src:e.icon,sx:{width:28,height:28,bgcolor:`transparent`},children:u(l,{fontSize:`small`})}),a(b,{sx:{minWidth:160},children:[u(m,{children:e.name}),u(m,{variant:`caption`,sx:{opacity:.7},children:r?_.t(`aiu_unsupported`):C[c]||``})]}),s?u(d,{select:!0,size:`small`,label:_.t(`aiu_provider`),value:this.state.providerChoice[e.id]||``,onChange:t=>this.setState({providerChoice:{...this.state.providerChoice,[e.id]:t.target.value}}),sx:{minWidth:160},children:Object.entries(C).map(([e,t])=>u(i,{value:e,children:t},e))}):null,n?this.renderThreshold(e.id,n):null,u(t,{checked:!!n,disabled:r||s&&!this.state.providerChoice[e.id],onChange:t=>this.toggleCredential(e,t.target.checked),sx:{ml:n?0:`auto`}})]},e.id)}renderItem(){let e=this.state.credentials.map(e=>({name:e.name,element:this.renderCredentialRow(e)}));return e.push({name:_.t(`aiu_claudeTitle`),element:this.renderClaudeRow()}),e.sort((e,t)=>e.name.localeCompare(t.name)),u(b,{"data-testid":`aiu-config`,sx:{maxWidth:720},children:u(p,{variant:`outlined`,children:a(x,{children:[u(m,{variant:`h6`,sx:{mb:.5},children:_.t(`aiu_storedTitle`)}),u(m,{variant:`body2`,sx:{opacity:.8,mb:1},children:_.t(`aiu_storedHint`)}),this.state.credentialsLoaded?e.map(e=>e.element):u(y,{size:24}),this.state.credentialsLoaded&&this.state.credentials.length===0?u(c,{severity:`info`,sx:{mt:1},children:_.t(`aiu_noCredentials`)}):null]})})})}};export{T as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./virtual_mf-exposes___mfe_internal__AiUsageComponentSet__customComponents_js-BZ-CVpVo.js";import"./virtual_mf-REMOTE_ENTRY_ID___mfe_internal__AiUsageComponentSet__customComponents_js-l7jtElkM.js";import{Ba as e,Qt as t,Sa as n,Va as r,Za as i,_o as a,in as o,ni as s,sn as c}from"./_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare___mf_0_iobroker_mf_1_gui_mf_2_components__loadShare__.js-DwHNIjSR.js";import{t as l}from"./_virtual_mf___mfe_internal__AiUsageComponentSet__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-C8-GjKo4.js";import{t as u}from"./ConfigPanel-qivVprTj.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})(),a();var d={aiu_claudeTitle:`Claude subscription`,aiu_signedIn:`Signed in`,aiu_signInAgain:`Sign in again`,aiu_saveFirst:`Save the settings first — the sign-in link will appear here.`,aiu_waitingForLink:`Waiting for the sign-in link from the instance …`,aiu_step1:`1. Open the sign-in page and log in with your Claude account.`,aiu_step2:`2. Copy the code shown on the last page and redeem it here.`,aiu_openSignIn:`Open sign-in page`,aiu_copyLink:`Copy link`,aiu_codeLabel:`Code`,aiu_redeem:`Redeem`,aiu_signInDone:`Signed in — usage data arrives with the next poll.`,aiu_signInFailed:`Sign-in failed`,aiu_instanceNotRunning:`The instance is not running — start it to sign in.`,aiu_storedTitle:`AI accounts`,aiu_storedHint:`Your centrally stored AI credentials plus the Claude subscription — switch on what to monitor. New keys are added under Settings → Credentials.`,aiu_noCredentials:`No AI credentials stored yet — add them in the admin settings under Credentials.`,aiu_unsupported:`No usage query available`,aiu_provider:`Provider`,aiu_warnAt:`Warn at %`,aiu_claudeCaption:`Subscription — signs in with your Claude account instead of a key`},f={aiu_claudeTitle:`Claude-Abo`,aiu_signedIn:`Angemeldet`,aiu_signInAgain:`Neu anmelden`,aiu_saveFirst:`Zuerst die Einstellungen speichern — der Anmelde-Link erscheint dann hier.`,aiu_waitingForLink:`Warte auf den Anmelde-Link der Instanz …`,aiu_step1:`1. Anmeldeseite öffnen und mit Ihrem Claude-Konto anmelden.`,aiu_step2:`2. Den Code der letzten Seite kopieren und hier einlösen.`,aiu_openSignIn:`Anmeldeseite öffnen`,aiu_copyLink:`Link kopieren`,aiu_codeLabel:`Code`,aiu_redeem:`Einlösen`,aiu_signInDone:`Angemeldet — die Verbrauchsdaten kommen mit der nächsten Abfrage.`,aiu_signInFailed:`Anmeldung fehlgeschlagen`,aiu_instanceNotRunning:`Die Instanz läuft nicht — zum Anmelden bitte starten.`,aiu_storedTitle:`KI-Konten`,aiu_storedHint:`Ihre zentral gespeicherten KI-Zugangsdaten plus das Claude-Abo — einschalten, was überwacht werden soll. Neue Schlüssel unter Einstellungen → Zugangsdaten.`,aiu_noCredentials:`Noch keine KI-Zugangsdaten gespeichert — im Admin unter Einstellungen → Zugangsdaten anlegen.`,aiu_unsupported:`Keine Verbrauchsabfrage verfügbar`,aiu_provider:`Anbieter`,aiu_warnAt:`Warnen ab %`,aiu_claudeCaption:`Abo — meldet sich mit Ihrem Claude-Konto an statt mit einem Schlüssel`},p={aiu_claudeTitle:`Подписка Claude`,aiu_signedIn:`Вход выполнен`,aiu_signInAgain:`Войти заново`,aiu_saveFirst:`Сначала сохраните настройки — здесь появится ссылка для входа.`,aiu_waitingForLink:`Ожидание ссылки для входа от экземпляра …`,aiu_step1:`1. Откройте страницу входа и войдите со своим аккаунтом Claude.`,aiu_step2:`2. Скопируйте код с последней страницы и активируйте его здесь.`,aiu_openSignIn:`Открыть страницу входа`,aiu_copyLink:`Копировать ссылку`,aiu_codeLabel:`Код`,aiu_redeem:`Активировать`,aiu_signInDone:`Вход выполнен — данные придут со следующим опросом.`,aiu_signInFailed:`Ошибка входа`,aiu_instanceNotRunning:`Экземпляр не запущен — запустите его для входа.`,aiu_storedTitle:`Аккаунты ИИ`,aiu_storedHint:`Ваши централизованно сохранённые данные доступа ИИ плюс подписка Claude — включите, что нужно отслеживать. Новые ключи: Настройки → Учётные данные.`,aiu_noCredentials:`Данные доступа ИИ ещё не сохранены — добавьте их в настройках администратора.`,aiu_unsupported:`Запрос расхода недоступен`,aiu_provider:`Провайдер`,aiu_warnAt:`Предупреждать с %`,aiu_claudeCaption:`Подписка — вход через ваш аккаунт Claude вместо ключа`},m={aiu_claudeTitle:`Assinatura Claude`,aiu_signedIn:`Sessão iniciada`,aiu_signInAgain:`Iniciar sessão novamente`,aiu_saveFirst:`Guarde primeiro as definições — o link de início de sessão aparecerá aqui.`,aiu_waitingForLink:`A aguardar o link de início de sessão da instância …`,aiu_step1:`1. Abra a página de início de sessão e entre com a sua conta Claude.`,aiu_step2:`2. Copie o código da última página e resgate-o aqui.`,aiu_openSignIn:`Abrir página de início de sessão`,aiu_copyLink:`Copiar link`,aiu_codeLabel:`Código`,aiu_redeem:`Resgatar`,aiu_signInDone:`Sessão iniciada — os dados chegam na próxima consulta.`,aiu_signInFailed:`Falha no início de sessão`,aiu_instanceNotRunning:`A instância não está em execução — inicie-a para entrar.`,aiu_storedTitle:`Contas de IA`,aiu_storedHint:`As suas credenciais de IA guardadas centralmente mais a assinatura Claude — ative o que deseja monitorizar. Novas chaves em Definições → Credenciais.`,aiu_noCredentials:`Ainda não há credenciais de IA guardadas — adicione-as nas definições do administrador.`,aiu_unsupported:`Consulta de uso indisponível`,aiu_provider:`Fornecedor`,aiu_warnAt:`Avisar a partir de %`,aiu_claudeCaption:`Assinatura — inicia sessão com a sua conta Claude em vez de uma chave`},h={aiu_claudeTitle:`Claude-abonnement`,aiu_signedIn:`Aangemeld`,aiu_signInAgain:`Opnieuw aanmelden`,aiu_saveFirst:`Sla eerst de instellingen op — de aanmeldlink verschijnt dan hier.`,aiu_waitingForLink:`Wachten op de aanmeldlink van de instantie …`,aiu_step1:`1. Open de aanmeldpagina en log in met uw Claude-account.`,aiu_step2:`2. Kopieer de code van de laatste pagina en wissel die hier in.`,aiu_openSignIn:`Aanmeldpagina openen`,aiu_copyLink:`Link kopiëren`,aiu_codeLabel:`Code`,aiu_redeem:`Inwisselen`,aiu_signInDone:`Aangemeld — de gebruiksgegevens komen bij de volgende opvraging.`,aiu_signInFailed:`Aanmelden mislukt`,aiu_instanceNotRunning:`De instantie draait niet — start deze om aan te melden.`,aiu_storedTitle:`AI-accounts`,aiu_storedHint:`Uw centraal opgeslagen AI-toegangsgegevens plus het Claude-abonnement — schakel in wat u wilt bewaken. Nieuwe sleutels via Instellingen → Toegangsgegevens.`,aiu_noCredentials:`Nog geen AI-toegangsgegevens opgeslagen — voeg ze toe in de admin-instellingen.`,aiu_unsupported:`Geen verbruiksopvraging beschikbaar`,aiu_provider:`Aanbieder`,aiu_warnAt:`Waarschuwen vanaf %`,aiu_claudeCaption:`Abonnement — meldt zich aan met uw Claude-account in plaats van een sleutel`},g={aiu_claudeTitle:`Abonnement Claude`,aiu_signedIn:`Connecté`,aiu_signInAgain:`Se reconnecter`,aiu_saveFirst:`Enregistrez d'abord les réglages — le lien de connexion apparaîtra ici.`,aiu_waitingForLink:`En attente du lien de connexion de l'instance …`,aiu_step1:`1. Ouvrez la page de connexion et connectez-vous avec votre compte Claude.`,aiu_step2:`2. Copiez le code de la dernière page et validez-le ici.`,aiu_openSignIn:`Ouvrir la page de connexion`,aiu_copyLink:`Copier le lien`,aiu_codeLabel:`Code`,aiu_redeem:`Valider`,aiu_signInDone:`Connecté — les données arrivent à la prochaine interrogation.`,aiu_signInFailed:`Échec de la connexion`,aiu_instanceNotRunning:`L'instance ne tourne pas — démarrez-la pour vous connecter.`,aiu_storedTitle:`Comptes IA`,aiu_storedHint:`Vos identifiants IA enregistrés au niveau central plus l'abonnement Claude — activez ce qui doit être surveillé. Nouvelles clés via Réglages → Identifiants.`,aiu_noCredentials:`Aucun identifiant IA enregistré — ajoutez-les dans les réglages d'administration.`,aiu_unsupported:`Aucune interrogation d'utilisation disponible`,aiu_provider:`Fournisseur`,aiu_warnAt:`Avertir à partir de %`,aiu_claudeCaption:`Abonnement — se connecte avec votre compte Claude au lieu d'une clé`},_={aiu_claudeTitle:`Abbonamento Claude`,aiu_signedIn:`Accesso effettuato`,aiu_signInAgain:`Accedi di nuovo`,aiu_saveFirst:`Salva prima le impostazioni — il link di accesso apparirà qui.`,aiu_waitingForLink:`In attesa del link di accesso dall'istanza …`,aiu_step1:`1. Apri la pagina di accesso ed entra con il tuo account Claude.`,aiu_step2:`2. Copia il codice dell'ultima pagina e riscattalo qui.`,aiu_openSignIn:`Apri pagina di accesso`,aiu_copyLink:`Copia link`,aiu_codeLabel:`Codice`,aiu_redeem:`Riscatta`,aiu_signInDone:`Accesso effettuato — i dati arrivano con la prossima interrogazione.`,aiu_signInFailed:`Accesso non riuscito`,aiu_instanceNotRunning:`L'istanza non è in esecuzione — avviala per accedere.`,aiu_storedTitle:`Account IA`,aiu_storedHint:`Le tue credenziali IA salvate centralmente più l'abbonamento Claude — attiva ciò che vuoi monitorare. Nuove chiavi in Impostazioni → Credenziali.`,aiu_noCredentials:`Nessuna credenziale IA salvata — aggiungile nelle impostazioni di amministrazione.`,aiu_unsupported:`Nessuna interrogazione dei consumi disponibile`,aiu_provider:`Fornitore`,aiu_warnAt:`Avvisa da %`,aiu_claudeCaption:`Abbonamento — accede con il tuo account Claude invece di una chiave`},v={aiu_claudeTitle:`Suscripción Claude`,aiu_signedIn:`Sesión iniciada`,aiu_signInAgain:`Iniciar sesión de nuevo`,aiu_saveFirst:`Guarde primero la configuración — el enlace de inicio de sesión aparecerá aquí.`,aiu_waitingForLink:`Esperando el enlace de inicio de sesión de la instancia …`,aiu_step1:`1. Abra la página de inicio de sesión y entre con su cuenta Claude.`,aiu_step2:`2. Copie el código de la última página y canjéelo aquí.`,aiu_openSignIn:`Abrir página de inicio de sesión`,aiu_copyLink:`Copiar enlace`,aiu_codeLabel:`Código`,aiu_redeem:`Canjear`,aiu_signInDone:`Sesión iniciada — los datos llegan con la próxima consulta.`,aiu_signInFailed:`Error al iniciar sesión`,aiu_instanceNotRunning:`La instancia no está en marcha — iníciela para entrar.`,aiu_storedTitle:`Cuentas de IA`,aiu_storedHint:`Sus credenciales de IA guardadas centralmente más la suscripción Claude — active lo que quiera supervisar. Nuevas claves en Ajustes → Credenciales.`,aiu_noCredentials:`Aún no hay credenciales de IA guardadas — añádalas en los ajustes de administración.`,aiu_unsupported:`Consulta de uso no disponible`,aiu_provider:`Proveedor`,aiu_warnAt:`Avisar desde %`,aiu_claudeCaption:`Suscripción — inicia sesión con su cuenta Claude en lugar de una clave`},y={aiu_claudeTitle:`Subskrypcja Claude`,aiu_signedIn:`Zalogowano`,aiu_signInAgain:`Zaloguj ponownie`,aiu_saveFirst:`Najpierw zapisz ustawienia — link logowania pojawi się tutaj.`,aiu_waitingForLink:`Oczekiwanie na link logowania z instancji …`,aiu_step1:`1. Otwórz stronę logowania i zaloguj się kontem Claude.`,aiu_step2:`2. Skopiuj kod z ostatniej strony i zrealizuj go tutaj.`,aiu_openSignIn:`Otwórz stronę logowania`,aiu_copyLink:`Kopiuj link`,aiu_codeLabel:`Kod`,aiu_redeem:`Zrealizuj`,aiu_signInDone:`Zalogowano — dane przyjdą przy następnym odpytaniu.`,aiu_signInFailed:`Logowanie nie powiodło się`,aiu_instanceNotRunning:`Instancja nie działa — uruchom ją, aby się zalogować.`,aiu_storedTitle:`Konta AI`,aiu_storedHint:`Twoje centralnie zapisane dane dostępu AI plus subskrypcja Claude — włącz, co ma być monitorowane. Nowe klucze w Ustawienia → Dane dostępu.`,aiu_noCredentials:`Brak zapisanych danych dostępu AI — dodaj je w ustawieniach administratora.`,aiu_unsupported:`Zapytanie o zużycie niedostępne`,aiu_provider:`Dostawca`,aiu_warnAt:`Ostrzegaj od %`,aiu_claudeCaption:`Subskrypcja — loguje się kontem Claude zamiast klucza`},b={aiu_claudeTitle:`Підписка Claude`,aiu_signedIn:`Вхід виконано`,aiu_signInAgain:`Увійти знову`,aiu_saveFirst:`Спочатку збережіть налаштування — посилання для входу з'явиться тут.`,aiu_waitingForLink:`Очікування посилання для входу від екземпляра …`,aiu_step1:`1. Відкрийте сторінку входу та увійдіть своїм акаунтом Claude.`,aiu_step2:`2. Скопіюйте код з останньої сторінки та активуйте його тут.`,aiu_openSignIn:`Відкрити сторінку входу`,aiu_copyLink:`Копіювати посилання`,aiu_codeLabel:`Код`,aiu_redeem:`Активувати`,aiu_signInDone:`Вхід виконано — дані надійдуть із наступним опитуванням.`,aiu_signInFailed:`Помилка входу`,aiu_instanceNotRunning:`Екземпляр не запущено — запустіть його для входу.`,aiu_storedTitle:`Акаунти ШІ`,aiu_storedHint:`Ваші централізовано збережені дані доступу ШІ плюс підписка Claude — увімкніть те, що треба відстежувати. Нові ключі: Налаштування → Дані доступу.`,aiu_noCredentials:`Ще немає збережених даних доступу ШІ — додайте їх у налаштуваннях адміністратора.`,aiu_unsupported:`Запит використання недоступний`,aiu_provider:`Постачальник`,aiu_warnAt:`Попереджати від %`,aiu_claudeCaption:`Підписка — вхід через ваш акаунт Claude замість ключа`},x={aiu_claudeTitle:`Claude 订阅`,aiu_signedIn:`已登录`,aiu_signInAgain:`重新登录`,aiu_saveFirst:`请先保存设置——登录链接随后会显示在这里。`,aiu_waitingForLink:`正在等待实例提供登录链接……`,aiu_step1:`1. 打开登录页面并用您的 Claude 账户登录。`,aiu_step2:`2. 复制最后页面上的代码并在此兑换。`,aiu_openSignIn:`打开登录页面`,aiu_copyLink:`复制链接`,aiu_codeLabel:`代码`,aiu_redeem:`兑换`,aiu_signInDone:`已登录——数据将随下次查询到达。`,aiu_signInFailed:`登录失败`,aiu_instanceNotRunning:`实例未运行——请启动后再登录。`,aiu_storedTitle:`AI 账户`,aiu_storedHint:`您集中保存的 AI 凭据以及 Claude 订阅——开启要监控的项目。新密钥请在 设置 → 凭据 中添加。`,aiu_noCredentials:`尚未保存任何 AI 凭据——请在管理设置中添加。`,aiu_unsupported:`无可用的用量查询`,aiu_provider:`提供商`,aiu_warnAt:`警告阈值 %`,aiu_claudeCaption:`订阅——使用您的 Claude 账户登录,无需密钥`},S=class extends t{constructor(e){super(e,{...e}),this.state={...this.state,data:{accounts:[]},originalData:{accounts:[]},theme:this.createTheme()};let t={en:d,de:f,ru:p,pt:m,nl:h,fr:g,it:_,es:v,pl:y,uk:b,"zh-cn":x};for(let[e,n]of Object.entries(t))o.extendTranslations(n,e);let n=(navigator.language||navigator.userLanguage||`en`).toLowerCase();o.setLanguage(n.startsWith(`zh`)?`zh-cn`:n.substring(0,2))}render(){return this.state.loaded?r(e,{injectFirst:!0,children:r(n,{theme:this.state.theme,children:r(s,{sx:{height:`100%`,bgcolor:`background.default`,color:`text.primary`},children:r(`div`,{style:{padding:50,width:760},children:r(u,{oContext:{adapterName:`ai-usage`,socket:this.socket,instance:0,themeType:this.state.theme.palette.mode,isFloatComma:!0,dateFormat:``,forceUpdate:()=>{},systemConfig:{},theme:this.state.theme,_themeName:this.state.themeName,onCommandRunning:()=>{}},alive:!0,changed:!1,themeName:this.state.theme.palette.mode,common:{},attr:`_accounts`,data:this.state.data,originalData:this.state.originalData,onError:()=>{},schema:{url:`custom/customComponents.js`,i18n:!0,name:`AiUsageComponentSet/Components/ConfigPanel`,type:`custom`},onChange:e=>this.setState({data:e})})})})})}):r(e,{injectFirst:!0,children:r(n,{theme:this.state.theme,children:r(c,{themeType:this.state.themeType})})})}};a(),window.adapterName=`ai-usage`;var C=document.getElementById(`root`);C&&l(C).render(r(i.StrictMode,{children:r(S,{socket:{port:8081}})}));
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./virtual_mf-exposes___mfe_internal__AiUsageComponentSet__customComponents_js-BZ-CVpVo.js";export{e as default};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Components-Bd545388.js","./ConfigPanel-qivVprTj.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{t as e}from"./vite-preload-helper-B7qeedMF.js";var t={"./Components":async()=>{let t=await e(()=>import(`./Components-Bd545388.js`),__vite__mapDeps([0,1]),import.meta.url),n={};return Object.assign(n,t),Object.defineProperty(n,"__esModule",{value:!0,enumerable:!1}),n}};export{t as default};
|