@aixnn/aixautots 0.0.0-stage → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ export { AutomationQueue, MirrorSession, SCHEMA_KEY, SCRCPY_PROFILES, normalizeDevices, qualityMessage, schemaDefaults, schemaToVariables, submitBatch, targetParam, variablesToSchema } from '../chunk-V4MXFPDX.js';
2
+ export { DeviceSession, getIceServers, mintViewerToken, pullFile, pushFile } from '../chunk-IJVNII5N.js';
3
+ export { DeviceChannel, DeviceTunnel, FlowRun, ScriptDebugger, mintDeviceAccess, wsUrlFromAccess } from '../chunk-OXIM6EYO.js';
4
+ export { AdminApi, AixAuthError, AixClient, AixDeviceOffline, AixError, AixLocked, AixProtocolError, AixTimeout, ApiTokensApi, AuthApi, BillingApi, ClustersApi, DevicesApi, EnvRun, FleetApi, ImagesApi, LlmApi, LocalNodeController, LocatorsApi, NodesApi, ProjectsApi, ReconnectingSocket, RestClient, ScriptsApi, ShortcutsApi, TasksApi, UsersApi, WebhooksApi, authHeader, buildAuthProvider, createCachedUserCredential, createClient, detectEnvOs, envBlocker, errorFromRet, executionStreamEventsAfter, executionWsTicketUrl, executionWsUrl, getLocale, isEnvEventFrame, isExecutionFrame, isFleetRunTerminal, isFridaEventFrame, isRetFrame, isScriptletEventFrame, isStatusFrame, joinUrl, parseIncoming, resolveConfig, restClient, runEnvToFinish, setLocale, summarizeEnv, t } from '../chunk-TATL3HTE.js';
5
+ export { classifyDrag, mapKey, toDevicePoint } from '../chunk-NWFYTFMI.js';
@@ -0,0 +1,2 @@
1
+ export { DeviceSession, pullFile, pushFile } from './chunk-IJVNII5N.js';
2
+ import './chunk-TATL3HTE.js';
@@ -0,0 +1 @@
1
+ export { AixI18nProvider, useAixLang, useAixT } from '../chunk-64Q7BBIQ.js';
@@ -0,0 +1 @@
1
+ export { AixNavProvider, useAixNav } from '../chunk-5BMFMDQR.js';
@@ -0,0 +1,7 @@
1
+ export { DevicesProvider, GROUP_MIRROR_MAX, InspectorProvider, NodesProvider, ShortcutsProvider, mapDevice, preflightTaskAgentDevice, useAdmin, useApiTokens, useAuth, useAutomationQueue, useBilling, useClusters, useCommands, useDeviceActions, useDevices, useDevicesView, useEnvGate, useFleetRun, useFlowRun, useGroupMirror, useImages, useInspector, useInspectorView, useLlm, useLocators, useMirror, useNodes, useNodesView, useProjects, useScriptRun, useScripts, useShortcutsView, useTaskAgentRun, useTaskStatus, useTasks, useWebhooks } from '../chunk-O34SNDQB.js';
2
+ import '../chunk-V4MXFPDX.js';
3
+ import '../chunk-IJVNII5N.js';
4
+ export { AixProvider, useAixConfig, useClient, useDevice, useEnvRun, useQuery, useScript } from '../chunk-UINEPEIE.js';
5
+ import '../chunk-OXIM6EYO.js';
6
+ import '../chunk-TATL3HTE.js';
7
+ import '../chunk-NWFYTFMI.js';
@@ -0,0 +1,425 @@
1
+ import { useAixT } from '../chunk-64Q7BBIQ.js';
2
+ import { cn, Button, Badge, Input } from '../chunk-EVHTAXQG.js';
3
+ import { useBilling } from '../chunk-O34SNDQB.js';
4
+ import '../chunk-V4MXFPDX.js';
5
+ import '../chunk-IJVNII5N.js';
6
+ import { useClient } from '../chunk-UINEPEIE.js';
7
+ import '../chunk-OXIM6EYO.js';
8
+ import '../chunk-TATL3HTE.js';
9
+ import '../chunk-NWFYTFMI.js';
10
+ import { useState, useEffect } from 'react';
11
+ import { SlidersHorizontal, Server, CalendarClock, Smartphone, ArrowUpCircle, ArrowDownCircle, HeadphonesIcon, Wallet, X, RefreshCw } from 'lucide-react';
12
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
13
+
14
+ var TABLE = {
15
+ topup: { icon: ArrowUpCircle, i18nKey: "billing.kind.topup", sign: "credit" },
16
+ platform_session: { icon: Smartphone, i18nKey: "billing.kind.platform_session", sign: "debit" },
17
+ subscription: { icon: CalendarClock, i18nKey: "billing.kind.subscription", sign: "debit" },
18
+ own_node_daily: { icon: Server, i18nKey: "billing.kind.own_node_daily", sign: "debit" },
19
+ adjust: { icon: SlidersHorizontal, i18nKey: "billing.kind.adjust", sign: "debit" }
20
+ };
21
+ var FALLBACK = {
22
+ icon: ArrowDownCircle,
23
+ i18nKey: "billing.kind.adjust",
24
+ sign: "debit"
25
+ };
26
+ function ledgerKindMeta(kind, amount) {
27
+ const base = TABLE[kind] ?? FALLBACK;
28
+ if (kind === "adjust" && amount !== void 0) {
29
+ return { ...base, sign: amount >= 0 ? "credit" : "debit" };
30
+ }
31
+ return base;
32
+ }
33
+ function RechargeMethods() {
34
+ const t = useAixT();
35
+ const channels = [
36
+ {
37
+ key: "wechat",
38
+ label: t("recharge.wechat"),
39
+ icon: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-5 w-5 fill-current", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.295.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-3.898-6.348-7.601-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178A1.17 1.17 0 0 1 4.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178 1.17 1.17 0 0 1-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 0 1 .598.082l1.584.926a.272.272 0 0 0 .14.047c.134 0 .24-.111.24-.247 0-.06-.023-.12-.038-.177l-.327-1.233a.582.582 0 0 1-.023-.156.49.49 0 0 1 .201-.398C23.024 18.48 24 16.82 24 14.98c0-3.21-2.931-5.837-7.063-6.122zm-3.494 3.096c.529 0 .957.44.957.983a.97.97 0 0 1-.957.981.97.97 0 0 1-.957-.981c0-.544.429-.983.957-.983zm4.976 0c.529 0 .957.44.957.983a.97.97 0 0 1-.957.981.97.97 0 0 1-.957-.981c0-.544.428-.983.957-.983z" }) }),
40
+ color: "text-green-500",
41
+ bg: "bg-green-500/10"
42
+ },
43
+ {
44
+ key: "alipay",
45
+ label: t("recharge.alipay"),
46
+ icon: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-5 w-5 fill-current", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M21.422 15.358c-3.83-1.153-6.055-1.84-6.055-1.84s1.485-3.37 1.822-5.51H13.5V6.85h4.5V5.768H13.5V3h-2.723v2.768H6.234v1.082h4.543v1.158H7.09v1.056h8.35c-.217 1.115-.672 2.514-1.207 3.528-1.983-.53-4.084-.946-5.873-.622-3.586.646-4.783 3.204-4.5 5.084.295 1.95 2.156 3.603 5.019 3.603 2.85 0 5.535-1.61 7.534-4.477 1.91.853 4.286 1.805 6.586 2.56L24 16.74c0-.001-.887-.864-2.578-1.382zm-12.27 2.936c-2.064 0-3.357-1.025-3.52-2.137-.186-1.25.814-2.477 2.658-2.797 1.016-.18 2.357.04 3.82.59-1.366 2.78-2.91 4.344-4.958 4.344z" }) }),
47
+ color: "text-blue-500",
48
+ bg: "bg-blue-500/10"
49
+ }
50
+ ];
51
+ return /* @__PURE__ */ jsxs("section", { children: [
52
+ /* @__PURE__ */ jsx("h3", { className: "mb-1 text-xs font-semibold text-foreground", children: t("recharge.methods") }),
53
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs text-muted-foreground", children: t("recharge.desc") }),
54
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: [
55
+ channels.map((ch) => /* @__PURE__ */ jsxs(
56
+ "div",
57
+ {
58
+ className: "flex cursor-default items-center gap-2.5 rounded-md border border-border px-3 py-2.5 transition-colors hover:bg-secondary/40",
59
+ title: t("recharge.comingSoon"),
60
+ children: [
61
+ /* @__PURE__ */ jsx("span", { className: cn("flex h-8 w-8 shrink-0 items-center justify-center rounded-full", ch.bg, ch.color), children: ch.icon }),
62
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
63
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-foreground", children: ch.label }),
64
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: t("recharge.comingSoon") })
65
+ ] })
66
+ ]
67
+ },
68
+ ch.key
69
+ )),
70
+ /* @__PURE__ */ jsxs("div", { className: "flex cursor-default items-center gap-2.5 rounded-md border border-border px-3 py-2.5 transition-colors hover:bg-secondary/40", children: [
71
+ /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-muted/40 text-muted-foreground", children: /* @__PURE__ */ jsx(HeadphonesIcon, { className: "h-4 w-4" }) }),
72
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
73
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-foreground", children: t("recharge.contact") }),
74
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: t("recharge.contactDesc") })
75
+ ] })
76
+ ] })
77
+ ] })
78
+ ] });
79
+ }
80
+ function RechargeDrawer({ open, onClose }) {
81
+ const t = useAixT();
82
+ const { data: balance, loading } = useBilling();
83
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
84
+ /* @__PURE__ */ jsx(
85
+ "div",
86
+ {
87
+ className: cn(
88
+ "fixed inset-0 z-30 bg-black/40 transition-opacity duration-300",
89
+ open ? "opacity-100" : "pointer-events-none opacity-0"
90
+ ),
91
+ onClick: onClose
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsxs(
95
+ "div",
96
+ {
97
+ className: cn(
98
+ "fixed right-0 top-0 z-40 flex h-full w-full max-w-md flex-col border-l border-border bg-card transition-transform duration-300 ease-in-out",
99
+ open ? "translate-x-0" : "translate-x-full"
100
+ ),
101
+ role: "dialog",
102
+ "aria-label": t("recharge.title"),
103
+ children: [
104
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 py-3", children: [
105
+ /* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-body-md font-semibold text-foreground", children: [
106
+ /* @__PURE__ */ jsx(Wallet, { className: "h-4 w-4" }),
107
+ t("recharge.title")
108
+ ] }),
109
+ /* @__PURE__ */ jsx(
110
+ "button",
111
+ {
112
+ type: "button",
113
+ "aria-label": t("common.close"),
114
+ onClick: onClose,
115
+ className: "rounded p-1 text-muted-foreground hover:bg-secondary hover:text-foreground",
116
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
117
+ }
118
+ )
119
+ ] }),
120
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [
121
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-border bg-card p-4", children: [
122
+ /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Wallet, { className: "h-5 w-5" }) }),
123
+ /* @__PURE__ */ jsxs("div", { children: [
124
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("billing.balance") }),
125
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold text-foreground", children: balance ? `${balance.balance} ${balance.currency}` : loading ? t("billing.loading") : "\u2014" })
126
+ ] })
127
+ ] }),
128
+ /* @__PURE__ */ jsx(RechargeMethods, {})
129
+ ] })
130
+ ]
131
+ }
132
+ )
133
+ ] });
134
+ }
135
+ function BillingPage() {
136
+ const t = useAixT();
137
+ const client = useClient();
138
+ const { data: balance, loading, error, refetch: refresh } = useBilling();
139
+ const [subs, setSubs] = useState([]);
140
+ const [charges, setCharges] = useState([]);
141
+ const [rechargeOpen, setRechargeOpen] = useState(false);
142
+ useEffect(() => {
143
+ let cancelled = false;
144
+ (async () => {
145
+ try {
146
+ const [s, c] = await Promise.all([
147
+ client.billing.subscriptions().catch(() => []),
148
+ client.billing.ownNodeCharges().catch(() => [])
149
+ ]);
150
+ if (!cancelled) {
151
+ setSubs(s);
152
+ setCharges(c);
153
+ }
154
+ } catch {
155
+ }
156
+ })();
157
+ return () => {
158
+ cancelled = true;
159
+ };
160
+ }, [client]);
161
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
162
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2 sm:px-6", children: [
163
+ /* @__PURE__ */ jsx("h1", { className: "text-body-md font-semibold text-foreground", children: t("billing.title") }),
164
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
165
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "sm", onClick: () => void refresh(), disabled: loading, children: [
166
+ /* @__PURE__ */ jsx(RefreshCw, { className: cn("h-3.5 w-3.5", loading && "animate-spin") }),
167
+ t("billing.refresh")
168
+ ] }),
169
+ /* @__PURE__ */ jsxs(Button, { variant: "primary", size: "sm", onClick: () => setRechargeOpen(true), children: [
170
+ /* @__PURE__ */ jsx(Wallet, { className: "h-3.5 w-3.5" }),
171
+ t("recharge.title")
172
+ ] })
173
+ ] })
174
+ ] }),
175
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4 overflow-auto p-3 sm:p-6", children: [
176
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error.message }),
177
+ /* @__PURE__ */ jsx(LedgerSection, { rows: balance?.recent ?? [], loading, t }),
178
+ /* @__PURE__ */ jsx(SubsSection, { subs, t }),
179
+ /* @__PURE__ */ jsx(OwnNodeSection, { charges, t })
180
+ ] }),
181
+ /* @__PURE__ */ jsx(RechargeDrawer, { open: rechargeOpen, onClose: () => setRechargeOpen(false) })
182
+ ] });
183
+ }
184
+ function LedgerSection({ rows, loading, t }) {
185
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-lg border border-border bg-card p-3 sm:p-4", children: [
186
+ /* @__PURE__ */ jsx("h2", { className: "mb-2 text-xs font-semibold text-foreground", children: t("billing.ledger") }),
187
+ rows.length === 0 ? /* @__PURE__ */ jsx("p", { className: "py-6 text-center text-xs text-muted-foreground", children: loading ? t("common.loading") : t("billing.ledger.empty") }) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-xs", children: [
188
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border text-left text-muted-foreground", children: [
189
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 pr-2 font-medium", children: t("billing.col.kind") }),
190
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 pr-2 text-right font-medium", children: t("billing.col.amount") }),
191
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 pr-2 text-right font-medium", children: t("billing.col.balanceAfter") }),
192
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 pr-2 font-medium", children: t("billing.col.ref") }),
193
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 font-medium", children: t("billing.col.time") })
194
+ ] }) }),
195
+ /* @__PURE__ */ jsx("tbody", { children: rows.map((r) => {
196
+ const meta = ledgerKindMeta(r.kind);
197
+ const Icon = meta.icon;
198
+ const credit = meta.sign === "credit";
199
+ return /* @__PURE__ */ jsxs("tr", { className: "border-b border-border/50", children: [
200
+ /* @__PURE__ */ jsx("td", { className: "py-1.5 pr-2", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-foreground", children: [
201
+ /* @__PURE__ */ jsx(
202
+ Icon,
203
+ {
204
+ className: cn("h-3.5 w-3.5", credit ? "text-green-500" : "text-muted-foreground")
205
+ }
206
+ ),
207
+ t(meta.i18nKey)
208
+ ] }) }),
209
+ /* @__PURE__ */ jsxs(
210
+ "td",
211
+ {
212
+ className: cn(
213
+ "py-1.5 pr-2 text-right font-mono",
214
+ credit ? "text-green-500" : "text-destructive"
215
+ ),
216
+ children: [
217
+ credit ? "+" : "-",
218
+ String(r.amount)
219
+ ]
220
+ }
221
+ ),
222
+ /* @__PURE__ */ jsx("td", { className: "py-1.5 pr-2 text-right font-mono text-muted-foreground", children: String(r.balance_after) }),
223
+ /* @__PURE__ */ jsx("td", { className: "max-w-[12rem] truncate py-1.5 pr-2 text-muted-foreground", title: r.ref, children: r.ref }),
224
+ /* @__PURE__ */ jsx("td", { className: "py-1.5 text-muted-foreground", children: new Date(r.created_at).toLocaleString() })
225
+ ] }, r.id);
226
+ }) })
227
+ ] }) })
228
+ ] });
229
+ }
230
+ function SubsSection({ subs, t }) {
231
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-lg border border-border bg-card p-3 sm:p-4", children: [
232
+ /* @__PURE__ */ jsx("h2", { className: "mb-2 text-xs font-semibold text-foreground", children: t("billing.subs") }),
233
+ subs.length === 0 ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-xs text-muted-foreground", children: t("billing.subs.empty") }) : /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: subs.map((s) => /* @__PURE__ */ jsxs(
234
+ "div",
235
+ {
236
+ className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-md border border-border/60 px-2.5 py-1.5 text-xs",
237
+ children: [
238
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: s.tier }),
239
+ /* @__PURE__ */ jsx(Badge, { variant: s.status === "active" ? "success" : "muted", children: s.status }),
240
+ s.remaining_hours != null && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
241
+ t("billing.subs.remaining"),
242
+ ": ",
243
+ String(s.remaining_hours)
244
+ ] }),
245
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
246
+ t("billing.subs.expires"),
247
+ ": ",
248
+ new Date(s.expires_at).toLocaleDateString()
249
+ ] }),
250
+ s.bound_device_id && /* @__PURE__ */ jsxs("span", { className: "truncate font-mono text-muted-foreground", title: s.bound_device_id, children: [
251
+ t("billing.subs.boundDevice"),
252
+ ": ",
253
+ s.bound_device_id.slice(0, 8)
254
+ ] })
255
+ ]
256
+ },
257
+ s.id
258
+ )) })
259
+ ] });
260
+ }
261
+ function OwnNodeSection({ charges, t }) {
262
+ return /* @__PURE__ */ jsxs("section", { className: "rounded-lg border border-border bg-card p-3 sm:p-4", children: [
263
+ /* @__PURE__ */ jsx("h2", { className: "mb-2 text-xs font-semibold text-foreground", children: t("billing.ownNode") }),
264
+ charges.length === 0 ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-xs text-muted-foreground", children: t("billing.ownNode.empty") }) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-xs", children: [
265
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border text-left text-muted-foreground", children: [
266
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 pr-2 font-medium", children: t("billing.ownNode.day") }),
267
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 pr-2 text-right font-medium", children: t("billing.ownNode.devices") }),
268
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 pr-2 text-right font-medium", children: t("billing.ownNode.billable") }),
269
+ /* @__PURE__ */ jsx("th", { className: "py-1.5 text-right font-medium", children: t("billing.ownNode.amount") })
270
+ ] }) }),
271
+ /* @__PURE__ */ jsx("tbody", { children: charges.map((c) => /* @__PURE__ */ jsxs("tr", { className: "border-b border-border/50", children: [
272
+ /* @__PURE__ */ jsx("td", { className: "py-1.5 pr-2 text-foreground", children: c.day }),
273
+ /* @__PURE__ */ jsx("td", { className: "py-1.5 pr-2 text-right text-muted-foreground", children: c.device_count }),
274
+ /* @__PURE__ */ jsx("td", { className: "py-1.5 pr-2 text-right text-muted-foreground", children: c.billable }),
275
+ /* @__PURE__ */ jsxs("td", { className: "py-1.5 text-right font-mono text-foreground", children: [
276
+ String(c.amount),
277
+ " ",
278
+ c.currency
279
+ ] })
280
+ ] }, c.id)) })
281
+ ] }) })
282
+ ] });
283
+ }
284
+ function RechargePage() {
285
+ const t = useAixT();
286
+ const { data: balance, loading, error, refetch: refresh } = useBilling();
287
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
288
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2 sm:px-6", children: [
289
+ /* @__PURE__ */ jsx("h1", { className: "text-body-md font-semibold text-foreground", children: t("recharge.title") }),
290
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "sm", onClick: () => void refresh(), disabled: loading, children: [
291
+ /* @__PURE__ */ jsx(RefreshCw, { className: cn("h-3.5 w-3.5", loading && "animate-spin") }),
292
+ t("billing.refresh")
293
+ ] })
294
+ ] }),
295
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4 overflow-auto p-3 sm:p-6", children: [
296
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error.message }),
297
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-lg border border-border bg-card p-4 sm:flex-row sm:items-center sm:justify-between", children: [
298
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
299
+ /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Wallet, { className: "h-5 w-5" }) }),
300
+ /* @__PURE__ */ jsxs("div", { children: [
301
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("billing.balance") }),
302
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold text-foreground", children: balance ? `${balance.balance} ${balance.currency}` : loading ? t("billing.loading") : "\u2014" })
303
+ ] })
304
+ ] }),
305
+ /* @__PURE__ */ jsxs("p", { className: "text-xs font-medium text-primary shrink-0", children: [
306
+ t("recharge.title"),
307
+ " \u2193"
308
+ ] })
309
+ ] }),
310
+ /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-border bg-card p-3 sm:p-4", children: /* @__PURE__ */ jsx(RechargeMethods, {}) })
311
+ ] })
312
+ ] });
313
+ }
314
+ function TopupDrawer({ open, onClose, ownerUserId, ownerLabel, onDone }) {
315
+ const t = useAixT();
316
+ const { topup } = useBilling();
317
+ const [amount, setAmount] = useState("");
318
+ const [note, setNote] = useState("");
319
+ const [submitting, setSubmitting] = useState(false);
320
+ const [error, setError] = useState(null);
321
+ const [result, setResult] = useState(null);
322
+ const numeric = Number(amount);
323
+ const canSubmit = !submitting && Number.isFinite(numeric) && numeric > 0;
324
+ const submit = async () => {
325
+ if (!Number.isFinite(numeric) || numeric <= 0) {
326
+ setError(t("topup.amountInvalid"));
327
+ return;
328
+ }
329
+ setError(null);
330
+ setSubmitting(true);
331
+ try {
332
+ const res = await topup({
333
+ owner_user_id: ownerUserId,
334
+ amount: numeric,
335
+ note: note.trim() || void 0
336
+ });
337
+ setResult(res.new_balance);
338
+ onDone?.(res.new_balance);
339
+ } catch (err) {
340
+ setError(t("topup.failed", { err: String(err) }));
341
+ } finally {
342
+ setSubmitting(false);
343
+ }
344
+ };
345
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
346
+ /* @__PURE__ */ jsx(
347
+ "div",
348
+ {
349
+ className: cn(
350
+ "fixed inset-0 z-30 bg-black/40 transition-opacity duration-300",
351
+ open ? "opacity-100" : "pointer-events-none opacity-0"
352
+ ),
353
+ onClick: onClose
354
+ }
355
+ ),
356
+ /* @__PURE__ */ jsxs(
357
+ "div",
358
+ {
359
+ className: cn(
360
+ "fixed right-0 top-0 z-40 flex h-full w-full max-w-md flex-col border-l border-border bg-card transition-transform duration-300 ease-in-out",
361
+ open ? "translate-x-0" : "translate-x-full"
362
+ ),
363
+ children: [
364
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 py-3", children: [
365
+ /* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-body-md font-semibold text-foreground", children: [
366
+ /* @__PURE__ */ jsx(Wallet, { className: "h-4 w-4" }),
367
+ t("topup.title")
368
+ ] }),
369
+ /* @__PURE__ */ jsx(
370
+ "button",
371
+ {
372
+ type: "button",
373
+ "aria-label": t("common.close"),
374
+ onClick: onClose,
375
+ className: "rounded p-1 text-muted-foreground hover:bg-secondary hover:text-foreground",
376
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
377
+ }
378
+ )
379
+ ] }),
380
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [
381
+ /* @__PURE__ */ jsxs("div", { children: [
382
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium", children: t("topup.target") }),
383
+ /* @__PURE__ */ jsx("div", { className: "rounded-md border border-border bg-secondary/40 px-2.5 py-1.5 text-xs text-foreground", children: ownerLabel || ownerUserId })
384
+ ] }),
385
+ /* @__PURE__ */ jsxs("div", { children: [
386
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium", children: t("topup.amount") }),
387
+ /* @__PURE__ */ jsx(
388
+ Input,
389
+ {
390
+ type: "number",
391
+ min: 0,
392
+ value: amount,
393
+ placeholder: t("topup.amountPlaceholder"),
394
+ onChange: (e) => setAmount(e.target.value)
395
+ }
396
+ )
397
+ ] }),
398
+ /* @__PURE__ */ jsxs("div", { children: [
399
+ /* @__PURE__ */ jsx("label", { className: "mb-1 block text-xs font-medium", children: t("topup.note") }),
400
+ /* @__PURE__ */ jsx(
401
+ Input,
402
+ {
403
+ value: note,
404
+ placeholder: t("topup.notePlaceholder"),
405
+ onChange: (e) => setNote(e.target.value)
406
+ }
407
+ )
408
+ ] }),
409
+ result != null && /* @__PURE__ */ jsx("p", { className: "text-xs text-green-500", children: t("topup.done", { balance: String(result) }) }),
410
+ error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error })
411
+ ] }),
412
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-border p-4", children: [
413
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, children: t("common.cancel") }),
414
+ /* @__PURE__ */ jsxs(Button, { variant: "primary", size: "sm", onClick: submit, disabled: !canSubmit, children: [
415
+ /* @__PURE__ */ jsx(Wallet, { className: "h-3.5 w-3.5" }),
416
+ submitting ? t("topup.submitting") : t("topup.submit")
417
+ ] })
418
+ ] })
419
+ ]
420
+ }
421
+ )
422
+ ] });
423
+ }
424
+
425
+ export { BillingPage, RechargeDrawer, RechargeMethods, RechargePage, TopupDrawer, ledgerKindMeta };
@@ -0,0 +1,9 @@
1
+ export { AddWirelessDeviceDialog, DeviceCreate, NodePicker, ProxySpoofStep, RealDiscoverStep, VirtualSpecStep } from '../chunk-BSHHYM72.js';
2
+ import '../chunk-EVHTAXQG.js';
3
+ import '../chunk-O34SNDQB.js';
4
+ import '../chunk-V4MXFPDX.js';
5
+ import '../chunk-IJVNII5N.js';
6
+ import '../chunk-UINEPEIE.js';
7
+ import '../chunk-OXIM6EYO.js';
8
+ import '../chunk-TATL3HTE.js';
9
+ import '../chunk-NWFYTFMI.js';
@@ -0,0 +1,10 @@
1
+ export { DeviceBootSplash, DeviceMirror, MirrorSurface } from '../chunk-SVK2AY3J.js';
2
+ import '../chunk-OEZFYKL6.js';
3
+ import '../chunk-CVV7FOMQ.js';
4
+ import '../chunk-O34SNDQB.js';
5
+ import '../chunk-V4MXFPDX.js';
6
+ import '../chunk-IJVNII5N.js';
7
+ import '../chunk-UINEPEIE.js';
8
+ import '../chunk-OXIM6EYO.js';
9
+ import '../chunk-TATL3HTE.js';
10
+ import '../chunk-NWFYTFMI.js';
@@ -0,0 +1,15 @@
1
+ export { BulkInstallAppsDialog, DeleteDeviceDialog, DeviceCard, DeviceConnect, DeviceDetailDrawer, DeviceEditDialog, DeviceSelector, DeviceTerminal, DevicesPage, FileManager, FingerprintPanel, GroupMirrorModal, NodeRegister, RecycleBinPanel, RefreshParamsButton, RunScriptDialog, ScriptParamForm, SharedParamsForm, ShortcutBar, ShortcutEditDialog, ShortcutRunDialog, TagEditor, TaskAgentDialog, resolveSharedRow, variablesToParams } from '../chunk-YOT7HZBU.js';
2
+ import '../chunk-64Q7BBIQ.js';
3
+ import '../chunk-FW23FLAF.js';
4
+ import '../chunk-SVK2AY3J.js';
5
+ import '../chunk-OEZFYKL6.js';
6
+ import '../chunk-CVV7FOMQ.js';
7
+ import '../chunk-BSHHYM72.js';
8
+ import '../chunk-EVHTAXQG.js';
9
+ export { createAgentTaskRunner, preflightTaskAgentDevice } from '../chunk-O34SNDQB.js';
10
+ import '../chunk-V4MXFPDX.js';
11
+ import '../chunk-IJVNII5N.js';
12
+ import '../chunk-UINEPEIE.js';
13
+ import '../chunk-OXIM6EYO.js';
14
+ import '../chunk-TATL3HTE.js';
15
+ import '../chunk-NWFYTFMI.js';