feat(usage): read alibaba's token plan through the official CLI, not only a scraped session
dawn's token-plan keys are inference-only, so we reverse-engineered the console endpoint from a browser HAR. That worked, but it was the wrong shape of solution: the provider ships a supported CLI, and CodexBar's docs (MIT, read as reference only — dawn does not want us depending on it) name both it and the `quota-config` endpoint we had missed. - `UsageRequest` is now a union: `{kind:"http",...}` or `{kind:"command", command, args, timeoutMs}`. The core still spawns nothing; it asks, and the host answers. A host that will not run commands replies `status: 127` and the feed routes around it into the captured-session path. - a new credential kind, `cli`: no secret, because the provider's own CLI is already signed in. - the alibaba feed tries `bl usage token-plan --console-region <id> --console-site <site> --output json` first, over the four region variants (`intl`/`cn`/`intl-personal`/`cn-personal`), and falls back to the console session. One parser reads both payloads, because the CLI answers with the same field names the console wraps in `data.DataV2.data.data`: `per*Percentage` is a FRACTION and `per*ResetTime` is epoch MILLISECONDS. - two corrections from the reference: `sec_token` is optional (some accounts are not given one, and the console proceeds without it — ours used to fail), and `quota-config` reports per-tier allowances, so the report now says "Token plan pro: weekly 40000, 5h 12000 credits" beside the percentage. Remaining days and reset cards become notes. - the coding-agent host runs only allowlisted command names (`bl`), with the environment narrowed to PATH/HOME/locale/timezone/proxies, a timeout and a 64 KiB stdout cap; a refusal or a missing binary comes back as a status the feed treats as data. - the Zig core and the Swift driver mirror all of it, including the command request in the Swift decoder and a `runCommand` that applies the same allowlist, timeout and cap. Verified: zig unit + C ABI tests, the twelve-case parity suite, the Swift smoke test (which now shows `alibaba=4 calls`), 71 pi-ai usage tests, 45 coding-agent usage tests, and `npm run check` end to end. The child proved the new surface bites: dropping `kind` from command requests fails parity and the Swift smoke immediately. Caveat, stated rather than papered over: `bl` is not installed on this machine, so the CLI path is tested against recorded payloads and scripted hosts, not live.
28 unmodified lines2930313233333435363738394011 unmodified lines28 unmodified lineschar *usage_providers(void);
/* Advance feed state. * Returns either: * {"requests":[{"method","url","headers":[["k","v"]],"body"?}]} * {"requests":[{"kind":"http","method","url","headers":[["k","v"]],"body"?}]} * or: * {"requests":[{"kind":"command","command","args":[],"stdin"?,"timeoutMs"?}]} * or: * {"report":{providerName, accountId?, email?, planType?, limits[], balance?, notes?[], error?}} */char *usage_advance(const char *provider, size_t provider_len, const char *credential_json, size_t credential_len,11 unmodified lines15 unmodified lines1617181920202122232439 unmodified lines6465666768697071727374757670777879808182838485868788209 unmodified linesExpand all298299300301302303290291292293294295296297298299300301304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342303304305306307308343344345346198 unmodified linesExpand all15 unmodified linespub const supported_providers = [_]ProviderInfo{ .{ .provider = "alibaba", .providerName = "Alibaba Model Studio", .credentialKinds = &[_][]const u8{"session"}, .credentialKinds = &[_][]const u8{ "cli", "session" }, }, .{ .provider = "anthropic", .providerName = "Anthropic",39 unmodified lines status: []const u8, detail: ?[]const u8 = null,};
pub const UsageRequestKind = enum { http, command,};
pub const UsageRequest = struct { kind: UsageRequestKind = .http, // http method: []const u8 = "GET", url: []const u8, url: []const u8 = "", headers: []const [2][]const u8 = &[_][2][]const u8{}, body: ?[]const u8 = null, // command command: []const u8 = "", args: []const []const u8 = &[_][]const u8{}, stdin: ?[]const u8 = null, timeoutMs: ?i64 = null,};
pub const UsageResponse = struct { status: i64,209 unmodified linesExpand all .requests => |reqs| { try w.raw("{\"requests\":["); for (reqs, 0..) |req, i| { if (i > 0) try w.byte(','); switch (req.kind) { .http => { try w.raw("{\"method\":"); try w.string(req.method); try w.raw(",\"url\":"); try w.string(req.url); try w.raw(",\"headers\":["); for (req.headers, 0..) |h, hi| { if (hi > 0) try w.byte(','); try w.raw("["); try w.string(h[0]); try w.byte(','); try w.string(h[1]); try w.raw("]"); try w.raw("{\"kind\":\"http\",\"method\":"); try w.string(req.method); try w.raw(",\"url\":"); try w.string(req.url); try w.raw(",\"headers\":["); for (req.headers, 0..) |h, hi| { if (hi > 0) try w.byte(','); try w.raw("["); try w.string(h[0]); try w.byte(','); try w.string(h[1]); try w.raw("]"); } try w.raw("]"); if (req.body) |body| { try w.raw(",\"body\":"); try w.string(body); } try w.byte('}'); }, .command => { try w.raw("{\"kind\":\"command\",\"command\":"); try w.string(req.command); try w.raw(",\"args\":["); for (req.args, 0..) |arg, ai| { if (ai > 0) try w.byte(','); try w.string(arg); } try w.byte(']'); if (req.stdin) |st| { try w.raw(",\"stdin\":"); try w.string(st); } if (req.timeoutMs) |to| { try w.print(",\"timeoutMs\":{d}", .{to}); } try w.byte('}'); }, } try w.raw("]"); if (req.body) |body| { try w.raw(",\"body\":"); try w.string(body); } try w.byte('}'); } try w.raw("]}"); }, .report => |rep| {198 unmodified linesExpand all280 unmodified linesExpand all281282283284285285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346291292293294295296347348349350351352353354355356357358359299360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393301394395396397398399400401402310311312403404405406280 unmodified linesExpand all try std.testing.expect(std.mem.indexOf(u8, text, "\"limits\":[]") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"notes\":[\"Account is unavailable\"]") != null);}
test "alibaba 3 POST requests with form encoding and weekly fraction conversion" {test "alibaba CLI answer parse: fraction to percent and epoch ms kept" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const a = arena.allocator();
const cred = "{\"kind\":\"cli\",\"config\":{\"region\":\"intl-personal\"},\"accountId\":\"custom-id\",\"email\":\"dev@example.com\"}"; const cli_body = \\[{"status":0,"body":"{\"per5HourPercentage\":0.5,\"per1WeekPercentage\":0.83603712139856,\"per1WeekResetTime\":1790021160000}"}] ; const text = try advance(a, "alibaba", cred, cli_body, 1_700_000_000_000); try std.testing.expect(std.mem.indexOf(u8, text, "\"label\":\"Session\",\"usedPercent\":50,\"windowLabel\":\"5h window\",\"status\":\"ok\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"label\":\"Weekly\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"resetsAt\":1790021160000") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"windowLabel\":\"7d window\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"notes\":[\"read through the bailian CLI (intl-personal)\"]") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"accountId\":\"custom-id\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"email\":\"dev@example.com\"") != null);}test "alibaba wrapped console parse" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const a = arena.allocator();
const raw_json = \\{"data":{"DataV2":{"data":{"data":{"per1WeekPercentage":0.83603712139856,"per1WeekResetTime":1790021160000}}}}} ; const parsed_val = try std.json.parseFromSlice(std.json.Value, a, raw_json, .{}); const parsed = try usage.alibaba.parseAlibabaUsage(a, parsed_val.value); try std.testing.expectEqual(@as(usize, 1), parsed.limits.len); try std.testing.expectEqualStrings("Weekly", parsed.limits[0].label); try std.testing.expectEqualStrings("7d window", parsed.limits[0].windowLabel.?); try std.testing.expectEqual(@as(i64, 1790021160000), parsed.limits[0].resetsAt.?); try std.testing.expect(parsed.limits[0].usedPercent.? > 83.6 and parsed.limits[0].usedPercent.? < 83.7);}
test "alibaba argument vector for two regions" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const a = arena.allocator();
// intl-personal const cred_intl = "{\"kind\":\"cli\",\"config\":{\"region\":\"intl-personal\"}}"; const req_intl = try advance(a, "alibaba", cred_intl, "[]", 0); try std.testing.expect(std.mem.indexOf(u8, req_intl, "\"kind\":\"command\"") != null); try std.testing.expect(std.mem.indexOf(u8, req_intl, "\"command\":\"bl\"") != null); try std.testing.expect(std.mem.indexOf(u8, req_intl, "\"ap-southeast-1\"") != null); try std.testing.expect(std.mem.indexOf(u8, req_intl, "\"international\"") != null); try std.testing.expect(std.mem.indexOf(u8, req_intl, "\"timeoutMs\":15000") != null);
// cn-personal const cred_cn = "{\"kind\":\"cli\",\"config\":{\"region\":\"cn-personal\"}}"; const req_cn = try advance(a, "alibaba", cred_cn, "[]", 0); try std.testing.expect(std.mem.indexOf(u8, req_cn, "\"cn-beijing\"") != null); try std.testing.expect(std.mem.indexOf(u8, req_cn, "\"domestic\"") != null);}
test "alibaba 127 with session fallback" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const a = arena.allocator();
const cred = "{\"kind\":\"session\",\"session\":{\"secToken\":\"sec123\",\"region\":\"ap-southeast-1\"}}"; const req_text = try advance(a, "alibaba", cred, "[]", 0); // 3 requests issued try std.testing.expect(std.mem.indexOf(u8, req_text, "zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/usage") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/subscription") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/reset-card/list") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "params=%7B%22Api%22") != null); const resp_127 = "[{\"status\":127,\"body\":\"this host does not run commands (bl)\"}]"; const req_text = try advance(a, "alibaba", cred, resp_127, 0);
// 4 console HTTP requests issued try std.testing.expect(std.mem.indexOf(u8, req_text, "\"kind\":\"http\"") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "zeldaHttp.apikeyMgr.%2Ftokenplan%2Fpersonal%2Fapi%2Fv2%2Fusage") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "zeldaHttp.apikeyMgr.%2Ftokenplan%2Fpersonal%2Fapi%2Fv2%2Fsubscription") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "zeldaHttp.apikeyMgr.%2Ftokenplan%2Fpersonal%2Fapi%2Fv2%2Fquota-config") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "zeldaHttp.apikeyMgr.%2Ftokenplan%2Fpersonal%2Fapi%2Fv2%2Freset-card%2Flist") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "sec_token=sec123") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "region=ap-southeast-1") != null);}
// Response with weekly fraction 0.83603712139856 -> Weekly limit with ~83.6037% usedtest "alibaba 127 without session error" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const a = arena.allocator();
const cred = "{\"kind\":\"cli\"}"; const resp_127 = "[{\"status\":127,\"body\":\"this host does not run commands (bl)\"}]"; const text = try advance(a, "alibaba", cred, resp_127, 0);
try std.testing.expect(std.mem.indexOf(u8, text, "capture-alibaba-session.mjs") != null);}
test "alibaba missing sec_token is omitted from form body" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const a = arena.allocator();
const cred = "{\"kind\":\"session\",\"session\":{\"region\":\"ap-southeast-1\"}}"; const resp_127 = "[{\"status\":127,\"body\":\"no commands\"}]"; const req_text = try advance(a, "alibaba", cred, resp_127, 0);
try std.testing.expect(std.mem.indexOf(u8, req_text, "\"kind\":\"http\"") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "params=") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "region=ap-southeast-1") != null); try std.testing.expect(std.mem.indexOf(u8, req_text, "sec_token") == null);}
test "alibaba console answers: plan, remaining days, tier credits and reset cards" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const a = arena.allocator();
const cred = "{\"kind\":\"session\",\"session\":{\"secToken\":\"sec123\",\"region\":\"ap-southeast-1\"}}"; const body = \\[{"status":200,"body":"{\"data\":{\"api\":\"zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/usage\",\"DataV2\":{\"data\":{\"data\":{\"per1WeekPercentage\":0.83603712139856,\"per1WeekResetTime\":1790021160000}}}}}"},{"status":200,"body":"{\"data\":{\"api\":\"zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/subscription\",\"DataV2\":{\"data\":{\"data\":{\"specCode\":\"pro\",\"instanceCode\":\"inst-123\",\"remainingDays\":29}}}}}"},{"status":200,"body":"{\"data\":{\"api\":\"zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/reset-card/list\",\"DataV2\":{\"data\":{\"data\":[{\"cardId\":\"c1\"}]}}}}"}] \\[{"status":200,"body":"{\"data\":{\"DataV2\":{\"data\":{\"data\":{\"per1WeekPercentage\":0.83603712139856,\"per1WeekResetTime\":1790021160000}}}}}"},{"status":200,"body":"{\"data\":{\"DataV2\":{\"data\":{\"data\":{\"specCode\":\"pro\",\"instanceCode\":\"inst-123\",\"remainingDays\":29}}}}}"},{"status":200,"body":"{\"data\":{\"DataV2\":{\"data\":{\"data\":{\"pro\":{\"weekly\":40000,\"five_hour\":12000}}}}}}"},{"status":200,"body":"{\"data\":{\"DataV2\":{\"data\":{\"data\":[{\"cardId\":\"c1\"}]}}}}"}] ;
const text = try advance(a, "alibaba", cred, body, 0); try std.testing.expect(std.mem.indexOf(u8, text, "\"planType\":\"pro\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"accountId\":\"inst-123\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"label\":\"Weekly\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"resetsAt\":1790021160000") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"windowLabel\":\"7d window\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "\"detail\":\"29 days remaining\"") != null); try std.testing.expect(std.mem.indexOf(u8, text, "29 days remaining") != null); try std.testing.expect(std.mem.indexOf(u8, text, "1 reset card available") != null); try std.testing.expect(std.mem.indexOf(u8, text, "Token plan pro: weekly 40000, 5h 12000 credits") != null); try std.testing.expect(std.mem.indexOf(u8, text, "29 days remaining in the plan") != null); try std.testing.expect(std.mem.indexOf(u8, text, "1 reset cards available") != null);}2 unmodified lines34567789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687121314888990919293949596179798991001017 unmodified lines109110111112333435363738394041424344454647484950515253545556575859606162636465666768113114707111511611775767778798081118119120121122848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201231241251261271281291301231311321251261331341351361371301311321331341351361371381391401411421381391401411421431441451451461471481491471481491501511521541531541561571581551561571581621631641651661671681691591601711721731741751761771781791801811821831841611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941871881891951961971981992002012022032042052062072082092102112122132142152162172182192201921931941952212222232242252262272282292302312322332342352362372382392402411981992422432442452462472012022482492502512522042052532542552562572582592602612622632642652662672072082092102112122682692702712722732742142152162172182192202752762772222232242252262272282292302312782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113122362372382392402412422432443133143153163173182462472482492502513193203213223233243252533263272553283292572582592602612622632642652662672682693303313323332723343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643656 unmodified lines3723733743753763773783793803813823833843852972982993003013023033043053863873883893903073083093103913923933133943953153963973983993194004013214024033233244044054064073273284084094104114124134144154164174184193313323333343353363373383394204214224234244254264274284294304314324334344354363433443453463473483493504374384394404414424434444454464474484494504514524534544553553564564574584593603613624603643654614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086092 unmodified lines//! Mirrors packages/ai/src/utils/usage/providers/alibaba.ts field for field.const std = @import("std");const usage = @import("../usage.zig");
pub const ALIBABA_GATEWAY_URL = "https://bailian-singapore-cs.alibabacloud.com/data/api.json";pub const AlibabaRegion = enum { intl, cn, @"intl-personal", @"cn-personal",
pub fn toString(self: AlibabaRegion) []const u8 { return switch (self) { .intl => "intl", .cn => "cn", .@"intl-personal" => "intl-personal", .@"cn-personal" => "cn-personal", }; }
pub fn fromString(str: []const u8) ?AlibabaRegion { if (std.mem.eql(u8, str, "intl")) return .intl; if (std.mem.eql(u8, str, "cn")) return .cn; if (std.mem.eql(u8, str, "intl-personal")) return .@"intl-personal"; if (std.mem.eql(u8, str, "cn-personal")) return .@"cn-personal"; return null; }};
pub const RegionInfo = struct { currentRegionId: []const u8, cliConsoleSite: []const u8, quotaHost: []const u8, productCode: []const u8,};
pub fn getRegionInfo(region: AlibabaRegion) RegionInfo { return switch (region) { .intl => .{ .currentRegionId = "ap-southeast-1", .cliConsoleSite = "international", .quotaHost = "https://modelstudio.console.alibabacloud.com", .productCode = "sfm_tokenplanteams_dp_intl", }, .cn => .{ .currentRegionId = "cn-beijing", .cliConsoleSite = "domestic", .quotaHost = "https://bailian.console.aliyun.com", .productCode = "sfm_tokenplanteams_dp_cn", }, .@"intl-personal" => .{ .currentRegionId = "ap-southeast-1", .cliConsoleSite = "international", .quotaHost = "https://bailian-singapore-cs.alibabacloud.com", .productCode = "sfm_tokenplansolo_public_intl", }, .@"cn-personal" => .{ .currentRegionId = "cn-beijing", .cliConsoleSite = "domestic", .quotaHost = "https://bailian-cs.console.aliyun.com", .productCode = "sfm_tokenplansolo_public_cn", }, };}
pub const ALIBABA_CLI_TIMEOUT_MS: i64 = 15_000;
pub fn alibabaCliArguments(alloc: std.mem.Allocator, region: AlibabaRegion) ![]const []const u8 { const info = getRegionInfo(region); const args = try alloc.alloc([]const u8, 8); args[0] = "usage"; args[1] = "token-plan"; args[2] = "--console-region"; args[3] = info.currentRegionId; args[4] = "--console-site"; args[5] = info.cliConsoleSite; args[6] = "--output"; args[7] = "json"; return args;}
pub const ALIBABA_USAGE_API = "zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/usage";pub const ALIBABA_SUBSCRIPTION_API = "zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/subscription";pub const ALIBABA_QUOTA_CONFIG_API = "zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/quota-config";pub const ALIBABA_RESET_CARD_API = "zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/reset-card/list";
pub fn buildGatewayUrl(alloc: std.mem.Allocator, base_url: []const u8, api: []const u8) ![]const u8 { const clean_base = if (std.mem.indexOfScalar(u8, base_url, '?')) |idx| base_url[0..idx] else base_url; return try std.fmt.allocPrint(alloc, "{s}?action=IntlBroadScopeAspnGateway&product=sfm_bailian&api={s}&_v=", .{ clean_base, api });fn stringOf(value: ?std.json.Value) ?[]const u8 { const s = usage.asString(value) orelse return null; const trimmed = std.mem.trim(u8, s, " \t\r\n"); if (trimmed.len == 0) return null; return trimmed;}
/// Unwrap the console's envelope (`data.DataV2.data.data`) when present. The CLI answers with the/// inner payload directly, so one parser covers both.fn unwrapEnvelope(value: ?std.json.Value) ?std.json.Value {pub fn unwrapEnvelope(value: ?std.json.Value) ?std.json.Value { const root = usage.asObject(value) orelse return value; const data = usage.asObject(root.get("data")); if (data) |d| { const data_v2 = usage.asObject(d.get("DataV2"));7 unmodified lines } return value;}
fn extractErrorMessage(value: ?std.json.Value) ?[]const u8 { const root = usage.asObject(value) orelse return null; const data = usage.asObject(root.get("data")); const data_v2 = if (data) |d| usage.asObject(d.get("DataV2")) else null; const v2_data = if (data_v2) |v2| usage.asObject(v2.get("data")) else null;
if (v2_data) |v2d| { const success_val = v2d.get("success"); const is_success = if (success_val) |sv| switch (sv) { .bool => |b| b, else => true, } else true; if (!is_success) { if (usage.asString(v2d.get("msg"))) |m| { const trimmed = std.mem.trim(u8, m, " \t\r\n"); if (trimmed.len > 0) return trimmed; } } }
if (data) |d| { if (usage.asString(d.get("errorMsg"))) |em| { const trimmed = std.mem.trim(u8, em, " \t\r\n"); if (trimmed.len > 0) return trimmed; } }
if (usage.asString(root.get("message"))) |m| { const trimmed = std.mem.trim(u8, m, " \t\r\n"); if (trimmed.len > 0) return trimmed; }
return null;}
pub const ParseAlibabaResult = struct {pub const ParseUsageResult = struct { limits: []const usage.UsageLimit = &[_]usage.UsageLimit{}, planType: ?[]const u8 = null, instanceCode: ?[]const u8 = null, notes: []const []const u8 = &[_][]const u8{},};
pub fn parseAlibabaUsage( alloc: std.mem.Allocator, usage_payload: ?std.json.Value, subscription_payload: ?std.json.Value, reset_card_payload: ?std.json.Value,) !ParseAlibabaResult { var notes = std.ArrayList([]const u8).empty;pub fn parseAlibabaUsage(alloc: std.mem.Allocator, payload: ?std.json.Value) !ParseUsageResult { const inner_val = unwrapEnvelope(payload); const inner = usage.asObject(inner_val); var limits = std.ArrayList(usage.UsageLimit).empty;
// Subscription parsing const sub_unwrapped = unwrapEnvelope(subscription_payload); const sub_data = usage.asObject(sub_unwrapped); const plan_type = if (sub_data) |sd| usage.asString(sd.get("specCode")) else null; const instance_code = if (sub_data) |sd| usage.asString(sd.get("instanceCode")) else null; const remaining_days = if (sub_data) |sd| usage.asNumber(sd.get("remainingDays")) else null;
if (remaining_days) |rd| { const note = try std.fmt.allocPrint(alloc, "{d} days remaining", .{@as(i64, @intFromFloat(rd))}); try notes.append(alloc, note); }
// Reset card parsing const card_unwrapped = unwrapEnvelope(reset_card_payload); const card_array = usage.asArray(card_unwrapped); if (card_array) |ca| { if (ca.items.len > 0) { const count = ca.items.len; const suffix: []const u8 = if (count == 1) "" else "s"; const note = try std.fmt.allocPrint(alloc, "{d} reset card{s} available", .{ count, suffix }); try notes.append(alloc, note); } }
// Usage limits const usage_unwrapped = unwrapEnvelope(usage_payload); const usage_data = usage.asObject(usage_unwrapped); if (usage_data) |ud| { // Optional 5h session window const session_frac = usage.asNumber(ud.get("per5HourPercentage")); const session_reset = usage.asNumber(ud.get("per5HourResetTime")); if (session_frac != null or session_reset != null) { // Converted FROM fraction (0..1) to percent (0..100) const session_used_pct: ?f64 = if (session_frac) |sf| sf * 100.0 else null; // Already epoch milliseconds from per5HourResetTime (no conversion needed) const session_reset_ms: ?i64 = if (session_reset) |sr| @intFromFloat(sr) else null;
if (inner) |ud| { // Session: per5HourPercentage (0..1 fraction) -> percent if (usage.asNumber(ud.get("per5HourPercentage"))) |sf| { const used_pct = sf * 100.0; const reset = usage.asNumber(ud.get("per5HourResetTime")); const reset_ms: ?i64 = if (reset) |r| @as(i64, @intFromFloat(r)) else null; try limits.append(alloc, .{ .label = "Session", .usedPercent = session_used_pct, .usedPercent = used_pct, .windowLabel = "5h window", .resetsAt = session_reset_ms, .status = usage.statusFor(session_used_pct), .resetsAt = reset_ms, .status = usage.statusFor(used_pct), }); }
// 7d weekly window const weekly_frac = usage.asNumber(ud.get("per1WeekPercentage")); const weekly_reset = usage.asNumber(ud.get("per1WeekResetTime")); if (weekly_frac != null or weekly_reset != null) { // Converted FROM fraction (0..1) to percent (0..100) const weekly_used_pct: ?f64 = if (weekly_frac) |wf| wf * 100.0 else null; // Already epoch milliseconds from per1WeekResetTime (no conversion needed) const weekly_reset_ms: ?i64 = if (weekly_reset) |wr| @intFromFloat(wr) else null; const detail: ?[]const u8 = if (remaining_days) |rd| try std.fmt.allocPrint(alloc, "{d} days remaining", .{@as(i64, @intFromFloat(rd))}) else null;
// Weekly: per1WeekPercentage (0..1 fraction) -> percent if (usage.asNumber(ud.get("per1WeekPercentage"))) |wf| { const used_pct = wf * 100.0; const reset = usage.asNumber(ud.get("per1WeekResetTime")); const reset_ms: ?i64 = if (reset) |r| @as(i64, @intFromFloat(r)) else null; try limits.append(alloc, .{ .label = "Weekly", .usedPercent = weekly_used_pct, .usedPercent = used_pct, .windowLabel = "7d window", .resetsAt = weekly_reset_ms, .status = usage.statusFor(weekly_used_pct), .detail = detail, .resetsAt = reset_ms, .status = usage.statusFor(used_pct), }); } }
return ParseAlibabaResult{ return .{ .limits = limits.items, .planType = plan_type, .instanceCode = instance_code, .notes = notes.items, .notes = &[_][]const u8{}, };}
fn buildFormBody(alloc: std.mem.Allocator, params_json: []const u8, sec_token: []const u8, region: []const u8) ![]const u8 { const enc_params = try usage.urlEncode(alloc, params_json); const enc_token = try usage.urlEncode(alloc, sec_token); const enc_region = try usage.urlEncode(alloc, region); return try std.fmt.allocPrint(alloc, "params={s}&sec_token={s}®ion={s}", .{ enc_params, enc_token, enc_region });}
pub fn advance(pub fn parseAlibabaQuotaConfig( alloc: std.mem.Allocator, credential_json: []const u8, responses_json: []const u8, _now_ms: i64,) !usage.Outcome { _ = _now_ms; const cred_parsed = std.json.parseFromSlice(std.json.Value, alloc, credential_json, .{}) catch { return .{ .report = .{ .error_message = "invalid credential JSON" } }; }; const cred_root = usage.asObject(cred_parsed.value) orelse { return .{ .report = .{ .error_message = "invalid credential JSON" } }; }; const kind = usage.asString(cred_root.get("kind")) orelse ""; if (!std.mem.eql(u8, kind, "session")) { return .{ .report = .{ .error_message = "alibaba needs a session credential" } }; payload: ?std.json.Value, plan_type: ?[]const u8,) ![]const []const u8 { const inner_val = unwrapEnvelope(payload); const tiers = usage.asObject(inner_val) orelse return &[_][]const u8{}; const pt = plan_type orelse return &[_][]const u8{};
const lowered = try alloc.alloc(u8, pt.len); _ = std.ascii.lowerString(lowered, pt);
const tier = usage.asObject(tiers.get(lowered)) orelse return &[_][]const u8{}; const weekly = usage.asNumber(tier.get("weekly")); const five_hour = usage.asNumber(tier.get("five_hour"));
if (weekly == null and five_hour == null) return &[_][]const u8{};
var note_buf = std.ArrayList(u8).empty; try note_buf.appendSlice(alloc, "Token plan "); try note_buf.appendSlice(alloc, pt); try note_buf.appendSlice(alloc, ": ");
var parts_wrote = false; if (weekly) |w| { const w_str = try std.fmt.allocPrint(alloc, "weekly {d}", .{@as(i64, @intFromFloat(w))}); try note_buf.appendSlice(alloc, w_str); parts_wrote = true; } if (five_hour) |fh| { if (parts_wrote) try note_buf.appendSlice(alloc, ", "); const fh_str = try std.fmt.allocPrint(alloc, "5h {d}", .{@as(i64, @intFromFloat(fh))}); try note_buf.appendSlice(alloc, fh_str); } try note_buf.appendSlice(alloc, " credits");
const session_val = cred_root.get("session"); const session = usage.asObject(session_val) orelse { return .{ .report = .{ .error_message = "alibaba session credential missing session object" } }; const notes = try alloc.alloc([]const u8, 1); notes[0] = note_buf.items; return notes;}
pub const ConsoleSession = struct { host: []const u8, region: []const u8, secToken: ?[]const u8 = null, headers: ?std.json.ObjectMap = null,};
pub fn parseConsoleSession(session_val: ?std.json.Value, default_host: []const u8) ?ConsoleSession { const session = usage.asObject(session_val) orelse return null; const region = stringOf(session.get("region")) orelse return null; const host = stringOf(session.get("url")) orelse default_host; const secToken = stringOf(session.get("secToken")); const headers = usage.asObject(session.get("headers")); return .{ .host = host, .region = region, .secToken = secToken, .headers = headers, };}
const sec_token_raw = usage.asString(session.get("secToken")); const sec_token = if (sec_token_raw) |st| std.mem.trim(u8, st, " \t\r\n") else ""; if (sec_token.len == 0) { return .{ .report = .{ .error_message = "alibaba session missing secToken" } };pub fn regionFor(cred_root: ?std.json.ObjectMap, session: ?ConsoleSession) AlibabaRegion { const root = cred_root orelse return .@"intl-personal"; const kind = usage.asString(root.get("kind")) orelse ""; if (std.mem.eql(u8, kind, "cli")) { const config = usage.asObject(root.get("config")); if (config) |c| { if (stringOf(c.get("region"))) |r_str| { if (AlibabaRegion.fromString(r_str)) |r| return r; } } } if (std.mem.eql(u8, kind, "session") and session != null) { if (std.mem.startsWith(u8, session.?.region, "cn")) { return .@"cn-personal"; } else { return .@"intl-personal"; } } return .@"intl-personal";}
const region_raw = usage.asString(session.get("region")); const region = if (region_raw) |r| std.mem.trim(u8, r, " \t\r\n") else "ap-southeast-1";pub fn buildGatewayUrl(alloc: std.mem.Allocator, host: []const u8, api: []const u8) ![]const u8 { const base = if (std.mem.indexOf(u8, host, "/data/api.json") != null) host else try std.fmt.allocPrint(alloc, "{s}/data/api.json", .{host});
const base_url_raw = usage.asString(session.get("url")); const base_url = if (base_url_raw) |u| std.mem.trim(u8, u, " \t\r\n") else ALIBABA_GATEWAY_URL; const clean_base = if (std.mem.indexOfScalar(u8, base, '?')) |idx| base[0..idx] else base; const enc_api = try usage.urlEncode(alloc, api); return try std.fmt.allocPrint(alloc, "{s}?action=IntlBroadScopeAspnGateway&product=sfm_bailian&api={s}&_v=", .{ clean_base, enc_api });}
const cred_account_id = usage.asString(cred_root.get("accountId")); const cred_email = usage.asString(cred_root.get("email"));pub fn buildFormBody( alloc: std.mem.Allocator, api: []const u8, region: AlibabaRegion, session: ConsoleSession,) ![]const u8 { const info = getRegionInfo(region); var pw = usage.Writer.init(alloc); try pw.raw("{\"Api\":"); try pw.string(api); try pw.raw(",\"V\":\"1.0\",\"Data\":{\"cornerstoneParam\":{\"protocol\":\"V2\",\"console\":\"ONE_CONSOLE\",\"productCode\":\"p_efm\",\"domain\":\"modelstudio.console.alibabacloud.com\",\"consoleSite\":\"MODELSTUDIO_ALBABACLOUD\",\"xsp_lang\":\"en-US\",\"feUrl\":"); const fe_url = try std.fmt.allocPrint(alloc, "https://modelstudio.console.alibabacloud.com/{s}/subscription/token-plan/personal", .{info.currentRegionId}); try pw.string(fe_url); try pw.raw("}");
const resp_parsed = std.json.parseFromSlice(std.json.Value, alloc, responses_json, .{}) catch { return .{ .report = .{ .error_message = "invalid responses JSON" } }; }; const resp_array = usage.asArray(resp_parsed.value) orelse { return .{ .report = .{ .error_message = "invalid responses JSON" } }; }; if (std.mem.eql(u8, api, ALIBABA_SUBSCRIPTION_API)) { try pw.raw(",\"queryInstanceInfoRequest\":{\"commodityCode\":"); try pw.string(info.productCode); try pw.raw("}"); } try pw.raw("}}");
if (resp_array.items.len == 0) { var base_headers = std.ArrayList([2][]const u8).empty; try base_headers.append(alloc, .{ "content-type", "application/x-www-form-urlencoded" }); try base_headers.append(alloc, .{ "accept", "*/*" }); try base_headers.append(alloc, .{ "origin", "https://modelstudio.console.alibabacloud.com" }); const referer = try std.fmt.allocPrint(alloc, "https://modelstudio.console.alibabacloud.com/{s}/subscription/token-plan/personal", .{region}); try base_headers.append(alloc, .{ "referer", referer }); const enc_params = try usage.urlEncode(alloc, pw.items()); const enc_region = try usage.urlEncode(alloc, session.region);
const session_headers = usage.asObject(session.get("headers")); if (session_headers) |sh| { var it = sh.iterator(); while (it.next()) |entry| { if (usage.asString(entry.value_ptr.*)) |val| { const key_lower = try alloc.alloc(u8, entry.key_ptr.*.len); _ = std.ascii.lowerString(key_lower, entry.key_ptr.*); if (!std.mem.eql(u8, key_lower, "content-type")) { try base_headers.append(alloc, .{ key_lower, val }); } if (session.secToken) |tok| { if (tok.len > 0) { const enc_tok = try usage.urlEncode(alloc, tok); return try std.fmt.allocPrint(alloc, "params={s}®ion={s}&sec_token={s}", .{ enc_params, enc_region, enc_tok }); } } return try std.fmt.allocPrint(alloc, "params={s}®ion={s}", .{ enc_params, enc_region });}
pub fn consoleRequests( alloc: std.mem.Allocator, session: ConsoleSession, region: AlibabaRegion,) ![]const usage.UsageRequest { const apis = [_][]const u8{ ALIBABA_USAGE_API, ALIBABA_SUBSCRIPTION_API, ALIBABA_QUOTA_CONFIG_API, ALIBABA_RESET_CARD_API, };
var base_headers = std.ArrayList([2][]const u8).empty; if (session.headers) |sh| { var it = sh.iterator(); while (it.next()) |entry| { if (usage.asString(entry.value_ptr.*)) |val| { const key_lower = try alloc.alloc(u8, entry.key_ptr.*.len); _ = std.ascii.lowerString(key_lower, entry.key_ptr.*); if (!std.mem.eql(u8, key_lower, "content-type") and !std.mem.eql(u8, key_lower, "accept") and !std.mem.eql(u8, key_lower, "origin") and !std.mem.eql(u8, key_lower, "referer")) { try base_headers.append(alloc, .{ key_lower, val }); } } } }
const usage_json = \\{"Api":"zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/usage","V":"1.0","Data":{"cornerstoneParam":{"protocol":"V2","console":"ONE_CONSOLE","productCode":"p_efm","domain":"modelstudio.console.alibabacloud.com","consoleSite":"MODELSTUDIO_ALBABACLOUD","xsp_lang":"en-US"}}} ; const sub_json = \\{"Api":"zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/subscription","V":"1.0","Data":{"queryInstanceInfoRequest":{"commodityCode":"sfm_tokenplansolo_public_intl"},"cornerstoneParam":{"protocol":"V2","console":"ONE_CONSOLE","productCode":"p_efm","domain":"modelstudio.console.alibabacloud.com","consoleSite":"MODELSTUDIO_ALBABACLOUD","xsp_lang":"en-US"}}} ; const card_json = \\{"Api":"zeldaHttp.apikeyMgr./tokenplan/personal/api/v2/reset-card/list","V":"1.0","Data":{"cornerstoneParam":{"protocol":"V2","console":"ONE_CONSOLE","productCode":"p_efm","domain":"modelstudio.console.alibabacloud.com","consoleSite":"MODELSTUDIO_ALBABACLOUD","xsp_lang":"en-US"}}} ; try base_headers.append(alloc, .{ "content-type", "application/x-www-form-urlencoded" }); try base_headers.append(alloc, .{ "accept", "*/*" }); try base_headers.append(alloc, .{ "origin", "https://modelstudio.console.alibabacloud.com" }); const referer = try std.fmt.allocPrint(alloc, "https://modelstudio.console.alibabacloud.com/{s}/subscription/token-plan/personal", .{session.region}); try base_headers.append(alloc, .{ "referer", referer });
const usage_body = try buildFormBody(alloc, usage_json, sec_token, region); const sub_body = try buildFormBody(alloc, sub_json, sec_token, region); const card_body = try buildFormBody(alloc, card_json, sec_token, region);
const requests = try alloc.alloc(usage.UsageRequest, 3); requests[0] = .{ const requests = try alloc.alloc(usage.UsageRequest, apis.len); for (apis, 0..) |api, i| { const url = try buildGatewayUrl(alloc, session.host, api); const body = try buildFormBody(alloc, api, region, session); requests[i] = .{ .kind = .http, .method = "POST", .url = try buildGatewayUrl(alloc, base_url, ALIBABA_USAGE_API), .url = url, .headers = base_headers.items, .body = usage_body, .body = body, }; requests[1] = .{ .method = "POST", .url = try buildGatewayUrl(alloc, base_url, ALIBABA_SUBSCRIPTION_API), .headers = base_headers.items, .body = sub_body, }; requests[2] = .{ .method = "POST", .url = try buildGatewayUrl(alloc, base_url, ALIBABA_RESET_CARD_API), .headers = base_headers.items, .body = card_body, }; return .{ .requests = requests }; } return requests;}
// Match responses by api field or fallback to positionalfn getResetCardsCount(body_str: ?[]const u8, alloc: std.mem.Allocator) ?usize { const bs = body_str orelse return null; const parsed = std.json.parseFromSlice(std.json.Value, alloc, bs, .{}) catch return null; if (usage.asArray(parsed.value)) |arr| { return arr.items.len; } const unwrapped = unwrapEnvelope(parsed.value); if (usage.asArray(unwrapped)) |arr| { return arr.items.len; } return null;}
pub fn reportFromConsole( alloc: std.mem.Allocator, cred_root: ?std.json.ObjectMap, resp_array: std.json.Array,) !usage.Outcome { const cred_email = if (cred_root) |cr| stringOf(cr.get("email")) else null;
if (resp_array.items.len == 0) { return .{ .report = .{ .error_message = "console gateway HTTP no response" } }; }
// Match responses: first try by api in envelope, otherwise positional var usage_resp: ?std.json.ObjectMap = null; var sub_resp: ?std.json.ObjectMap = null; var quota_resp: ?std.json.ObjectMap = null; var card_resp: ?std.json.ObjectMap = null;
for (resp_array.items) |r_val| { const r_obj = usage.asObject(r_val) orelse continue;6 unmodified lines if (std.mem.eql(u8, a, ALIBABA_USAGE_API)) { usage_resp = r_obj; } else if (std.mem.eql(u8, a, ALIBABA_SUBSCRIPTION_API)) { sub_resp = r_obj; } else if (std.mem.eql(u8, a, ALIBABA_QUOTA_CONFIG_API)) { quota_resp = r_obj; } else if (std.mem.eql(u8, a, ALIBABA_RESET_CARD_API)) { card_resp = r_obj; } } } } else |_| {} }
if (usage_resp == null and resp_array.items.len > 0) { usage_resp = usage.asObject(resp_array.items[0]); } if (sub_resp == null and resp_array.items.len > 1) { sub_resp = usage.asObject(resp_array.items[1]); } if (card_resp == null and resp_array.items.len > 2) { card_resp = usage.asObject(resp_array.items[2]); } if (usage_resp == null and resp_array.items.len > 0) usage_resp = usage.asObject(resp_array.items[0]); if (sub_resp == null and resp_array.items.len > 1) sub_resp = usage.asObject(resp_array.items[1]); if (quota_resp == null and resp_array.items.len > 2) quota_resp = usage.asObject(resp_array.items[2]); if (card_resp == null and resp_array.items.len > 3) card_resp = usage.asObject(resp_array.items[3]);
if (usage_resp == null) { return .{ .report = .{ .error_message = "HTTP no response" } }; } const status = usage.asNumber(usage_resp.?.get("status")); const status = if (usage_resp) |ro| usage.asNumber(ro.get("status")) else null; if (status == null or status.? != 200.0) { const err_text = if (status) |st| try std.fmt.allocPrint(alloc, "HTTP {d}", .{@as(i64, @intFromFloat(st))}) try std.fmt.allocPrint(alloc, "console gateway HTTP {d}", .{@as(i64, @intFromFloat(st))}) else "HTTP no response"; "console gateway HTTP no response"; return .{ .report = .{ .error_message = err_text } }; }
const usage_b_str = usage.asString(usage_resp.?.get("body")); const usage_b_str = if (usage_resp) |ro| usage.asString(ro.get("body")) else null; if (usage_b_str == null) { return .{ .report = .{ .error_message = "usage body is not JSON" } }; return .{ .report = .{ .error_message = "console gateway HTTP no response" } }; } const usage_b_parsed = std.json.parseFromSlice(std.json.Value, alloc, usage_b_str.?, .{}) catch { return .{ .report = .{ .error_message = "usage body is not JSON" } }; const usage_parsed = std.json.parseFromSlice(std.json.Value, alloc, usage_b_str.?, .{}) catch { return .{ .report = .{ .error_message = "console gateway HTTP no response" } }; };
if (extractErrorMessage(usage_b_parsed.value)) |msg| { return .{ .report = .{ .error_message = msg } }; const parsed = try parseAlibabaUsage(alloc, usage_parsed.value);
// Subscription response var sub_val: ?std.json.Value = null; if (sub_resp) |ro| { if (usage.asString(ro.get("body"))) |bs| { if (std.json.parseFromSlice(std.json.Value, alloc, bs, .{})) |p| { sub_val = p.value; } else |_| {} } }
var sub_json_val: ?std.json.Value = null; if (sub_resp) |sr| { const st = usage.asNumber(sr.get("status")); if (st != null and st.? == 200.0) { if (usage.asString(sr.get("body"))) |sb_str| { if (std.json.parseFromSlice(std.json.Value, alloc, sb_str, .{})) |sb_parsed| { sub_json_val = sb_parsed.value; } else |_| {} } const sub_unwrapped = unwrapEnvelope(sub_val); const sub_obj = usage.asObject(sub_unwrapped); const plan_type = if (sub_obj) |so| stringOf(so.get("specCode")) else null; const instance_code = if (sub_obj) |so| stringOf(so.get("instanceCode")) else null; const remaining_days = if (sub_obj) |so| usage.asNumber(so.get("remainingDays")) else null;
// Quota config response var quota_val: ?std.json.Value = null; if (quota_resp) |ro| { if (usage.asString(ro.get("body"))) |bs| { if (std.json.parseFromSlice(std.json.Value, alloc, bs, .{})) |p| { quota_val = p.value; } else |_| {} } } const quota_notes = try parseAlibabaQuotaConfig(alloc, quota_val, plan_type);
var card_json_val: ?std.json.Value = null; if (card_resp) |cr| { const st = usage.asNumber(cr.get("status")); if (st != null and st.? == 200.0) { if (usage.asString(cr.get("body"))) |cb_str| { if (std.json.parseFromSlice(std.json.Value, alloc, cb_str, .{})) |cb_parsed| { card_json_val = cb_parsed.value; } else |_| {} var notes = std.ArrayList([]const u8).empty; for (parsed.notes) |n| try notes.append(alloc, n); for (quota_notes) |n| try notes.append(alloc, n);
if (remaining_days) |rd| { const note = try std.fmt.allocPrint(alloc, "{d} days remaining in the plan", .{@as(i64, @intFromFloat(rd))}); try notes.append(alloc, note); }
if (card_resp) |ro| { const card_b_str = usage.asString(ro.get("body")); if (getResetCardsCount(card_b_str, alloc)) |count| { if (count > 0) { const note = try std.fmt.allocPrint(alloc, "{d} reset cards available", .{count}); try notes.append(alloc, note); } } }
const parsed = try parseAlibabaUsage(alloc, usage_b_parsed.value, sub_json_val, card_json_val); const account_id = cred_account_id orelse parsed.instanceCode; const err_msg: ?[]const u8 = if (parsed.limits.len == 0) "the token plan reported no windows" else null;
return .{ .report = .{ .planType = parsed.planType, .accountId = account_id, .email = cred_email, .limits = parsed.limits, .notes = parsed.notes, .error_message = null, .planType = plan_type, .accountId = instance_code, .email = cred_email, .notes = notes.items, .error_message = err_msg, }, };}
pub const CliReportOutcome = struct { report: ?usage.ReportOutcome = null, reason: ?[]const u8 = null,};
pub fn reportFromCli( alloc: std.mem.Allocator, cred_root: ?std.json.ObjectMap, resp0: std.json.ObjectMap, region: AlibabaRegion,) !CliReportOutcome { const cred_account_id = if (cred_root) |cr| stringOf(cr.get("accountId")) else null; const cred_email = if (cred_root) |cr| stringOf(cr.get("email")) else null;
const status_num = usage.asNumber(resp0.get("status")); const status = if (status_num) |sn| @as(i64, @intFromFloat(sn)) else -1;
if (status != 0 and status != 200) { const reason = try std.fmt.allocPrint(alloc, "bailian CLI failed (exit {d})", .{status}); return .{ .reason = reason }; }
const body_str = usage.asString(resp0.get("body")); if (body_str) |bs| { if (std.json.parseFromSlice(std.json.Value, alloc, bs, .{})) |parsed_val| { const parsed = try parseAlibabaUsage(alloc, parsed_val.value); if (parsed.limits.len > 0) { const note = try std.fmt.allocPrint(alloc, "read through the bailian CLI ({s})", .{region.toString()}); const notes = try alloc.alloc([]const u8, 1); notes[0] = note; return .{ .report = .{ .limits = parsed.limits, .accountId = cred_account_id, .email = cred_email, .notes = notes, .error_message = null, }, }; } } else |_| {} }
return .{ .reason = "the bailian CLI output carried no token-plan windows" };}
pub fn advance( alloc: std.mem.Allocator, credential_json: []const u8, responses_json: []const u8, _now_ms: i64,) !usage.Outcome { _ = _now_ms; const cred_parsed = std.json.parseFromSlice(std.json.Value, alloc, credential_json, .{}) catch { return .{ .report = .{ .error_message = "invalid credential JSON" } }; }; const cred_root = usage.asObject(cred_parsed.value);
const default_host = "https://bailian-singapore-cs.alibabacloud.com"; const session_val = if (cred_root) |cr| cr.get("session") else null; const session = parseConsoleSession(session_val, default_host); const region = regionFor(cred_root, session);
const resp_parsed = std.json.parseFromSlice(std.json.Value, alloc, responses_json, .{}) catch { return .{ .report = .{ .error_message = "invalid responses JSON" } }; }; const resp_array = usage.asArray(resp_parsed.value) orelse { return .{ .report = .{ .error_message = "invalid responses JSON" } }; };
if (resp_array.items.len == 0) { // Round 1: Official CLI first const cli_args = try alibabaCliArguments(alloc, region); const requests = try alloc.alloc(usage.UsageRequest, 1); requests[0] = .{ .kind = .command, .command = "bl", .args = cli_args, .timeoutMs = ALIBABA_CLI_TIMEOUT_MS, }; return .{ .requests = requests }; }
if (resp_array.items.len == 1) { const resp0_obj = usage.asObject(resp_array.items[0]); const status_num = if (resp0_obj) |ro| usage.asNumber(ro.get("status")) else null; const status = if (status_num) |sn| @as(i64, @intFromFloat(sn)) else -1; const unavailable = (status == 127);
if (!unavailable) { if (resp0_obj) |ro| { const cli_outcome = try reportFromCli(alloc, cred_root, ro, region); if (cli_outcome.report) |rep| { return .{ .report = rep }; } if (session == null) { const notes = try alloc.alloc([]const u8, 1); notes[0] = "a captured console session would be the fallback"; return .{ .report = .{ .limits = &[_]usage.UsageLimit{}, .error_message = cli_outcome.reason orelse "the bailian CLI gave no usable output", .notes = notes, }, }; } } else if (session == null) { const notes = try alloc.alloc([]const u8, 1); notes[0] = "a captured console session would be the fallback"; return .{ .report = .{ .limits = &[_]usage.UsageLimit{}, .error_message = "the bailian CLI gave no usable output", .notes = notes, }, }; } } else if (session == null) { return .{ .report = .{ .limits = &[_]usage.UsageLimit{}, .error_message = "needs a session credential when the host runs no commands; capture a console HAR with scripts/capture-alibaba-session.mjs", }, }; }
return .{ .requests = try consoleRequests(alloc, session.?, region) }; }
if (session == null) { return .{ .report = .{ .limits = &[_]usage.UsageLimit{}, .error_message = "alibaba needs a cli or session credential", }, }; }
return try reportFromConsole(alloc, cred_root, resp_array);}1234567891011121314151617181920212223242526{ "code": "200", "data": { "DataV2": { "data": { "success": true, "data": { "lite": { "five_hour": 700, "weekly": 2500 }, "standard": { "five_hour": 3000, "weekly": 10000 }, "pro": { "five_hour": 12000, "weekly": 40000 } }, "httpStatus": 200 } }, "successResponse": true }}