@carrierllc/mcp 0.13.13 → 0.13.15
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/dist/{chunk-OJITGTFO.js → chunk-QXIY42R6.js} +494 -5
- package/dist/chunk-QXIY42R6.js.map +1 -0
- package/dist/cli.js +93 -5
- package/dist/cli.js.map +1 -1
- package/dist/index.js +185 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/plugin/carrier/.claude-plugin/plugin.json +1 -1
- package/plugin/carrier/skills/issue-esim/SKILL.md +73 -8
- package/plugin/carrier/skills/issue-esim/references/glossary.md +14 -0
- package/plugin/carrier/skills/publish-storefront/SKILL.md +14 -6
- package/dist/chunk-OJITGTFO.js.map +0 -1
|
@@ -1820,7 +1820,7 @@ function storefrontScreen(input) {
|
|
|
1820
1820
|
// package.json
|
|
1821
1821
|
var package_default = {
|
|
1822
1822
|
name: "@carrierllc/mcp",
|
|
1823
|
-
version: "0.13.
|
|
1823
|
+
version: "0.13.15",
|
|
1824
1824
|
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).",
|
|
1825
1825
|
license: "MIT",
|
|
1826
1826
|
author: "Carrier (Lifecycle Innovations Limited)",
|
|
@@ -2705,7 +2705,7 @@ function packageTemplateModifyFromToolJson(changes, method) {
|
|
|
2705
2705
|
return packageTemplateModifyParams(body, method);
|
|
2706
2706
|
}
|
|
2707
2707
|
|
|
2708
|
-
// ../../packages/ocs-client/dist/chunk-
|
|
2708
|
+
// ../../packages/ocs-client/dist/chunk-MNVQV5ST.js
|
|
2709
2709
|
import { z } from "zod";
|
|
2710
2710
|
var OCS_V1_METHODS = /* @__PURE__ */ new Set([
|
|
2711
2711
|
"getResellerInfo",
|
|
@@ -2749,6 +2749,10 @@ var OCS_V1_METHODS = /* @__PURE__ */ new Set([
|
|
|
2749
2749
|
"resetSubsGzCounter",
|
|
2750
2750
|
"sendMtSms"
|
|
2751
2751
|
]);
|
|
2752
|
+
var OCS_FORBIDDEN_METHODS = /* @__PURE__ */ new Set([
|
|
2753
|
+
"createAccount",
|
|
2754
|
+
"createSubscriber"
|
|
2755
|
+
]);
|
|
2752
2756
|
var OcsResponseEnvelope = z.object({
|
|
2753
2757
|
status: z.object({
|
|
2754
2758
|
code: z.number(),
|
|
@@ -3050,7 +3054,7 @@ async function runWithBudget(method, attempt, budget = ocsBudgetFor(method)) {
|
|
|
3050
3054
|
throw lastTimeout ?? new OcsTimeoutError(method, budget.attemptMs, budget.totalMs, Math.max(attempts, 1));
|
|
3051
3055
|
}
|
|
3052
3056
|
|
|
3053
|
-
// ../../packages/ocs-client/dist/chunk-
|
|
3057
|
+
// ../../packages/ocs-client/dist/chunk-4F7VPWOS.js
|
|
3054
3058
|
var RATE_LIMIT = 10;
|
|
3055
3059
|
var WINDOW_MS = 1e3;
|
|
3056
3060
|
var windows = /* @__PURE__ */ new Map();
|
|
@@ -3331,7 +3335,7 @@ var OcsApiError = class extends Error {
|
|
|
3331
3335
|
var OcsUnknownMethodError = class extends Error {
|
|
3332
3336
|
constructor(method) {
|
|
3333
3337
|
super(
|
|
3334
|
-
`[${method}] is not a known OCS v1 method. It is not in the verified set of ${OCS_V1_METHODS.size} methods (createAccount/createSubscriber do not exist on the OCS). If this is a genuinely new method, add it to OCS_V1_METHODS or construct the client without { strictMethods: true }.`
|
|
3338
|
+
`[${method}] is not a known OCS v1 method. It is not in the verified set of ${OCS_V1_METHODS.size} methods (createAccount/createSubscriber do not exist on the OCS). ` + (OCS_FORBIDDEN_METHODS.has(method) ? `${method} is a proven phantom method and is always rejected regardless of client options.` : `If this is a genuinely new method, add it to OCS_V1_METHODS or construct the client without { strictMethods: true }.`)
|
|
3335
3339
|
);
|
|
3336
3340
|
this.method = method;
|
|
3337
3341
|
this.name = "OcsUnknownMethodError";
|
|
@@ -3456,6 +3460,9 @@ var OcsClient = class {
|
|
|
3456
3460
|
_warnedMethods = /* @__PURE__ */ new Set();
|
|
3457
3461
|
_warnedValidation = /* @__PURE__ */ new Set();
|
|
3458
3462
|
async call(method, params = {}, token) {
|
|
3463
|
+
if (OCS_FORBIDDEN_METHODS.has(method)) {
|
|
3464
|
+
throw new OcsUnknownMethodError(method);
|
|
3465
|
+
}
|
|
3459
3466
|
if (!OCS_V1_METHODS.has(method)) {
|
|
3460
3467
|
if (this._strictMethods) throw new OcsUnknownMethodError(method);
|
|
3461
3468
|
if (!this._warnedMethods.has(method)) {
|
|
@@ -4790,6 +4797,482 @@ function collapseGyStays(events) {
|
|
|
4790
4797
|
function gyCountryHistoryFromResponse(response) {
|
|
4791
4798
|
return collapseGyStays(extractGyEvents(response));
|
|
4792
4799
|
}
|
|
4800
|
+
var NETWORK_DEFAULT_MODES = ["cheapest_available", "all", "custom"];
|
|
4801
|
+
var SYSTEM_NETWORK_DEFAULT = "cheapest_available";
|
|
4802
|
+
var isoOf = (r) => String(r.operator?.countryIso2 ?? "").trim().toUpperCase();
|
|
4803
|
+
var networkIdOf = (r) => {
|
|
4804
|
+
const n = r.operator?.networkId ?? r.networkid;
|
|
4805
|
+
return typeof n === "number" && Number.isFinite(n) ? n : void 0;
|
|
4806
|
+
};
|
|
4807
|
+
function normaliseCountries(countries) {
|
|
4808
|
+
const out = /* @__PURE__ */ new Set();
|
|
4809
|
+
for (const c of countries) {
|
|
4810
|
+
const iso = String(c ?? "").trim().toUpperCase();
|
|
4811
|
+
if (/^[A-Z]{2}$/.test(iso)) out.add(iso);
|
|
4812
|
+
}
|
|
4813
|
+
return [...out].sort();
|
|
4814
|
+
}
|
|
4815
|
+
function isRuleAvailable(rule, now) {
|
|
4816
|
+
if (rule.active === false) return false;
|
|
4817
|
+
if (rule.hidden === true) return false;
|
|
4818
|
+
const t = now.getTime();
|
|
4819
|
+
if (rule.startdate) {
|
|
4820
|
+
const s = Date.parse(rule.startdate);
|
|
4821
|
+
if (Number.isFinite(s) && s > t) return false;
|
|
4822
|
+
}
|
|
4823
|
+
if (rule.enddate) {
|
|
4824
|
+
const e = Date.parse(rule.enddate);
|
|
4825
|
+
if (Number.isFinite(e) && e <= t) return false;
|
|
4826
|
+
}
|
|
4827
|
+
return true;
|
|
4828
|
+
}
|
|
4829
|
+
function cheapestAvailableForCountry(rules, country, now) {
|
|
4830
|
+
const iso = String(country ?? "").trim().toUpperCase();
|
|
4831
|
+
if (!/^[A-Z]{2}$/.test(iso)) {
|
|
4832
|
+
return {
|
|
4833
|
+
country: iso,
|
|
4834
|
+
networks: [],
|
|
4835
|
+
candidateCount: 0,
|
|
4836
|
+
warnings: [
|
|
4837
|
+
{ code: "NO_COUNTRY", message: `"${country}" is not an ISO-3166 alpha-2 country code.` }
|
|
4838
|
+
]
|
|
4839
|
+
};
|
|
4840
|
+
}
|
|
4841
|
+
if (!rules || rules.length === 0) {
|
|
4842
|
+
return {
|
|
4843
|
+
country: iso,
|
|
4844
|
+
networks: [],
|
|
4845
|
+
candidateCount: 0,
|
|
4846
|
+
warnings: [
|
|
4847
|
+
{
|
|
4848
|
+
code: "NO_TARIFF_DATA",
|
|
4849
|
+
country: iso,
|
|
4850
|
+
message: `No tariff data was available, so ${iso} stays open to all networks. It was not narrowed to the cheapest.`
|
|
4851
|
+
}
|
|
4852
|
+
]
|
|
4853
|
+
};
|
|
4854
|
+
}
|
|
4855
|
+
const best = /* @__PURE__ */ new Map();
|
|
4856
|
+
const currencies = /* @__PURE__ */ new Set();
|
|
4857
|
+
for (const r of rules) {
|
|
4858
|
+
if (isoOf(r) !== iso) continue;
|
|
4859
|
+
if (!isRuleAvailable(r, now)) continue;
|
|
4860
|
+
const rate = r.datarate;
|
|
4861
|
+
if (typeof rate !== "number" || !Number.isFinite(rate) || rate <= 0) continue;
|
|
4862
|
+
const id = networkIdOf(r);
|
|
4863
|
+
if (id === void 0) continue;
|
|
4864
|
+
const currency = String(
|
|
4865
|
+
r.currency?.currencycode ?? (r.currencyid !== void 0 ? `id:${r.currencyid}` : "?")
|
|
4866
|
+
);
|
|
4867
|
+
currencies.add(currency);
|
|
4868
|
+
const cur = best.get(id);
|
|
4869
|
+
if (!cur || rate < cur.datarate) {
|
|
4870
|
+
best.set(id, {
|
|
4871
|
+
networkId: id,
|
|
4872
|
+
operatorName: String(r.operator?.operatorName ?? `network ${id}`),
|
|
4873
|
+
datarate: rate,
|
|
4874
|
+
currency
|
|
4875
|
+
});
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4878
|
+
if (best.size === 0) {
|
|
4879
|
+
return {
|
|
4880
|
+
country: iso,
|
|
4881
|
+
networks: [],
|
|
4882
|
+
candidateCount: 0,
|
|
4883
|
+
warnings: [
|
|
4884
|
+
{
|
|
4885
|
+
code: "NO_AVAILABLE_NETWORK",
|
|
4886
|
+
country: iso,
|
|
4887
|
+
message: `No network with a usable data rate was found for ${iso}, so it stays open to all networks. It was not narrowed to the cheapest.`
|
|
4888
|
+
}
|
|
4889
|
+
]
|
|
4890
|
+
};
|
|
4891
|
+
}
|
|
4892
|
+
if (currencies.size > 1) {
|
|
4893
|
+
return {
|
|
4894
|
+
country: iso,
|
|
4895
|
+
networks: [],
|
|
4896
|
+
candidateCount: best.size,
|
|
4897
|
+
warnings: [
|
|
4898
|
+
{
|
|
4899
|
+
code: "MIXED_CURRENCY",
|
|
4900
|
+
country: iso,
|
|
4901
|
+
message: `Rates for ${iso} are in more than one currency (${[...currencies].sort().join(", ")}), so they cannot be compared. It stays open to all networks.`
|
|
4902
|
+
}
|
|
4903
|
+
]
|
|
4904
|
+
};
|
|
4905
|
+
}
|
|
4906
|
+
const min = Math.min(...[...best.values()].map((n) => n.datarate));
|
|
4907
|
+
const networks = [...best.values()].filter((n) => n.datarate === min).sort((a, b) => a.networkId - b.networkId);
|
|
4908
|
+
const warnings = [];
|
|
4909
|
+
if (best.size === 1) {
|
|
4910
|
+
warnings.push({
|
|
4911
|
+
code: "SINGLE_NETWORK",
|
|
4912
|
+
country: iso,
|
|
4913
|
+
message: `Only one network is available for ${iso}, so "cheapest" and "all" are the same there.`
|
|
4914
|
+
});
|
|
4915
|
+
}
|
|
4916
|
+
return { country: iso, networks, candidateCount: best.size, warnings };
|
|
4917
|
+
}
|
|
4918
|
+
function validateNetworkChoice(choice) {
|
|
4919
|
+
if (!choice || typeof choice !== "object") return "A network choice must be an object.";
|
|
4920
|
+
const c = choice;
|
|
4921
|
+
if (!NETWORK_DEFAULT_MODES.includes(c.mode)) {
|
|
4922
|
+
return `mode must be one of: ${NETWORK_DEFAULT_MODES.join(", ")}.`;
|
|
4923
|
+
}
|
|
4924
|
+
if (c.mode === "custom") {
|
|
4925
|
+
const id = c.steeringListId;
|
|
4926
|
+
if (typeof id !== "number" || !Number.isInteger(id) || id <= 0) {
|
|
4927
|
+
return "mode custom needs steeringListId, a positive integer from list_steering_lists.";
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
return null;
|
|
4931
|
+
}
|
|
4932
|
+
function pickChoice(input) {
|
|
4933
|
+
const layers = [
|
|
4934
|
+
["sim_override", input.simOverride],
|
|
4935
|
+
["package_override", input.packageOverride],
|
|
4936
|
+
["org_default", input.orgDefault]
|
|
4937
|
+
];
|
|
4938
|
+
const skipped = [];
|
|
4939
|
+
for (const [source, choice] of layers) {
|
|
4940
|
+
if (choice === null || choice === void 0) continue;
|
|
4941
|
+
const problem = validateNetworkChoice(choice);
|
|
4942
|
+
if (problem) {
|
|
4943
|
+
skipped.push({
|
|
4944
|
+
code: "INVALID_CHOICE",
|
|
4945
|
+
message: `The ${source.replace("_", " ")} is invalid and was ignored: ${problem}`
|
|
4946
|
+
});
|
|
4947
|
+
continue;
|
|
4948
|
+
}
|
|
4949
|
+
return { choice, source, skipped };
|
|
4950
|
+
}
|
|
4951
|
+
return { choice: { mode: SYSTEM_NETWORK_DEFAULT }, source: "system_default", skipped };
|
|
4952
|
+
}
|
|
4953
|
+
function resolveNetworkPlan(input) {
|
|
4954
|
+
const { choice, source, skipped } = pickChoice(input);
|
|
4955
|
+
const countries = normaliseCountries(input.countries);
|
|
4956
|
+
const warnings = [...skipped];
|
|
4957
|
+
if (choice.mode === "custom") {
|
|
4958
|
+
return {
|
|
4959
|
+
source,
|
|
4960
|
+
mode: "custom",
|
|
4961
|
+
outcome: "use_list",
|
|
4962
|
+
steeringListId: choice.steeringListId,
|
|
4963
|
+
// validated by pickChoice
|
|
4964
|
+
networks: [],
|
|
4965
|
+
perCountry: [],
|
|
4966
|
+
fellBackToAll: false,
|
|
4967
|
+
warnings,
|
|
4968
|
+
priceBasis: null
|
|
4969
|
+
};
|
|
4970
|
+
}
|
|
4971
|
+
if (choice.mode === "all") {
|
|
4972
|
+
return {
|
|
4973
|
+
source,
|
|
4974
|
+
mode: "all",
|
|
4975
|
+
outcome: "allow_all",
|
|
4976
|
+
networks: [],
|
|
4977
|
+
perCountry: [],
|
|
4978
|
+
fellBackToAll: false,
|
|
4979
|
+
warnings,
|
|
4980
|
+
priceBasis: null
|
|
4981
|
+
};
|
|
4982
|
+
}
|
|
4983
|
+
if (countries.length === 0) {
|
|
4984
|
+
warnings.push({
|
|
4985
|
+
code: "NO_COUNTRY",
|
|
4986
|
+
message: "No valid country was given, so nothing could be narrowed. The SIM stays open to all networks."
|
|
4987
|
+
});
|
|
4988
|
+
return {
|
|
4989
|
+
source,
|
|
4990
|
+
mode: "cheapest_available",
|
|
4991
|
+
outcome: "allow_all",
|
|
4992
|
+
networks: [],
|
|
4993
|
+
perCountry: [],
|
|
4994
|
+
fellBackToAll: true,
|
|
4995
|
+
warnings,
|
|
4996
|
+
priceBasis: null
|
|
4997
|
+
};
|
|
4998
|
+
}
|
|
4999
|
+
const perCountry = countries.map((c) => cheapestAvailableForCountry(input.tariffRules, c, input.now));
|
|
5000
|
+
for (const pc of perCountry) warnings.push(...pc.warnings);
|
|
5001
|
+
const byId = /* @__PURE__ */ new Map();
|
|
5002
|
+
for (const pc of perCountry) for (const n of pc.networks) byId.set(n.networkId, n);
|
|
5003
|
+
const networks = [...byId.values()].sort((a, b) => a.networkId - b.networkId);
|
|
5004
|
+
const unresolved = perCountry.some((pc) => pc.networks.length === 0);
|
|
5005
|
+
if (networks.length === 0) {
|
|
5006
|
+
return {
|
|
5007
|
+
source,
|
|
5008
|
+
mode: "cheapest_available",
|
|
5009
|
+
outcome: "allow_all",
|
|
5010
|
+
networks: [],
|
|
5011
|
+
perCountry,
|
|
5012
|
+
fellBackToAll: true,
|
|
5013
|
+
warnings,
|
|
5014
|
+
priceBasis: null
|
|
5015
|
+
};
|
|
5016
|
+
}
|
|
5017
|
+
return {
|
|
5018
|
+
source,
|
|
5019
|
+
mode: "cheapest_available",
|
|
5020
|
+
outcome: "restrict",
|
|
5021
|
+
networks,
|
|
5022
|
+
perCountry,
|
|
5023
|
+
fellBackToAll: unresolved,
|
|
5024
|
+
warnings,
|
|
5025
|
+
priceBasis: "wholesale_datarate_per_mb"
|
|
5026
|
+
};
|
|
5027
|
+
}
|
|
5028
|
+
function steeringListsFromRaw(raw) {
|
|
5029
|
+
const arr = Array.isArray(raw) ? raw : raw && typeof raw === "object" ? raw.data ?? raw.steeringLists ?? raw.list ?? [] : [];
|
|
5030
|
+
if (!Array.isArray(arr)) return [];
|
|
5031
|
+
const out = [];
|
|
5032
|
+
for (const item of arr) {
|
|
5033
|
+
if (!item || typeof item !== "object") continue;
|
|
5034
|
+
const o = item;
|
|
5035
|
+
const id = Number(o.id ?? o.steeringListId ?? o.steeringlistid);
|
|
5036
|
+
if (!Number.isInteger(id) || id <= 0) continue;
|
|
5037
|
+
const nets = o.networks ?? o.networkList ?? o.operators ?? [];
|
|
5038
|
+
const networkIds = Array.isArray(nets) ? nets.map((n) => {
|
|
5039
|
+
if (typeof n === "number") return n;
|
|
5040
|
+
if (n && typeof n === "object") {
|
|
5041
|
+
const r = n;
|
|
5042
|
+
return Number(r.networkId ?? r.networkid ?? r.id);
|
|
5043
|
+
}
|
|
5044
|
+
return NaN;
|
|
5045
|
+
}).filter((n) => Number.isInteger(n)) : [];
|
|
5046
|
+
out.push({ id, name: String(o.name ?? o.steeringListName ?? `list ${id}`), networkIds });
|
|
5047
|
+
}
|
|
5048
|
+
return out;
|
|
5049
|
+
}
|
|
5050
|
+
function planAssignment(plan, lists) {
|
|
5051
|
+
if (plan.outcome === "allow_all") {
|
|
5052
|
+
return {
|
|
5053
|
+
action: "leave_open",
|
|
5054
|
+
reason: plan.fellBackToAll ? "Fell back to all networks; see warnings. No steering list is set." : "The choice is all networks. No steering list is set."
|
|
5055
|
+
};
|
|
5056
|
+
}
|
|
5057
|
+
if (plan.outcome === "use_list") {
|
|
5058
|
+
const id = plan.steeringListId;
|
|
5059
|
+
const known = lists.some((l) => l.id === id);
|
|
5060
|
+
return known ? { action: "assign", steeringListId: id, reason: "Chosen custom list exists." } : {
|
|
5061
|
+
action: "leave_open",
|
|
5062
|
+
reason: `Steering list ${id} was not found in this reseller's lists, so nothing is assigned.`
|
|
5063
|
+
};
|
|
5064
|
+
}
|
|
5065
|
+
const want = new Set(plan.networks.map((n) => n.networkId));
|
|
5066
|
+
const match = lists.find(
|
|
5067
|
+
(l) => l.networkIds.length === want.size && l.networkIds.every((id) => want.has(id))
|
|
5068
|
+
);
|
|
5069
|
+
if (match) {
|
|
5070
|
+
return {
|
|
5071
|
+
action: "assign",
|
|
5072
|
+
steeringListId: match.id,
|
|
5073
|
+
reason: `List "${match.name}" holds exactly the cheapest networks.`
|
|
5074
|
+
};
|
|
5075
|
+
}
|
|
5076
|
+
const countries = plan.perCountry.filter((p) => p.networks.length > 0).map((p) => p.country);
|
|
5077
|
+
return {
|
|
5078
|
+
action: "needs_list",
|
|
5079
|
+
networks: plan.networks,
|
|
5080
|
+
suggestedName: `cheapest-${countries.join("-").toLowerCase()}`,
|
|
5081
|
+
reason: "No existing list holds exactly these networks. Creating one has no REST method; it needs the browser agent or the OCS dashboard."
|
|
5082
|
+
};
|
|
5083
|
+
}
|
|
5084
|
+
function tariffRulesFromRaw(raw) {
|
|
5085
|
+
if (Array.isArray(raw)) return raw;
|
|
5086
|
+
if (raw && typeof raw === "object") {
|
|
5087
|
+
const obj = raw;
|
|
5088
|
+
for (const key of ["rule", "listTariffRule", "rules", "data"]) {
|
|
5089
|
+
const v = obj[key];
|
|
5090
|
+
if (Array.isArray(v)) return v;
|
|
5091
|
+
if (v && typeof v === "object") {
|
|
5092
|
+
const nested = v.rule;
|
|
5093
|
+
if (Array.isArray(nested)) return nested;
|
|
5094
|
+
}
|
|
5095
|
+
}
|
|
5096
|
+
}
|
|
5097
|
+
return null;
|
|
5098
|
+
}
|
|
5099
|
+
var NETWORK_DEFAULT_KEY_PREFIX = "netdefault:";
|
|
5100
|
+
function networkDefaultKey(partition) {
|
|
5101
|
+
return `${NETWORK_DEFAULT_KEY_PREFIX}${partition}`;
|
|
5102
|
+
}
|
|
5103
|
+
function parseStoredNetworkDefault(raw) {
|
|
5104
|
+
if (!raw || typeof raw !== "object") return null;
|
|
5105
|
+
const r = raw;
|
|
5106
|
+
if (validateNetworkChoice(r) !== null) return null;
|
|
5107
|
+
const choice = {
|
|
5108
|
+
mode: r.mode,
|
|
5109
|
+
updatedAt: typeof r.updatedAt === "string" ? r.updatedAt : ""
|
|
5110
|
+
};
|
|
5111
|
+
if (r.mode === "custom") choice.steeringListId = r.steeringListId;
|
|
5112
|
+
if (typeof r.updatedBy === "string") choice.updatedBy = r.updatedBy;
|
|
5113
|
+
return choice;
|
|
5114
|
+
}
|
|
5115
|
+
var listNetworks = (ns) => ns.map((n) => `${n.operatorName} (${n.datarate} ${n.currency}/MB)`).join(", ");
|
|
5116
|
+
function buildNetworkPlanReport(input) {
|
|
5117
|
+
const plan = resolveNetworkPlan({
|
|
5118
|
+
countries: input.countries,
|
|
5119
|
+
tariffRules: input.tariffError ? null : tariffRulesFromRaw(input.tariffRaw),
|
|
5120
|
+
orgDefault: input.orgDefault ?? null,
|
|
5121
|
+
packageOverride: input.packageOverride ?? null,
|
|
5122
|
+
simOverride: input.simOverride ?? null,
|
|
5123
|
+
now: input.now
|
|
5124
|
+
});
|
|
5125
|
+
if (input.tariffError && plan.mode === "cheapest_available") {
|
|
5126
|
+
plan.warnings.push({
|
|
5127
|
+
code: "FETCH_FAILED",
|
|
5128
|
+
message: `The tariff could not be read (${input.tariffError}).`
|
|
5129
|
+
});
|
|
5130
|
+
}
|
|
5131
|
+
if (input.steeringListsError) {
|
|
5132
|
+
plan.warnings.push({
|
|
5133
|
+
code: "FETCH_FAILED",
|
|
5134
|
+
message: `The steering lists could not be read (${input.steeringListsError}).`
|
|
5135
|
+
});
|
|
5136
|
+
}
|
|
5137
|
+
let assignment;
|
|
5138
|
+
if (input.steeringListsError && (plan.outcome === "restrict" || plan.outcome === "use_list")) {
|
|
5139
|
+
assignment = {
|
|
5140
|
+
action: "leave_open",
|
|
5141
|
+
reason: "The steering lists could not be read, so no list can be matched or checked. Nothing is assigned."
|
|
5142
|
+
};
|
|
5143
|
+
} else {
|
|
5144
|
+
assignment = planAssignment(plan, steeringListsFromRaw(input.steeringListsRaw));
|
|
5145
|
+
}
|
|
5146
|
+
let summary;
|
|
5147
|
+
if (plan.outcome === "restrict") {
|
|
5148
|
+
summary = `Cheapest available: ${listNetworks(plan.networks)}.`;
|
|
5149
|
+
if (plan.fellBackToAll) summary += " Some countries could not be narrowed and stay open to all networks.";
|
|
5150
|
+
} else if (plan.outcome === "use_list") {
|
|
5151
|
+
summary = `Custom steering list ${plan.steeringListId}.`;
|
|
5152
|
+
} else if (plan.fellBackToAll) {
|
|
5153
|
+
summary = "FELL BACK TO ALL NETWORKS: the cheapest network could not be determined. See warnings.";
|
|
5154
|
+
} else {
|
|
5155
|
+
summary = "All networks are allowed (chosen).";
|
|
5156
|
+
}
|
|
5157
|
+
return { plan, assignment, applied: false, summary };
|
|
5158
|
+
}
|
|
5159
|
+
function networkDefaultPartition(identity) {
|
|
5160
|
+
if (identity.orgId) return identity.orgId;
|
|
5161
|
+
return `user:${identity.sub.replace(/^clerk_/, "")}`;
|
|
5162
|
+
}
|
|
5163
|
+
var fail = (status, code, error) => ({
|
|
5164
|
+
ok: false,
|
|
5165
|
+
status,
|
|
5166
|
+
error,
|
|
5167
|
+
code
|
|
5168
|
+
});
|
|
5169
|
+
var msg = (e) => e instanceof Error ? e.message : String(e);
|
|
5170
|
+
function parseOptionalChoice(value, label) {
|
|
5171
|
+
if (value === void 0 || value === null) return { choice: null };
|
|
5172
|
+
const problem = validateNetworkChoice(value);
|
|
5173
|
+
if (problem) return { error: `${label}: ${problem}` };
|
|
5174
|
+
const v = value;
|
|
5175
|
+
return { choice: v.mode === "custom" ? { mode: "custom", steeringListId: v.steeringListId } : { mode: v.mode } };
|
|
5176
|
+
}
|
|
5177
|
+
var NO_STORE_WARNING = {
|
|
5178
|
+
code: "INVALID_CHOICE",
|
|
5179
|
+
message: "This surface has no stored org default (local stdio mode), so it could not be read. Only the system default and the overrides you pass apply here."
|
|
5180
|
+
};
|
|
5181
|
+
async function getNetworkDefault(io) {
|
|
5182
|
+
const pending = io.readStored();
|
|
5183
|
+
const warnings = [];
|
|
5184
|
+
let stored = null;
|
|
5185
|
+
if (pending === void 0) {
|
|
5186
|
+
warnings.push(NO_STORE_WARNING);
|
|
5187
|
+
} else {
|
|
5188
|
+
const raw = await Promise.resolve(pending).catch(() => null);
|
|
5189
|
+
stored = parseStoredNetworkDefault(raw);
|
|
5190
|
+
if (raw !== null && raw !== void 0 && stored === null) {
|
|
5191
|
+
warnings.push({
|
|
5192
|
+
code: "INVALID_CHOICE",
|
|
5193
|
+
message: "The stored org default is unreadable and was ignored; the system default applies."
|
|
5194
|
+
});
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
return {
|
|
5198
|
+
ok: true,
|
|
5199
|
+
data: {
|
|
5200
|
+
modes: NETWORK_DEFAULT_MODES,
|
|
5201
|
+
systemDefault: SYSTEM_NETWORK_DEFAULT,
|
|
5202
|
+
orgDefault: stored,
|
|
5203
|
+
effectiveMode: stored?.mode ?? SYSTEM_NETWORK_DEFAULT,
|
|
5204
|
+
warnings,
|
|
5205
|
+
appliesTo: "new_assignments_only"
|
|
5206
|
+
}
|
|
5207
|
+
};
|
|
5208
|
+
}
|
|
5209
|
+
async function setNetworkDefault(io, body, actor, now) {
|
|
5210
|
+
const parsed = parseOptionalChoice(body, "body");
|
|
5211
|
+
if ("error" in parsed) return fail(400, "VALIDATION_ERROR", parsed.error);
|
|
5212
|
+
if (parsed.choice === null) return fail(400, "VALIDATION_ERROR", "body: A network choice must be an object.");
|
|
5213
|
+
const choice = parsed.choice;
|
|
5214
|
+
if (!io.writeStored) {
|
|
5215
|
+
return fail(501, "NO_STORE", "This surface has no store for the org default. Set it through the REST API, the Console or the hosted MCP server.");
|
|
5216
|
+
}
|
|
5217
|
+
if (choice.mode === "custom") {
|
|
5218
|
+
let listsRaw;
|
|
5219
|
+
try {
|
|
5220
|
+
listsRaw = await io.callOcs("listSteeringList", await io.resolveResellerId());
|
|
5221
|
+
} catch (e) {
|
|
5222
|
+
return fail(502, "OCS_ERROR", msg(e));
|
|
5223
|
+
}
|
|
5224
|
+
if (!steeringListsFromRaw(listsRaw).some((l) => l.id === choice.steeringListId)) {
|
|
5225
|
+
return fail(400, "VALIDATION_ERROR", `Steering list ${choice.steeringListId} was not found. Pick one from list_steering_lists.`);
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
const record = { ...choice, updatedAt: now.toISOString(), updatedBy: actor };
|
|
5229
|
+
await io.writeStored(record);
|
|
5230
|
+
return { ok: true, data: { orgDefault: record, appliesTo: "new_assignments_only" } };
|
|
5231
|
+
}
|
|
5232
|
+
async function planNetworkDefault(io, req, now) {
|
|
5233
|
+
if (!req || !Array.isArray(req.countries) || req.countries.length === 0) {
|
|
5234
|
+
return fail(400, "VALIDATION_ERROR", "countries required: a non-empty array of ISO-3166 alpha-2 codes");
|
|
5235
|
+
}
|
|
5236
|
+
const sim = parseOptionalChoice(req.simOverride, "simOverride");
|
|
5237
|
+
if ("error" in sim) return fail(400, "VALIDATION_ERROR", sim.error);
|
|
5238
|
+
const pkg = parseOptionalChoice(req.packageOverride, "packageOverride");
|
|
5239
|
+
if ("error" in pkg) return fail(400, "VALIDATION_ERROR", pkg.error);
|
|
5240
|
+
let resellerId;
|
|
5241
|
+
if (req.resellerId !== void 0 && req.resellerId !== null) {
|
|
5242
|
+
resellerId = Number(req.resellerId);
|
|
5243
|
+
if (!Number.isInteger(resellerId) || resellerId <= 0) {
|
|
5244
|
+
return fail(400, "VALIDATION_ERROR", "resellerId must be a positive integer");
|
|
5245
|
+
}
|
|
5246
|
+
} else {
|
|
5247
|
+
try {
|
|
5248
|
+
resellerId = await io.resolveResellerId();
|
|
5249
|
+
} catch (e) {
|
|
5250
|
+
return fail(502, "OCS_ERROR", msg(e));
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
const settle = async (method) => {
|
|
5254
|
+
try {
|
|
5255
|
+
return { data: await io.callOcs(method, resellerId), error: null };
|
|
5256
|
+
} catch (e) {
|
|
5257
|
+
return { data: void 0, error: msg(e) };
|
|
5258
|
+
}
|
|
5259
|
+
};
|
|
5260
|
+
const [tariff, lists, view] = await Promise.all([settle("getCustomerTariff"), settle("listSteeringList"), getNetworkDefault(io)]);
|
|
5261
|
+
const orgDefault = view.ok && view.data.orgDefault ? view.data.orgDefault.mode === "custom" ? { mode: "custom", steeringListId: view.data.orgDefault.steeringListId } : { mode: view.data.orgDefault.mode } : null;
|
|
5262
|
+
const report = buildNetworkPlanReport({
|
|
5263
|
+
countries: req.countries.map((x) => String(x)),
|
|
5264
|
+
tariffRaw: tariff.data,
|
|
5265
|
+
tariffError: tariff.error,
|
|
5266
|
+
steeringListsRaw: lists.data,
|
|
5267
|
+
steeringListsError: lists.error,
|
|
5268
|
+
orgDefault,
|
|
5269
|
+
packageOverride: pkg.choice,
|
|
5270
|
+
simOverride: sim.choice,
|
|
5271
|
+
now
|
|
5272
|
+
});
|
|
5273
|
+
if (view.ok) report.plan.warnings.push(...view.data.warnings);
|
|
5274
|
+
return { ok: true, data: report };
|
|
5275
|
+
}
|
|
4793
5276
|
|
|
4794
5277
|
// src/lib/storefront-logo.ts
|
|
4795
5278
|
function clampHex(hex, fallback) {
|
|
@@ -4916,6 +5399,12 @@ export {
|
|
|
4916
5399
|
networkEventRows,
|
|
4917
5400
|
summarizeNetworkEvents,
|
|
4918
5401
|
gyCountryHistoryFromResponse,
|
|
5402
|
+
NETWORK_DEFAULT_MODES,
|
|
5403
|
+
networkDefaultKey,
|
|
5404
|
+
networkDefaultPartition,
|
|
5405
|
+
getNetworkDefault,
|
|
5406
|
+
setNetworkDefault,
|
|
5407
|
+
planNetworkDefault,
|
|
4919
5408
|
generateStorefrontLogo,
|
|
4920
5409
|
run,
|
|
4921
5410
|
which,
|
|
@@ -4954,4 +5443,4 @@ export {
|
|
|
4954
5443
|
storefrontScreen,
|
|
4955
5444
|
CARRIER_VERSION
|
|
4956
5445
|
};
|
|
4957
|
-
//# sourceMappingURL=chunk-
|
|
5446
|
+
//# sourceMappingURL=chunk-QXIY42R6.js.map
|