iobroker.ai-usage 0.2.0 → 0.4.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 +135 -24
- package/admin/ai-usage.svg +12 -17
- 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 +33 -4
- 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 +86 -6
- 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 +122 -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 +9 -5
- 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/lib/snapshot-tree.js +21 -9
- package/build/lib/snapshot-tree.js.map +2 -2
- package/build/main.js +283 -151
- package/build/main.js.map +2 -2
- package/io-package.json +46 -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
|
@@ -0,0 +1,38 @@
|
|
|
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 sign_in_exports = {};
|
|
20
|
+
__export(sign_in_exports, {
|
|
21
|
+
SIGN_IN_FLOWS: () => SIGN_IN_FLOWS,
|
|
22
|
+
attemptExpired: () => attemptExpired
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(sign_in_exports);
|
|
25
|
+
const SIGN_IN_FLOWS = {
|
|
26
|
+
"claude-sub": "paste-code",
|
|
27
|
+
"chatgpt-sub": "device-code",
|
|
28
|
+
"gemini-sub": "paste-url"
|
|
29
|
+
};
|
|
30
|
+
function attemptExpired(expiresAt, now) {
|
|
31
|
+
return now >= expiresAt;
|
|
32
|
+
}
|
|
33
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34
|
+
0 && (module.exports = {
|
|
35
|
+
SIGN_IN_FLOWS,
|
|
36
|
+
attemptExpired
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=sign-in.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/sign-in.ts"],
|
|
4
|
+
"sourcesContent": ["import type { SignInFlow } from \"./provider\";\n\n/** Which sign-in flow a subscription uses \u2014 see {@link SignInFlow} for why they differ. */\nexport const SIGN_IN_FLOWS: Record<string, SignInFlow> = {\n \"claude-sub\": \"paste-code\",\n \"chatgpt-sub\": \"device-code\",\n \"gemini-sub\": \"paste-url\",\n};\n\n/** The live state of one subscription row, as the admin panel renders it. */\nexport type SignInState =\n /** Signed in, tokens usable. */\n | { status: \"signed-in\" }\n /** Nothing started yet. */\n | { status: \"signed-out\" }\n /** Claude/Gemini: the user has to open the link and paste something back. */\n | { status: \"awaiting-paste\"; url: string; flow: SignInFlow }\n /** ChatGPT: the user types this code on the provider's page; the adapter waits. */\n | { status: \"awaiting-device\"; userCode: string; verificationUrl: string; expiresAt: number }\n /** The last attempt failed \u2014 reason is user-facing. */\n | { status: \"failed\"; reason: string };\n\n/**\n * Whether a running sign-in attempt is over.\n *\n * @param expiresAt end of the attempt window (ms since epoch)\n * @param now current time (ms)\n * @returns true when the attempt can no longer succeed\n */\nexport function attemptExpired(expiresAt: number, now: number): boolean {\n return now >= expiresAt;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,gBAA4C;AAAA,EACvD,cAAc;AAAA,EACd,eAAe;AAAA,EACf,cAAc;AAChB;AAsBO,SAAS,eAAe,WAAmB,KAAsB;AACtE,SAAO,OAAO;AAChB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var snapshot_tree_exports = {};
|
|
20
20
|
__export(snapshot_tree_exports, {
|
|
21
|
+
limitingWindow: () => limitingWindow,
|
|
21
22
|
mapSnapshot: () => mapSnapshot,
|
|
22
23
|
maxLimitPercent: () => maxLimitPercent
|
|
23
24
|
});
|
|
@@ -156,19 +157,30 @@ function mapSnapshot(accountId, accountName, provider, snapshot) {
|
|
|
156
157
|
}
|
|
157
158
|
return { objects, writes };
|
|
158
159
|
}
|
|
159
|
-
function
|
|
160
|
-
var _a, _b
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
160
|
+
function limitingWindow(snapshot) {
|
|
161
|
+
var _a, _b;
|
|
162
|
+
let best;
|
|
163
|
+
for (const limit of (_a = snapshot.limits) != null ? _a : []) {
|
|
164
|
+
if (limit.scoped) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (!best || limit.percent > best.percent) {
|
|
168
|
+
best = { percent: limit.percent, label: limit.label };
|
|
169
|
+
}
|
|
167
170
|
}
|
|
168
|
-
|
|
171
|
+
const credits = (_b = snapshot.credits) == null ? void 0 : _b.percent;
|
|
172
|
+
if (credits !== void 0 && (!best || credits > best.percent)) {
|
|
173
|
+
best = { percent: credits, label: "Credits" };
|
|
174
|
+
}
|
|
175
|
+
return best;
|
|
176
|
+
}
|
|
177
|
+
function maxLimitPercent(snapshot) {
|
|
178
|
+
var _a;
|
|
179
|
+
return (_a = limitingWindow(snapshot)) == null ? void 0 : _a.percent;
|
|
169
180
|
}
|
|
170
181
|
// Annotate the CommonJS export names for ESM import in node:
|
|
171
182
|
0 && (module.exports = {
|
|
183
|
+
limitingWindow,
|
|
172
184
|
mapSnapshot,
|
|
173
185
|
maxLimitPercent
|
|
174
186
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/snapshot-tree.ts"],
|
|
4
|
-
"sourcesContent": ["import type { UsageSnapshot } from \"./provider\";\nimport { sanitizeId } from \"./pure-helpers\";\n\n/** An object to create: id (relative to the instance), type and common. */\nexport interface ObjectDef {\n /** Object id relative to the instance root. */\n id: string;\n /** ioBroker object type. */\n type: \"device\" | \"channel\" | \"state\";\n /** The object's common. */\n common: {\n name: string | Record<string, string>;\n type?: \"boolean\" | \"number\" | \"string\";\n role?: string;\n read?: boolean;\n write?: boolean;\n unit?: string;\n min?: number;\n max?: number;\n };\n}\n\n/** A state value to write (ack). */\nexport interface StateWrite {\n /** State id relative to the instance root. */\n id: string;\n /** The value. */\n value: boolean | number | string;\n}\n\n/**\n * A read-only state definition plus its value \u2014 the tree builder's working unit.\n *\n * @param id the state id\n * @param name the object name\n * @param type the value type\n * @param role the state role\n * @param value the current value\n * @param unit optional unit\n * @returns the def/value pair\n */\nfunction state(\n id: string,\n name: string,\n type: \"boolean\" | \"number\" | \"string\",\n role: string,\n value: boolean | number | string,\n unit?: string,\n): { def: ObjectDef; write: StateWrite } {\n const common: ObjectDef[\"common\"] = { name, type, role, read: true, write: false };\n if (unit !== undefined) {\n common.unit = unit;\n }\n return { def: { id, type: \"state\", common }, write: { id, value } };\n}\n\n/** The result of mapping one snapshot: objects to upsert (parents first) and values to write. */\nexport interface TreeResult {\n /** Objects in creation order (device, channels, states). */\n objects: ObjectDef[];\n /** State values to write with ack. */\n writes: StateWrite[];\n}\n\n/**\n * Map one account snapshot onto the harmonised object tree: `limits.*`, `credits.*`,\n * `costs.*`, `tokens.*` (+ `models.*`) \u2014 only what the snapshot carries is created,\n * so the tree mirrors exactly what the provider's source delivers.\n *\n * @param accountId the id-safe account id (device node)\n * @param accountName the display name for the device object\n * @param provider the provider kind (device object name suffix)\n * @param snapshot the fetched snapshot\n * @returns objects (parents first) and state writes\n */\nexport function mapSnapshot(\n accountId: string,\n accountName: string,\n provider: string,\n snapshot: UsageSnapshot,\n): TreeResult {\n const objects: ObjectDef[] = [];\n const writes: StateWrite[] = [];\n const add = (pair: { def: ObjectDef; write: StateWrite }): void => {\n objects.push(pair.def);\n writes.push(pair.write);\n };\n const channel = (id: string, name: string): void => {\n objects.push({ id, type: \"channel\", common: { name } });\n };\n\n objects.push({ id: accountId, type: \"device\", common: { name: `${accountName} (${provider})` } });\n\n if (snapshot.limits && snapshot.limits.length > 0) {\n channel(`${accountId}.limits`, \"Limit windows\");\n for (const limit of snapshot.limits) {\n const windowId = sanitizeId(limit.name);\n if (!windowId) {\n continue;\n }\n channel(`${accountId}.limits.${windowId}`, limit.label);\n add(\n state(`${accountId}.limits.${windowId}.percent`, `${limit.label} used`, \"number\", \"value\", limit.percent, \"%\"),\n );\n if (limit.resetAt !== undefined) {\n add(\n state(`${accountId}.limits.${windowId}.resetAt`, `${limit.label} resets at`, \"string\", \"date\", limit.resetAt),\n );\n }\n }\n }\n\n const credits = snapshot.credits;\n if (credits) {\n channel(`${accountId}.credits`, \"Credits\");\n const unit = credits.pieces ? \"\" : credits.currency;\n if (credits.used !== undefined) {\n add(state(`${accountId}.credits.used`, \"Credits used\", \"number\", \"value\", credits.used, unit));\n }\n if (credits.limit !== undefined) {\n add(state(`${accountId}.credits.limit`, \"Credits limit\", \"number\", \"value\", credits.limit, unit));\n }\n if (credits.remaining !== undefined) {\n add(state(`${accountId}.credits.remaining`, \"Credits remaining\", \"number\", \"value\", credits.remaining, unit));\n }\n if (credits.percent !== undefined) {\n add(state(`${accountId}.credits.percent`, \"Credits used (percent)\", \"number\", \"value\", credits.percent, \"%\"));\n }\n if (credits.granted !== undefined) {\n add(state(`${accountId}.credits.granted`, \"Granted balance\", \"number\", \"value\", credits.granted, unit));\n }\n if (credits.toppedUp !== undefined) {\n add(state(`${accountId}.credits.toppedUp`, \"Topped-up balance\", \"number\", \"value\", credits.toppedUp, unit));\n }\n }\n\n const costs = snapshot.costs;\n if (costs) {\n channel(`${accountId}.costs`, \"Costs\");\n if (costs.today !== undefined) {\n add(state(`${accountId}.costs.today`, \"Costs today\", \"number\", \"value\", costs.today, costs.currency));\n }\n if (costs.month !== undefined) {\n add(state(`${accountId}.costs.month`, \"Costs this month\", \"number\", \"value\", costs.month, costs.currency));\n }\n if (costs.total !== undefined) {\n add(state(`${accountId}.costs.total`, \"Costs total (lifetime)\", \"number\", \"value\", costs.total, costs.currency));\n }\n if (costs.projectedMonth !== undefined) {\n add(\n state(\n `${accountId}.costs.projectedMonth`,\n \"Costs projected month-end (computed)\",\n \"number\",\n \"value\",\n costs.projectedMonth,\n costs.currency,\n ),\n );\n }\n }\n\n const tokens = snapshot.tokens;\n if (tokens) {\n channel(`${accountId}.tokens`, \"Tokens\");\n if (tokens.inputToday !== undefined) {\n add(state(`${accountId}.tokens.inputToday`, \"Input tokens today\", \"number\", \"value\", tokens.inputToday));\n }\n if (tokens.outputToday !== undefined) {\n add(state(`${accountId}.tokens.outputToday`, \"Output tokens today\", \"number\", \"value\", tokens.outputToday));\n }\n if (tokens.perModel && tokens.perModel.length > 0) {\n channel(`${accountId}.models`, \"Per-model usage\");\n for (const model of tokens.perModel) {\n const modelId = sanitizeId(model.model);\n if (!modelId) {\n continue;\n }\n channel(`${accountId}.models.${modelId}`, model.model);\n if (model.tokens !== undefined) {\n add(\n state(\n `${accountId}.models.${modelId}.tokensToday`,\n `${model.model} tokens today`,\n \"number\",\n \"value\",\n model.tokens,\n ),\n );\n }\n if (model.cost !== undefined) {\n add(\n state(\n `${accountId}.models.${modelId}.costToday`,\n `${model.model} costs today`,\n \"number\",\n \"value\",\n model.cost,\n snapshot.costs?.currency ?? \"USD\",\n ),\n );\n }\n }\n }\n }\n\n if (snapshot.available !== undefined) {\n add(state(`${accountId}.available`, \"Balance sufficient for calls\", \"boolean\", \"indicator\", snapshot.available));\n }\n\n return { objects, writes };\n}\n\n/**\n * The
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { UsageSnapshot } from \"./provider\";\nimport { sanitizeId } from \"./pure-helpers\";\n\n/** An object to create: id (relative to the instance), type and common. */\nexport interface ObjectDef {\n /** Object id relative to the instance root. */\n id: string;\n /** ioBroker object type. */\n type: \"device\" | \"channel\" | \"state\";\n /** The object's common. */\n common: {\n name: string | Record<string, string>;\n type?: \"boolean\" | \"number\" | \"string\";\n role?: string;\n read?: boolean;\n write?: boolean;\n unit?: string;\n min?: number;\n max?: number;\n };\n}\n\n/** A state value to write (ack). */\nexport interface StateWrite {\n /** State id relative to the instance root. */\n id: string;\n /** The value. */\n value: boolean | number | string;\n}\n\n/**\n * A read-only state definition plus its value \u2014 the tree builder's working unit.\n *\n * @param id the state id\n * @param name the object name\n * @param type the value type\n * @param role the state role\n * @param value the current value\n * @param unit optional unit\n * @returns the def/value pair\n */\nfunction state(\n id: string,\n name: string,\n type: \"boolean\" | \"number\" | \"string\",\n role: string,\n value: boolean | number | string,\n unit?: string,\n): { def: ObjectDef; write: StateWrite } {\n const common: ObjectDef[\"common\"] = { name, type, role, read: true, write: false };\n if (unit !== undefined) {\n common.unit = unit;\n }\n return { def: { id, type: \"state\", common }, write: { id, value } };\n}\n\n/** The result of mapping one snapshot: objects to upsert (parents first) and values to write. */\nexport interface TreeResult {\n /** Objects in creation order (device, channels, states). */\n objects: ObjectDef[];\n /** State values to write with ack. */\n writes: StateWrite[];\n}\n\n/**\n * Map one account snapshot onto the harmonised object tree: `limits.*`, `credits.*`,\n * `costs.*`, `tokens.*` (+ `models.*`) \u2014 only what the snapshot carries is created,\n * so the tree mirrors exactly what the provider's source delivers.\n *\n * @param accountId the id-safe account id (device node)\n * @param accountName the display name for the device object\n * @param provider the provider kind (device object name suffix)\n * @param snapshot the fetched snapshot\n * @returns objects (parents first) and state writes\n */\nexport function mapSnapshot(\n accountId: string,\n accountName: string,\n provider: string,\n snapshot: UsageSnapshot,\n): TreeResult {\n const objects: ObjectDef[] = [];\n const writes: StateWrite[] = [];\n const add = (pair: { def: ObjectDef; write: StateWrite }): void => {\n objects.push(pair.def);\n writes.push(pair.write);\n };\n const channel = (id: string, name: string): void => {\n objects.push({ id, type: \"channel\", common: { name } });\n };\n\n objects.push({ id: accountId, type: \"device\", common: { name: `${accountName} (${provider})` } });\n\n if (snapshot.limits && snapshot.limits.length > 0) {\n channel(`${accountId}.limits`, \"Limit windows\");\n for (const limit of snapshot.limits) {\n const windowId = sanitizeId(limit.name);\n if (!windowId) {\n continue;\n }\n channel(`${accountId}.limits.${windowId}`, limit.label);\n add(\n state(`${accountId}.limits.${windowId}.percent`, `${limit.label} used`, \"number\", \"value\", limit.percent, \"%\"),\n );\n if (limit.resetAt !== undefined) {\n add(\n state(`${accountId}.limits.${windowId}.resetAt`, `${limit.label} resets at`, \"string\", \"date\", limit.resetAt),\n );\n }\n }\n }\n\n const credits = snapshot.credits;\n if (credits) {\n channel(`${accountId}.credits`, \"Credits\");\n const unit = credits.pieces ? \"\" : credits.currency;\n if (credits.used !== undefined) {\n add(state(`${accountId}.credits.used`, \"Credits used\", \"number\", \"value\", credits.used, unit));\n }\n if (credits.limit !== undefined) {\n add(state(`${accountId}.credits.limit`, \"Credits limit\", \"number\", \"value\", credits.limit, unit));\n }\n if (credits.remaining !== undefined) {\n add(state(`${accountId}.credits.remaining`, \"Credits remaining\", \"number\", \"value\", credits.remaining, unit));\n }\n if (credits.percent !== undefined) {\n add(state(`${accountId}.credits.percent`, \"Credits used (percent)\", \"number\", \"value\", credits.percent, \"%\"));\n }\n if (credits.granted !== undefined) {\n add(state(`${accountId}.credits.granted`, \"Granted balance\", \"number\", \"value\", credits.granted, unit));\n }\n if (credits.toppedUp !== undefined) {\n add(state(`${accountId}.credits.toppedUp`, \"Topped-up balance\", \"number\", \"value\", credits.toppedUp, unit));\n }\n }\n\n const costs = snapshot.costs;\n if (costs) {\n channel(`${accountId}.costs`, \"Costs\");\n if (costs.today !== undefined) {\n add(state(`${accountId}.costs.today`, \"Costs today\", \"number\", \"value\", costs.today, costs.currency));\n }\n if (costs.month !== undefined) {\n add(state(`${accountId}.costs.month`, \"Costs this month\", \"number\", \"value\", costs.month, costs.currency));\n }\n if (costs.total !== undefined) {\n add(state(`${accountId}.costs.total`, \"Costs total (lifetime)\", \"number\", \"value\", costs.total, costs.currency));\n }\n if (costs.projectedMonth !== undefined) {\n add(\n state(\n `${accountId}.costs.projectedMonth`,\n \"Costs projected month-end (computed)\",\n \"number\",\n \"value\",\n costs.projectedMonth,\n costs.currency,\n ),\n );\n }\n }\n\n const tokens = snapshot.tokens;\n if (tokens) {\n channel(`${accountId}.tokens`, \"Tokens\");\n if (tokens.inputToday !== undefined) {\n add(state(`${accountId}.tokens.inputToday`, \"Input tokens today\", \"number\", \"value\", tokens.inputToday));\n }\n if (tokens.outputToday !== undefined) {\n add(state(`${accountId}.tokens.outputToday`, \"Output tokens today\", \"number\", \"value\", tokens.outputToday));\n }\n if (tokens.perModel && tokens.perModel.length > 0) {\n channel(`${accountId}.models`, \"Per-model usage\");\n for (const model of tokens.perModel) {\n const modelId = sanitizeId(model.model);\n if (!modelId) {\n continue;\n }\n channel(`${accountId}.models.${modelId}`, model.model);\n if (model.tokens !== undefined) {\n add(\n state(\n `${accountId}.models.${modelId}.tokensToday`,\n `${model.model} tokens today`,\n \"number\",\n \"value\",\n model.tokens,\n ),\n );\n }\n if (model.cost !== undefined) {\n add(\n state(\n `${accountId}.models.${modelId}.costToday`,\n `${model.model} costs today`,\n \"number\",\n \"value\",\n model.cost,\n snapshot.costs?.currency ?? \"USD\",\n ),\n );\n }\n }\n }\n }\n\n if (snapshot.available !== undefined) {\n add(state(`${accountId}.available`, \"Balance sufficient for calls\", \"boolean\", \"indicator\", snapshot.available));\n }\n\n return { objects, writes };\n}\n\n/**\n * The window that decides how full an account is: the highest PLAN-WIDE limit, or\n * the granted budget when the account has no windows at all.\n *\n * Windows marked `scoped` are left out on purpose \u2014 they cover a single model and\n * may sit at 100 % permanently for a model the user never touches, which would\n * pin the account's warning on forever. Their datapoints still exist; they just\n * do not speak for the account.\n *\n * @param snapshot the snapshot\n * @returns percent plus the label that produced it, or undefined when nothing applies\n */\nexport function limitingWindow(snapshot: UsageSnapshot): { percent: number; label: string } | undefined {\n let best: { percent: number; label: string } | undefined;\n for (const limit of snapshot.limits ?? []) {\n if (limit.scoped) {\n continue;\n }\n if (!best || limit.percent > best.percent) {\n best = { percent: limit.percent, label: limit.label };\n }\n }\n const credits = snapshot.credits?.percent;\n if (credits !== undefined && (!best || credits > best.percent)) {\n best = { percent: credits, label: \"Credits\" };\n }\n return best;\n}\n\n/**\n * The highest plan-wide limit percent in a snapshot, or undefined when it has none.\n *\n * @param snapshot the snapshot\n * @returns the maximum percent\n */\nexport function maxLimitPercent(snapshot: UsageSnapshot): number | undefined {\n return limitingWindow(snapshot)?.percent;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAA2B;AAwC3B,SAAS,MACP,IACA,MACA,MACA,MACA,OACA,MACuC;AACvC,QAAM,SAA8B,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,OAAO,MAAM;AACjF,MAAI,SAAS,QAAW;AACtB,WAAO,OAAO;AAAA,EAChB;AACA,SAAO,EAAE,KAAK,EAAE,IAAI,MAAM,SAAS,OAAO,GAAG,OAAO,EAAE,IAAI,MAAM,EAAE;AACpE;AAqBO,SAAS,YACd,WACA,aACA,UACA,UACY;AAhFd;AAiFE,QAAM,UAAuB,CAAC;AAC9B,QAAM,SAAuB,CAAC;AAC9B,QAAM,MAAM,CAAC,SAAsD;AACjE,YAAQ,KAAK,KAAK,GAAG;AACrB,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AACA,QAAM,UAAU,CAAC,IAAY,SAAuB;AAClD,YAAQ,KAAK,EAAE,IAAI,MAAM,WAAW,QAAQ,EAAE,KAAK,EAAE,CAAC;AAAA,EACxD;AAEA,UAAQ,KAAK,EAAE,IAAI,WAAW,MAAM,UAAU,QAAQ,EAAE,MAAM,GAAG,WAAW,KAAK,QAAQ,IAAI,EAAE,CAAC;AAEhG,MAAI,SAAS,UAAU,SAAS,OAAO,SAAS,GAAG;AACjD,YAAQ,GAAG,SAAS,WAAW,eAAe;AAC9C,eAAW,SAAS,SAAS,QAAQ;AACnC,YAAM,eAAW,gCAAW,MAAM,IAAI;AACtC,UAAI,CAAC,UAAU;AACb;AAAA,MACF;AACA,cAAQ,GAAG,SAAS,WAAW,QAAQ,IAAI,MAAM,KAAK;AACtD;AAAA,QACE,MAAM,GAAG,SAAS,WAAW,QAAQ,YAAY,GAAG,MAAM,KAAK,SAAS,UAAU,SAAS,MAAM,SAAS,GAAG;AAAA,MAC/G;AACA,UAAI,MAAM,YAAY,QAAW;AAC/B;AAAA,UACE,MAAM,GAAG,SAAS,WAAW,QAAQ,YAAY,GAAG,MAAM,KAAK,cAAc,UAAU,QAAQ,MAAM,OAAO;AAAA,QAC9G;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,SAAS;AACzB,MAAI,SAAS;AACX,YAAQ,GAAG,SAAS,YAAY,SAAS;AACzC,UAAM,OAAO,QAAQ,SAAS,KAAK,QAAQ;AAC3C,QAAI,QAAQ,SAAS,QAAW;AAC9B,UAAI,MAAM,GAAG,SAAS,iBAAiB,gBAAgB,UAAU,SAAS,QAAQ,MAAM,IAAI,CAAC;AAAA,IAC/F;AACA,QAAI,QAAQ,UAAU,QAAW;AAC/B,UAAI,MAAM,GAAG,SAAS,kBAAkB,iBAAiB,UAAU,SAAS,QAAQ,OAAO,IAAI,CAAC;AAAA,IAClG;AACA,QAAI,QAAQ,cAAc,QAAW;AACnC,UAAI,MAAM,GAAG,SAAS,sBAAsB,qBAAqB,UAAU,SAAS,QAAQ,WAAW,IAAI,CAAC;AAAA,IAC9G;AACA,QAAI,QAAQ,YAAY,QAAW;AACjC,UAAI,MAAM,GAAG,SAAS,oBAAoB,0BAA0B,UAAU,SAAS,QAAQ,SAAS,GAAG,CAAC;AAAA,IAC9G;AACA,QAAI,QAAQ,YAAY,QAAW;AACjC,UAAI,MAAM,GAAG,SAAS,oBAAoB,mBAAmB,UAAU,SAAS,QAAQ,SAAS,IAAI,CAAC;AAAA,IACxG;AACA,QAAI,QAAQ,aAAa,QAAW;AAClC,UAAI,MAAM,GAAG,SAAS,qBAAqB,qBAAqB,UAAU,SAAS,QAAQ,UAAU,IAAI,CAAC;AAAA,IAC5G;AAAA,EACF;AAEA,QAAM,QAAQ,SAAS;AACvB,MAAI,OAAO;AACT,YAAQ,GAAG,SAAS,UAAU,OAAO;AACrC,QAAI,MAAM,UAAU,QAAW;AAC7B,UAAI,MAAM,GAAG,SAAS,gBAAgB,eAAe,UAAU,SAAS,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IACtG;AACA,QAAI,MAAM,UAAU,QAAW;AAC7B,UAAI,MAAM,GAAG,SAAS,gBAAgB,oBAAoB,UAAU,SAAS,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IAC3G;AACA,QAAI,MAAM,UAAU,QAAW;AAC7B,UAAI,MAAM,GAAG,SAAS,gBAAgB,0BAA0B,UAAU,SAAS,MAAM,OAAO,MAAM,QAAQ,CAAC;AAAA,IACjH;AACA,QAAI,MAAM,mBAAmB,QAAW;AACtC;AAAA,QACE;AAAA,UACE,GAAG,SAAS;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,SAAS;AACxB,MAAI,QAAQ;AACV,YAAQ,GAAG,SAAS,WAAW,QAAQ;AACvC,QAAI,OAAO,eAAe,QAAW;AACnC,UAAI,MAAM,GAAG,SAAS,sBAAsB,sBAAsB,UAAU,SAAS,OAAO,UAAU,CAAC;AAAA,IACzG;AACA,QAAI,OAAO,gBAAgB,QAAW;AACpC,UAAI,MAAM,GAAG,SAAS,uBAAuB,uBAAuB,UAAU,SAAS,OAAO,WAAW,CAAC;AAAA,IAC5G;AACA,QAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAAG;AACjD,cAAQ,GAAG,SAAS,WAAW,iBAAiB;AAChD,iBAAW,SAAS,OAAO,UAAU;AACnC,cAAM,cAAU,gCAAW,MAAM,KAAK;AACtC,YAAI,CAAC,SAAS;AACZ;AAAA,QACF;AACA,gBAAQ,GAAG,SAAS,WAAW,OAAO,IAAI,MAAM,KAAK;AACrD,YAAI,MAAM,WAAW,QAAW;AAC9B;AAAA,YACE;AAAA,cACE,GAAG,SAAS,WAAW,OAAO;AAAA,cAC9B,GAAG,MAAM,KAAK;AAAA,cACd;AAAA,cACA;AAAA,cACA,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF;AACA,YAAI,MAAM,SAAS,QAAW;AAC5B;AAAA,YACE;AAAA,cACE,GAAG,SAAS,WAAW,OAAO;AAAA,cAC9B,GAAG,MAAM,KAAK;AAAA,cACd;AAAA,cACA;AAAA,cACA,MAAM;AAAA,eACN,oBAAS,UAAT,mBAAgB,aAAhB,YAA4B;AAAA,YAC9B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS,cAAc,QAAW;AACpC,QAAI,MAAM,GAAG,SAAS,cAAc,gCAAgC,WAAW,aAAa,SAAS,SAAS,CAAC;AAAA,EACjH;AAEA,SAAO,EAAE,SAAS,OAAO;AAC3B;AAcO,SAAS,eAAe,UAAyE;AAjOxG;AAkOE,MAAI;AACJ,aAAW,UAAS,cAAS,WAAT,YAAmB,CAAC,GAAG;AACzC,QAAI,MAAM,QAAQ;AAChB;AAAA,IACF;AACA,QAAI,CAAC,QAAQ,MAAM,UAAU,KAAK,SAAS;AACzC,aAAO,EAAE,SAAS,MAAM,SAAS,OAAO,MAAM,MAAM;AAAA,IACtD;AAAA,EACF;AACA,QAAM,WAAU,cAAS,YAAT,mBAAkB;AAClC,MAAI,YAAY,WAAc,CAAC,QAAQ,UAAU,KAAK,UAAU;AAC9D,WAAO,EAAE,SAAS,SAAS,OAAO,UAAU;AAAA,EAC9C;AACA,SAAO;AACT;AAQO,SAAS,gBAAgB,UAA6C;AAxP7E;AAyPE,UAAO,oBAAe,QAAQ,MAAvB,mBAA0B;AACnC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|