@fluid-app/fluid-cli-localization 0.1.309 → 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 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, two command groups: `fluid countries` opens a market and
13
- * `fluid translations` translates what its shoppers see. The country flow
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
@@ -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;;;iBC/FS,4BAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;;;;AD2FP;;;;;cElLM,MAAA,EAAQ,WAAA"}
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$1(ctx) {
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$1(ctx), iso);
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$1(ctx), iso);
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$1(ctx));
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$1(ctx);
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$1(ctx);
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$1(ctx);
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$1(ctx);
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$1(ctx);
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$1(ctx);
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$1(ctx);
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$1(ctx);
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$1(ctx);
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, two command groups: `fluid countries` opens a market and
4496
- * `fluid translations` translates what its shoppers see. The country flow
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