@carrierllc/mcp 0.9.2 → 0.9.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.
- package/README.md +5 -5
- package/dist/{chunk-4XHSOF62.js → chunk-KHNJNJX3.js} +325 -4
- package/dist/chunk-KHNJNJX3.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.js +318 -196
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/plugin/carrier/README.md +1 -1
- package/dist/chunk-4XHSOF62.js.map +0 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Natural language control of your MVNO/eSIM fleet. 43 OCS tools + 8 intelligence
|
|
|
12
12
|
### Interactive CLI (non-developers)
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
npx -y @carrierllc/mcp
|
|
15
|
+
npx -y -p @carrierllc/mcp carrier-mcp
|
|
16
16
|
# opens the Carrier TUI: status, sign-up/sign-in, install MCP, fleet NL examples
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -51,7 +51,7 @@ flags. Two rules apply everywhere:
|
|
|
51
51
|
### Stdio server (token env)
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
ESIMVAULT_API_TOKEN=your_key npx -y @carrierllc/mcp
|
|
54
|
+
ESIMVAULT_API_TOKEN=your_key npx -y -p @carrierllc/mcp carrier-mcp
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
Get a key at [mcp.carrier.llc](https://mcp.carrier.llc) or an org API key from the console.
|
|
@@ -67,7 +67,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
|
67
67
|
"mcpServers": {
|
|
68
68
|
"carrier": {
|
|
69
69
|
"command": "npx",
|
|
70
|
-
"args": ["-y", "@carrierllc/mcp"],
|
|
70
|
+
"args": ["-y", "-p", "@carrierllc/mcp", "carrier-mcp"],
|
|
71
71
|
"env": {
|
|
72
72
|
"ESIMVAULT_API_TOKEN": "YOUR_KEY"
|
|
73
73
|
}
|
|
@@ -85,7 +85,7 @@ Add to `~/.cursor/mcp.json`:
|
|
|
85
85
|
"mcpServers": {
|
|
86
86
|
"carrier": {
|
|
87
87
|
"command": "npx",
|
|
88
|
-
"args": ["-y", "@carrierllc/mcp"],
|
|
88
|
+
"args": ["-y", "-p", "@carrierllc/mcp", "carrier-mcp"],
|
|
89
89
|
"env": {
|
|
90
90
|
"ESIMVAULT_API_TOKEN": "YOUR_KEY"
|
|
91
91
|
}
|
|
@@ -103,7 +103,7 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
103
103
|
"mcpServers": {
|
|
104
104
|
"carrier": {
|
|
105
105
|
"command": "npx",
|
|
106
|
-
"args": ["-y", "@carrierllc/mcp"],
|
|
106
|
+
"args": ["-y", "-p", "@carrierllc/mcp", "carrier-mcp"],
|
|
107
107
|
"env": {
|
|
108
108
|
"ESIMVAULT_API_TOKEN": "YOUR_KEY"
|
|
109
109
|
}
|
|
@@ -1792,7 +1792,7 @@ function storefrontScreen(input) {
|
|
|
1792
1792
|
// package.json
|
|
1793
1793
|
var package_default = {
|
|
1794
1794
|
name: "@carrierllc/mcp",
|
|
1795
|
-
version: "0.9.
|
|
1795
|
+
version: "0.9.3",
|
|
1796
1796
|
description: "Carrier MCP \u2014 natural-language control of MVNO/eSIM fleets via eSIMVault OCS. Stdio mode for direct integration with Claude Desktop, Cursor, Windsurf, and MCP-compatible clients. Ships the `carrier` CLI (plugin install + white-label eSIM storefront scaffold).",
|
|
1797
1797
|
license: "MIT",
|
|
1798
1798
|
author: "Carrier (Lifecycle Innovations Limited)",
|
|
@@ -1840,7 +1840,7 @@ var package_default = {
|
|
|
1840
1840
|
zod: "^4.4.3"
|
|
1841
1841
|
},
|
|
1842
1842
|
devDependencies: {
|
|
1843
|
-
"@cloudflare/workers-types": "^
|
|
1843
|
+
"@cloudflare/workers-types": "^5.20260819.1",
|
|
1844
1844
|
"@types/node": "^26.1.2",
|
|
1845
1845
|
"@typescript-eslint/eslint-plugin": "^8.59.4",
|
|
1846
1846
|
"@typescript-eslint/parser": "^8.67.0",
|
|
@@ -1876,7 +1876,113 @@ var package_default = {
|
|
|
1876
1876
|
// src/version.ts
|
|
1877
1877
|
var CARRIER_VERSION = package_default.version;
|
|
1878
1878
|
|
|
1879
|
-
// ../../packages/ocs-client/dist/chunk-
|
|
1879
|
+
// ../../packages/ocs-client/dist/chunk-CGMK4FTD.js
|
|
1880
|
+
var DEFAULT_OCS_BUDGET = {
|
|
1881
|
+
attemptMs: 3e4,
|
|
1882
|
+
maxAttempts: 3,
|
|
1883
|
+
totalMs: 75e3
|
|
1884
|
+
};
|
|
1885
|
+
var OCS_METHOD_BUDGETS = {
|
|
1886
|
+
// 3.4 MB, 88-128 s measured. 180 s is 1.4x the slowest observation. One
|
|
1887
|
+
// attempt: payload size does not vary, so a retry only doubles the wait.
|
|
1888
|
+
getCustomerTariff: { attemptMs: 18e4, maxAttempts: 1, totalMs: 18e4 }
|
|
1889
|
+
};
|
|
1890
|
+
var MIN_ATTEMPT_BUDGET_MS = 1e3;
|
|
1891
|
+
var BACKOFF_BASE_MS = 500;
|
|
1892
|
+
var OcsTimeoutError = class extends Error {
|
|
1893
|
+
constructor(method, timeoutMs, budgetMs = timeoutMs, attempts = 1) {
|
|
1894
|
+
super(
|
|
1895
|
+
`[${method}] OCS request timed out after ${timeoutMs}ms` + (attempts > 1 ? ` on each of ${attempts} attempts` : "") + (budgetMs > timeoutMs ? ` (budget ${budgetMs}ms)` : "") + `. The upstream did not deliver a complete response in time \u2014 usually an oversized payload or a wedged upstream. Narrow the request, or raise OCS_TIMEOUT_MS / OCS_TOTAL_TIMEOUT_MS if this method is legitimately slower here.`
|
|
1896
|
+
);
|
|
1897
|
+
this.method = method;
|
|
1898
|
+
this.timeoutMs = timeoutMs;
|
|
1899
|
+
this.budgetMs = budgetMs;
|
|
1900
|
+
this.attempts = attempts;
|
|
1901
|
+
this.name = "OcsTimeoutError";
|
|
1902
|
+
}
|
|
1903
|
+
method;
|
|
1904
|
+
timeoutMs;
|
|
1905
|
+
budgetMs;
|
|
1906
|
+
attempts;
|
|
1907
|
+
};
|
|
1908
|
+
function envInt(name) {
|
|
1909
|
+
const proc = globalThis["process"];
|
|
1910
|
+
const parsed = Number(proc?.env?.[name]);
|
|
1911
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
1912
|
+
}
|
|
1913
|
+
function ocsBudgetFor(method) {
|
|
1914
|
+
const base = OCS_METHOD_BUDGETS[method] ?? DEFAULT_OCS_BUDGET;
|
|
1915
|
+
const attemptMs = envInt("OCS_TIMEOUT_MS") ?? base.attemptMs;
|
|
1916
|
+
const totalMs = Math.max(envInt("OCS_TOTAL_TIMEOUT_MS") ?? base.totalMs, attemptMs);
|
|
1917
|
+
return { attemptMs, maxAttempts: base.maxAttempts, totalMs };
|
|
1918
|
+
}
|
|
1919
|
+
function sleep2(ms, signal) {
|
|
1920
|
+
return new Promise((resolve) => {
|
|
1921
|
+
const timer = setTimeout(finish, ms);
|
|
1922
|
+
function finish() {
|
|
1923
|
+
clearTimeout(timer);
|
|
1924
|
+
signal.removeEventListener("abort", finish);
|
|
1925
|
+
resolve();
|
|
1926
|
+
}
|
|
1927
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
async function withDeadline(work, deadline, ms) {
|
|
1931
|
+
let timer;
|
|
1932
|
+
try {
|
|
1933
|
+
return await Promise.race([
|
|
1934
|
+
work,
|
|
1935
|
+
new Promise((_resolve, reject) => {
|
|
1936
|
+
timer = setTimeout(() => reject(deadline), ms);
|
|
1937
|
+
})
|
|
1938
|
+
]);
|
|
1939
|
+
} finally {
|
|
1940
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
async function runWithBudget(method, attempt, budget = ocsBudgetFor(method)) {
|
|
1944
|
+
const deadlineAt = Date.now() + budget.totalMs;
|
|
1945
|
+
const budgetController = new AbortController();
|
|
1946
|
+
const budgetTimer = setTimeout(() => budgetController.abort(), budget.totalMs);
|
|
1947
|
+
let attempts = 0;
|
|
1948
|
+
let lastTimeout;
|
|
1949
|
+
try {
|
|
1950
|
+
for (let i = 0; i < budget.maxAttempts; i++) {
|
|
1951
|
+
const remaining = deadlineAt - Date.now();
|
|
1952
|
+
if (remaining < MIN_ATTEMPT_BUDGET_MS) break;
|
|
1953
|
+
const attemptMs = Math.min(budget.attemptMs, remaining);
|
|
1954
|
+
attempts++;
|
|
1955
|
+
const attemptController = new AbortController();
|
|
1956
|
+
const onBudgetAbort = () => attemptController.abort();
|
|
1957
|
+
budgetController.signal.addEventListener("abort", onBudgetAbort, { once: true });
|
|
1958
|
+
const attemptTimer = setTimeout(() => attemptController.abort(), attemptMs);
|
|
1959
|
+
const breach = new OcsTimeoutError(method, attemptMs, budget.totalMs, attempts);
|
|
1960
|
+
try {
|
|
1961
|
+
return await withDeadline(
|
|
1962
|
+
attempt(attemptController.signal, attemptMs),
|
|
1963
|
+
breach,
|
|
1964
|
+
attemptMs
|
|
1965
|
+
);
|
|
1966
|
+
} catch (err) {
|
|
1967
|
+
if (!(err instanceof OcsTimeoutError)) throw err;
|
|
1968
|
+
lastTimeout = new OcsTimeoutError(method, attemptMs, budget.totalMs, attempts);
|
|
1969
|
+
} finally {
|
|
1970
|
+
clearTimeout(attemptTimer);
|
|
1971
|
+
budgetController.signal.removeEventListener("abort", onBudgetAbort);
|
|
1972
|
+
attemptController.abort();
|
|
1973
|
+
}
|
|
1974
|
+
if (i === budget.maxAttempts - 1) break;
|
|
1975
|
+
const backoff = Math.random() * BACKOFF_BASE_MS * 2 ** i;
|
|
1976
|
+
if (Date.now() + backoff + MIN_ATTEMPT_BUDGET_MS > deadlineAt) break;
|
|
1977
|
+
await sleep2(backoff, budgetController.signal);
|
|
1978
|
+
}
|
|
1979
|
+
} finally {
|
|
1980
|
+
clearTimeout(budgetTimer);
|
|
1981
|
+
}
|
|
1982
|
+
throw lastTimeout ?? new OcsTimeoutError(method, budget.attemptMs, budget.totalMs, Math.max(attempts, 1));
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
// ../../packages/ocs-client/dist/chunk-OPUTHPZF.js
|
|
1880
1986
|
var ENDPOINT_LIMITS_PER_MIN = {
|
|
1881
1987
|
// Global sentinel (keyed as "__global__")
|
|
1882
1988
|
__global__: 600,
|
|
@@ -2036,6 +2142,24 @@ function getRateLimitWindowCounts(resellerKey, endpoint) {
|
|
|
2036
2142
|
}
|
|
2037
2143
|
return { calls_in_window, batch_calls_in_window };
|
|
2038
2144
|
}
|
|
2145
|
+
var OCS_PARAM_RENAMES = {
|
|
2146
|
+
getResellerInfo: { resellerId: "id" }
|
|
2147
|
+
};
|
|
2148
|
+
function applyParamRenames(method, params) {
|
|
2149
|
+
const renames = OCS_PARAM_RENAMES[method];
|
|
2150
|
+
if (!renames || !params || typeof params !== "object" || Array.isArray(params)) {
|
|
2151
|
+
return params;
|
|
2152
|
+
}
|
|
2153
|
+
const record = params;
|
|
2154
|
+
let out;
|
|
2155
|
+
for (const [from, to] of Object.entries(renames)) {
|
|
2156
|
+
if (!Object.prototype.hasOwnProperty.call(record, from)) continue;
|
|
2157
|
+
out ??= { ...record };
|
|
2158
|
+
if (!Object.prototype.hasOwnProperty.call(record, to)) out[to] = record[from];
|
|
2159
|
+
delete out[from];
|
|
2160
|
+
}
|
|
2161
|
+
return out ?? params;
|
|
2162
|
+
}
|
|
2039
2163
|
|
|
2040
2164
|
// ../../packages/ocs-client/dist/chunk-JWSVJVAF.js
|
|
2041
2165
|
var OCS_MAX_USAGE_WINDOW_DAYS = 7;
|
|
@@ -2388,6 +2512,195 @@ var ROUTER_RULES = `Rules:
|
|
|
2388
2512
|
7. A tool answers the question only if its description says it does. Do not infer capability from the tool's NAME: several names share words with unrelated questions, and picking on the name alone has produced confidently wrong answers.
|
|
2389
2513
|
8. Read the "Do NOT use this to \u2026" steers in a description as hard exclusions. They exist because that tool is the common wrong answer for a neighbouring question, and they name the tool to use instead.
|
|
2390
2514
|
9. Prefer carrier_clarify over a tool that would return real data about a different question. Answering "which subscribers erode margin" when the user asked "what do my users' megabytes cost in total" is worse than admitting the gap, because the output looks like an answer.`;
|
|
2515
|
+
var OCS_LIST_KEYS = {
|
|
2516
|
+
subscribers: ["subscriberList"],
|
|
2517
|
+
templates: ["template", "prepaidPackageTemplate"],
|
|
2518
|
+
zones: ["listDetailedLocationZone", "locationZone", "zone", "zones"],
|
|
2519
|
+
resellers: ["reseller"],
|
|
2520
|
+
packages: ["prepaidPackage", "package"]
|
|
2521
|
+
};
|
|
2522
|
+
function ocsArray(data, keys) {
|
|
2523
|
+
if (Array.isArray(data)) return data;
|
|
2524
|
+
if (data === null || typeof data !== "object") return [];
|
|
2525
|
+
const candidates = typeof keys === "string" ? OCS_LIST_KEYS[keys] : keys;
|
|
2526
|
+
const obj = data;
|
|
2527
|
+
for (const key of candidates) {
|
|
2528
|
+
const v = obj[key];
|
|
2529
|
+
if (Array.isArray(v)) return v;
|
|
2530
|
+
}
|
|
2531
|
+
return [];
|
|
2532
|
+
}
|
|
2533
|
+
var FACET_TALLY_MAX = 25;
|
|
2534
|
+
var OCS_LIST_FACETS = {
|
|
2535
|
+
templates: [
|
|
2536
|
+
{ label: "recurring", paths: ["recurring"] },
|
|
2537
|
+
{
|
|
2538
|
+
label: "locationZone",
|
|
2539
|
+
paths: [
|
|
2540
|
+
"rdbLocationZones.locationzonename",
|
|
2541
|
+
"locationzonename",
|
|
2542
|
+
"locationzoneid"
|
|
2543
|
+
]
|
|
2544
|
+
}
|
|
2545
|
+
],
|
|
2546
|
+
subscribers: [{ label: "status", paths: ["status"] }],
|
|
2547
|
+
packages: [
|
|
2548
|
+
{ label: "status", paths: ["status"] },
|
|
2549
|
+
{ label: "recurring", paths: ["recurring"] }
|
|
2550
|
+
],
|
|
2551
|
+
zones: [],
|
|
2552
|
+
resellers: []
|
|
2553
|
+
};
|
|
2554
|
+
var OCS_LIST_NESTED = {
|
|
2555
|
+
resellers: { label: "accounts", path: "account" }
|
|
2556
|
+
};
|
|
2557
|
+
function pagingHints(data) {
|
|
2558
|
+
if (data === null || typeof data !== "object" || Array.isArray(data)) {
|
|
2559
|
+
return { hasMore: false, nbFound: void 0 };
|
|
2560
|
+
}
|
|
2561
|
+
const obj = data;
|
|
2562
|
+
return {
|
|
2563
|
+
hasMore: obj.hasMore === true,
|
|
2564
|
+
nbFound: typeof obj.nbFound === "number" ? obj.nbFound : void 0
|
|
2565
|
+
};
|
|
2566
|
+
}
|
|
2567
|
+
function readPath(row, path) {
|
|
2568
|
+
let cur = row;
|
|
2569
|
+
for (const seg of path.split(".")) {
|
|
2570
|
+
if (cur === null || typeof cur !== "object") return void 0;
|
|
2571
|
+
cur = cur[seg];
|
|
2572
|
+
}
|
|
2573
|
+
return cur;
|
|
2574
|
+
}
|
|
2575
|
+
function facetKey(v) {
|
|
2576
|
+
if (v === null || v === void 0) return null;
|
|
2577
|
+
if (typeof v === "boolean" || typeof v === "number") return String(v);
|
|
2578
|
+
if (typeof v === "string") return v;
|
|
2579
|
+
return null;
|
|
2580
|
+
}
|
|
2581
|
+
function ocsListSummary(data, kind, facets = OCS_LIST_FACETS[kind]) {
|
|
2582
|
+
const rows = ocsArray(data, kind);
|
|
2583
|
+
const breakdown = {};
|
|
2584
|
+
for (const facet of facets) {
|
|
2585
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2586
|
+
let missing = 0;
|
|
2587
|
+
for (const row of rows) {
|
|
2588
|
+
if (row === null || typeof row !== "object") {
|
|
2589
|
+
missing += 1;
|
|
2590
|
+
continue;
|
|
2591
|
+
}
|
|
2592
|
+
let key = null;
|
|
2593
|
+
for (const path of facet.paths) {
|
|
2594
|
+
key = facetKey(readPath(row, path));
|
|
2595
|
+
if (key !== null) break;
|
|
2596
|
+
}
|
|
2597
|
+
if (key === null) {
|
|
2598
|
+
missing += 1;
|
|
2599
|
+
continue;
|
|
2600
|
+
}
|
|
2601
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
2602
|
+
}
|
|
2603
|
+
if (counts.size === 0 && missing === 0) continue;
|
|
2604
|
+
const entry = { distinct: counts.size };
|
|
2605
|
+
if (counts.size > 0 && counts.size <= FACET_TALLY_MAX) {
|
|
2606
|
+
entry.counts = Object.fromEntries(
|
|
2607
|
+
[...counts].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)
|
|
2608
|
+
);
|
|
2609
|
+
}
|
|
2610
|
+
if (missing > 0) entry.missing = missing;
|
|
2611
|
+
breakdown[facet.label] = entry;
|
|
2612
|
+
}
|
|
2613
|
+
const { hasMore, nbFound } = pagingHints(data);
|
|
2614
|
+
const more = hasMore || nbFound !== void 0 && nbFound > rows.length;
|
|
2615
|
+
const summary = {
|
|
2616
|
+
total: rows.length,
|
|
2617
|
+
note: `Counted server-side: ${rows.length} row${rows.length === 1 ? "" : "s"} in this result. Use these figures directly rather than recounting the rows below. ` + (more ? "This is ONE PAGE \u2014 OCS holds more rows than are returned here" + (nbFound !== void 0 ? ` (${nbFound} match upstream)` : "") + ", so do not report `total` as a fleet-wide figure; narrow the filters or page for the rest." : "Nothing was truncated: these are all the rows OCS returned.")
|
|
2618
|
+
};
|
|
2619
|
+
if (more) {
|
|
2620
|
+
summary.moreAvailable = true;
|
|
2621
|
+
if (nbFound !== void 0) summary.upstreamTotal = nbFound;
|
|
2622
|
+
}
|
|
2623
|
+
const nest = OCS_LIST_NESTED[kind];
|
|
2624
|
+
if (nest) {
|
|
2625
|
+
const n = rows.reduce((acc, row) => {
|
|
2626
|
+
const child = row && typeof row === "object" ? readPath(row, nest.path) : void 0;
|
|
2627
|
+
return acc + (Array.isArray(child) ? child.length : 0);
|
|
2628
|
+
}, 0);
|
|
2629
|
+
summary.nested = { [nest.label]: n };
|
|
2630
|
+
summary.note += ` This envelope NESTS: \`total\` counts the outer rows, while there are ${n} ${nest.label} inside them under \`${nest.path}\`. A question about ${nest.label} is answered by that figure, not by \`total\`.`;
|
|
2631
|
+
}
|
|
2632
|
+
if (Object.keys(breakdown).length > 0) {
|
|
2633
|
+
summary.breakdown = breakdown;
|
|
2634
|
+
summary.note += " `breakdown` gives, per field, how many distinct values occur and how many rows carry each (`missing` counts rows where the field is absent).";
|
|
2635
|
+
}
|
|
2636
|
+
return summary;
|
|
2637
|
+
}
|
|
2638
|
+
function withOcsListSummary(data, kind, facets) {
|
|
2639
|
+
const summary = ocsListSummary(data, kind, facets);
|
|
2640
|
+
if (data !== null && typeof data === "object" && !Array.isArray(data)) {
|
|
2641
|
+
return { summary, ...data };
|
|
2642
|
+
}
|
|
2643
|
+
return { summary, [OCS_LIST_KEYS[kind][0]]: data };
|
|
2644
|
+
}
|
|
2645
|
+
var OCS_DATA_QUANTITY_TYPE = "33";
|
|
2646
|
+
function readBytes(entry) {
|
|
2647
|
+
const total = entry.total;
|
|
2648
|
+
if (total !== null && typeof total === "object") {
|
|
2649
|
+
const perType = total.quantityPerType;
|
|
2650
|
+
if (perType !== null && typeof perType === "object") {
|
|
2651
|
+
const v = perType[OCS_DATA_QUANTITY_TYPE];
|
|
2652
|
+
if (v !== void 0) return Number(v) || 0;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
return Number(entry.dataBytes ?? entry.dataVolume ?? entry.totalData ?? 0) || 0;
|
|
2656
|
+
}
|
|
2657
|
+
function extractDailyUsage(data) {
|
|
2658
|
+
const out = [];
|
|
2659
|
+
if (data === null || typeof data !== "object") return out;
|
|
2660
|
+
if (Array.isArray(data)) {
|
|
2661
|
+
for (const entry of data) {
|
|
2662
|
+
if (entry === null || typeof entry !== "object") continue;
|
|
2663
|
+
const e = entry;
|
|
2664
|
+
out.push({ date: String(e.date ?? e.day ?? "?"), bytes: readBytes(e) });
|
|
2665
|
+
}
|
|
2666
|
+
return out;
|
|
2667
|
+
}
|
|
2668
|
+
const usages = data.usages;
|
|
2669
|
+
if (!Array.isArray(usages)) return out;
|
|
2670
|
+
for (const usage of usages) {
|
|
2671
|
+
if (usage === null || typeof usage !== "object") continue;
|
|
2672
|
+
const periods = usage.subsPeriodUsages;
|
|
2673
|
+
if (!Array.isArray(periods)) continue;
|
|
2674
|
+
for (const period of periods) {
|
|
2675
|
+
if (period === null || typeof period !== "object") continue;
|
|
2676
|
+
const p = period;
|
|
2677
|
+
out.push({ date: String(p.day ?? p.date ?? "?"), bytes: readBytes(p) });
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
return out;
|
|
2681
|
+
}
|
|
2682
|
+
function daysUntil(dateStr) {
|
|
2683
|
+
const now = /* @__PURE__ */ new Date();
|
|
2684
|
+
const target = new Date(dateStr);
|
|
2685
|
+
return Math.ceil((target.getTime() - now.getTime()) / (1e3 * 60 * 60 * 24));
|
|
2686
|
+
}
|
|
2687
|
+
function formatBytes(bytes) {
|
|
2688
|
+
if (bytes === 0) return "0 B";
|
|
2689
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
2690
|
+
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
2691
|
+
return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${units[i]}`;
|
|
2692
|
+
}
|
|
2693
|
+
function isActiveSubscriber(row) {
|
|
2694
|
+
return (extractSubscriberStatus(row) ?? "").toUpperCase() === "ACTIVE";
|
|
2695
|
+
}
|
|
2696
|
+
function filterActiveSubscribers(rows) {
|
|
2697
|
+
return rows.filter((row) => isActiveSubscriber(row));
|
|
2698
|
+
}
|
|
2699
|
+
function subscriberRows(raw) {
|
|
2700
|
+
if (Array.isArray(raw)) return raw;
|
|
2701
|
+
const list = raw?.subscriberList;
|
|
2702
|
+
return Array.isArray(list) ? list : [];
|
|
2703
|
+
}
|
|
2391
2704
|
|
|
2392
2705
|
// src/lib/storefront-logo.ts
|
|
2393
2706
|
var OPENAI_KEY_NAMES = [
|
|
@@ -2510,9 +2823,11 @@ async function generateStorefrontLogo(input) {
|
|
|
2510
2823
|
}
|
|
2511
2824
|
|
|
2512
2825
|
export {
|
|
2826
|
+
runWithBudget,
|
|
2513
2827
|
acquireEndpointSlot,
|
|
2514
2828
|
getLimitForEndpoint,
|
|
2515
2829
|
getRateLimitWindowCounts,
|
|
2830
|
+
applyParamRenames,
|
|
2516
2831
|
OCS_MAX_USAGE_WINDOW_DAYS,
|
|
2517
2832
|
clampUsagePeriod,
|
|
2518
2833
|
lastNDaysPeriod,
|
|
@@ -2531,6 +2846,12 @@ export {
|
|
|
2531
2846
|
recordToolDescription,
|
|
2532
2847
|
buildRouterCatalog,
|
|
2533
2848
|
ROUTER_RULES,
|
|
2849
|
+
withOcsListSummary,
|
|
2850
|
+
extractDailyUsage,
|
|
2851
|
+
daysUntil,
|
|
2852
|
+
formatBytes,
|
|
2853
|
+
filterActiveSubscribers,
|
|
2854
|
+
subscriberRows,
|
|
2534
2855
|
generateStorefrontLogo,
|
|
2535
2856
|
run,
|
|
2536
2857
|
which,
|
|
@@ -2569,4 +2890,4 @@ export {
|
|
|
2569
2890
|
storefrontScreen,
|
|
2570
2891
|
CARRIER_VERSION
|
|
2571
2892
|
};
|
|
2572
|
-
//# sourceMappingURL=chunk-
|
|
2893
|
+
//# sourceMappingURL=chunk-KHNJNJX3.js.map
|