@fluid-app/fluid-cli-payments 0.1.320 → 0.1.322

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;iBAyDgB,0BAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;AAAA,cAiUD,MAAA,EAAQ,WAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;iBAgEgB,0BAAA,CACd,MAAA,EAAQ,OAAA,EACR,GAAA,EAAK,cAAA;AAAA,cA8UD,MAAA,EAAQ,WAAA"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { NAV_HELP, assertInteractive, createDomainCommand, terminalPrompter } from "@fluid-app/fluid-cli";
1
+ import { NAV_HELP, assertInteractive, createDomainCommand, declareInputs, exitOnInputsError, terminalPrompter } from "@fluid-app/fluid-cli";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { basename, extname } from "node:path";
4
4
  import prompts from "prompts";
@@ -611,6 +611,22 @@ const readLocalFile = async (path) => {
611
611
  bytes
612
612
  };
613
613
  };
614
+ /** A FileReader that serves the command's declared inputs. */
615
+ function inputsReader(inputs) {
616
+ return async (path) => {
617
+ let bytes;
618
+ try {
619
+ bytes = inputs.readFile(path);
620
+ } catch (error) {
621
+ exitOnInputsError(error);
622
+ throw new OnboardingError(`Can't read ${path}.`);
623
+ }
624
+ return {
625
+ name: basename(path),
626
+ bytes
627
+ };
628
+ };
629
+ }
614
630
  /** The company the token acts for. */
615
631
  async function currentCompanyId(client) {
616
632
  const me = await client.get("/api/company/v1/companies/me");
@@ -1133,6 +1149,38 @@ function coerce(field, key, raw) {
1133
1149
  return value;
1134
1150
  }
1135
1151
  }
1152
+ /** Split a `--file key=path` flag into its key and trimmed path. */
1153
+ function splitFile(raw) {
1154
+ const [key, path] = splitAssignment(raw, "--file");
1155
+ return [key, path.trim()];
1156
+ }
1157
+ /**
1158
+ * The local inputs of `--file key=path` flags: each path as a file, plus the
1159
+ * key it is bound to. An empty path is refused, and so is a repeated key
1160
+ * unless the field takes several files.
1161
+ */
1162
+ function fileInputs(files) {
1163
+ const specs = [];
1164
+ const counts = /* @__PURE__ */ new Map();
1165
+ for (const raw of files) {
1166
+ const [key, path] = splitFile(raw);
1167
+ if (!path) throw new OnboardingError(`--file ${key} needs a path.`);
1168
+ const index = counts.get(key) ?? 0;
1169
+ const repeatable = fieldFor(key)?.type === "files";
1170
+ if (index > 0 && !repeatable) throw new OnboardingError(`--file ${key} was given more than once.`);
1171
+ counts.set(key, index + 1);
1172
+ specs.push({
1173
+ kind: "ref",
1174
+ name: repeatable ? `file:${key}:${index}` : `file:${key}`,
1175
+ value: path
1176
+ });
1177
+ specs.push({
1178
+ kind: "file",
1179
+ path
1180
+ });
1181
+ }
1182
+ return specs;
1183
+ }
1136
1184
  /** Parse `--set` and `--file` flags into a plan. */
1137
1185
  function buildPlan(sets, files) {
1138
1186
  const plan = emptyPlan();
@@ -1159,18 +1207,19 @@ function buildPlan(sets, files) {
1159
1207
  plan[group][attributeOf(key)] = coerced;
1160
1208
  }
1161
1209
  for (const raw of files) {
1162
- const [key, path] = splitAssignment(raw, "--file");
1210
+ const [key, path] = splitFile(raw);
1163
1211
  const field = fieldFor(key);
1164
1212
  if (!field || ![
1165
1213
  "file",
1166
1214
  "files",
1167
1215
  "link_or_file"
1168
1216
  ].includes(field.type)) throw new OnboardingError(field ? `${key} isn't a document; use --set.` : `Unknown document "${key}". Run \`fluid payments onboarding fields\`.`);
1169
- if (!path.trim()) throw new OnboardingError(`--file ${key} needs a path.`);
1217
+ if (!path) throw new OnboardingError(`--file ${key} needs a path.`);
1218
+ if (field.type !== "files" && plan.files.some((f) => f.key === key)) throw new OnboardingError(`--file ${key} was given more than once.`);
1170
1219
  plan.files.push({
1171
1220
  key,
1172
1221
  field,
1173
- path: path.trim()
1222
+ path
1174
1223
  });
1175
1224
  }
1176
1225
  return plan;
@@ -2192,7 +2241,7 @@ function registerOnboardingCommands(parent, ctx) {
2192
2241
  if (!OPTION_LISTS.includes(list)) throw new OnboardingError(`List must be one of ${OPTION_LISTS.join(", ")}.`);
2193
2242
  ctx.output(await listOptions(await client(ctx), list, opts.country));
2194
2243
  }));
