@fluid-app/fluid-cli-localization 0.1.310 → 0.1.311
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/index.d.mts +13 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +100 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -4,17 +4,26 @@ import { Command } from "commander";
|
|
|
4
4
|
//#region src/countries/commands.d.ts
|
|
5
5
|
declare function registerCountriesCommands(parent: Command, ctx: CommandContext): void;
|
|
6
6
|
//#endregion
|
|
7
|
+
//#region src/markets/commands.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Register `fluid markets list|add-country|remove-country` on `parent`.
|
|
10
|
+
*
|
|
11
|
+
* @param parent - the `markets` command group
|
|
12
|
+
* @param ctx - the CLI command context
|
|
13
|
+
*/
|
|
14
|
+
declare function registerMarketsCommands(parent: Command, ctx: CommandContext): void;
|
|
15
|
+
//#endregion
|
|
7
16
|
//#region src/translations/commands.d.ts
|
|
8
17
|
declare function registerTranslationsCommands(parent: Command, ctx: CommandContext): void;
|
|
9
18
|
//#endregion
|
|
10
19
|
//#region src/index.d.ts
|
|
11
20
|
/**
|
|
12
|
-
* One plugin,
|
|
13
|
-
* `fluid
|
|
14
|
-
* hands language and translation work to `fluid translations`, so each step
|
|
21
|
+
* One plugin, three command groups: `fluid countries` opens a market,
|
|
22
|
+
* `fluid markets` configures them, and `fluid translations` translates what
|
|
23
|
+
* its shoppers see. The country flow hands language and translation work to `fluid translations`, so each step
|
|
15
24
|
* has one implementation.
|
|
16
25
|
*/
|
|
17
26
|
declare const plugin: FluidPlugin;
|
|
18
27
|
//#endregion
|
|
19
|
-
export { plugin as default, registerCountriesCommands, registerTranslationsCommands };
|
|
28
|
+
export { plugin as default, registerCountriesCommands, registerMarketsCommands, registerTranslationsCommands };
|
|
20
29
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/countries/commands.ts","../src/translations/commands.ts","../src/index.ts"],"mappings":";;;;iBAiMgB,yBAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;
|
|
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;;;;iBCpKgB,uBAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;iBCqES,4BAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;AF2FP;;;;;;AAAA,cGhLM,MAAA,EAAQ,WAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -3736,7 +3736,7 @@ function clip(text, max = 200) {
|
|
|
3736
3736
|
}
|
|
3737
3737
|
//#endregion
|
|
3738
3738
|
//#region src/countries/commands.ts
|
|
3739
|
-
async function client$
|
|
3739
|
+
async function client$2(ctx) {
|
|
3740
3740
|
return await ctx.getClient();
|
|
3741
3741
|
}
|
|
3742
3742
|
/** The company_country attributes `plan` shows and `open` sends. */
|
|
@@ -3789,7 +3789,7 @@ async function countryEnrollment(api, countryCode, atlas) {
|
|
|
3789
3789
|
}
|
|
3790
3790
|
function registerCountriesCommands(parent, ctx) {
|
|
3791
3791
|
parent.command("atlas <iso>").description("Show Fluid's Country Atlas for a market: modes, tax, legal, address, payments, languages, agreements").option("--agreement <localId>", "Print one atlas agreement's full text in every language instead").action((iso, opts) => run(async () => {
|
|
3792
|
-
const result = await fetchAtlas(await client$
|
|
3792
|
+
const result = await fetchAtlas(await client$2(ctx), iso);
|
|
3793
3793
|
if (!result.covered || !result.atlas) {
|
|
3794
3794
|
ctx.output({
|
|
3795
3795
|
country: result.countryCode,
|
|
@@ -3813,11 +3813,11 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
3813
3813
|
});
|
|
3814
3814
|
}));
|
|
3815
3815
|
parent.command("compliance <iso>").description("Show the compliance view of the atlas: disclosure pages, cookie rule, tax display, unit pricing").action((iso) => run(async () => {
|
|
3816
|
-
const { countryCode, atlas } = await requireAtlas(await client$
|
|
3816
|
+
const { countryCode, atlas } = await requireAtlas(await client$2(ctx), iso);
|
|
3817
3817
|
ctx.output(complianceView(countryCode, atlas));
|
|
3818
3818
|
}));
|
|
3819
3819
|
parent.command("list").description("List the countries this company sells in").action(() => run(async () => {
|
|
3820
|
-
const countries = await listCompanyCountries(await client$
|
|
3820
|
+
const countries = await listCompanyCountries(await client$2(ctx));
|
|
3821
3821
|
ctx.output(countries.map((cc) => ({
|
|
3822
3822
|
companyCountryId: cc.id,
|
|
3823
3823
|
iso: cc.country?.iso ?? null,
|
|
@@ -3835,7 +3835,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
3835
3835
|
})));
|
|
3836
3836
|
}));
|
|
3837
3837
|
withOpenOptions(parent.command("plan <iso>").description("Preview a country setup without changing anything: the seeded settings, languages, agreements, and checklist")).action((iso, opts) => run(async () => {
|
|
3838
|
-
const api = await client$
|
|
3838
|
+
const api = await client$2(ctx);
|
|
3839
3839
|
const { countryCode, atlas, mode, attributes } = await seededAttributes(api, iso, opts);
|
|
3840
3840
|
const [existing, languages, agreements, warehouses] = await Promise.all([
|
|
3841
3841
|
findCompanyCountry(api, countryCode),
|
|
@@ -3863,7 +3863,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
3863
3863
|
});
|
|
3864
3864
|
}));
|
|
3865
3865
|
withOpenOptions(parent.command("open <iso>").description("Add the country to the company, seeded from the atlas: currency, mode, tax, 3-D Secure, legal, address layout, payment order (changes live config)").option("--legacy-defaults", "Also let Fluid add its generic country agreements and forms", false).option("--reseed", "If the country is already open, write the atlas values over its current settings", false).option("--yes", "Confirm without a prompt", false)).action((iso, opts) => run(async () => {
|
|
3866
|
-
const api = await client$
|
|
3866
|
+
const api = await client$2(ctx);
|
|
3867
3867
|
const { countryCode, attributes } = await seededAttributes(api, iso, opts);
|
|
3868
3868
|
const existing = await findCompanyCountry(api, countryCode);
|
|
3869
3869
|
if (existing && !opts.reseed) {
|
|
@@ -3894,7 +3894,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
3894
3894
|
});
|
|
3895
3895
|
}));
|
|
3896
3896
|
parent.command("update <iso>").description("Change named settings on an open country and leave the rest as they are, e.g. its entity or settlement currency (changes live config)").option("--warehouse-id <id>", "The warehouse that fulfills orders for the country").option("--business-id <id>", "The local tax or business registration number").option("--entity-registered", "The company has a legally registered local entity").option("--settlement-currency <code>", "Settle in this currency, e.g. USD").option("--set <key=value>", "Set a company country field, e.g. entity_id=12 or legal_settings.cooling_off_period_days=30 (repeatable)", collect, []).option("--yes", "Confirm without a prompt", false).action((iso, opts) => run(async () => {
|
|
3897
|
-
const api = await client$
|
|
3897
|
+
const api = await client$2(ctx);
|
|
3898
3898
|
const countryCode = countryCodeOf(iso);
|
|
3899
3899
|
const existing = await requireCompanyCountry(api, countryCode);
|
|
3900
3900
|
const body = partialCountryUpdate(existing, {
|
|
@@ -3912,7 +3912,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
3912
3912
|
});
|
|
3913
3913
|
}));
|
|
3914
3914
|
parent.command("languages <iso>").description("Compare the market's major languages with the company's; `fluid translations enable` turns the missing ones on").action((iso) => run(async () => {
|
|
3915
|
-
const api = await client$
|
|
3915
|
+
const api = await client$2(ctx);
|
|
3916
3916
|
const { countryCode, atlas } = await requireAtlas(api, iso);
|
|
3917
3917
|
const states = languageStates(atlas, await listLanguages(api));
|
|
3918
3918
|
const off = states.filter((s) => !s.enabled && s.languageId !== null);
|
|
@@ -3924,7 +3924,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
3924
3924
|
});
|
|
3925
3925
|
}));
|
|
3926
3926
|
parent.command("agreements <iso>").description("Match the atlas agreements to the company's; --create adds the missing ones to the country in every atlas language, --translate rewrites the atlas translations onto ones already on it (changes live config)").option("--create", "Create each missing atlas agreement on the country", false).option("--translate", "Write the atlas translations onto the agreements already on the country, e.g. after enabling a language", false).option("--only <localId>", "With --create or --translate, just this atlas agreement, e.g. agreement_2 (repeatable)", collect, []).option("--yes", "Confirm without a prompt", false).action((iso, opts) => run(async () => {
|
|
3927
|
-
const api = await client$
|
|
3927
|
+
const api = await client$2(ctx);
|
|
3928
3928
|
const { countryCode, atlas } = await requireAtlas(api, iso);
|
|
3929
3929
|
const cc = await requireCompanyCountry(api, countryCode);
|
|
3930
3930
|
const states = agreementStates(atlas, await listAgreements(api), cc.id);
|
|
@@ -3997,7 +3997,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
3997
3997
|
}));
|
|
3998
3998
|
parent.command("forms <iso>").description("Compare the atlas enrollment fields with the country's Post Purchase forms; --create sets up its enrollment form, as a draft unless --activate (changes live config)").option("--create", "Create the country's enrollment form, or add the missing atlas fields to it", false).option("--form <id>", "With --create, add to this Post Purchase form for the country instead").option("--activate", "With --create, publish the form so enrollment asks for its fields now", false).option("--skip-sensitive", "With --create, leave out fields stored as sensitive, which need the forms manage-sensitive permission", false).option("--yes", "Confirm without a prompt", false).action((iso, opts) => run(async () => {
|
|
3999
3999
|
if (!opts.create && (opts.form || opts.activate || opts.skipSensitive)) throw new LocalizationError("--form, --activate and --skip-sensitive go with --create.");
|
|
4000
|
-
const api = await client$
|
|
4000
|
+
const api = await client$2(ctx);
|
|
4001
4001
|
const { countryCode, atlas } = await requireAtlas(api, iso);
|
|
4002
4002
|
const country = await catalogCountry(api, countryCode);
|
|
4003
4003
|
const options = {
|
|
@@ -4036,7 +4036,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
4036
4036
|
});
|
|
4037
4037
|
}));
|
|
4038
4038
|
parent.command("prices <iso>").description("Convert every variant's price from another country into this one's currency at an exchange rate. A dry run unless --write (changes live prices)").option("--from-country <iso>", "The country whose prices are converted", "US").option("--rate <rate>", "Units of the new currency per unit of the source currency, e.g. 0.92; --write needs it").option("--fields <list>", `Price fields to convert, comma-separated, from ${PRICE_FIELDS.join(", ")}`, DEFAULT_PRICE_FIELDS.join(",")).option("--status <status>", "Product status to include (repeatable)", collect, []).option("--overwrite", "Also replace prices the country already has", false).option("--activate", "Put each converted variant on sale in the country", false).option("--sample <n>", "How many before→after examples to print", "10").option("--write", "Save the converted prices; without it nothing is written", false).option("--yes", "Confirm --write without a prompt", false).action((iso, opts) => run(async () => {
|
|
4039
|
-
const api = await client$
|
|
4039
|
+
const api = await client$2(ctx);
|
|
4040
4040
|
const targetIso = countryCodeOf(iso);
|
|
4041
4041
|
const sourceIso = countryCodeOf(opts.fromCountry);
|
|
4042
4042
|
if (targetIso === sourceIso) throw new LocalizationError("--from-country is the country being priced.");
|
|
@@ -4128,7 +4128,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
4128
4128
|
}));
|
|
4129
4129
|
parent.command("walk [iso]").description("Open a country by answering questions: the atlas, mode, languages, agreements and defaults, then prices and translations (changes live config)").action((iso) => run(async () => {
|
|
4130
4130
|
assertInteractive("`plan`, `open`, `prices`, `agreements` and `fluid translations enable`");
|
|
4131
|
-
const api = await client$
|
|
4131
|
+
const api = await client$2(ctx);
|
|
4132
4132
|
const prompter = terminalPrompter();
|
|
4133
4133
|
const result = await walkCountry({
|
|
4134
4134
|
api,
|
|
@@ -4142,7 +4142,7 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
4142
4142
|
if (result.failures.length > 0) process.exitCode = 1;
|
|
4143
4143
|
}));
|
|
4144
4144
|
parent.command("status <iso>").description("Check a country's setup against the atlas, including whether your active products have prices in it, and list what's left, ending with the launch checklist").action((iso) => run(async () => {
|
|
4145
|
-
const api = await client$
|
|
4145
|
+
const api = await client$2(ctx);
|
|
4146
4146
|
const { countryCode, atlas } = await requireAtlas(api, iso);
|
|
4147
4147
|
const cc = await findCompanyCountry(api, countryCode);
|
|
4148
4148
|
const [languages, agreements] = cc ? await Promise.all([listLanguages(api), listAgreements(api)]) : [[], []];
|
|
@@ -4159,6 +4159,88 @@ function registerCountriesCommands(parent, ctx) {
|
|
|
4159
4159
|
}));
|
|
4160
4160
|
}
|
|
4161
4161
|
//#endregion
|
|
4162
|
+
//#region src/markets/api.ts
|
|
4163
|
+
const MARKETS_PATH = "/api/company/v2026-10/markets";
|
|
4164
|
+
const MARKET_CONFIG_DISABLED_MESSAGE = "Markets configuration is not enabled for this company.";
|
|
4165
|
+
/**
|
|
4166
|
+
* The error to show for a failed markets call: the server's `message`, a
|
|
4167
|
+
* fixed text for a disabled release, and a retry hint for `retry_later`.
|
|
4168
|
+
* Keeps the HTTP status so the failure report carries it.
|
|
4169
|
+
*/
|
|
4170
|
+
function marketsFailure(err) {
|
|
4171
|
+
const status = statusOf(err);
|
|
4172
|
+
const body = err?.body;
|
|
4173
|
+
const code = typeof body?.["error"] === "string" ? body["error"] : void 0;
|
|
4174
|
+
let message;
|
|
4175
|
+
if (code === "market_config_disabled") message = MARKET_CONFIG_DISABLED_MESSAGE;
|
|
4176
|
+
else if (typeof body?.["message"] === "string") {
|
|
4177
|
+
message = body["message"];
|
|
4178
|
+
if (code === "retry_later" && !/try again/i.test(message)) message = `${message} Try again.`;
|
|
4179
|
+
} else if (code === "retry_later") message = "The company is busy. Try again.";
|
|
4180
|
+
else message = errorDetail(err).message;
|
|
4181
|
+
const details = body?.["details"];
|
|
4182
|
+
if (details && typeof details === "object" && Object.keys(details).length > 0) message = `${message} (${JSON.stringify(details)})`;
|
|
4183
|
+
const failure = new LocalizationError(message);
|
|
4184
|
+
return status === void 0 ? failure : Object.assign(failure, { status });
|
|
4185
|
+
}
|
|
4186
|
+
async function guarded(call) {
|
|
4187
|
+
try {
|
|
4188
|
+
return await call();
|
|
4189
|
+
} catch (err) {
|
|
4190
|
+
throw marketsFailure(err);
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
/** GET /api/company/v2026-10/markets: markets, their countries, and active countries without a market. */
|
|
4194
|
+
function listMarkets(client) {
|
|
4195
|
+
return guarded(() => client.get(MARKETS_PATH));
|
|
4196
|
+
}
|
|
4197
|
+
/** POST /api/company/v2026-10/markets/countries: gives a country its own market, creating the company country when it is new. */
|
|
4198
|
+
function addMarketCountry(client, iso, currency) {
|
|
4199
|
+
return guarded(() => client.post(`${MARKETS_PATH}/countries`, {
|
|
4200
|
+
country_iso: iso,
|
|
4201
|
+
...currency ? { currency } : {}
|
|
4202
|
+
}));
|
|
4203
|
+
}
|
|
4204
|
+
/** DELETE /api/company/v2026-10/markets/countries/:iso: removes the company country, and its market when it was the market's last country and no other country falls back to it. */
|
|
4205
|
+
async function removeMarketCountry(client, iso) {
|
|
4206
|
+
await guarded(() => client.delete(`${MARKETS_PATH}/countries/${iso}`));
|
|
4207
|
+
}
|
|
4208
|
+
//#endregion
|
|
4209
|
+
//#region src/markets/commands.ts
|
|
4210
|
+
async function client$1(ctx) {
|
|
4211
|
+
return await ctx.getClient();
|
|
4212
|
+
}
|
|
4213
|
+
function currencyCodeOf(raw) {
|
|
4214
|
+
const code = raw.trim().toUpperCase();
|
|
4215
|
+
if (!/^[A-Z]{3}$/.test(code)) throw new LocalizationError(`"${raw}" isn't a three-letter currency code, e.g. EUR or JPY.`);
|
|
4216
|
+
return code;
|
|
4217
|
+
}
|
|
4218
|
+
/**
|
|
4219
|
+
* Register `fluid markets list|add-country|remove-country` on `parent`.
|
|
4220
|
+
*
|
|
4221
|
+
* @param parent - the `markets` command group
|
|
4222
|
+
* @param ctx - the CLI command context
|
|
4223
|
+
*/
|
|
4224
|
+
function registerMarketsCommands(parent, ctx) {
|
|
4225
|
+
parent.command("list").description("List the company's markets with their countries and currencies, and active countries that have no market").option("--json", "Print JSON (the default output)", false).action(() => run(async () => {
|
|
4226
|
+
ctx.output(await listMarkets(await client$1(ctx)));
|
|
4227
|
+
}));
|
|
4228
|
+
parent.command("add-country <iso>").description("Give a country its own market. A new country needs --currency; an existing unassigned one is provisioned").option("--currency <code>", "Currency for a new country, e.g. EUR. For an existing country it must match its currency").action((iso, opts) => run(async () => {
|
|
4229
|
+
const code = countryCodeOf(iso);
|
|
4230
|
+
const currency = opts.currency ? currencyCodeOf(opts.currency) : void 0;
|
|
4231
|
+
ctx.output(await addMarketCountry(await client$1(ctx), code, currency));
|
|
4232
|
+
}));
|
|
4233
|
+
parent.command("remove-country <iso>").description("Remove a country from the company, and its market when it was the market's last country and no other country falls back to it").option("--yes", "Confirm without a prompt", false).action((iso, opts) => run(async () => {
|
|
4234
|
+
const code = countryCodeOf(iso);
|
|
4235
|
+
await confirmChange(`Remove ${code} and its market settings from this company?`, opts.yes);
|
|
4236
|
+
await removeMarketCountry(await client$1(ctx), code);
|
|
4237
|
+
ctx.output({
|
|
4238
|
+
country: code,
|
|
4239
|
+
removed: true
|
|
4240
|
+
});
|
|
4241
|
+
}));
|
|
4242
|
+
}
|
|
4243
|
+
//#endregion
|
|
4162
4244
|
//#region src/translations/commands.ts
|
|
4163
4245
|
async function client(ctx) {
|
|
4164
4246
|
return await ctx.getClient();
|
|
@@ -4492,9 +4574,9 @@ function registerTranslationsCommands(parent, ctx) {
|
|
|
4492
4574
|
//#endregion
|
|
4493
4575
|
//#region src/index.ts
|
|
4494
4576
|
/**
|
|
4495
|
-
* One plugin,
|
|
4496
|
-
* `fluid
|
|
4497
|
-
* hands language and translation work to `fluid translations`, so each step
|
|
4577
|
+
* One plugin, three command groups: `fluid countries` opens a market,
|
|
4578
|
+
* `fluid markets` configures them, and `fluid translations` translates what
|
|
4579
|
+
* its shoppers see. The country flow hands language and translation work to `fluid translations`, so each step
|
|
4498
4580
|
* has one implementation.
|
|
4499
4581
|
*/
|
|
4500
4582
|
const plugin = {
|
|
@@ -4502,10 +4584,11 @@ const plugin = {
|
|
|
4502
4584
|
version: "0.1.1",
|
|
4503
4585
|
register(ctx) {
|
|
4504
4586
|
ctx.program.addCommand(createDomainCommand("countries", "Open a country from Fluid's Country Atlas: settings, prices in its currency, agreements, and a status check", registerCountriesCommands));
|
|
4587
|
+
ctx.program.addCommand(createDomainCommand("markets", "List the company's markets and add or remove a country with its own market", registerMarketsCommands));
|
|
4505
4588
|
ctx.program.addCommand(createDomainCommand("translations", "Add a language and translate what shoppers see: storefront, navigation, theme, agreements, and more", registerTranslationsCommands));
|
|
4506
4589
|
}
|
|
4507
4590
|
};
|
|
4508
4591
|
//#endregion
|
|
4509
|
-
export { plugin as default, registerCountriesCommands, registerTranslationsCommands };
|
|
4592
|
+
export { plugin as default, registerCountriesCommands, registerMarketsCommands, registerTranslationsCommands };
|
|
4510
4593
|
|
|
4511
4594
|
//# sourceMappingURL=index.mjs.map
|