@fluid-app/fluid-cli-localization 0.1.410 → 0.1.411
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 +11 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +127 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -169,6 +169,17 @@ to and whether enrollment asks for it (`collected`, `inDraft`, `missing` or
|
|
|
169
169
|
whole save and the command says so. `--skip-sensitive` creates the rest and
|
|
170
170
|
lists the ones it left out.
|
|
171
171
|
|
|
172
|
+
## `fluid markets` ordering and currencies
|
|
173
|
+
|
|
174
|
+
| Command | What it does |
|
|
175
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
176
|
+
| `reorder <market...>` | Sets the full market order (ids or names, every market once). The first becomes the fallback. `--preview` writes nothing; `--yes` skips the prompt. |
|
|
177
|
+
| `set-fallback <market>` | Makes a market the fallback. Refused, with the countries listed, while the fallback prices countries that have no market. `--preview` writes nothing; `--yes`. |
|
|
178
|
+
| `currency add <market> <currency>` | Adds a currency to a market. Adding one it already has is a no-op. |
|
|
179
|
+
| `currency remove <market> <currency>` | Removes a currency from a market. Refused with the counts while it is billed, priced, or the market's last. `--yes` skips the prompt. |
|
|
180
|
+
|
|
181
|
+
Every API refusal prints its code and details. Needs the market-config release.
|
|
182
|
+
|
|
172
183
|
## `fluid translations`
|
|
173
184
|
|
|
174
185
|
| Command | What it does |
|
package/dist/index.d.mts
CHANGED
|
@@ -6,7 +6,7 @@ declare function registerCountriesCommands(parent: Command, ctx: CommandContext)
|
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/markets/commands.d.ts
|
|
8
8
|
/**
|
|
9
|
-
* Register `fluid markets list|add-country|remove-country|rename|create|move|delete` on `parent`.
|
|
9
|
+
* Register `fluid markets list|add-country|remove-country|rename|create|move|delete|reorder|set-fallback|currency add|currency remove` on `parent`.
|
|
10
10
|
*
|
|
11
11
|
* @param parent - the `markets` command group
|
|
12
12
|
* @param ctx - the CLI command context
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/countries/commands.ts","../src/markets/commands.ts","../src/translations/commands.ts","../src/index.ts"],"mappings":";;;;iBAiMgB,yBAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;;;AAFP;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/countries/commands.ts","../src/markets/commands.ts","../src/translations/commands.ts","../src/index.ts"],"mappings":";;;;iBAiMgB,yBAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;;;AAFP;;;;iBCnHgB,uBAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;iBCoBS,4BAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;AF2FP;;;;;;AAAA,cGhLM,MAAA,EAAQ,WAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -4162,10 +4162,39 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
4162
4162
|
//#region src/markets/api.ts
|
|
4163
4163
|
const MARKETS_PATH = "/api/company/v2026-10/markets";
|
|
4164
4164
|
const MARKET_CONFIG_DISABLED_MESSAGE = "Markets configuration is not enabled for this company.";
|
|
4165
|
+
function listed(value) {
|
|
4166
|
+
if (Array.isArray(value)) return value.map(listed).join(", ");
|
|
4167
|
+
if (value && typeof value === "object") return Object.entries(value).map(([k, v]) => `${k} ${listed(v)}`).join(", ");
|
|
4168
|
+
return String(value);
|
|
4169
|
+
}
|
|
4170
|
+
function summaryOf(code, details) {
|
|
4171
|
+
const has = (key) => details[key] !== void 0;
|
|
4172
|
+
switch (code) {
|
|
4173
|
+
case "fallback_would_unprice": return has("isos") ? `would leave ${listed(details["isos"])} unpriced` : void 0;
|
|
4174
|
+
case "currency_billed": return has("countries") ? `billed in ${listed(details["countries"])}` : void 0;
|
|
4175
|
+
case "currency_has_prices": {
|
|
4176
|
+
const parts = [
|
|
4177
|
+
["prices per tier", "prices_per_tier"],
|
|
4178
|
+
["bundle prices", "bundle_prices"],
|
|
4179
|
+
["adjusted price lists", "adjusted_price_lists"]
|
|
4180
|
+
].flatMap(([label, key]) => {
|
|
4181
|
+
const value = details[key];
|
|
4182
|
+
return !value || Array.isArray(value) && value.length === 0 || typeof value === "object" && Object.keys(value).length === 0 ? [] : [`${label}: ${listed(value)}`];
|
|
4183
|
+
});
|
|
4184
|
+
return parts.length > 0 ? parts.join("; ") : void 0;
|
|
4185
|
+
}
|
|
4186
|
+
case "positions_mismatch": {
|
|
4187
|
+
const parts = Object.entries(details).map(([key, value]) => `${key.replace(/_/g, " ")}: ${listed(value)}`);
|
|
4188
|
+
return parts.length > 0 ? parts.join("; ") : void 0;
|
|
4189
|
+
}
|
|
4190
|
+
default: return;
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4165
4193
|
/**
|
|
4166
4194
|
* The error to show for a failed markets call: the server's `message`, a
|
|
4167
4195
|
* fixed text for a disabled release, and a retry hint for `retry_later`.
|
|
4168
|
-
*
|
|
4196
|
+
* Known refusal codes with details print a readable summary; others append
|
|
4197
|
+
* the details as JSON. Keeps the HTTP status, `code` and raw `details` on the error.
|
|
4169
4198
|
*/
|
|
4170
4199
|
function marketsFailure(err, withCode = false) {
|
|
4171
4200
|
const status = statusOf(err);
|
|
@@ -4180,8 +4209,14 @@ function marketsFailure(err, withCode = false) {
|
|
|
4180
4209
|
} else if (code === "retry_later") message = "The company is busy. Try again.";
|
|
4181
4210
|
else message = errorDetail(err).message;
|
|
4182
4211
|
const details = body?.["details"];
|
|
4183
|
-
if (details && typeof details === "object" && Object.keys(details).length > 0)
|
|
4184
|
-
|
|
4212
|
+
if (details && typeof details === "object" && Object.keys(details).length > 0) {
|
|
4213
|
+
const summary = summaryOf(code, details);
|
|
4214
|
+
message = summary ? `${message.replace(` [${code}]`, "")} (${code}): ${summary}` : `${message} (${JSON.stringify(details)})`;
|
|
4215
|
+
}
|
|
4216
|
+
const failure = Object.assign(new LocalizationError(message), {
|
|
4217
|
+
...code ? { code } : {},
|
|
4218
|
+
...details ? { details } : {}
|
|
4219
|
+
});
|
|
4185
4220
|
return status === void 0 ? failure : Object.assign(failure, { status });
|
|
4186
4221
|
}
|
|
4187
4222
|
async function guarded(call, withCode = false) {
|
|
@@ -4234,12 +4269,40 @@ function previewMarketDeletion(client, id) {
|
|
|
4234
4269
|
async function deleteMarket(client, id, confirmName) {
|
|
4235
4270
|
await guarded(() => client.delete(`${MARKETS_PATH}/${encodeURIComponent(id)}?confirm_name=${encodeURIComponent(confirmName)}`), true);
|
|
4236
4271
|
}
|
|
4272
|
+
/** GET /api/company/v2026-10/markets/positions/preview: what putting the markets in this order would change. */
|
|
4273
|
+
function previewReorder(client, ids) {
|
|
4274
|
+
const query = ids.map((id) => `market_ids[]=${encodeURIComponent(id)}`).join("&");
|
|
4275
|
+
return guarded(() => client.get(`${MARKETS_PATH}/positions/preview?${query}`), true);
|
|
4276
|
+
}
|
|
4277
|
+
/** PUT /api/company/v2026-10/markets/positions: sets the full market order; the first market becomes the fallback. Returns the markets. */
|
|
4278
|
+
function reorderMarkets(client, ids) {
|
|
4279
|
+
return guarded(() => client.put(`${MARKETS_PATH}/positions`, { market_ids: ids }), true);
|
|
4280
|
+
}
|
|
4281
|
+
/** GET /api/company/v2026-10/markets/:id/fallback/preview: what making the market the fallback would change. */
|
|
4282
|
+
function previewFallback(client, id) {
|
|
4283
|
+
return guarded(() => client.get(`${MARKETS_PATH}/${encodeURIComponent(id)}/fallback/preview`), true);
|
|
4284
|
+
}
|
|
4285
|
+
/** POST /api/company/v2026-10/markets/:id/fallback: makes the market the fallback. Sends no body. Returns the markets. */
|
|
4286
|
+
function setFallback(client, id) {
|
|
4287
|
+
return guarded(() => client.post(`${MARKETS_PATH}/${encodeURIComponent(id)}/fallback`), true);
|
|
4288
|
+
}
|
|
4289
|
+
/** POST /api/company/v2026-10/markets/:id/currencies: adds a currency to the market. */
|
|
4290
|
+
function addMarketCurrency(client, id, code) {
|
|
4291
|
+
return guarded(() => client.post(`${MARKETS_PATH}/${encodeURIComponent(id)}/currencies`, { currency: code }), true);
|
|
4292
|
+
}
|
|
4293
|
+
/** DELETE /api/company/v2026-10/markets/:id/currencies/:iso: removes an unused currency from the market. */
|
|
4294
|
+
async function removeMarketCurrency(client, id, code) {
|
|
4295
|
+
await guarded(() => client.delete(`${MARKETS_PATH}/${encodeURIComponent(id)}/currencies/${encodeURIComponent(code)}`), true);
|
|
4296
|
+
}
|
|
4237
4297
|
//#endregion
|
|
4238
4298
|
//#region src/markets/commands.ts
|
|
4239
4299
|
const MAX_CREATE_COUNTRIES = 10;
|
|
4240
4300
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4241
4301
|
async function resolveMarketId(api, ref) {
|
|
4242
4302
|
const { markets } = await listMarkets(api);
|
|
4303
|
+
return marketIdIn(markets, ref);
|
|
4304
|
+
}
|
|
4305
|
+
function marketIdIn(markets, ref) {
|
|
4243
4306
|
const byId = markets.find((m) => m.id.toLowerCase() === ref.toLowerCase());
|
|
4244
4307
|
if (byId) return byId.id;
|
|
4245
4308
|
if (UUID.test(ref)) throw new LocalizationError(`No market with id ${ref}.`);
|
|
@@ -4258,7 +4321,7 @@ function currencyCodeOf(raw) {
|
|
|
4258
4321
|
return code;
|
|
4259
4322
|
}
|
|
4260
4323
|
/**
|
|
4261
|
-
* Register `fluid markets list|add-country|remove-country|rename|create|move|delete` on `parent`.
|
|
4324
|
+
* Register `fluid markets list|add-country|remove-country|rename|create|move|delete|reorder|set-fallback|currency add|currency remove` on `parent`.
|
|
4262
4325
|
*
|
|
4263
4326
|
* @param parent - the `markets` command group
|
|
4264
4327
|
* @param ctx - the CLI command context
|
|
@@ -4324,6 +4387,66 @@ function registerMarketsCommands(parent, ctx) {
|
|
|
4324
4387
|
deleted: true
|
|
4325
4388
|
});
|
|
4326
4389
|
}));
|
|
4390
|
+
parent.command("reorder <market...>").description("Set the full market order (ids or names, every market once). The first market becomes the fallback").option("--preview", "Show what the new order would change; write nothing", false).option("--yes", "Confirm without a prompt", false).action((refs, opts) => run(async () => {
|
|
4391
|
+
const api = await client$1(ctx);
|
|
4392
|
+
const { markets } = await listMarkets(api);
|
|
4393
|
+
const ids = refs.map((ref) => marketIdIn(markets, ref));
|
|
4394
|
+
const repeated = refs.filter((_, i) => ids.indexOf(ids[i]) !== i);
|
|
4395
|
+
if (repeated.length > 0) throw new LocalizationError(`Each market can be listed once: ${repeated.join(", ")} repeated.`);
|
|
4396
|
+
const missing = markets.filter((m) => !ids.includes(m.id));
|
|
4397
|
+
if (missing.length > 0) throw new LocalizationError(`The order must list every market. Missing: ${missing.map((m) => m.name).join(", ")}.`);
|
|
4398
|
+
if (opts.preview) {
|
|
4399
|
+
ctx.output(await previewReorder(api, ids));
|
|
4400
|
+
return;
|
|
4401
|
+
}
|
|
4402
|
+
const current = markets.some((m) => m.is_fallback !== void 0) ? markets.find((m) => m.is_fallback) : markets[0];
|
|
4403
|
+
if (!opts.yes && process.stdin.isTTY) ctx.output(await previewReorder(api, ids));
|
|
4404
|
+
if (current && current.id !== ids[0]) await confirmChange(`Reorder markets? ${markets.find((m) => m.id === ids[0]).name} becomes the fallback.`, opts.yes);
|
|
4405
|
+
ctx.output(await reorderMarkets(api, ids));
|
|
4406
|
+
}));
|
|
4407
|
+
parent.command("set-fallback <market>").description("Make a market the fallback. Refused while the fallback prices countries that have no market").option("--preview", "Show what the change would affect; write nothing", false).option("--yes", "Confirm without a prompt", false).action((ref, opts) => run(async () => {
|
|
4408
|
+
const api = await client$1(ctx);
|
|
4409
|
+
const id = await resolveMarketId(api, ref);
|
|
4410
|
+
const preview = await previewFallback(api, id);
|
|
4411
|
+
if (!preview.fallback && !preview.proposed_fallback) {
|
|
4412
|
+
ctx.output({ message: "No fallback is configured." });
|
|
4413
|
+
return;
|
|
4414
|
+
}
|
|
4415
|
+
const blocked = preview.unpriced_countries ?? [];
|
|
4416
|
+
if (blocked.length > 0) {
|
|
4417
|
+
if (opts.preview) ctx.output(preview);
|
|
4418
|
+
throw new LocalizationError(`Cannot change the fallback while these countries are priced through it: ${blocked.join(", ")}. Assign them to a market first.`);
|
|
4419
|
+
}
|
|
4420
|
+
if (opts.preview) {
|
|
4421
|
+
ctx.output(preview);
|
|
4422
|
+
return;
|
|
4423
|
+
}
|
|
4424
|
+
if (!opts.yes && process.stdin.isTTY) ctx.output(preview);
|
|
4425
|
+
await confirmChange(`Make ${ref} the fallback market?`, opts.yes);
|
|
4426
|
+
ctx.output(await setFallback(api, id));
|
|
4427
|
+
}));
|
|
4428
|
+
const currency = parent.command("currency").description("Add or remove a currency on a market");
|
|
4429
|
+
currency.command("add <market> <currency>").description("Add a currency to a market. Adding one it has is a no-op").action((ref, raw) => run(async () => {
|
|
4430
|
+
const code = currencyCodeOf(raw);
|
|
4431
|
+
const api = await client$1(ctx);
|
|
4432
|
+
const written = await addMarketCurrency(api, await resolveMarketId(api, ref), code);
|
|
4433
|
+
ctx.output({
|
|
4434
|
+
...written,
|
|
4435
|
+
note: written.outcome === "added" ? `${code} added.` : `${code} already present.`
|
|
4436
|
+
});
|
|
4437
|
+
}));
|
|
4438
|
+
currency.command("remove <market> <currency>").description("Remove a currency from a market. Refused while it is billed, priced, or the market's last").option("--yes", "Confirm without a prompt", false).action((ref, raw, opts) => run(async () => {
|
|
4439
|
+
const code = currencyCodeOf(raw);
|
|
4440
|
+
const api = await client$1(ctx);
|
|
4441
|
+
const id = await resolveMarketId(api, ref);
|
|
4442
|
+
await confirmChange(`Remove ${code} from market ${ref}?`, opts.yes);
|
|
4443
|
+
await removeMarketCurrency(api, id, code);
|
|
4444
|
+
ctx.output({
|
|
4445
|
+
market_id: id,
|
|
4446
|
+
currency: code,
|
|
4447
|
+
removed: true
|
|
4448
|
+
});
|
|
4449
|
+
}));
|
|
4327
4450
|
}
|
|
4328
4451
|
//#endregion
|
|
4329
4452
|
//#region src/translations/commands.ts
|