2195
- onboarding.command("set").description("Save fields and upload documents, then print what's still missing (changes live data)").option("--set <key=value>", "A field from `fields`, e.g. entity.legal_name=Acme Inc (repeatable)", collect, []).option("--file <key=path>", "Upload a document, e.g. entity.business_license=./license.pdf (repeatable)", collect, []).option("--entity <id|new>", "Which legal entity entity.* fields go to").option("--bank <id|new>", "Which bank account bank.* fields go to").option("--owner <id|new>", "Which person owner.* fields go to").option("--id-type <type>", `Government ID type for owner.government_issued_ids: ${ID_TYPES.join(", ")}`).option("--replace-files", "Replace a multi-file document's files instead of adding to them", false).option("--yes", "Confirm without a prompt", false).action((opts) => run(async () => {
2244
+ declareInputs(onboarding.command("set").description("Save fields and upload documents, then print what's still missing (changes live data)").option("--set <key=value>", "A field from `fields`, e.g. entity.legal_name=Acme Inc (repeatable)", collect, []).option("--file <key=path>", "Upload a document, e.g. entity.business_license=./license.pdf (repeatable)", collect, []).option("--entity <id|new>", "Which legal entity entity.* fields go to").option("--bank <id|new>", "Which bank account bank.* fields go to").option("--owner <id|new>", "Which person owner.* fields go to").option("--id-type <type>", `Government ID type for owner.government_issued_ids: ${ID_TYPES.join(", ")}`).option("--replace-files", "Replace a multi-file document's files instead of adding to them", false).option("--yes", "Confirm without a prompt", false).action((opts) => run(async () => {
2196
2245
  const plan = buildPlan(opts.set, opts.file);
2197
2246
  if (isEmptyPlan(plan)) throw new OnboardingError("Pass fields with --set key=value or documents with --file key=path.");
2198
2247
  const targets = {
@@ -2206,7 +2255,7 @@ function registerOnboardingCommands(parent, ctx) {
2206
2255
  const companyId = await currentCompanyId(api);
2207
2256
  const snapshot = await loadSnapshot(api, companyId);
2208
2257
  await confirmChange(`Save ${opts.set.length + opts.file.length} onboarding change(s) for company ${companyId}?`, opts.yes);
2209
- const saved = await applyPlan(api, snapshot, plan, targets);
2258
+ const saved = await applyPlan(api, snapshot, plan, targets, inputsReader(ctx.inputs));
2210
2259
  const after = summarize(await loadSnapshot(api, companyId));
2211
2260
  ctx.output({
2212
2261
  saved,
@@ -2217,7 +2266,7 @@ function registerOnboardingCommands(parent, ctx) {
2217
2266
  steps: after.steps,
2218
2267
  missing: after.missing
2219
2268
  });
2220
- }));
2269
+ })), (opts) => fileInputs(opts["file"] ?? []));
2221
2270
  onboarding.command("walk").description("Answer the form question by question in the terminal: go back, skip, jump to a step, or change an answer; each answer is saved as you go (changes live data)").option("--step <id>", `Start at a step: ${STEPS.map((s) => s.id).join(", ")}`).action((opts) => run(async () => {
2222
2271
  assertInteractive("`show` to see what's missing and `set` to fill it in");
2223
2272
  const step = opts.step;
@@ -2227,7 +2276,8 @@ function registerOnboardingCommands(parent, ctx) {
2227
2276
  ctx.output(await walkOnboarding({
2228
2277
  api,
2229
2278
  companyId,
2230
- prompter: terminalPrompter()
2279
+ prompter: terminalPrompter(),
2280
+ readLocal: inputsReader(ctx.inputs)
2231
2281
  }, { step }));
2232
2282
  }));
2233
2283
  onboarding.command("remove <record> <id>").description("Remove a legal entity, bank account, or person by id, or a country by ISO code (changes live data)").option("--yes", "Confirm without a prompt", false).action((record, id, opts) => run(async () => {