dsh-plugin-subscription-oauth 0.3.0 → 0.5.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/lib/auth/ccswitch.d.ts +36 -0
- package/lib/auth/ccswitch.js +75 -0
- package/lib/auth/rpc.d.ts +8 -1
- package/lib/auth/rpc.js +29 -17
- package/lib/client/UsageChip.d.ts +188 -0
- package/lib/client/UsageChip.js +347 -0
- package/lib/client/index.d.ts +28 -1
- package/lib/client/index.js +46 -1
- package/lib/client/locales.d.ts +4 -0
- package/lib/client/locales.js +4 -0
- package/lib/client/styles.d.ts +15 -1
- package/lib/client/styles.js +128 -1
- package/lib/client/subscriptions-rpc.d.ts +53 -1
- package/lib/client/subscriptions-rpc.js +56 -0
- package/lib/client.js +652 -5
- package/lib/client.js.map +1 -1
- package/lib/protocol.d.ts +50 -1
- package/lib/protocol.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cc-switch balance query, reimplemented for the plugin's node half.
|
|
3
|
+
*
|
|
4
|
+
* cc-switch (github.com/farion1231/cc-switch) reads a DeepSeek-compatible provider's
|
|
5
|
+
* balance with `GET https://api.deepseek.com/user/balance`, an `Authorization: Bearer
|
|
6
|
+
* <api key>` header, and a 15 s timeout. This is that request, with the URL hardcoded
|
|
7
|
+
* exactly as cc-switch does — the provider's own base URL is never substituted in.
|
|
8
|
+
*
|
|
9
|
+
* The endpoint answers `{ is_available, balance_infos: [{ currency, total_balance, … }] }`,
|
|
10
|
+
* where a balance is a number or a numeric string. The module reduces that to the one
|
|
11
|
+
* figure a status chip needs: the first currency's total. Anything else — a missing key,
|
|
12
|
+
* a non-2xx answer, malformed JSON — resolves to nothing, so the caller shows no balance
|
|
13
|
+
* rather than a wrong one.
|
|
14
|
+
*
|
|
15
|
+
* @module dsh-plugin-subscription-oauth/auth/ccswitch
|
|
16
|
+
*/
|
|
17
|
+
import type { FetchFn } from '../http.js';
|
|
18
|
+
/** One currency's balance, normalised from the endpoint's answer. */
|
|
19
|
+
export interface CcSwitchBalance {
|
|
20
|
+
/** The currency the balance is denominated in. */
|
|
21
|
+
currency: string;
|
|
22
|
+
/** The remaining balance, as a decimal string. */
|
|
23
|
+
total: string;
|
|
24
|
+
/** Whether the account reports itself as usable. */
|
|
25
|
+
available: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Query one provider's balance the way cc-switch does.
|
|
29
|
+
*
|
|
30
|
+
* @param input - the provider's API key, and optionally a fetch to substitute in tests.
|
|
31
|
+
* @returns the balance, or undefined when the provider did not answer with one.
|
|
32
|
+
*/
|
|
33
|
+
export declare function queryCcSwitchBalance(input: {
|
|
34
|
+
apiKey: string;
|
|
35
|
+
fetchFn?: FetchFn;
|
|
36
|
+
}): Promise<CcSwitchBalance | undefined>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cc-switch balance query, reimplemented for the plugin's node half.
|
|
3
|
+
*
|
|
4
|
+
* cc-switch (github.com/farion1231/cc-switch) reads a DeepSeek-compatible provider's
|
|
5
|
+
* balance with `GET https://api.deepseek.com/user/balance`, an `Authorization: Bearer
|
|
6
|
+
* <api key>` header, and a 15 s timeout. This is that request, with the URL hardcoded
|
|
7
|
+
* exactly as cc-switch does — the provider's own base URL is never substituted in.
|
|
8
|
+
*
|
|
9
|
+
* The endpoint answers `{ is_available, balance_infos: [{ currency, total_balance, … }] }`,
|
|
10
|
+
* where a balance is a number or a numeric string. The module reduces that to the one
|
|
11
|
+
* figure a status chip needs: the first currency's total. Anything else — a missing key,
|
|
12
|
+
* a non-2xx answer, malformed JSON — resolves to nothing, so the caller shows no balance
|
|
13
|
+
* rather than a wrong one.
|
|
14
|
+
*
|
|
15
|
+
* @module dsh-plugin-subscription-oauth/auth/ccswitch
|
|
16
|
+
*/
|
|
17
|
+
import { proxiedFetch } from '../http.js';
|
|
18
|
+
/** Read a balance field that may be a number or a numeric string. */
|
|
19
|
+
function num(value) {
|
|
20
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
21
|
+
return String(value);
|
|
22
|
+
if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value)))
|
|
23
|
+
return value.trim();
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Query one provider's balance the way cc-switch does.
|
|
28
|
+
*
|
|
29
|
+
* @param input - the provider's API key, and optionally a fetch to substitute in tests.
|
|
30
|
+
* @returns the balance, or undefined when the provider did not answer with one.
|
|
31
|
+
*/
|
|
32
|
+
export async function queryCcSwitchBalance(input) {
|
|
33
|
+
const fetchFn = input.fetchFn ?? proxiedFetch;
|
|
34
|
+
let response;
|
|
35
|
+
try {
|
|
36
|
+
// cc-switch's exact request shape: hardcoded URL, bearer auth, 15 s timeout.
|
|
37
|
+
response = await fetchFn('https://api.deepseek.com/user/balance', {
|
|
38
|
+
headers: { authorization: `Bearer ${input.apiKey}`, accept: 'application/json' },
|
|
39
|
+
signal: AbortSignal.timeout(15_000),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
if (!response.ok)
|
|
46
|
+
return undefined;
|
|
47
|
+
let payload;
|
|
48
|
+
try {
|
|
49
|
+
payload = await response.json();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
if (typeof payload !== 'object' || payload === null)
|
|
55
|
+
return undefined;
|
|
56
|
+
const record = payload;
|
|
57
|
+
const infos = record.balance_infos;
|
|
58
|
+
if (!Array.isArray(infos))
|
|
59
|
+
return undefined;
|
|
60
|
+
for (const raw of infos) {
|
|
61
|
+
if (typeof raw !== 'object' || raw === null)
|
|
62
|
+
continue;
|
|
63
|
+
const info = raw;
|
|
64
|
+
const total = num(info.total_balance);
|
|
65
|
+
if (total === undefined)
|
|
66
|
+
continue;
|
|
67
|
+
const currency = typeof info.currency === 'string' && info.currency.trim() !== '' ? info.currency.trim() : 'CNY';
|
|
68
|
+
return {
|
|
69
|
+
currency,
|
|
70
|
+
total,
|
|
71
|
+
available: record.is_available !== false,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
package/lib/auth/rpc.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How one named credential resolves to a value.
|
|
3
|
+
*
|
|
4
|
+
* The host's credential service owns this; the RPC layer only calls it, so the balance
|
|
5
|
+
* query does not re-derive how a key is stored.
|
|
6
|
+
*/
|
|
7
|
+
export type CredentialResolver = (ref: string) => Promise<string | undefined>;
|
|
1
8
|
/**
|
|
2
9
|
* The host-side transport behind the Settings page.
|
|
3
10
|
*
|
|
@@ -21,7 +28,7 @@ import type { SubscriptionRegistry } from './registry.js';
|
|
|
21
28
|
* @param payload - the request's decoded payload.
|
|
22
29
|
* @returns the envelope result.
|
|
23
30
|
*/
|
|
24
|
-
export declare function dispatchRpc(registry: SubscriptionRegistry, endpoint: string, payload: unknown): Promise<RpcResult>;
|
|
31
|
+
export declare function dispatchRpc(registry: SubscriptionRegistry, endpoint: string, payload: unknown, resolveCredential?: CredentialResolver): Promise<RpcResult>;
|
|
25
32
|
/**
|
|
26
33
|
* Register every endpoint route on the `connection` service, when one exists.
|
|
27
34
|
*
|
package/lib/auth/rpc.js
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The host-side transport behind the Settings page.
|
|
3
|
-
*
|
|
4
|
-
* Each endpoint is served as its own `POST /api/subscription-oauth.<endpoint>`
|
|
5
|
-
* Fetch route on the `connection` service. `connection` is deliberately not in
|
|
6
|
-
* the plugin's `inject` list: a headless composition has no connection service,
|
|
7
|
-
* and the provider routes must still work there. Nothing else is registered
|
|
8
|
-
* when it is absent, so the browser half simply finds no routes.
|
|
9
|
-
*
|
|
10
|
-
* @module dsh-plugin-subscription-oauth/auth/rpc
|
|
11
|
-
*/
|
|
12
1
|
import { BAD_REQUEST, ProviderError } from '../errors.js';
|
|
2
|
+
import { queryCcSwitchBalance } from './ccswitch.js';
|
|
13
3
|
import { RPC_ENDPOINTS, RPC_PREFIX } from '../protocol.js';
|
|
14
4
|
/** Wrap a value as a successful envelope result. */
|
|
15
5
|
function success(value) {
|
|
@@ -85,9 +75,9 @@ function requiredProvider(payload, endpoint) {
|
|
|
85
75
|
* @param payload - the request's decoded payload.
|
|
86
76
|
* @returns the envelope result.
|
|
87
77
|
*/
|
|
88
|
-
export async function dispatchRpc(registry, endpoint, payload) {
|
|
78
|
+
export async function dispatchRpc(registry, endpoint, payload, resolveCredential) {
|
|
89
79
|
try {
|
|
90
|
-
return success(await runEndpoint(registry, endpoint, payload));
|
|
80
|
+
return success(await runEndpoint(registry, endpoint, payload, resolveCredential));
|
|
91
81
|
}
|
|
92
82
|
catch (error) {
|
|
93
83
|
return failure(error);
|
|
@@ -97,7 +87,7 @@ export async function dispatchRpc(registry, endpoint, payload) {
|
|
|
97
87
|
* The endpoint table.
|
|
98
88
|
* @throws {ProviderError} for a request the registry refuses.
|
|
99
89
|
*/
|
|
100
|
-
async function runEndpoint(registry, endpoint, payload) {
|
|
90
|
+
async function runEndpoint(registry, endpoint, payload, resolveCredential) {
|
|
101
91
|
switch (endpoint) {
|
|
102
92
|
case 'status':
|
|
103
93
|
return registry.status();
|
|
@@ -145,6 +135,21 @@ async function runEndpoint(registry, endpoint, payload) {
|
|
|
145
135
|
}
|
|
146
136
|
case 'usage':
|
|
147
137
|
return registry.usage(requiredProvider(payload, endpoint), booleanField(payload, 'force'));
|
|
138
|
+
case 'ccswitch-balance': {
|
|
139
|
+
// A manually added provider's balance, by cc-switch's query. The caller names the
|
|
140
|
+
// credential reference the provider's profile uses (its apiKeyEnv), and the host's
|
|
141
|
+
// credential service resolves it. No key, or a key the provider does not answer
|
|
142
|
+
// for, means no balance — never a fabricated zero.
|
|
143
|
+
if (resolveCredential === undefined)
|
|
144
|
+
return undefined;
|
|
145
|
+
const credentialRef = stringField(payload, 'credentialRef');
|
|
146
|
+
if (credentialRef === undefined)
|
|
147
|
+
return undefined;
|
|
148
|
+
const apiKey = await resolveCredential(credentialRef);
|
|
149
|
+
if (apiKey === undefined)
|
|
150
|
+
return undefined;
|
|
151
|
+
return await queryCcSwitchBalance({ apiKey });
|
|
152
|
+
}
|
|
148
153
|
case 'reload':
|
|
149
154
|
return registry.reload();
|
|
150
155
|
default:
|
|
@@ -152,7 +157,7 @@ async function runEndpoint(registry, endpoint, payload) {
|
|
|
152
157
|
}
|
|
153
158
|
}
|
|
154
159
|
/** Build the Fetch route for one endpoint. */
|
|
155
|
-
function rpcRoute(endpoint, registry) {
|
|
160
|
+
function rpcRoute(endpoint, registry, resolveCredential) {
|
|
156
161
|
const method = `${RPC_PREFIX}${endpoint}`;
|
|
157
162
|
return {
|
|
158
163
|
path: `/api/${method}`,
|
|
@@ -176,7 +181,7 @@ function rpcRoute(endpoint, registry) {
|
|
|
176
181
|
if (envelopeRequest.type !== 'client-request' || envelopeRequest.method !== method) {
|
|
177
182
|
return rejection(rpcId, 'gateway/bad-request', `${method} received an envelope for another method`, 400);
|
|
178
183
|
}
|
|
179
|
-
return envelope(rpcId, await dispatchRpc(registry, endpoint, envelopeRequest.payload));
|
|
184
|
+
return envelope(rpcId, await dispatchRpc(registry, endpoint, envelopeRequest.payload, resolveCredential));
|
|
180
185
|
},
|
|
181
186
|
};
|
|
182
187
|
}
|
|
@@ -191,10 +196,17 @@ export function registerSubscriptionRpc(ctx, registry) {
|
|
|
191
196
|
const connection = connectionCtx.get('connection');
|
|
192
197
|
if (connection === undefined)
|
|
193
198
|
return;
|
|
199
|
+
// The cc-switch balance endpoint resolves a credential reference through the host's
|
|
200
|
+
// credential service. It is optional: a composition with no credential service still
|
|
201
|
+
// serves every other endpoint, and the balance endpoint simply answers nothing.
|
|
202
|
+
const credentials = connectionCtx.get('credentials');
|
|
203
|
+
const resolveCredential = credentials?.resolve === undefined
|
|
204
|
+
? undefined
|
|
205
|
+
: async (ref) => (await credentials.resolve?.(ref))?.value;
|
|
194
206
|
const register = (route) => connection.fetch.register(route);
|
|
195
207
|
for (const endpoint of RPC_ENDPOINTS) {
|
|
196
208
|
const method = `${RPC_PREFIX}${endpoint}`;
|
|
197
|
-
connectionCtx.effect(() => register(rpcRoute(endpoint, registry)), `dsh-plugin-subscription-oauth: /api/${method} route`);
|
|
209
|
+
connectionCtx.effect(() => register(rpcRoute(endpoint, registry, resolveCredential)), `dsh-plugin-subscription-oauth: /api/${method} route`);
|
|
198
210
|
}
|
|
199
211
|
});
|
|
200
212
|
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The usage chip that rides the composer's bottom bar.
|
|
3
|
+
*
|
|
4
|
+
* The bar itself is a slot the shell owns. `conversation.composer.dock` is a
|
|
5
|
+
* session-scoped `list`, and the shell's own stats pills (`tok/s`, cache hit) and its
|
|
6
|
+
* context meter register into it; this chip joins as the last entry, so it reads to the
|
|
7
|
+
* right of the context meter. It is deliberately compact — an abbreviated route name
|
|
8
|
+
* and the percentage — because the bar is a status line, not a dashboard; the full
|
|
9
|
+
* figure, its reset and the meter appear when the chip is clicked.
|
|
10
|
+
*
|
|
11
|
+
* Two silences are deliberate: a provider this plugin does not own shows nothing rather
|
|
12
|
+
* than a fabricated zero, and switching to a foreign provider keeps the last own reading
|
|
13
|
+
* on screen instead of blanking the bar — the shell's own pills already speak for the
|
|
14
|
+
* foreign one.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-plugin-subscription-oauth/client/UsageChip
|
|
17
|
+
*/
|
|
18
|
+
import type { ReactNode } from 'react';
|
|
19
|
+
import type { SessionStandardProps } from '@deepseek-ai/dsh-client-ui-slots';
|
|
20
|
+
import type { SubscriptionsCall, AccountBalanceCall, CcSwitchBalanceCall } from './subscriptions-rpc.js';
|
|
21
|
+
import type { ProviderUsage, UsageWindow } from '../protocol.js';
|
|
22
|
+
/** Injected props the chip is registered with. */
|
|
23
|
+
export interface UsageChipInjected {
|
|
24
|
+
/** The plugin's own RPC caller. */
|
|
25
|
+
call: SubscriptionsCall;
|
|
26
|
+
/** Copy for the active locale. */
|
|
27
|
+
t: (key: 'usageChipTitle' | 'usageChipFull', values?: Record<string, string | number>) => string;
|
|
28
|
+
/** Whether the provider is one this plugin serves. */
|
|
29
|
+
isOwnProvider: (provider: string) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The DeepSeek account's balance, when the session uses it.
|
|
32
|
+
*
|
|
33
|
+
* The host owns that account's grant and the platform endpoint, so the chip asks the
|
|
34
|
+
* host rather than re-deriving either. It resolves to `undefined` when the account is
|
|
35
|
+
* signed out or the read fails, in which case the chip stays silent.
|
|
36
|
+
*/
|
|
37
|
+
accountBalance: AccountBalanceCall;
|
|
38
|
+
/**
|
|
39
|
+
* A manually added provider's balance, by cc-switch's query.
|
|
40
|
+
*
|
|
41
|
+
* The caller names the credential reference the provider's profile uses (its
|
|
42
|
+
* `apiKeyEnv`); the host's credential service resolves it, and the node half asks
|
|
43
|
+
* cc-switch's balance endpoint. It resolves to `undefined` when there is no key or
|
|
44
|
+
* the provider did not answer.
|
|
45
|
+
*/
|
|
46
|
+
ccSwitchBalance: CcSwitchBalanceCall;
|
|
47
|
+
/**
|
|
48
|
+
* The credential reference a manually added provider's balance query uses, by provider
|
|
49
|
+
* id.
|
|
50
|
+
*
|
|
51
|
+
* A manually added provider is not one this plugin serves and has no account route, so
|
|
52
|
+
* the only way to read its balance is cc-switch's query, which needs the provider's API
|
|
53
|
+
* key. That key is named by the provider's profile (`apiKeyEnv`), and the host's
|
|
54
|
+
* credential service resolves the name; this map is the one place a provider id is tied
|
|
55
|
+
* to that name. A provider with no entry gets no balance.
|
|
56
|
+
*/
|
|
57
|
+
ccSwitchCredentialRef: (provider: string) => string | undefined;
|
|
58
|
+
}
|
|
59
|
+
/** One model choice, as the host records it. */
|
|
60
|
+
export interface ModelSelection {
|
|
61
|
+
/** Provider route key. */
|
|
62
|
+
readonly provider: string;
|
|
63
|
+
/** Model id. */
|
|
64
|
+
readonly model: string;
|
|
65
|
+
/** Reasoning effort, when one was chosen. */
|
|
66
|
+
readonly reasoningEffort?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The session's model-selection projection, as the host wires it.
|
|
70
|
+
*
|
|
71
|
+
* `next` is a selection the user has made but not yet used; `lastUsed` is the one a
|
|
72
|
+
* request actually ran with. Reading `next` first is what makes the chip follow the
|
|
73
|
+
* picker immediately rather than only after the next message.
|
|
74
|
+
*/
|
|
75
|
+
export interface ModelSelectionProjection {
|
|
76
|
+
/** The last selection a request ran with. */
|
|
77
|
+
readonly lastUsed: ModelSelection | null;
|
|
78
|
+
/** The selection in force now. */
|
|
79
|
+
readonly next: ModelSelection | null;
|
|
80
|
+
}
|
|
81
|
+
/** The session's provider, from its model-selection projection. */
|
|
82
|
+
export declare function providerOf(projection: ModelSelectionProjection | null | undefined): string | undefined;
|
|
83
|
+
/** What one route's allowance reduces to for a single line. */
|
|
84
|
+
export interface ChipReading {
|
|
85
|
+
/** Route the figures belong to. */
|
|
86
|
+
provider: string;
|
|
87
|
+
/** Name to show, as the route states it. */
|
|
88
|
+
label: string;
|
|
89
|
+
/** Every window that states a figure, in the order the route stated them. */
|
|
90
|
+
windows: readonly UsageWindow[];
|
|
91
|
+
/** The window worth showing in the compact line: the one closest to its limit. */
|
|
92
|
+
window: UsageWindow;
|
|
93
|
+
/** Plan name, when the provider stated one. */
|
|
94
|
+
plan?: string;
|
|
95
|
+
}
|
|
96
|
+
/** One currency's balance, as the host's account controller reports it. */
|
|
97
|
+
export interface ChipBalance {
|
|
98
|
+
/** The wallet's currency. */
|
|
99
|
+
currency: string;
|
|
100
|
+
/** Remaining balance, as a decimal string. */
|
|
101
|
+
balance: string;
|
|
102
|
+
/** Whether this is a bonus / promotional wallet rather than topped-up credit. */
|
|
103
|
+
bonus: boolean;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Reduce the host's account-balance payload to the wallets the chip shows.
|
|
107
|
+
*
|
|
108
|
+
* Bonus wallets are shown after the topped-up ones, so a reader sees their own credit
|
|
109
|
+
* first and any promotional credit as a secondary figure.
|
|
110
|
+
*
|
|
111
|
+
* @param value - the host's ready balance, or undefined when there is none.
|
|
112
|
+
* @returns the wallets, topped-up first then bonus, or undefined when nothing is usable.
|
|
113
|
+
*/
|
|
114
|
+
export declare function balanceOf(value: {
|
|
115
|
+
value?: readonly {
|
|
116
|
+
currency: string;
|
|
117
|
+
balance: string;
|
|
118
|
+
}[];
|
|
119
|
+
bonusWallets?: readonly {
|
|
120
|
+
currency: string;
|
|
121
|
+
balance: string;
|
|
122
|
+
}[];
|
|
123
|
+
} | {
|
|
124
|
+
status: string;
|
|
125
|
+
} | null | undefined): readonly ChipBalance[] | undefined;
|
|
126
|
+
/**
|
|
127
|
+
* Format one wallet for the chip's compact line.
|
|
128
|
+
*
|
|
129
|
+
* A balance is money, not a percentage, so it renders as `¥6.89` rather than a meter;
|
|
130
|
+
* the currency prefix keeps two currencies from being mistaken for one sum.
|
|
131
|
+
*
|
|
132
|
+
* @param wallet - the wallet to show.
|
|
133
|
+
* @returns the short form, e.g. `¥6.89` or `+¥2` for a bonus wallet.
|
|
134
|
+
*/
|
|
135
|
+
export declare function formatBalance(wallet: ChipBalance): string;
|
|
136
|
+
/**
|
|
137
|
+
* The short form of a route's name.
|
|
138
|
+
*
|
|
139
|
+
* @param provider - the route id.
|
|
140
|
+
* @param label - the route's own display name.
|
|
141
|
+
* @returns an abbreviation that still identifies the route.
|
|
142
|
+
*/
|
|
143
|
+
export declare function shortLabel(provider: string, label: string): string;
|
|
144
|
+
/**
|
|
145
|
+
* The short form of a window's name.
|
|
146
|
+
*
|
|
147
|
+
* @param label - the window's own name, e.g. `weekly`.
|
|
148
|
+
* @returns an abbreviation, or the label itself when it is already short.
|
|
149
|
+
*/
|
|
150
|
+
export declare function shortWindow(label: string): string;
|
|
151
|
+
/**
|
|
152
|
+
* Pick the window a single line should show.
|
|
153
|
+
*
|
|
154
|
+
* A plan can meter several windows at once (a rolling five-hour one and a weekly one).
|
|
155
|
+
* The most constrained is the one that will stop work soonest, so it earns the space;
|
|
156
|
+
* ties fall to the earlier window, which is the order the providers state them in.
|
|
157
|
+
*
|
|
158
|
+
* @param windows - the route's metered windows.
|
|
159
|
+
* @returns the window to show, or undefined when none states a figure.
|
|
160
|
+
*/
|
|
161
|
+
export declare function pickWindow(windows: readonly UsageWindow[]): UsageWindow | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* Reduce one route's usage to what the chip renders.
|
|
164
|
+
*
|
|
165
|
+
* @param provider - the route the figures came from.
|
|
166
|
+
* @param label - the route's display name.
|
|
167
|
+
* @param usage - the accounts the route answered for.
|
|
168
|
+
* @returns the reading, or undefined when the route stated no figure.
|
|
169
|
+
*/
|
|
170
|
+
export declare function readingOf(provider: string, label: string, usage: readonly ProviderUsage[]): ChipReading | undefined;
|
|
171
|
+
/**
|
|
172
|
+
* Format a window's reset the way the settings cards do.
|
|
173
|
+
*
|
|
174
|
+
* The rule is shared with the cards on purpose: a figure reading `6d20h` here and
|
|
175
|
+
* something else there would be two answers to one question.
|
|
176
|
+
*
|
|
177
|
+
* @param at - epoch milliseconds, or undefined when the provider states none.
|
|
178
|
+
* @param now - the instant to measure from.
|
|
179
|
+
* @returns a short phrase, or undefined when there is no reset to show.
|
|
180
|
+
*/
|
|
181
|
+
export declare function formatReset(at: number | undefined, now: number): string | undefined;
|
|
182
|
+
/**
|
|
183
|
+
* The composer's usage chip.
|
|
184
|
+
*
|
|
185
|
+
* @param props - injected RPC caller, copy, and the session's provider reader.
|
|
186
|
+
* @returns the chip, or null when there is nothing true to say.
|
|
187
|
+
*/
|
|
188
|
+
export declare function UsageChip({ call, t, isOwnProvider, accountBalance, ccSwitchBalance, ccSwitchCredentialRef, useProjection }: UsageChipInjected & SessionStandardProps): ReactNode;
|