@fluid-app/fluid-cli-payments 0.0.0-stage → 0.1.0
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 +68 -2
- package/dist/index.d.mts +20 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1922 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +81 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/fields.ts","../src/requirements.ts","../src/types.ts","../src/api.ts","../src/mask.ts","../src/assign.ts","../src/summary.ts","../src/walk.ts","../src/index.ts"],"sourcesContent":["// The payments onboarding field schema, as the admin app's form and the\n// onboarding endpoints define it. Requirement rules mirror the admin's\n// `components/Onboarding/utils/validation.ts`, which is what decides whether\n// the form can be submitted; the server only checks types.\n\nexport type Group =\n | \"info\"\n | \"underwriting\"\n | \"entity\"\n | \"bank\"\n | \"owner\"\n | \"country\";\n\nexport type StepId =\n | \"business-type\"\n | \"business-info\"\n | \"legal-entities\"\n | \"bank-accounts\"\n | \"personal-info\"\n | \"relevant-persons\"\n | \"countries\"\n | \"underwriting\"\n | \"terms-and-conditions\";\n\nexport const STEPS: ReadonlyArray<{ id: StepId; name: string }> = [\n { id: \"business-type\", name: \"The Basics\" },\n { id: \"business-info\", name: \"Business Info\" },\n { id: \"legal-entities\", name: \"Legal Entities\" },\n { id: \"bank-accounts\", name: \"Bank Accounts\" },\n { id: \"personal-info\", name: \"Personal Info\" },\n { id: \"relevant-persons\", name: \"Relevant Persons\" },\n { id: \"countries\", name: \"Countries\" },\n { id: \"underwriting\", name: \"Underwriting\" },\n { id: \"terms-and-conditions\", name: \"Terms & Conditions\" },\n];\n\nexport type FieldType =\n | \"boolean\"\n | \"string\"\n | \"text\"\n | \"yes_no\"\n | \"date\"\n | \"email\"\n | \"url\"\n | \"phone\"\n | \"number\"\n | \"percent\"\n | \"enum\"\n | \"country\"\n | \"currency\"\n | \"mcc\"\n | \"business_type\"\n | \"file\"\n | \"files\"\n | \"link_or_file\";\n\nexport type Requirement = \"always\" | \"conditional\" | \"optional\";\n\nexport interface FieldDef {\n /** The key passed to `--set` or `--file`, e.g. `entity.legal_name`. */\n key: string;\n group: Group;\n type: FieldType;\n label: string;\n required: Requirement;\n /** For conditional fields: when the field becomes required. */\n when?: string;\n options?: readonly string[];\n /** Masked in every output. */\n sensitive?: boolean;\n /** Sent as a string, for numeric answers the API stores as text. */\n sendAsText?: boolean;\n step: StepId;\n}\n\nconst f = (\n key: string,\n type: FieldType,\n label: string,\n step: StepId,\n required: Requirement = \"always\",\n extra: Partial<FieldDef> = {},\n): FieldDef => ({\n key,\n group: key.split(\".\")[0] as Group,\n type,\n label,\n required,\n step,\n ...extra,\n});\n\nconst MLM = \"underwriting.company_is_mlm is true\";\nconst HEALTH = \"underwriting.sells_health_supplements is true\";\n\nconst INGREDIENTS = [\n [\"kratom\", \"Kratom\"],\n [\"ephedra\", \"Ephedra\"],\n [\"cannabis\", \"Cannabis\"],\n [\"cbd\", \"CBD\"],\n [\"aristolochia\", \"Aristolochia\"],\n [\"germanium\", \"Germanium\"],\n] as const;\n\nconst DISEASE_CLAIMS = [\n [\"cancer\", \"cancer\"],\n [\"impotency\", \"impotency\"],\n [\"alzheimers\", \"Alzheimer's\"],\n [\"memory_loss\", \"memory loss\"],\n] as const;\n\nexport const FIELDS: readonly FieldDef[] = [\n // ---------------------------------------------------------------- basics\n f(\n \"info.beneficial_individual_owner\",\n \"boolean\",\n \"Does any individual own 25% or more of the business?\",\n \"business-type\",\n ),\n f(\n \"info.user_is_owner\",\n \"boolean\",\n \"Are you one of those owners?\",\n \"business-type\",\n \"conditional\",\n { when: \"info.beneficial_individual_owner is true\" },\n ),\n f(\n \"info.beneficial_business_owner\",\n \"boolean\",\n \"Does another business own 25% or more of the business?\",\n \"business-type\",\n ),\n f(\n \"info.other_legal_entities\",\n \"boolean\",\n \"Does the business operate through more than one legal entity?\",\n \"business-type\",\n ),\n f(\n \"info.user_has_authority\",\n \"boolean\",\n \"Are you authorised to act for the business?\",\n \"business-type\",\n ),\n f(\n \"info.user_is_signatory\",\n \"boolean\",\n \"Are you an authorised signatory?\",\n \"business-type\",\n ),\n f(\n \"info.operates_internationally\",\n \"boolean\",\n \"Does the business sell outside its home country?\",\n \"business-type\",\n \"optional\",\n ),\n f(\n \"info.business_structure_complexity\",\n \"enum\",\n \"Ownership structure\",\n \"business-type\",\n \"optional\",\n { options: [\"simple\", \"complex\"] },\n ),\n f(\n \"underwriting.company_is_mlm\",\n \"boolean\",\n \"Is the business a direct-sales (MLM) company? Turns on the MLM questions.\",\n \"business-type\",\n \"optional\",\n ),\n\n // -------------------------------------------------------------- entities\n f(\"entity.legal_name\", \"string\", \"Legal company name\", \"business-info\"),\n f(\n \"entity.trading_name\",\n \"string\",\n \"Trading (DBA) name\",\n \"business-info\",\n \"optional\",\n ),\n f(\n \"entity.classification\",\n \"business_type\",\n \"Business type, from `options business-types`\",\n \"business-info\",\n ),\n f(\n \"entity.business_identification_number\",\n \"string\",\n \"Business tax ID: EIN in the US, VAT ID in VAT countries\",\n \"business-info\",\n \"always\",\n { sensitive: true },\n ),\n f(\n \"entity.registration_number\",\n \"string\",\n \"Business registration number\",\n \"business-info\",\n ),\n f(\n \"entity.date_of_incorporation\",\n \"date\",\n \"Date of incorporation (YYYY-MM-DD)\",\n \"business-info\",\n ),\n f(\n \"entity.phone\",\n \"phone\",\n \"Business phone, at least 8 digits\",\n \"business-info\",\n ),\n f(\n \"entity.phone_country_code\",\n \"string\",\n \"Phone country code, e.g. +1\",\n \"business-info\",\n \"optional\",\n ),\n f(\n \"entity.website\",\n \"url\",\n \"Website, starting with http:// or https://\",\n \"business-info\",\n ),\n f(\n \"entity.primary_mcc\",\n \"mcc\",\n \"Primary merchant category code, from `options mcc-codes`\",\n \"business-info\",\n ),\n f(\n \"entity.secondary_mcc\",\n \"mcc\",\n \"Secondary merchant category code\",\n \"business-info\",\n \"optional\",\n ),\n f(\"entity.address1\", \"string\", \"Registered street address\", \"business-info\"),\n f(\n \"entity.address2\",\n \"string\",\n \"Registered address line 2\",\n \"business-info\",\n \"optional\",\n ),\n f(\"entity.city\", \"string\", \"Registered city\", \"business-info\"),\n f(\n \"entity.province\",\n \"string\",\n \"Registered state or province\",\n \"business-info\",\n ),\n f(\"entity.postal_code\", \"string\", \"Registered postal code\", \"business-info\"),\n f(\n \"entity.country_iso\",\n \"country\",\n \"Registered country (ISO code, e.g. US)\",\n \"business-info\",\n ),\n f(\n \"entity.business_registration_certificate\",\n \"file\",\n \"Business registration certificate\",\n \"business-info\",\n ),\n f(\"entity.business_license\", \"file\", \"Business license\", \"business-info\"),\n f(\n \"entity.articles_of_incorporation\",\n \"file\",\n \"Articles of incorporation\",\n \"business-info\",\n ),\n f(\"entity.w_9\", \"file\", \"IRS form W-9\", \"business-info\", \"conditional\", {\n when: \"entity.country_iso is US\",\n }),\n f(\n \"entity.last_3_months_processing_statements\",\n \"files\",\n \"Last three months of card processing statements\",\n \"business-info\",\n \"optional\",\n ),\n\n // --------------------------------------------------------- bank accounts\n f(\"bank.bank_name\", \"string\", \"Bank name\", \"bank-accounts\"),\n f(\"bank.holder_name\", \"string\", \"Account holder name\", \"bank-accounts\"),\n f(\n \"bank.account_number\",\n \"string\",\n \"Account number or IBAN\",\n \"bank-accounts\",\n \"always\",\n { sensitive: true },\n ),\n f(\n \"bank.routing_number\",\n \"string\",\n \"Routing number\",\n \"bank-accounts\",\n \"conditional\",\n { when: \"bank.country_iso is US\", sensitive: true },\n ),\n f(\n \"bank.swift_bic\",\n \"string\",\n \"SWIFT/BIC code\",\n \"bank-accounts\",\n \"conditional\",\n { when: \"bank.country_iso is not US\" },\n ),\n f(\"bank.country_iso\", \"country\", \"Bank country (ISO code)\", \"bank-accounts\"),\n f(\n \"bank.currency_iso\",\n \"currency\",\n \"Account currency (ISO code, e.g. USD)\",\n \"bank-accounts\",\n ),\n f(\"bank.city\", \"string\", \"Bank city\", \"bank-accounts\"),\n f(\n \"bank.entity_id\",\n \"number\",\n \"Legal entity the account belongs to (defaults to the primary entity)\",\n \"bank-accounts\",\n \"optional\",\n ),\n f(\n \"bank.last_3_months_bank_statements\",\n \"files\",\n \"Last three months of bank statements\",\n \"bank-accounts\",\n ),\n f(\n \"bank.bank_letter_or_voided_check\",\n \"file\",\n \"Bank letter or voided check\",\n \"bank-accounts\",\n ),\n\n // ---------------------------------------------------------------- owners\n f(\"owner.full_name\", \"string\", \"Full legal name\", \"personal-info\"),\n f(\"owner.work_email\", \"email\", \"Work email\", \"personal-info\"),\n f(\n \"owner.date_of_birth\",\n \"date\",\n \"Date of birth (YYYY-MM-DD)\",\n \"personal-info\",\n \"always\",\n { sensitive: true },\n ),\n f(\"owner.place_of_birth\", \"string\", \"Place of birth\", \"personal-info\"),\n f(\"owner.nationality\", \"country\", \"Nationality (ISO code)\", \"personal-info\"),\n f(\n \"owner.country_iso\",\n \"country\",\n \"Country of residence (ISO code)\",\n \"personal-info\",\n ),\n f(\"owner.street_address\", \"string\", \"Home street address\", \"personal-info\"),\n f(\"owner.city\", \"string\", \"Home city\", \"personal-info\"),\n f(\"owner.state\", \"string\", \"Home state or province\", \"personal-info\"),\n f(\"owner.postcode\", \"string\", \"Home postcode\", \"personal-info\"),\n f(\"owner.phone\", \"phone\", \"Phone\", \"personal-info\"),\n f(\n \"owner.identification_number\",\n \"string\",\n \"Personal ID number (SSN in the US)\",\n \"personal-info\",\n \"always\",\n { sensitive: true },\n ),\n f(\"owner.position\", \"string\", \"Job title\", \"personal-info\"),\n f(\n \"owner.native_name\",\n \"string\",\n \"Name in native script\",\n \"personal-info\",\n \"optional\",\n ),\n f(\n \"owner.is_managing_director\",\n \"boolean\",\n \"Managing director\",\n \"relevant-persons\",\n \"optional\",\n ),\n f(\n \"owner.is_beneficial_owner\",\n \"boolean\",\n \"Owns 25% or more\",\n \"relevant-persons\",\n \"optional\",\n ),\n f(\n \"owner.percent_ownership\",\n \"percent\",\n \"Ownership percentage, 25 or more for a beneficial owner\",\n \"relevant-persons\",\n \"conditional\",\n { when: \"owner.is_beneficial_owner is true\" },\n ),\n f(\n \"owner.is_authorized_signatory\",\n \"boolean\",\n \"Authorised signatory\",\n \"relevant-persons\",\n \"optional\",\n ),\n f(\n \"owner.onboarding_contact\",\n \"boolean\",\n \"The person filling in the form (one per company)\",\n \"personal-info\",\n \"optional\",\n ),\n f(\n \"owner.entity_id\",\n \"number\",\n \"Legal entity the person belongs to (defaults to the primary entity)\",\n \"relevant-persons\",\n \"optional\",\n ),\n f(\n \"owner.government_issued_ids\",\n \"files\",\n \"Government ID: passport photo page, or the front and back of a driver's license or national ID. Pass --id-type.\",\n \"personal-info\",\n ),\n f(\n \"owner.proof_of_residence\",\n \"file\",\n \"Proof of residence, such as a utility bill\",\n \"personal-info\",\n ),\n\n // ------------------------------------------------------------- countries\n f(\n \"country.<ISO>.currency\",\n \"currency\",\n \"Currency customers pay in for that country\",\n \"countries\",\n ),\n f(\n \"country.<ISO>.settlement_currency\",\n \"currency\",\n \"Currency payouts settle in\",\n \"countries\",\n ),\n f(\n \"country.<ISO>.entity_id\",\n \"number\",\n \"Legal entity that sells in that country (defaults to the primary entity)\",\n \"countries\",\n ),\n f(\n \"country.<ISO>.entity_legally_registered\",\n \"boolean\",\n \"The entity is legally registered to sell there; must be true\",\n \"countries\",\n ),\n\n // ---------------------------------------------------------- underwriting\n f(\n \"underwriting.company_description\",\n \"text\",\n \"What the company does\",\n \"underwriting\",\n ),\n f(\n \"underwriting.management_stability\",\n \"text\",\n \"How long the management team has been in place\",\n \"underwriting\",\n ),\n f(\n \"underwriting.uses_third_party_accounting\",\n \"yes_no\",\n \"Uses a third-party accounting firm (Yes - firm name / No)\",\n \"underwriting\",\n ),\n f(\n \"underwriting.financials_audited\",\n \"boolean\",\n \"Financial statements are audited (true or false). The six financial statements are required either way.\",\n \"underwriting\",\n ),\n f(\n \"underwriting.projected_annual_sales_volume\",\n \"number\",\n \"Projected annual sales volume\",\n \"underwriting\",\n ),\n f(\n \"underwriting.average_order_value\",\n \"number\",\n \"Average order value\",\n \"underwriting\",\n ),\n f(\n \"underwriting.cit_share_percentage\",\n \"percent\",\n \"% of sales that are one-time purchases (CIT); CIT + MIT = 100\",\n \"underwriting\",\n ),\n f(\n \"underwriting.mit_share_percentage\",\n \"percent\",\n \"% of sales that are subscriptions (MIT); CIT + MIT = 100\",\n \"underwriting\",\n ),\n f(\n \"underwriting.balance_sheet_year1\",\n \"file\",\n \"Balance sheet, most recent year\",\n \"underwriting\",\n ),\n f(\n \"underwriting.balance_sheet_year2\",\n \"file\",\n \"Balance sheet, previous year\",\n \"underwriting\",\n ),\n f(\n \"underwriting.income_statement_year1\",\n \"file\",\n \"Income statement, most recent year\",\n \"underwriting\",\n ),\n f(\n \"underwriting.income_statement_year2\",\n \"file\",\n \"Income statement, previous year\",\n \"underwriting\",\n ),\n f(\n \"underwriting.cash_flow_year1\",\n \"file\",\n \"Cash flow statement or P&L, most recent year\",\n \"underwriting\",\n ),\n f(\n \"underwriting.cash_flow_year2\",\n \"file\",\n \"Cash flow statement or P&L, previous year\",\n \"underwriting\",\n ),\n f(\n \"underwriting.has_compliance_officer\",\n \"yes_no\",\n \"Has a compliance officer (Yes - name / No)\",\n \"underwriting\",\n ),\n f(\n \"underwriting.compliance_officer_responsibilities\",\n \"text\",\n \"The compliance officer's responsibilities\",\n \"underwriting\",\n ),\n f(\n \"underwriting.distributor_monitoring_policies\",\n \"text\",\n \"How the company monitors its members' activity\",\n \"underwriting\",\n ),\n f(\n \"underwriting.suspicious_activity_escalation_process\",\n \"text\",\n \"How suspicious activity is escalated\",\n \"underwriting\",\n ),\n f(\n \"underwriting.retains_outside_legal_counsel\",\n \"yes_no\",\n \"Retains outside legal counsel (Yes - firm / No)\",\n \"underwriting\",\n ),\n f(\n \"underwriting.investigations_description\",\n \"text\",\n 'Past or current regulatory investigations, or \"None\"',\n \"underwriting\",\n ),\n f(\n \"underwriting.negative_media_events\",\n \"text\",\n 'Negative media coverage, or \"None\"',\n \"underwriting\",\n ),\n f(\n \"underwriting.bbb_rating\",\n \"string\",\n 'Better Business Bureau rating, or \"N/A\"',\n \"underwriting\",\n ),\n f(\n \"underwriting.trustpilot_rating\",\n \"string\",\n 'Trustpilot rating, or \"N/A\"',\n \"underwriting\",\n ),\n f(\n \"underwriting.terms_and_conditions\",\n \"link_or_file\",\n \"Storefront terms & conditions: a URL (.link) or a file\",\n \"underwriting\",\n ),\n f(\n \"underwriting.refund_or_return_policy\",\n \"link_or_file\",\n \"Refund or return policy: a URL (.link) or a file\",\n \"underwriting\",\n ),\n f(\n \"underwriting.privacy_policy\",\n \"link_or_file\",\n \"Privacy policy: a URL (.link) or a file\",\n \"underwriting\",\n ),\n\n // MLM questions\n f(\n \"underwriting.mlm_ownership_structure\",\n \"text\",\n \"How the business is owned and controlled\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.mlm_ownership_structure_file\",\n \"file\",\n \"Ownership chart\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.commission_payment_method\",\n \"text\",\n \"How commissions are paid\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.commission_payment_channels\",\n \"text\",\n \"Channels commissions are paid through\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.commission_payment_countries\",\n \"text\",\n \"Countries commissions are paid in\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.compensation_plan\",\n \"files\",\n \"Compensation plan\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.recruiter_commission_for_recruiting\",\n \"yes_no\",\n \"Members earn commission just for recruiting (Yes - details / No)\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.all_distributors_can_profit\",\n \"yes_no\",\n \"Every member can profit (Yes / No - details)\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.provides_average_compensation_report\",\n \"yes_no\",\n \"Publishes an average compensation report (Yes / No)\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.income_disclosure_statement\",\n \"link_or_file\",\n \"Income disclosure statement\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_identification_requirements\",\n \"text\",\n \"How members are identified at sign-up\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_pii_collected\",\n \"text\",\n \"Personal data collected from members\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_due_diligence\",\n \"text\",\n \"Due diligence on new members\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_country_restrictions\",\n \"text\",\n \"Countries members may not operate in\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_decline_termination_reasons\",\n \"text\",\n \"Reasons a member is declined or terminated\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_cross_border_sales\",\n \"yes_no\",\n \"Members may sell internationally (Yes - details / No)\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_training_description\",\n \"text\",\n \"Training given to members\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_policies\",\n \"link_or_file\",\n \"Member policies and procedures\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.sample_distributor_agreement\",\n \"link_or_file\",\n \"Sample member agreement\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.business_opportunity_disclosures\",\n \"link_or_file\",\n \"Business opportunity disclosures\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.fulfillment_agreement\",\n \"link_or_file\",\n \"Fulfillment agreement\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.manufacturing_agreement\",\n \"link_or_file\",\n \"Manufacturing agreement\",\n \"underwriting\",\n \"conditional\",\n { when: MLM },\n ),\n f(\n \"underwriting.distributor_retention_turnover_rates\",\n \"text\",\n \"Member retention and turnover rates\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.owners_principals_list\",\n \"text\",\n \"Owners and principals\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.product_service_description\",\n \"text\",\n \"Products and services sold\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.revenue_from_recruiting_percentage\",\n \"percent\",\n \"% of revenue from recruiting\",\n \"underwriting\",\n \"optional\",\n { sendAsText: true },\n ),\n f(\n \"underwriting.revenue_from_website_percentage\",\n \"percent\",\n \"% of revenue from the website\",\n \"underwriting\",\n \"optional\",\n { sendAsText: true },\n ),\n f(\n \"underwriting.retail_sales_outside_downline_percentage\",\n \"percent\",\n \"% of retail sales to people outside the downline\",\n \"underwriting\",\n \"optional\",\n { sendAsText: true },\n ),\n f(\n \"underwriting.compliance_monitoring_processes\",\n \"text\",\n \"Compliance monitoring processes\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.signup_fees_description\",\n \"text\",\n \"Sign-up fees\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.training_types_description\",\n \"text\",\n \"Types of training offered\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.purchase_requirements_description\",\n \"text\",\n \"Purchase requirements for members\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.ftc_compliance_description\",\n \"text\",\n \"How the company complies with FTC guidance\",\n \"underwriting\",\n \"optional\",\n ),\n\n // Health products\n f(\n \"underwriting.sells_health_supplements\",\n \"boolean\",\n \"Sells health products or supplements. Turns on the health questions.\",\n \"underwriting\",\n \"optional\",\n ),\n f(\n \"underwriting.is_product_manufacturer\",\n \"yes_no\",\n \"Manufactures its own products (Yes / No - manufacturer)\",\n \"underwriting\",\n \"conditional\",\n { when: HEALTH },\n ),\n f(\n \"underwriting.marketing_methods_description\",\n \"text\",\n \"How the products are marketed\",\n \"underwriting\",\n \"conditional\",\n { when: HEALTH },\n ),\n f(\n \"underwriting.cancellation_methods_description\",\n \"text\",\n \"How customers cancel subscriptions\",\n \"underwriting\",\n \"conditional\",\n { when: HEALTH },\n ),\n f(\n \"underwriting.scientific_studies_description\",\n \"text\",\n \"Scientific studies or evidence behind the products\",\n \"underwriting\",\n \"conditional\",\n { when: HEALTH },\n ),\n f(\n \"underwriting.health_product_lawsuit_history\",\n \"text\",\n 'Lawsuits or investigations about the products, or \"None\"',\n \"underwriting\",\n \"conditional\",\n { when: HEALTH },\n ),\n ...INGREDIENTS.flatMap(([id, label]) => [\n f(\n `underwriting.contains_${id}`,\n \"boolean\",\n `A product contains ${label}`,\n \"underwriting\",\n \"optional\",\n ),\n f(\n `underwriting.${id}_product_names`,\n \"text\",\n `Products containing ${label}`,\n \"underwriting\",\n \"conditional\",\n { when: `underwriting.contains_${id} is true` },\n ),\n ]),\n f(\n \"underwriting.contains_none_listed\",\n \"boolean\",\n \"No product contains any listed ingredient. With health products, one contains_* must be true.\",\n \"underwriting\",\n \"optional\",\n ),\n ...DISEASE_CLAIMS.flatMap(([id, label]) => [\n f(\n `underwriting.claims_${id}_treatment`,\n \"boolean\",\n `A product claims to treat ${label}`,\n \"underwriting\",\n \"optional\",\n ),\n f(\n `underwriting.${id}_treatment_products`,\n \"text\",\n `Products claiming to treat ${label}`,\n \"underwriting\",\n \"conditional\",\n { when: `underwriting.claims_${id}_treatment is true` },\n ),\n ]),\n f(\n \"underwriting.claims_no_diseases\",\n \"boolean\",\n \"No product claims to treat a disease. With health products, one claims_* must be true.\",\n \"underwriting\",\n \"optional\",\n ),\n];\n\nexport const INGREDIENT_IDS = INGREDIENTS.map(([id, label]) => ({ id, label }));\nexport const DISEASE_CLAIM_IDS = DISEASE_CLAIMS.map(([id, label]) => ({\n id,\n label,\n}));\n\nexport const ID_TYPES = [\"passport\", \"license\", \"national_id\"] as const;\nexport type IdType = (typeof ID_TYPES)[number];\n\n/** Document uploads are refused above this size. */\nexport const MAX_UPLOAD_BYTES = 10 * 1024 * 1024;\n\nconst BY_KEY = new Map(FIELDS.map((field) => [field.key, field]));\n\n/** The definition for a `--set`/`--file` key, normalising a country key\n * like `country.us.currency` to its `country.<ISO>.currency` entry. */\nexport function fieldFor(key: string): FieldDef | undefined {\n const country = /^country\\.([A-Za-z]{2})\\.(\\w+)$/.exec(key);\n if (country) return BY_KEY.get(`country.<ISO>.${country[2]}`);\n return BY_KEY.get(key);\n}\n\nexport function isSensitive(key: string): boolean {\n return fieldFor(key)?.sensitive === true;\n}\n\n/** Strip the group prefix: `entity.legal_name` -> `legal_name`. */\nexport function attributeOf(key: string): string {\n return key.slice(key.indexOf(\".\") + 1);\n}\n","// What still stands between a company and submitting its payments\n// onboarding. Ported from the admin app's validation\n// (`components/Onboarding/utils/validation.ts`), which is what blocks the\n// \"Accept and Continue\" button; the API itself only checks types.\n\nimport {\n DISEASE_CLAIM_IDS,\n fieldFor,\n INGREDIENT_IDS,\n STEPS,\n type StepId,\n} from \"./fields.js\";\nimport type {\n BankAccount,\n Entity,\n FileRef,\n Owner,\n Snapshot,\n UnderwritingInfo,\n} from \"./types.js\";\n\nexport interface Target {\n entity?: number;\n bank?: number;\n owner?: number;\n}\n\nexport interface Missing {\n step: StepId;\n /** The `--set`/`--file` key that fixes it. */\n field: string;\n message: string;\n /** Which record the field belongs to; absent when the record doesn't\n * exist yet and `set` will create it. */\n target?: Target;\n /** A ready-made fragment for `fluid payments onboarding set`. */\n fix: string;\n}\n\nexport interface StepReport {\n id: StepId;\n name: string;\n complete: boolean;\n missing: number;\n}\n\n/** The server's step keys. Submission means all of these are 100 and the\n * terms are agreed (`PaymentsStatus::IndexAction#onboarding_completed?`). */\nexport const SERVER_STEP_KEYS = [\n \"basic_info\",\n \"business_info\",\n \"legal_entities\",\n \"bank_accounts_i\",\n \"bank_accounts_ii\",\n \"personal_info\",\n \"relevant_persons\",\n \"countries\",\n \"underwriting\",\n] as const;\n\nconst filled = (value: unknown): boolean =>\n typeof value === \"string\"\n ? value.trim() !== \"\"\n : value !== null && value !== undefined && value !== false;\n\nconst hasFiles = (value: unknown): boolean =>\n Array.isArray(value) && value.length > 0;\n\nfunction targetFlag(target?: Target): string {\n if (!target) return \"\";\n if (target.entity !== undefined) return `--entity ${target.entity} `;\n if (target.bank !== undefined) return `--bank ${target.bank} `;\n if (target.owner !== undefined) return `--owner ${target.owner} `;\n return \"\";\n}\n\nfunction fixFor(field: string, target?: Target): string {\n const type = fieldFor(field)?.type;\n const prefix = targetFlag(target);\n if (type === \"file\" || type === \"files\") {\n const idType =\n field === \"owner.government_issued_ids\"\n ? \" --id-type <passport|license|national_id>\"\n : \"\";\n return `${prefix}--file ${field}=<path>${idType}`;\n }\n if (type === \"link_or_file\") {\n return `${prefix}--set ${field}.link=<url> (or --file ${field}=<path>)`;\n }\n return `${prefix}--set ${field}=<value>`;\n}\n\nclass Collector {\n readonly items: Missing[] = [];\n\n add(step: StepId, field: string, message: string, target?: Target): void {\n const key = `${step}|${field}|${JSON.stringify(target ?? {})}`;\n if (\n this.items.some(\n (m) => `${m.step}|${m.field}|${JSON.stringify(m.target ?? {})}` === key,\n )\n )\n return;\n this.items.push({\n step,\n field,\n message,\n ...(target ? { target } : {}),\n fix: fixFor(field, target),\n });\n }\n}\n\nconst VAT_COUNTRIES = new Set([\n \"GB\",\n \"DE\",\n \"FR\",\n \"IT\",\n \"ES\",\n \"NL\",\n \"BE\",\n \"AT\",\n \"SE\",\n \"DK\",\n \"FI\",\n \"NO\",\n \"CH\",\n \"PL\",\n \"CZ\",\n \"HU\",\n \"RO\",\n \"BG\",\n \"HR\",\n \"SI\",\n \"SK\",\n \"EE\",\n \"LV\",\n \"LT\",\n \"MT\",\n \"CY\",\n \"LU\",\n \"IE\",\n \"PT\",\n \"GR\",\n]);\n\nexport function primaryEntity(entities: readonly Entity[]): Entity | undefined {\n return entities.find((e) => e.primary === true) ?? entities[0];\n}\n\nexport function onboardingContact(owners: readonly Owner[]): Owner | undefined {\n return owners.find((o) => o.onboarding_contact === true);\n}\n\nexport function primaryBankAccount(\n snapshot: Pick<Snapshot, \"entities\" | \"bankAccounts\">,\n): BankAccount | undefined {\n const explicit = snapshot.bankAccounts.find((a) => a.primary === true);\n if (explicit) return explicit;\n const entity = primaryEntity(snapshot.entities);\n return entity\n ? snapshot.bankAccounts.find((a) => a.entity_id === entity.id)\n : undefined;\n}\n\nfunction entityCountry(entity: Partial<Entity>): string {\n return String(\n entity.country_iso || entity.registered_address?.[\"country_code\"] || \"\",\n ).toUpperCase();\n}\n\nfunction checkEntity(\n c: Collector,\n step: StepId,\n entity: Partial<Entity>,\n target?: Target,\n): void {\n const value = (attr: string) => entity[attr];\n const nested: Record<string, string> = {\n province: \"state\",\n country_iso: \"country_code\",\n };\n const address = (attr: string) =>\n filled(value(attr))\n ? value(attr)\n : entity.registered_address?.[nested[attr] ?? attr];\n\n const required: Array<[string, string]> = [\n [\"legal_name\", \"Legal company name is required\"],\n [\"classification\", \"Business type is required\"],\n [\"registration_number\", \"Business registration number is required\"],\n [\"date_of_incorporation\", \"Date of incorporation is required\"],\n [\"phone\", \"Phone number is required\"],\n [\"website\", \"Website is required\"],\n [\"primary_mcc\", \"Primary MCC is required\"],\n ];\n for (const [attr, message] of required) {\n if (!filled(value(attr))) c.add(step, `entity.${attr}`, message, target);\n }\n const addressFields: Array<[string, string]> = [\n [\"address1\", \"Street address is required\"],\n [\"city\", \"City is required\"],\n [\"province\", \"State/Province is required\"],\n [\"postal_code\", \"Postal code is required\"],\n [\"country_iso\", \"Country is required\"],\n ];\n for (const [attr, message] of addressFields) {\n if (!filled(address(attr))) c.add(step, `entity.${attr}`, message, target);\n }\n\n const country = entityCountry(entity);\n if (!filled(value(\"business_identification_number\"))) {\n c.add(\n step,\n \"entity.business_identification_number\",\n country === \"US\"\n ? \"Employer Identification Number (EIN) is required\"\n : VAT_COUNTRIES.has(country)\n ? \"VAT ID is required\"\n : \"Business tax ID is required\",\n target,\n );\n }\n const files: Array<[string, string]> = [\n [\n \"business_registration_certificate\",\n \"Business registration certificate is required\",\n ],\n [\"business_license\", \"Business license is required\"],\n [\"articles_of_incorporation\", \"Articles of incorporation is required\"],\n ];\n if (country === \"US\") files.push([\"w_9\", \"W-9 is required for US entities\"]);\n for (const [base, message] of files) {\n if (!filled(value(`${base}_file_url`)))\n c.add(step, `entity.${base}`, message, target);\n }\n\n const website = String(value(\"website\") ?? \"\").trim();\n if (website && !/^https?:\\/\\//.test(website)) {\n c.add(\n step,\n \"entity.website\",\n \"Website must start with http:// or https://\",\n target,\n );\n }\n const phone = String(value(\"phone\") ?? \"\").trim();\n if (phone && !/^[\\d\\s\\-+()]{8,}$/.test(phone)) {\n c.add(\n step,\n \"entity.phone\",\n \"Phone number must have at least 8 digits\",\n target,\n );\n }\n}\n\nfunction checkBank(\n c: Collector,\n account: Partial<BankAccount>,\n target?: Target,\n): void {\n const step: StepId = \"bank-accounts\";\n const required: Array<[string, string]> = [\n [\"bank_name\", \"Bank name is required\"],\n [\"holder_name\", \"Account holder name is required\"],\n [\"account_number\", \"Account number is required\"],\n [\"country_iso\", \"Bank country is required\"],\n [\"currency_iso\", \"Currency is required\"],\n [\"city\", \"Bank city is required\"],\n ];\n for (const [attr, message] of required) {\n if (!filled(account[attr])) c.add(step, `bank.${attr}`, message, target);\n }\n if (!filled(account[\"bank_letter_or_voided_check_file_url\"])) {\n c.add(\n step,\n \"bank.bank_letter_or_voided_check\",\n \"Bank letter or voided check is required\",\n target,\n );\n }\n const country = String(account.country_iso ?? \"\").toUpperCase();\n if (country === \"US\") {\n if (!filled(account[\"routing_number\"]))\n c.add(\n step,\n \"bank.routing_number\",\n \"Routing number is required for US accounts\",\n target,\n );\n } else if (country) {\n if (!filled(account[\"swift_bic\"]))\n c.add(\n step,\n \"bank.swift_bic\",\n \"SWIFT/BIC is required outside the US\",\n target,\n );\n } else {\n c.add(\n step,\n \"bank.routing_number\",\n \"Routing number (US) or SWIFT/BIC (elsewhere) is required once the country is set\",\n target,\n );\n }\n const statements =\n filled(account[\"last_3_months_bank_statements_file_url\"]) ||\n hasFiles(account.last_3_months_bank_statements);\n if (!statements)\n c.add(\n step,\n \"bank.last_3_months_bank_statements\",\n \"Last 3 months of bank statements are required\",\n target,\n );\n}\n\nfunction checkOwner(\n c: Collector,\n step: StepId,\n owner: Partial<Owner>,\n target?: Target,\n): void {\n const required: Array<[string, string]> = [\n [\"full_name\", \"Full name is required\"],\n [\"work_email\", \"Work email is required\"],\n [\"date_of_birth\", \"Date of birth is required\"],\n [\"place_of_birth\", \"Place of birth is required\"],\n [\"nationality\", \"Nationality is required\"],\n [\"country_iso\", \"Country of residence is required\"],\n [\"street_address\", \"Street address is required\"],\n [\"city\", \"City is required\"],\n [\"state\", \"State/Province is required\"],\n [\"postcode\", \"Postcode is required\"],\n [\"phone\", \"Phone number is required\"],\n [\"identification_number\", \"Identification number is required\"],\n [\"position\", \"Job title is required\"],\n ];\n for (const [attr, message] of required) {\n if (!filled(owner[attr])) c.add(step, `owner.${attr}`, message, target);\n }\n const email = String(owner[\"work_email\"] ?? \"\").trim();\n if (email && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email)) {\n c.add(\n step,\n \"owner.work_email\",\n \"Work email is not a valid address\",\n target,\n );\n }\n\n const ids: FileRef[] = Array.isArray(owner.government_issued_ids)\n ? owner.government_issued_ids\n : [];\n if (ids.length === 0) {\n c.add(\n step,\n \"owner.government_issued_ids\",\n \"Government-issued ID is required\",\n target,\n );\n } else {\n const type = ids[0]?.file_type;\n if ((type === \"license\" || type === \"national_id\") && ids.length === 1) {\n c.add(\n step,\n \"owner.government_issued_ids\",\n `Upload both the front and back of the ${type === \"license\" ? \"driver's license\" : \"national ID\"}`,\n target,\n );\n }\n }\n if (!filled(owner[\"proof_of_residence_file_url\"])) {\n c.add(\n step,\n \"owner.proof_of_residence\",\n \"Proof of residence is required\",\n target,\n );\n }\n\n if (owner.is_beneficial_owner === true) {\n const raw = String(owner.percent_ownership ?? \"\").trim();\n const pct = raw === \"\" ? Number.NaN : Number.parseFloat(raw);\n if (raw === \"\") {\n c.add(\n step,\n \"owner.percent_ownership\",\n \"Ownership percentage is required for a beneficial owner\",\n target,\n );\n } else if (Number.isNaN(pct) || pct < 25 || pct > 100) {\n c.add(\n step,\n \"owner.percent_ownership\",\n \"A beneficial owner must own between 25% and 100%\",\n target,\n );\n }\n }\n}\n\nconst POLICY_FIELDS = [\n \"terms_and_conditions\",\n \"refund_or_return_policy\",\n \"privacy_policy\",\n] as const;\nconst MLM_DOCUMENTS = [\n \"distributor_policies\",\n \"sample_distributor_agreement\",\n \"business_opportunity_disclosures\",\n \"income_disclosure_statement\",\n \"fulfillment_agreement\",\n \"manufacturing_agreement\",\n] as const;\nconst ALWAYS_TEXT = [\n \"company_description\",\n \"management_stability\",\n \"uses_third_party_accounting\",\n \"has_compliance_officer\",\n \"compliance_officer_responsibilities\",\n \"distributor_monitoring_policies\",\n \"suspicious_activity_escalation_process\",\n \"retains_outside_legal_counsel\",\n \"investigations_description\",\n \"negative_media_events\",\n \"bbb_rating\",\n \"trustpilot_rating\",\n \"projected_annual_sales_volume\",\n \"average_order_value\",\n] as const;\nconst MLM_TEXT = [\n \"mlm_ownership_structure\",\n \"commission_payment_method\",\n \"commission_payment_channels\",\n \"commission_payment_countries\",\n \"recruiter_commission_for_recruiting\",\n \"all_distributors_can_profit\",\n \"provides_average_compensation_report\",\n \"distributor_identification_requirements\",\n \"distributor_pii_collected\",\n \"distributor_due_diligence\",\n \"distributor_country_restrictions\",\n \"distributor_decline_termination_reasons\",\n \"distributor_cross_border_sales\",\n \"distributor_training_description\",\n] as const;\nconst HEALTH_TEXT = [\n \"is_product_manufacturer\",\n \"marketing_methods_description\",\n \"cancellation_methods_description\",\n \"scientific_studies_description\",\n \"health_product_lawsuit_history\",\n] as const;\nconst FINANCIAL_FILES = [\n \"balance_sheet_year1\",\n \"balance_sheet_year2\",\n \"income_statement_year1\",\n \"income_statement_year2\",\n \"cash_flow_year1\",\n \"cash_flow_year2\",\n] as const;\n\nfunction linkOrFile(u: UnderwritingInfo, field: string): boolean {\n const obj = (u[field] ?? {}) as FileRef;\n return (\n filled(obj.link) || filled(obj.file_url) || filled(u[`${field}_file_url`])\n );\n}\n\nfunction checkUnderwriting(c: Collector, u: UnderwritingInfo): void {\n const step: StepId = \"underwriting\";\n const isMlm = u[\"company_is_mlm\"] === true;\n const add = (attr: string, message = \"This field is required\") =>\n c.add(step, `underwriting.${attr}`, message);\n\n for (const attr of ALWAYS_TEXT) if (!filled(u[attr])) add(attr);\n if (typeof u[\"financials_audited\"] !== \"boolean\") add(\"financials_audited\");\n for (const base of FINANCIAL_FILES)\n if (!filled(u[`${base}_file_url`])) add(base);\n\n const cit = String(u[\"cit_share_percentage\"] ?? \"\").trim();\n const mit = String(u[\"mit_share_percentage\"] ?? \"\").trim();\n if (!cit)\n add(\"cit_share_percentage\", \"% one-time purchases (CIT) is required\");\n if (!mit) add(\"mit_share_percentage\", \"% subscriptions (MIT) is required\");\n if (cit && mit) {\n const citN = Number.parseFloat(cit);\n const mitN = Number.parseFloat(mit);\n if (Number.isNaN(citN) || citN < 0 || citN > 100)\n add(\"cit_share_percentage\", \"CIT must be between 0 and 100\");\n if (Number.isNaN(mitN) || mitN < 0 || mitN > 100)\n add(\"mit_share_percentage\", \"MIT must be between 0 and 100\");\n if (\n !Number.isNaN(citN) &&\n !Number.isNaN(mitN) &&\n Math.abs(citN + mitN - 100) > 0.01\n ) {\n add(\"cit_share_percentage\", \"CIT and MIT must total 100\");\n }\n }\n\n for (const field of POLICY_FIELDS) {\n if (!linkOrFile(u, field))\n add(field, \"A URL or an uploaded file is required\");\n }\n\n if (isMlm) {\n for (const attr of MLM_TEXT) if (!filled(u[attr])) add(attr);\n if (!filled(u[\"mlm_ownership_structure_file_url\"]))\n add(\"mlm_ownership_structure_file\", \"An ownership chart is required\");\n for (const field of MLM_DOCUMENTS) {\n if (!linkOrFile(u, field))\n add(field, \"A URL or an uploaded file is required\");\n }\n if (\n !hasFiles(u[\"compensation_plan\"]) &&\n !filled(u[\"compensation_plan_file_url\"])\n ) {\n add(\"compensation_plan\", \"Compensation plan is required\");\n }\n for (const attr of [\n \"revenue_from_recruiting_percentage\",\n \"revenue_from_website_percentage\",\n \"retail_sales_outside_downline_percentage\",\n ]) {\n const raw = String(u[attr] ?? \"\").trim();\n if (raw) {\n const n = Number.parseFloat(raw);\n if (Number.isNaN(n) || n < 0 || n > 100)\n add(attr, \"Must be a number between 0 and 100\");\n }\n }\n }\n\n if (u[\"sells_health_supplements\"] === true) {\n for (const attr of HEALTH_TEXT) if (!filled(u[attr])) add(attr);\n const anyIngredient =\n INGREDIENT_IDS.some(({ id }) => u[`contains_${id}`] === true) ||\n u[\"contains_none_listed\"] === true;\n if (!anyIngredient)\n add(\n \"contains_none_listed\",\n \"Set one contains_* field, or contains_none_listed=true\",\n );\n for (const { id, label } of INGREDIENT_IDS) {\n if (u[`contains_${id}`] === true && !filled(u[`${id}_product_names`])) {\n add(`${id}_product_names`, `List the products containing ${label}`);\n }\n }\n const anyClaim =\n DISEASE_CLAIM_IDS.some(\n ({ id }) => u[`claims_${id}_treatment`] === true,\n ) || u[\"claims_no_diseases\"] === true;\n if (!anyClaim)\n add(\n \"claims_no_diseases\",\n \"Set one claims_* field, or claims_no_diseases=true\",\n );\n for (const { id, label } of DISEASE_CLAIM_IDS) {\n if (\n u[`claims_${id}_treatment`] === true &&\n !filled(u[`${id}_treatment_products`])\n ) {\n add(\n `${id}_treatment_products`,\n `List the products claiming to treat ${label}`,\n );\n }\n }\n }\n}\n\n/** Every required field still missing, in form order. */\nexport function missingFields(\n snapshot: Omit<Snapshot, \"companyId\" | \"version\">,\n): Missing[] {\n const c = new Collector();\n const info = snapshot.info ?? {};\n\n // The Basics\n for (const key of [\n \"beneficial_individual_owner\",\n \"beneficial_business_owner\",\n \"other_legal_entities\",\n \"user_has_authority\",\n \"user_is_signatory\",\n ]) {\n if (typeof info[key] !== \"boolean\")\n c.add(\"business-type\", `info.${key}`, \"Answer true or false\");\n }\n if (\n info.beneficial_individual_owner === true &&\n typeof info.user_is_owner !== \"boolean\"\n ) {\n c.add(\"business-type\", \"info.user_is_owner\", \"Answer true or false\");\n }\n\n // Business info: the primary entity. Legal entities: every other one.\n const primary = primaryEntity(snapshot.entities);\n checkEntity(\n c,\n \"business-info\",\n primary ?? {},\n primary ? { entity: primary.id } : undefined,\n );\n for (const entity of snapshot.entities) {\n if (entity !== primary)\n checkEntity(c, \"legal-entities\", entity, { entity: entity.id });\n }\n\n // Bank accounts: the primary entity needs one; every account must be complete.\n const primaryAccount = primaryBankAccount(snapshot);\n checkBank(\n c,\n primaryAccount ?? {},\n primaryAccount ? { bank: primaryAccount.id } : undefined,\n );\n for (const account of snapshot.bankAccounts) {\n if (account !== primaryAccount) checkBank(c, account, { bank: account.id });\n }\n\n // Personal info: the person filling in the form. Relevant persons: everyone else.\n const contact = onboardingContact(snapshot.owners);\n checkOwner(\n c,\n \"personal-info\",\n contact ?? {},\n contact ? { owner: contact.id } : undefined,\n );\n for (const owner of snapshot.owners) {\n if (owner !== contact)\n checkOwner(c, \"relevant-persons\", owner, { owner: owner.id });\n }\n\n // Countries\n const countries = info.countries_info ?? [];\n const entityIds = new Set(snapshot.entities.map((e) => e.id));\n if (countries.length === 0) {\n c.add(\n \"countries\",\n \"country.<ISO>.currency\",\n \"Add at least one country the company sells in\",\n );\n }\n for (const entry of countries) {\n const iso = entry.country_iso;\n if (!filled(entry.currency))\n c.add(\"countries\", `country.${iso}.currency`, \"Currency is required\");\n if (!filled(entry.settlement_currency))\n c.add(\n \"countries\",\n `country.${iso}.settlement_currency`,\n \"Settlement currency is required\",\n );\n if (!entry.entity_id || !entityIds.has(entry.entity_id))\n c.add(\n \"countries\",\n `country.${iso}.entity_id`,\n \"Choose the legal entity that sells there\",\n );\n if (entry.entity_legally_registered !== true) {\n c.add(\n \"countries\",\n `country.${iso}.entity_legally_registered`,\n \"Confirm the entity is legally registered there (true)\",\n );\n }\n }\n\n checkUnderwriting(c, (info.underwriting_info ?? {}) as UnderwritingInfo);\n return c.items;\n}\n\nexport function termsAgreed(snapshot: Pick<Snapshot, \"info\">): boolean {\n return (\n snapshot.info.terms_and_conditions_info?.terms_and_conditions_agreed ===\n true\n );\n}\n\n/** Same rule the server uses to call the form submitted. */\nexport function isSubmitted(snapshot: Pick<Snapshot, \"info\">): boolean {\n if (!termsAgreed(snapshot)) return false;\n const steps = snapshot.info.onboarding_steps ?? {};\n return SERVER_STEP_KEYS.every((key) => Number(steps[key]) === 100);\n}\n\nexport type OnboardingStatus = \"not_started\" | \"in_progress\" | \"submitted\";\n\nexport function statusOf(\n snapshot: Omit<Snapshot, \"companyId\" | \"version\">,\n): OnboardingStatus {\n if (isSubmitted(snapshot)) return \"submitted\";\n const info = snapshot.info;\n const started =\n snapshot.entities.length > 0 ||\n snapshot.bankAccounts.length > 0 ||\n snapshot.owners.length > 0 ||\n typeof info.beneficial_individual_owner === \"boolean\" ||\n Object.keys(info.underwriting_info ?? {}).length > 0;\n return started ? \"in_progress\" : \"not_started\";\n}\n\nexport function stepReports(\n snapshot: Omit<Snapshot, \"companyId\" | \"version\">,\n missing: readonly Missing[],\n): StepReport[] {\n return STEPS.map((step) => {\n const count =\n step.id === \"terms-and-conditions\"\n ? termsAgreed(snapshot)\n ? 0\n : 1\n : missing.filter((m) => m.step === step.id).length;\n return {\n id: step.id,\n name: step.name,\n complete: count === 0,\n missing: count,\n };\n });\n}\n","// Wire shapes of the onboarding endpoints, kept to the fields the plugin reads.\n\nexport class OnboardingError extends Error {\n constructor(\n message: string,\n readonly details?: unknown,\n ) {\n super(message);\n this.name = \"OnboardingError\";\n }\n}\n\nexport interface FileRef {\n file_url?: string | null;\n file_name?: string | null;\n file_type?: string | null;\n link?: string | null;\n}\n\nexport type UnderwritingInfo = Record<string, unknown>;\n\nexport interface CountryInfo {\n entity_id: number;\n currency: string;\n settlement_currency: string;\n entity_legally_registered: boolean;\n country_id: number;\n country_iso: string;\n}\n\nexport interface OnboardingInfo {\n beneficial_individual_owner?: boolean | null;\n user_is_owner?: boolean | null;\n beneficial_business_owner?: boolean | null;\n other_legal_entities?: boolean | null;\n user_has_authority?: boolean | null;\n user_is_signatory?: boolean | null;\n onboarding_steps?: Record<string, number> | null;\n underwriting_info?: UnderwritingInfo | null;\n terms_and_conditions_info?: {\n terms_and_conditions_agreed?: boolean | null;\n terms_and_conditions_agreed_at?: string | null;\n terms_and_condition_signer_name?: string | null;\n terms_and_condition_signer_email?: string | null;\n } | null;\n countries_info?: CountryInfo[] | null;\n [key: string]: unknown;\n}\n\nexport interface Entity {\n id: number;\n legal_name?: string | null;\n primary?: boolean | null;\n status?: string | null;\n country_iso?: string | null;\n registered_address?: Record<string, string | null> | null;\n [key: string]: unknown;\n}\n\nexport interface BankAccount {\n id: number;\n entity_id: number;\n primary?: boolean | null;\n country_iso?: string | null;\n last_3_months_bank_statements?: FileRef[] | null;\n [key: string]: unknown;\n}\n\nexport interface Owner {\n id: number;\n entity_id?: number | null;\n full_name?: string | null;\n onboarding_contact?: boolean | null;\n is_beneficial_owner?: boolean | null;\n percent_ownership?: string | number | null;\n government_issued_ids?: FileRef[] | null;\n [key: string]: unknown;\n}\n\n/** Everything the onboarding form is built from. */\nexport interface Snapshot {\n companyId: number;\n info: OnboardingInfo;\n /** Sent back on a save so a concurrent edit answers 409 instead of being\n * overwritten. Null on servers that predate it. */\n version: number | null;\n entities: Entity[];\n bankAccounts: BankAccount[];\n owners: Owner[];\n}\n","// Calls to the onboarding endpoints the admin app's /settings/onboarding\n// form uses (`/api/companies/:company_id/...`).\n\nimport { readFile } from \"node:fs/promises\";\nimport { basename, extname } from \"node:path\";\n\nimport type { Plan } from \"./assign.js\";\nimport { attributeOf, MAX_UPLOAD_BYTES, type IdType } from \"./fields.js\";\nimport {\n isSubmitted,\n missingFields,\n onboardingContact,\n primaryBankAccount,\n primaryEntity,\n SERVER_STEP_KEYS,\n} from \"./requirements.js\";\nimport {\n OnboardingError,\n type BankAccount,\n type CountryInfo,\n type Entity,\n type FileRef,\n type OnboardingInfo,\n type Owner,\n type Snapshot,\n} from \"./types.js\";\n\n/** The slice of the CLI's API client these calls use. */\nexport interface OnboardingClient {\n get<T>(endpoint: string, params?: Record<string, unknown>): Promise<T>;\n post<T>(endpoint: string, body?: unknown): Promise<T>;\n put<T>(endpoint: string, body?: unknown): Promise<T>;\n delete<T>(endpoint: string): Promise<T>;\n requestWithFormData<T>(\n endpoint: string,\n formData: FormData,\n options?: { method?: \"POST\" | \"PUT\" | \"PATCH\" },\n ): Promise<T>;\n}\n\nexport interface LocalFile {\n name: string;\n bytes: Uint8Array;\n}\n\nexport type FileReader = (path: string) => Promise<LocalFile>;\n\nexport const readLocalFile: FileReader = async (path) => {\n let bytes: Uint8Array;\n try {\n bytes = await readFile(path);\n } catch {\n throw new OnboardingError(`Can't read ${path}.`);\n }\n return { name: basename(path), bytes };\n};\n\ninterface CompanyMeWire {\n data?: { company?: { id?: number } };\n company?: { id?: number };\n}\n\n/** The company the token acts for. */\nexport async function currentCompanyId(\n client: OnboardingClient,\n): Promise<number> {\n const me = await client.get<CompanyMeWire>(\"/api/company/v1/companies/me\");\n const id = me.data?.company?.id ?? me.company?.id;\n if (typeof id !== \"number\")\n throw new OnboardingError(\n \"Couldn't tell which company this token belongs to.\",\n );\n return id;\n}\n\nconst base = (companyId: number) => `/api/companies/${companyId}`;\n\n/** Where to find the form in the admin when no URL can be worked out. */\nexport const ONBOARDING_FORM_PATH = \"Settings > Onboarding\";\n\n/**\n * The admin's onboarding form for the environment the CLI talks to: the\n * admin host sits beside the API host (api.fluid.app → admin.fluid.app,\n * api.fluid-staging.app → admin.fluid-staging.app). Null for an API host\n * that doesn't follow that pattern, such as a local server.\n */\nexport function onboardingFormUrl(\n apiBase: string = process.env[\"FLUID_API_BASE\"] ?? \"https://api.fluid.app\",\n): string | null {\n try {\n const url = new URL(apiBase);\n if (!url.hostname.startsWith(\"api.\")) return null;\n return `${url.protocol}//admin.${url.hostname.slice(4)}/settings/onboarding`;\n } catch {\n return null;\n }\n}\n\n/** Where a person submits: the form's URL, or where to find it. */\nexport function onboardingFormLocation(): string {\n return onboardingFormUrl() ?? `${ONBOARDING_FORM_PATH} in the admin`;\n}\n\n/**\n * Whether the token is a person's sign-in. Submitting records who accepted\n * the terms, so it needs one: `fluid login` with email does, while a company\n * API token has no person behind it and `/api/me` refuses it.\n */\nexport async function signedInAsPerson(\n client: OnboardingClient,\n): Promise<boolean> {\n try {\n await client.get(\"/api/me\");\n return true;\n } catch (error) {\n const status = (error as { status?: unknown }).status;\n if (status === 401 || status === 403) return false;\n throw error;\n }\n}\n\ninterface InfoWire {\n company: {\n id: number;\n onboarding_info: OnboardingInfo | null;\n onboarding_info_version?: number | null;\n };\n}\n\nexport async function loadSnapshot(\n client: OnboardingClient,\n companyId: number,\n): Promise<Snapshot> {\n const [info, entities, banks, owners] = await Promise.all([\n client.get<InfoWire>(`${base(companyId)}/onboarding_info`),\n client.get<{ entities?: Entity[] }>(`${base(companyId)}/entities`),\n client.get<{ bank_accounts?: BankAccount[] }>(\n `${base(companyId)}/bank_accounts`,\n ),\n client.get<{ owners?: Owner[] }>(`${base(companyId)}/owners`),\n ]);\n return {\n companyId,\n info: info.company.onboarding_info ?? {},\n version: info.company.onboarding_info_version ?? null,\n entities: entities.entities ?? [],\n bankAccounts: banks.bank_accounts ?? [],\n owners: owners.owners ?? [],\n };\n}\n\nexport async function termsUrl(\n client: OnboardingClient,\n companyId: number,\n): Promise<string | null> {\n try {\n const res = await client.get<{ terms_and_conditions?: { url?: string } }>(\n `${base(companyId)}/onboarding_info/terms_and_conditions`,\n );\n return res.terms_and_conditions?.url ?? null;\n } catch {\n return null;\n }\n}\n\ninterface ProviderWire {\n display_name?: string;\n integration_class?: string;\n provider_type?: string;\n onboarding_status?: string;\n onboarding_time_estimate?: string | null;\n}\n\nexport interface ProviderStatus {\n name: string;\n type: string | null;\n onboardingStatus: string | null;\n timeEstimate: string | null;\n}\n\n/** Per-processor progress after submission. Null when the token can't read\n * payment accounts. */\nexport async function providerStatuses(\n client: OnboardingClient,\n companyId: number,\n): Promise<ProviderStatus[] | null> {\n try {\n const res = await client.get<{\n providers?: { psps?: ProviderWire[]; apms?: ProviderWire[] };\n }>(`${base(companyId)}/payments_status`);\n return [...(res.providers?.psps ?? []), ...(res.providers?.apms ?? [])].map(\n (p) => ({\n name: p.display_name ?? p.integration_class ?? \"unknown\",\n type: p.provider_type ?? null,\n onboardingStatus: p.onboarding_status ?? null,\n timeEstimate: p.onboarding_time_estimate ?? null,\n }),\n );\n } catch (error) {\n const status = (error as { status?: number }).status;\n if (status === 401 || status === 403) return null;\n throw error;\n }\n}\n\nconst CONTENT_TYPES: Record<string, string> = {\n \".pdf\": \"application/pdf\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".heic\": \"image/heic\",\n \".webp\": \"image/webp\",\n \".doc\": \"application/msword\",\n \".docx\":\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n};\n\ninterface UploadWire {\n url: string;\n filename: string;\n}\n\n/** Upload one document. Returns the stored reference; the signed URL is\n * never printed. */\nexport async function uploadDocument(\n client: OnboardingClient,\n companyId: number,\n file: LocalFile,\n documentType: string,\n): Promise<{ file_url: string; file_name: string }> {\n if (file.bytes.byteLength > MAX_UPLOAD_BYTES) {\n throw new OnboardingError(`${file.name} is over the 10 MB upload limit.`);\n }\n const form = new FormData();\n const type =\n CONTENT_TYPES[extname(file.name).toLowerCase()] ??\n \"application/octet-stream\";\n form.append(\n \"file\",\n new Blob([new Uint8Array(file.bytes)], { type }),\n file.name,\n );\n form.append(\"document_type\", documentType);\n const res = await client.requestWithFormData<UploadWire>(\n `${base(companyId)}/onboarding_info/upload_document`,\n form,\n { method: \"POST\" },\n );\n return { file_url: res.url, file_name: res.filename || file.name };\n}\n\n/** `--entity 12`, `--entity new`, or nothing for the default record. */\nexport type TargetArg = number | \"new\" | undefined;\n\nexport function parseTarget(flag: string, raw: string | undefined): TargetArg {\n if (raw === undefined) return undefined;\n if (raw === \"new\") return \"new\";\n const id = Number(raw);\n if (!Number.isInteger(id) || id <= 0)\n throw new OnboardingError(`${flag} takes a record id or \"new\".`);\n return id;\n}\n\nexport interface Targets {\n entity?: TargetArg;\n bank?: TargetArg;\n owner?: TargetArg;\n idType?: IdType;\n /** Replace a multi-file document's files instead of adding to them. */\n replaceFiles?: boolean;\n}\n\nexport interface SavedRecord {\n record: \"entity\" | \"bank\" | \"owner\" | \"onboarding_info\";\n id: number | null;\n action: \"created\" | \"updated\";\n}\n\nfunction findOr<T extends { id: number }>(\n records: readonly T[],\n id: number,\n label: string,\n): T {\n const found = records.find((r) => r.id === id);\n if (!found)\n throw new OnboardingError(\n `No ${label} with id ${id}. Run \\`fluid payments onboarding show\\` for the ids.`,\n );\n return found;\n}\n\nconst DOCUMENT_TYPES: Record<string, string> = {\n government_issued_ids: \"government_id\",\n mlm_ownership_structure_file: \"organizational_chart\",\n refund_or_return_policy: \"refund_return_policy\",\n sample_distributor_agreement: \"distributor_agreement\",\n income_disclosure_statement: \"income_disclosure\",\n};\n\nconst documentTypeOf = (attr: string) =>\n DOCUMENT_TYPES[attr] ?? attr.replace(/_year\\d$/, \"\").replace(/_file$/, \"\");\n\n/**\n * Save a plan. Order matters: an entity first, because bank accounts,\n * people, and countries default to the primary entity; the onboarding info\n * last, carrying the revision it was read at.\n */\nexport async function applyPlan(\n client: OnboardingClient,\n snapshot: Snapshot,\n plan: Plan,\n targets: Targets,\n readLocal: FileReader = readLocalFile,\n): Promise<SavedRecord[]> {\n const companyId = snapshot.companyId;\n const saved: SavedRecord[] = [];\n const filesFor = (group: string) =>\n plan.files.filter((f) => f.field.group === group);\n\n // ---- resolve the records each group writes to, before uploading anything\n const entityTouched =\n Object.keys(plan.entity).length > 0 || filesFor(\"entity\").length > 0;\n const bankTouched =\n Object.keys(plan.bank).length > 0 || filesFor(\"bank\").length > 0;\n const ownerTouched =\n Object.keys(plan.owner).length > 0 || filesFor(\"owner\").length > 0;\n\n let entity: Entity | undefined;\n if (targets.entity !== \"new\" && targets.entity !== undefined)\n entity = findOr(snapshot.entities, targets.entity, \"entity\");\n else if (targets.entity === undefined)\n entity = primaryEntity(snapshot.entities);\n if (\n entityTouched &&\n !entity &&\n typeof plan.entity[\"legal_name\"] !== \"string\"\n ) {\n throw new OnboardingError(\"Creating an entity needs entity.legal_name.\");\n }\n\n let bank: BankAccount | undefined;\n if (targets.bank !== \"new\" && targets.bank !== undefined)\n bank = findOr(snapshot.bankAccounts, targets.bank, \"bank account\");\n else if (targets.bank === undefined) bank = primaryBankAccount(snapshot);\n\n let owner: Owner | undefined;\n if (targets.owner !== \"new\" && targets.owner !== undefined)\n owner = findOr(snapshot.owners, targets.owner, \"person\");\n else if (targets.owner === undefined)\n owner = onboardingContact(snapshot.owners);\n if (ownerTouched && !owner && typeof plan.owner[\"full_name\"] !== \"string\") {\n throw new OnboardingError(\"Adding a person needs owner.full_name.\");\n }\n\n const idFiles = plan.files.filter(\n (f) => f.key === \"owner.government_issued_ids\",\n );\n if (idFiles.length > 0 && !targets.idType) {\n throw new OnboardingError(\n \"Uploading a government ID needs --id-type passport, license, or national_id.\",\n );\n }\n\n // ---- check everything that can fail locally before writing anything, so\n // a bad plan leaves the form untouched\n const willHaveEntity =\n entity !== undefined || entityTouched || snapshot.entities.length > 0;\n const entityFirst = (what: string) =>\n new OnboardingError(\n `Add the legal entity first (--set entity.legal_name=...), then ${what}.`,\n );\n if (\n bankTouched &&\n !bank &&\n plan.bank[\"entity_id\"] === undefined &&\n !willHaveEntity\n )\n throw entityFirst(\"add a bank account\");\n if (\n ownerTouched &&\n !owner &&\n plan.owner[\"entity_id\"] === undefined &&\n !willHaveEntity\n )\n throw entityFirst(\"add a person\");\n const existingCountries = snapshot.info.countries_info ?? [];\n const newIsos = Object.keys(plan.countries).filter(\n (iso) => !existingCountries.some((c) => c.country_iso === iso),\n );\n if (\n newIsos.some((iso) => plan.countries[iso]?.[\"entity_id\"] === undefined) &&\n !willHaveEntity\n )\n throw entityFirst(\"add a country\");\n const catalogue = newIsos.length > 0 ? await listCountries(client) : [];\n for (const iso of newIsos) {\n if (!catalogue.some((c) => c.iso.toUpperCase() === iso)) {\n throw new OnboardingError(\n `${iso} isn't a country Fluid knows. Run \\`fluid payments onboarding options countries\\`.`,\n );\n }\n }\n\n // ---- upload documents and turn them into attribute changes\n const entityPatch: Record<string, unknown> = { ...plan.entity };\n const bankPatch: Record<string, unknown> = { ...plan.bank };\n const ownerPatch: Record<string, unknown> = { ...plan.owner };\n const underwritingPatch: Record<string, unknown> = { ...plan.underwriting };\n const existingUnderwriting = (snapshot.info.underwriting_info ??\n {}) as Record<string, unknown>;\n\n const patches: Record<\n string,\n { patch: Record<string, unknown>; existing: Record<string, unknown> }\n > = {\n entity: { patch: entityPatch, existing: entity ?? {} },\n bank: { patch: bankPatch, existing: bank ?? {} },\n owner: { patch: ownerPatch, existing: owner ?? {} },\n underwriting: { patch: underwritingPatch, existing: existingUnderwriting },\n };\n\n for (const [attr, link] of Object.entries(plan.underwritingLinks)) {\n const current = (underwritingPatch[attr] ??\n existingUnderwriting[attr] ??\n {}) as FileRef;\n underwritingPatch[attr] = { ...current, link };\n }\n\n for (const file of plan.files) {\n const attr = attributeOf(file.key);\n const target = patches[file.field.group];\n if (!target) continue;\n const ref = await uploadDocument(\n client,\n companyId,\n await readLocal(file.path),\n documentTypeOf(attr),\n );\n\n if (file.field.type === \"file\") {\n target.patch[`${attr}_file_url`] = ref.file_url;\n target.patch[`${attr}_file_name`] = ref.file_name;\n } else if (file.field.type === \"link_or_file\") {\n const current = (target.patch[attr] ??\n target.existing[attr] ??\n {}) as FileRef;\n target.patch[attr] = { ...current, ...ref };\n } else {\n const item: FileRef =\n attr === \"government_issued_ids\"\n ? { ...ref, file_type: targets.idType }\n : ref;\n let current = (target.patch[attr] ??\n (targets.replaceFiles ? [] : target.existing[attr]) ??\n []) as FileRef[];\n // A new kind of ID replaces the old one rather than mixing documents.\n if (\n attr === \"government_issued_ids\" &&\n current.some((c) => c.file_type !== targets.idType)\n )\n current = [];\n target.patch[attr] = [...current, item];\n }\n }\n\n try {\n // ---- entity\n if (entityTouched) {\n if (entity) {\n const res = await client.put<{ entity: Entity }>(\n `${base(companyId)}/entities/${entity.id}`,\n { entity: entityPatch },\n );\n entity = res.entity ?? entity;\n saved.push({ record: \"entity\", id: entity.id, action: \"updated\" });\n } else {\n if (\n snapshot.entities.length === 0 &&\n entityPatch[\"primary\"] === undefined\n )\n entityPatch[\"primary\"] = true;\n const res = await client.post<{ entity: Entity }>(\n `${base(companyId)}/entities`,\n { entity: entityPatch },\n );\n entity = res.entity;\n saved.push({\n record: \"entity\",\n id: entity?.id ?? null,\n action: \"created\",\n });\n }\n }\n const defaultEntityId = (entity ?? primaryEntity(snapshot.entities))?.id;\n const needEntity = (what: string): number => {\n if (defaultEntityId === undefined) {\n throw new OnboardingError(\n `Add the legal entity first (--set entity.legal_name=...), then ${what}.`,\n );\n }\n return defaultEntityId;\n };\n\n // ---- bank account\n if (bankTouched) {\n if (bank) {\n const res = await client.put<{ bank_account: BankAccount }>(\n `${base(companyId)}/bank_accounts/${bank.id}`,\n { bank_account: bankPatch },\n );\n saved.push({\n record: \"bank\",\n id: res.bank_account?.id ?? bank.id,\n action: \"updated\",\n });\n } else {\n bankPatch[\"entity_id\"] ??= needEntity(\"add a bank account\");\n if (\n snapshot.bankAccounts.length === 0 &&\n bankPatch[\"primary\"] === undefined\n )\n bankPatch[\"primary\"] = true;\n const res = await client.post<{ bank_account: BankAccount }>(\n `${base(companyId)}/bank_accounts`,\n { bank_account: bankPatch },\n );\n saved.push({\n record: \"bank\",\n id: res.bank_account?.id ?? null,\n action: \"created\",\n });\n }\n }\n\n // ---- person\n if (ownerTouched) {\n if (owner) {\n const res = await client.put<{ owner: Owner }>(\n `${base(companyId)}/owners/${owner.id}`,\n { owner: ownerPatch },\n );\n saved.push({\n record: \"owner\",\n id: res.owner?.id ?? owner.id,\n action: \"updated\",\n });\n } else {\n ownerPatch[\"entity_id\"] ??= needEntity(\"add a person\");\n if (\n !onboardingContact(snapshot.owners) &&\n ownerPatch[\"onboarding_contact\"] === undefined\n ) {\n ownerPatch[\"onboarding_contact\"] = true;\n }\n const res = await client.post<{ owner: Owner }>(\n `${base(companyId)}/owners`,\n { owner: ownerPatch },\n );\n saved.push({\n record: \"owner\",\n id: res.owner?.id ?? null,\n action: \"created\",\n });\n }\n }\n\n // ---- onboarding info: answers, underwriting, countries\n const info: Record<string, unknown> = { ...plan.info };\n if (Object.keys(underwritingPatch).length > 0)\n info[\"underwriting_info\"] = underwritingPatch;\n if (Object.keys(plan.countries).length > 0) {\n info[\"countries_info\"] = mergeCountries(\n existingCountries,\n catalogue,\n plan.countries,\n () => needEntity(\"add a country\"),\n );\n }\n if (Object.keys(info).length > 0) {\n await putInfo(client, snapshot, info);\n saved.push({ record: \"onboarding_info\", id: null, action: \"updated\" });\n }\n } catch (error) {\n if (saved.length === 0) throw error;\n throw partialSave(saved, error);\n }\n\n return saved;\n}\n\n/** A write failed after earlier ones in the same `set` were saved. Say\n * exactly what was kept, so a retry doesn't create a record twice. */\nfunction partialSave(saved: SavedRecord[], error: unknown): OnboardingError {\n const body = (error as { body?: Record<string, unknown> | null }).body;\n const reason =\n typeof body?.[\"error_message\"] === \"string\"\n ? (body[\"error_message\"] as string)\n : error instanceof Error\n ? error.message\n : String(error);\n const kept = saved\n .map((r) => `${r.record}${r.id !== null ? ` ${r.id}` : \"\"} ${r.action}`)\n .join(\", \");\n return new OnboardingError(\n `Partly saved: ${kept}. The next write failed: ${reason} Run \\`fluid payments onboarding show\\`, then retry only what's still missing, targeting created records by id rather than with \"new\".`,\n {\n saved,\n failure: {\n ...(typeof (error as { status?: unknown }).status === \"number\"\n ? { status: (error as { status: number }).status }\n : {}),\n ...(body?.[\"errors\"] !== undefined ? { errors: body[\"errors\"] } : {}),\n },\n },\n );\n}\n\ninterface CountryWire {\n id: number;\n iso: string;\n name?: string | null;\n currency_code?: string | null;\n}\n\nexport async function listCountries(\n client: OnboardingClient,\n): Promise<CountryWire[]> {\n const res = await client.get<CountryWire[] | { countries?: CountryWire[] }>(\n \"/api/countries\",\n );\n return Array.isArray(res) ? res : (res.countries ?? []);\n}\n\nfunction mergeCountries(\n existing: readonly CountryInfo[],\n catalogue: readonly CountryWire[],\n changes: Plan[\"countries\"],\n defaultEntity: () => number,\n): CountryInfo[] {\n const merged = existing.map((c) => ({ ...c }));\n\n for (const [iso, change] of Object.entries(changes)) {\n let entry = merged.find((c) => c.country_iso === iso);\n if (!entry) {\n const country = catalogue.find((c) => c.iso.toUpperCase() === iso);\n if (!country)\n throw new OnboardingError(\n `${iso} isn't a country Fluid knows. Run \\`fluid payments onboarding options countries\\`.`,\n );\n entry = {\n country_id: country.id,\n country_iso: iso,\n entity_id:\n typeof change[\"entity_id\"] === \"number\"\n ? change[\"entity_id\"]\n : defaultEntity(),\n currency: country.currency_code ?? \"\",\n settlement_currency: \"\",\n entity_legally_registered: false,\n };\n merged.push(entry);\n }\n Object.assign(entry, change);\n }\n return merged;\n}\n\nasync function putInfo(\n client: OnboardingClient,\n snapshot: Snapshot,\n info: Record<string, unknown>,\n): Promise<void> {\n try {\n await client.put(`${base(snapshot.companyId)}/onboarding_info`, {\n ...(snapshot.version !== null\n ? { onboarding_info_version: snapshot.version }\n : {}),\n onboarding_info: info,\n });\n } catch (error) {\n if ((error as { status?: number }).status === 409) {\n throw new OnboardingError(\n \"Someone else changed the onboarding form since it was read. Run the command again.\",\n );\n }\n throw error;\n }\n}\n\n/** The step keys the admin app records as complete, in its own spelling. */\nconst COMPLETED_STEP_KEYS = [\n \"basic_info\",\n \"business_info\",\n \"legal_entities\",\n \"bank_accounts_i\",\n \"bank_accounts_ii\",\n \"personal_info\",\n \"relevant_persons\",\n \"countries\",\n \"compliance\",\n \"terms_and_conditions\",\n];\n\n/** Refuse while required fields are missing, naming each one. */\nexport function assertComplete(snapshot: Snapshot): void {\n const missing = missingFields(snapshot);\n if (missing.length > 0) {\n throw new OnboardingError(\n `${missing.length} required field(s) are still missing. Run \\`fluid payments onboarding show\\`.`,\n missing.map((m) => ({\n field: m.field,\n ...(m.target ? { target: m.target } : {}),\n message: m.message,\n })),\n );\n }\n}\n\n/**\n * Submit: mark every step complete and accept the terms, which is the\n * moment the server counts the form as submitted. Refuses while anything is\n * missing.\n */\nexport async function submitOnboarding(\n client: OnboardingClient,\n snapshot: Snapshot,\n): Promise<\"submitted\" | \"already_submitted\"> {\n if (isSubmitted(snapshot)) return \"already_submitted\";\n assertComplete(snapshot);\n const steps: Record<string, number> = Object.fromEntries(\n SERVER_STEP_KEYS.map((key) => [key, 100]),\n );\n steps[\"terms_and_conditions\"] = 100;\n await putInfo(client, snapshot, {\n onboarding_steps: steps,\n kyc_flow_current_step: \"terms_and_conditions\",\n kyc_flow_completed_steps: COMPLETED_STEP_KEYS.join(\",\"),\n terms_and_conditions_info: { terms_and_conditions_agreed: true },\n });\n return \"submitted\";\n}\n\nexport type RemovableRecord = \"entity\" | \"bank\" | \"owner\" | \"country\";\n\nexport async function removeRecord(\n client: OnboardingClient,\n snapshot: Snapshot,\n record: RemovableRecord,\n id: string,\n): Promise<{ removed: string; id: string }> {\n const companyId = snapshot.companyId;\n if (record === \"country\") {\n const iso = id.toUpperCase();\n const existing = snapshot.info.countries_info ?? [];\n if (!existing.some((c) => c.country_iso === iso))\n throw new OnboardingError(`${iso} isn't on the form.`);\n await putInfo(client, snapshot, {\n countries_info: existing.filter((c) => c.country_iso !== iso),\n });\n return { removed: \"country\", id: iso };\n }\n const numeric = Number(id);\n if (!Number.isInteger(numeric) || numeric <= 0)\n throw new OnboardingError(`\"${id}\" isn't a record id.`);\n const path = { entity: \"entities\", bank: \"bank_accounts\", owner: \"owners\" }[\n record\n ];\n const list = {\n entity: snapshot.entities,\n bank: snapshot.bankAccounts,\n owner: snapshot.owners,\n }[record];\n findOr(\n list as Array<{ id: number }>,\n numeric,\n record === \"bank\"\n ? \"bank account\"\n : record === \"owner\"\n ? \"person\"\n : \"entity\",\n );\n await client.delete(`${base(companyId)}/${path}/${numeric}`);\n return { removed: record, id: String(numeric) };\n}\n\nexport type OptionList =\n | \"business-types\"\n | \"mcc-codes\"\n | \"countries\"\n | \"currencies\";\nexport const OPTION_LISTS: readonly OptionList[] = [\n \"business-types\",\n \"mcc-codes\",\n \"countries\",\n \"currencies\",\n];\n\nexport async function listOptions(\n client: OnboardingClient,\n list: OptionList,\n country?: string,\n): Promise<unknown> {\n switch (list) {\n case \"business-types\": {\n const res = await client.get<{ business_types?: unknown[] }>(\n \"/api/business_types\",\n country ? { country_code: country.toUpperCase() } : undefined,\n );\n return res.business_types ?? [];\n }\n case \"mcc-codes\": {\n const res = await client.get<{ mcc_codes?: unknown[] }>(\"/api/mcc_codes\");\n return res.mcc_codes ?? [];\n }\n case \"countries\":\n return (await listCountries(client)).map((c) => ({\n iso: c.iso,\n name: c.name ?? null,\n currency: c.currency_code ?? null,\n }));\n case \"currencies\": {\n const res = await client.get<{ currencies?: unknown[] }>(\n \"/api/currencies\",\n );\n return res.currencies ?? [];\n }\n }\n}\n","// Onboarding holds tax IDs, bank accounts, and owners' ID numbers and dates\n// of birth. None of it is ever printed in full.\n\nimport { isSensitive } from \"./fields.js\";\n\n/** Keep only the last four characters, e.g. `*****6789`. Short values and\n * dates are hidden entirely. */\nexport function maskValue(value: unknown): unknown {\n if (value === null || value === undefined || value === \"\") return value;\n const text = String(value);\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(text)) return \"****-**-**\";\n const visible = text.replace(/[^A-Za-z0-9]/g, \"\");\n if (visible.length <= 4) return \"****\";\n return `${\"*\".repeat(Math.min(visible.length - 4, 8))}${visible.slice(-4)}`;\n}\n\n/** Mask a value when its `--set` key is a sensitive field. */\nexport function maskFor(key: string, value: unknown): unknown {\n return isSensitive(key) ? maskValue(value) : value;\n}\n\n/** Copy of a record with every listed attribute masked. */\nexport function maskAttributes<T extends Record<string, unknown>>(\n record: T,\n attributes: readonly string[],\n): T {\n const copy: Record<string, unknown> = { ...record };\n for (const attribute of attributes) {\n if (attribute in copy) copy[attribute] = maskValue(copy[attribute]);\n }\n return copy as T;\n}\n","// Turning `--set key=value` and `--file key=path` into per-record changes.\n\nimport {\n attributeOf,\n fieldFor,\n ID_TYPES,\n type FieldDef,\n type Group,\n type IdType,\n} from \"./fields.js\";\nimport { maskFor } from \"./mask.js\";\nimport { OnboardingError } from \"./types.js\";\n\nexport interface Assignment {\n key: string;\n value: unknown;\n}\n\nexport interface FileAssignment {\n key: string;\n field: FieldDef;\n path: string;\n}\n\n/** Changes grouped by the record they land on. */\nexport interface Plan {\n info: Record<string, unknown>;\n underwriting: Record<string, unknown>;\n /** `privacy_policy.link=...` style edits to link-or-file objects. */\n underwritingLinks: Record<string, string>;\n entity: Record<string, unknown>;\n bank: Record<string, unknown>;\n owner: Record<string, unknown>;\n /** Keyed by upper-case ISO code. */\n countries: Record<string, Record<string, unknown>>;\n files: FileAssignment[];\n}\n\nexport function emptyPlan(): Plan {\n return {\n info: {},\n underwriting: {},\n underwritingLinks: {},\n entity: {},\n bank: {},\n owner: {},\n countries: {},\n files: [],\n };\n}\n\nexport function isEmptyPlan(plan: Plan): boolean {\n return (\n plan.files.length === 0 &&\n [\n plan.info,\n plan.underwriting,\n plan.underwritingLinks,\n plan.entity,\n plan.bank,\n plan.owner,\n plan.countries,\n ].every((part) => Object.keys(part).length === 0)\n );\n}\n\nfunction splitAssignment(raw: string, flag: string): [string, string] {\n const eq = raw.indexOf(\"=\");\n if (eq <= 0)\n throw new OnboardingError(\n `${flag} expects key=value, got \"${raw.split(\"=\")[0]}\".`,\n );\n return [raw.slice(0, eq).trim(), raw.slice(eq + 1)];\n}\n\nconst unknownKey = (key: string) =>\n new OnboardingError(\n `Unknown field \"${key}\". Run \\`fluid payments onboarding fields\\` for the list.`,\n );\n\n/** Coerce a raw string to the field's type. Never quotes a sensitive value\n * back in an error. */\nexport function coerce(field: FieldDef, key: string, raw: string): unknown {\n const value = raw.trim();\n const bad = (expected: string) =>\n new OnboardingError(\n `${key} must be ${expected}${field.sensitive ? \"\" : `, got \"${value}\"`}.`,\n );\n\n switch (field.type) {\n case \"boolean\":\n if (/^(true|yes)$/i.test(value)) return true;\n if (/^(false|no)$/i.test(value)) return false;\n throw bad(\"true or false\");\n case \"number\":\n case \"percent\": {\n const n = Number(value);\n if (value === \"\" || Number.isNaN(n)) throw bad(\"a number\");\n if (field.type === \"percent\" && (n < 0 || n > 100))\n throw bad(\"between 0 and 100\");\n return field.sendAsText ? String(n) : n;\n }\n case \"mcc\": {\n const n = Number(value);\n if (!Number.isInteger(n) || n <= 0)\n throw bad(\"an MCC value from `options mcc-codes`\");\n return n;\n }\n case \"country\":\n if (!/^[A-Za-z]{2}$/.test(value)) throw bad(\"a two-letter country code\");\n return value.toUpperCase();\n case \"currency\":\n if (!/^[A-Za-z]{3}$/.test(value))\n throw bad(\"a three-letter currency code\");\n return value.toUpperCase();\n case \"date\":\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(value) || Number.isNaN(Date.parse(value)))\n throw bad(\"a date as YYYY-MM-DD\");\n return value;\n case \"email\":\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value))\n throw bad(\"an email address\");\n return value;\n case \"url\":\n if (!/^https?:\\/\\/\\S+$/.test(value))\n throw bad(\"a URL starting with http:// or https://\");\n return value;\n case \"phone\":\n if (!/^[\\d\\s\\-+()]{8,}$/.test(value))\n throw bad(\"a phone number with at least 8 digits\");\n return value;\n case \"enum\":\n if (!field.options?.includes(value))\n throw bad(`one of ${field.options?.join(\", \")}`);\n return value;\n case \"yes_no\":\n if (!/^(yes|no)\\b/i.test(value))\n throw bad('\"Yes\", \"No\", or \"Yes - details\"');\n return value;\n case \"file\":\n case \"files\":\n case \"link_or_file\":\n throw new OnboardingError(\n `${key} is a document. Upload it with --file ${key}=<path>.`,\n );\n default:\n if (value === \"\") throw bad(\"non-empty\");\n return value;\n }\n}\n\n/** Parse `--set` and `--file` flags into a plan. */\nexport function buildPlan(\n sets: readonly string[],\n files: readonly string[],\n): Plan {\n const plan = emptyPlan();\n\n for (const raw of sets) {\n const [key, value] = splitAssignment(raw, \"--set\");\n\n const link = /^underwriting\\.(\\w+)\\.link$/.exec(key);\n if (link) {\n const field = fieldFor(`underwriting.${link[1]}`);\n if (field?.type !== \"link_or_file\") throw unknownKey(key);\n const url = value.trim();\n if (!/^https?:\\/\\/\\S+$/.test(url))\n throw new OnboardingError(\n `${key} must be a URL starting with http:// or https://.`,\n );\n plan.underwritingLinks[link[1]!] = url;\n continue;\n }\n\n const field = fieldFor(key);\n if (!field) throw unknownKey(key);\n const coerced = coerce(field, key, value);\n\n const country = /^country\\.([A-Za-z]{2})\\.(\\w+)$/.exec(key);\n if (country) {\n const iso = country[1]!.toUpperCase();\n (plan.countries[iso] ??= {})[country[2]!] = coerced;\n continue;\n }\n const group = field.group as Exclude<Group, \"country\">;\n plan[group][attributeOf(key)] = coerced;\n }\n\n for (const raw of files) {\n const [key, path] = splitAssignment(raw, \"--file\");\n const field = fieldFor(key);\n if (!field || ![\"file\", \"files\", \"link_or_file\"].includes(field.type)) {\n throw new OnboardingError(\n field\n ? `${key} isn't a document; use --set.`\n : `Unknown document \"${key}\". Run \\`fluid payments onboarding fields\\`.`,\n );\n }\n if (!path.trim()) throw new OnboardingError(`--file ${key} needs a path.`);\n plan.files.push({ key, field, path: path.trim() });\n }\n\n return plan;\n}\n\nexport function parseIdType(raw: string | undefined): IdType | undefined {\n if (raw === undefined) return undefined;\n if (!(ID_TYPES as readonly string[]).includes(raw)) {\n throw new OnboardingError(\n `--id-type must be one of ${ID_TYPES.join(\", \")}.`,\n );\n }\n return raw as IdType;\n}\n\n/** What `set` changed, safe to print: sensitive values masked, documents by\n * file name only. */\nexport function describePlan(plan: Plan): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n const add = (group: string, part: Record<string, unknown>) => {\n for (const [attr, value] of Object.entries(part)) {\n const key = `${group}.${attr}`;\n out[key] = maskFor(key, value);\n }\n };\n add(\"info\", plan.info);\n add(\"underwriting\", plan.underwriting);\n for (const [attr, url] of Object.entries(plan.underwritingLinks))\n out[`underwriting.${attr}.link`] = url;\n add(\"entity\", plan.entity);\n add(\"bank\", plan.bank);\n add(\"owner\", plan.owner);\n for (const [iso, part] of Object.entries(plan.countries))\n add(`country.${iso}`, part);\n for (const file of plan.files) {\n const name = file.path.split(/[\\\\/]/).pop();\n const prior = out[file.key];\n out[file.key] = prior\n ? [prior, `uploaded ${name}`].flat()\n : `uploaded ${name}`;\n }\n return out;\n}\n","// What `show` prints: status, the steps, what's missing, and the records on\n// the form with every sensitive value masked.\n\nimport { maskValue } from \"./mask.js\";\nimport {\n missingFields,\n statusOf,\n stepReports,\n termsAgreed,\n type Missing,\n type OnboardingStatus,\n type StepReport,\n} from \"./requirements.js\";\nimport type { Snapshot } from \"./types.js\";\n\nexport interface Summary {\n companyId: number;\n status: OnboardingStatus;\n submitted: boolean;\n termsAgreed: boolean;\n /** True when nothing is missing and `submit` will go through. */\n readyToSubmit: boolean;\n missingCount: number;\n steps: StepReport[];\n missing: Missing[];\n records: {\n entities: Array<Record<string, unknown>>;\n bankAccounts: Array<Record<string, unknown>>;\n people: Array<Record<string, unknown>>;\n countries: Array<Record<string, unknown>>;\n };\n}\n\nexport function summarize(snapshot: Snapshot): Summary {\n const missing = missingFields(snapshot);\n const status = statusOf(snapshot);\n return {\n companyId: snapshot.companyId,\n status,\n submitted: status === \"submitted\",\n termsAgreed: termsAgreed(snapshot),\n readyToSubmit: missing.length === 0 && status !== \"submitted\",\n missingCount: missing.length,\n steps: stepReports(snapshot, missing),\n missing,\n records: {\n entities: snapshot.entities.map((e) => ({\n id: e.id,\n legal_name: e.legal_name ?? null,\n primary: e.primary === true,\n status: e.status ?? null,\n country_iso: e.country_iso ?? null,\n business_identification_number: maskValue(\n e[\"business_identification_number\"] ?? null,\n ),\n })),\n bankAccounts: snapshot.bankAccounts.map((b) => ({\n id: b.id,\n entity_id: b.entity_id,\n bank_name: b[\"bank_name\"] ?? null,\n primary: b.primary === true,\n country_iso: b.country_iso ?? null,\n currency_iso: b[\"currency_iso\"] ?? null,\n account_number: maskValue(b[\"account_number\"] ?? null),\n })),\n people: snapshot.owners.map((o) => ({\n id: o.id,\n entity_id: o.entity_id ?? null,\n full_name: o.full_name ?? null,\n position: o[\"position\"] ?? null,\n onboarding_contact: o.onboarding_contact === true,\n is_beneficial_owner: o.is_beneficial_owner === true,\n percent_ownership: o.percent_ownership ?? null,\n })),\n countries: (snapshot.info.countries_info ?? []).map((c) => ({\n country_iso: c.country_iso,\n currency: c.currency,\n settlement_currency: c.settlement_currency,\n entity_id: c.entity_id,\n entity_legally_registered: c.entity_legally_registered,\n })),\n },\n };\n}\n","// `fluid payments onboarding walk`: the form as a conversation. It asks\n// for each missing field in form order, saves every answer as it goes, and\n// lets a person go back, skip, jump to any step, or change a saved answer.\n// Answers go through the same parsing and saving as `set`.\n\nimport {\n applyPlan,\n listCountries,\n listOptions,\n loadSnapshot,\n onboardingFormLocation,\n onboardingFormUrl,\n signedInAsPerson,\n submitOnboarding,\n termsUrl,\n type FileReader,\n type OnboardingClient,\n} from \"./api.js\";\nimport { buildPlan } from \"./assign.js\";\nimport {\n FIELDS,\n fieldFor,\n ID_TYPES,\n STEPS,\n type FieldDef,\n type IdType,\n type StepId,\n} from \"./fields.js\";\nimport { maskFor } from \"./mask.js\";\nimport {\n missingFields,\n onboardingContact,\n primaryBankAccount,\n primaryEntity,\n type Missing,\n type Target,\n} from \"./requirements.js\";\nimport { summarize } from \"./summary.js\";\nimport {\n NAV_HELP,\n type Choice,\n type Prompter,\n type Question,\n} from \"@fluid-app/fluid-cli\";\nimport type { Snapshot } from \"./types.js\";\n\n/** One question: a field, on a particular record when there are several. */\nexport interface Slot {\n field: string;\n target?: Target;\n /** Why it's being asked, when it's missing. */\n reason?: string;\n}\n\nexport interface WalkResult {\n answered: number;\n skipped: string[];\n status: string;\n readyToSubmit: boolean;\n missingCount: number;\n submitted: boolean;\n /** Set when everything is filled in but a person has to submit. */\n submitUrl?: string;\n}\n\nexport interface WalkDeps {\n api: OnboardingClient;\n companyId: number;\n prompter: Prompter;\n readLocal?: FileReader;\n}\n\nconst slotKey = (slot: Slot) =>\n `${slot.field}|${JSON.stringify(slot.target ?? {})}`;\n\nconst stepName = (id: StepId) => STEPS.find((s) => s.id === id)?.name ?? id;\n\nconst fromMissing = (m: Missing): Slot => ({\n field: m.field,\n ...(m.target ? { target: m.target } : {}),\n reason: m.message,\n});\n\n// ------------------------------------------------------------ saved values\n\nfunction recordFor(snapshot: Snapshot, slot: Slot): Record<string, unknown> | undefined {\n const group = slot.field.split(\".\")[0];\n const t = slot.target ?? {};\n if (group === \"entity\")\n return t.entity\n ? snapshot.entities.find((e) => e.id === t.entity)\n : primaryEntity(snapshot.entities);\n if (group === \"bank\")\n return t.bank\n ? snapshot.bankAccounts.find((b) => b.id === t.bank)\n : primaryBankAccount(snapshot);\n if (group === \"owner\")\n return t.owner\n ? snapshot.owners.find((o) => o.id === t.owner)\n : onboardingContact(snapshot.owners);\n return undefined;\n}\n\n/** The saved value for a slot, or undefined when there's none. */\nexport function savedValue(snapshot: Snapshot, slot: Slot): unknown {\n const [group, ...path] = slot.field.split(\".\");\n const info = snapshot.info ?? {};\n let node: unknown;\n if (group === \"info\") node = info;\n else if (group === \"underwriting\") node = info.underwriting_info ?? {};\n else if (group === \"country\") {\n const iso = path.shift()?.toUpperCase();\n node = (info.countries_info ?? []).find((c) => c.country_iso === iso);\n } else node = recordFor(snapshot, slot);\n for (const part of path) {\n if (node === null || typeof node !== \"object\") return undefined;\n node = (node as Record<string, unknown>)[part];\n }\n return node === null || node === \"\" ? undefined : node;\n}\n\n/** A saved value as one short line, masked when sensitive. */\nexport function display(key: string, value: unknown): string | undefined {\n if (value === undefined) return undefined;\n const masked = maskFor(key, value);\n if (typeof masked === \"boolean\") return masked ? \"Yes\" : \"No\";\n if (Array.isArray(masked))\n return masked.map((v) => display(key, v) ?? \"\").filter(Boolean).join(\", \");\n if (masked && typeof masked === \"object\") {\n const ref = masked as { file_name?: string | null; link?: string | null };\n return ref.link ?? ref.file_name ?? undefined;\n }\n return String(masked);\n}\n\n// ------------------------------------------------------------- questions\n\ntype OptionFetch = () => Promise<Choice[]>;\n\nfunction optionSource(\n api: OnboardingClient,\n snapshot: Snapshot,\n field: FieldDef,\n): OptionFetch | undefined {\n switch (field.type) {\n case \"country\":\n return async () =>\n (await listCountries(api)).map((c) => ({\n title: c.name ? `${c.name} (${c.iso})` : c.iso,\n value: c.iso,\n }));\n case \"currency\":\n return async () =>\n ((await listOptions(api, \"currencies\")) as Array<{ code?: string; name?: string }>)\n .filter((c) => c.code)\n .map((c) => ({ title: `${c.code} — ${c.name ?? \"\"}`, value: c.code! }));\n case \"mcc\":\n return async () =>\n ((await listOptions(api, \"mcc-codes\")) as Array<{ value?: number; name?: string }>)\n .filter((c) => c.value !== undefined)\n .map((c) => ({ title: `${c.name} (${c.value})`, value: String(c.value) }));\n case \"business_type\": {\n const country = primaryEntity(snapshot.entities)?.country_iso ?? undefined;\n return async () =>\n ((await listOptions(api, \"business-types\", country ?? undefined)) as Array<{\n value?: string;\n name?: string;\n }>)\n .filter((c) => c.value)\n .map((c) => ({ title: c.name ?? c.value!, value: c.value! }));\n }\n default:\n return undefined;\n }\n}\n\nconst TYPE_HINTS: Partial<Record<FieldDef[\"type\"], string>> = {\n date: \"YYYY-MM-DD\",\n percent: \"0 to 100\",\n email: \"name@example.com\",\n url: \"https://…\",\n phone: \"with country code\",\n yes_no: 'Yes, No, or \"Yes - details\"',\n file: \"path to the file\",\n files: \"path to the file\",\n link_or_file: \"a https:// link or a file path\",\n};\n\nasync function questionFor(\n slot: Slot,\n field: FieldDef,\n current: string | undefined,\n options: Choice[] | undefined,\n section: string,\n canGoBack: boolean,\n): Promise<Question> {\n const base = { section, message: field.label, current, canGoBack };\n if (field.type === \"boolean\")\n return {\n ...base,\n kind: \"select\",\n choices: [\n { title: \"Yes\", value: \"true\" },\n { title: \"No\", value: \"false\" },\n ],\n };\n if (field.type === \"enum\" && field.options)\n return {\n ...base,\n kind: \"select\",\n choices: field.options.map((o) => ({ title: o, value: o })),\n };\n if (options && options.length > 0)\n return { ...base, kind: \"search\", choices: options, hint: \"type to filter\" };\n const hint = [TYPE_HINTS[field.type], slot.reason].filter(Boolean).join(\" · \");\n return {\n ...base,\n kind: field.sensitive ? \"secret\" : \"text\",\n ...(hint ? { hint } : {}),\n };\n}\n\n// ----------------------------------------------------------------- walk\n\nexport async function walkOnboarding(\n deps: WalkDeps,\n opts: { step?: StepId } = {},\n): Promise<WalkResult> {\n const { api, companyId, prompter } = deps;\n let snapshot = await loadSnapshot(api, companyId);\n const history: Slot[] = [];\n const skipped = new Set<string>();\n const optionCache = new Map<string, Choice[]>();\n let focus = opts.step;\n let forced: Slot | undefined;\n let answered = 0;\n let submitted = false;\n let submitUrl: string | undefined;\n\n prompter.note(NAV_HELP);\n\n const options = async (field: FieldDef): Promise<Choice[] | undefined> => {\n const source = optionSource(api, snapshot, field);\n if (!source) return undefined;\n const cacheKey = field.type === \"business_type\"\n ? `${field.type}:${primaryEntity(snapshot.entities)?.country_iso ?? \"\"}`\n : field.type;\n if (!optionCache.has(cacheKey)) {\n try {\n optionCache.set(cacheKey, await source());\n } catch {\n optionCache.set(cacheKey, []); // fall back to typing the value\n }\n }\n return optionCache.get(cacheKey);\n };\n\n const countryChoices = async (): Promise<Choice[]> => {\n if (!optionCache.has(\"country-pick\")) {\n try {\n optionCache.set(\n \"country-pick\",\n (await listCountries(api)).map((c) => ({\n title: c.name ? `${c.name} (${c.iso})` : c.iso,\n value: c.iso,\n })),\n );\n } catch {\n optionCache.set(\"country-pick\", []);\n }\n }\n return optionCache.get(\"country-pick\")!;\n };\n\n const goBack = (): boolean => {\n const previous = history.pop();\n if (!previous) {\n prompter.note(\"This is the first question.\");\n return false;\n }\n skipped.delete(slotKey(previous));\n forced = previous;\n return true;\n };\n\n /** Save one answer. False (after saying why) when it was refused. */\n const save = async (slot: Slot, field: FieldDef, raw: string): Promise<boolean> => {\n const value = raw.trim();\n let idType: IdType | undefined;\n try {\n let plan;\n if (field.type === \"link_or_file\" && /^https?:\\/\\//i.test(value)) {\n plan = buildPlan([`${slot.field}.link=${value}`], []);\n } else if ([\"file\", \"files\", \"link_or_file\"].includes(field.type)) {\n plan = buildPlan([], [`${slot.field}=${value}`]);\n if (slot.field === \"owner.government_issued_ids\") {\n const choice = await prompter.menu(\n \"Which kind of ID is it?\",\n ID_TYPES.map((t) => ({ title: t.replace(\"_\", \" \"), value: t })),\n );\n if (!choice) return false;\n idType = choice;\n }\n } else {\n plan = buildPlan([`${slot.field}=${value}`], []);\n }\n await applyPlan(\n api,\n snapshot,\n plan,\n {\n entity: slot.target?.entity,\n bank: slot.target?.bank,\n owner: slot.target?.owner,\n idType,\n },\n deps.readLocal,\n );\n } catch (error) {\n prompter.note(\n `Not saved: ${error instanceof Error ? error.message : String(error)}`,\n );\n return false;\n }\n snapshot = await loadSnapshot(api, companyId);\n return true;\n };\n\n /** Pick a field (and a record, when there are several) in a step. */\n const pickInStep = async (step: StepId): Promise<Slot | null> => {\n const fields = FIELDS.filter((f) => f.step === step && !f.key.includes(\"<ISO>\"));\n const slots: Slot[] = fields.map((f) => ({ field: f.key }));\n for (const country of snapshot.info.countries_info ?? []) {\n for (const f of FIELDS.filter((x) => x.step === step && x.key.includes(\"<ISO>\")))\n slots.push({ field: f.key.replace(\"<ISO>\", country.country_iso) });\n }\n if (slots.length === 0) {\n prompter.note(`${stepName(step)} has nothing to change here.`);\n return null;\n }\n const group = slots[0]!.field.split(\".\")[0];\n let target: Target | undefined;\n const records =\n group === \"entity\" ? snapshot.entities\n : group === \"bank\" ? snapshot.bankAccounts\n : group === \"owner\" ? snapshot.owners\n : [];\n if (records.length > 1) {\n const id = await prompter.menu(\n \"Which one?\",\n records.map((r) => ({\n title: String(\n (r as { legal_name?: string }).legal_name ??\n (r as { full_name?: string }).full_name ??\n (r as { country_iso?: string }).country_iso ??\n `#${r.id}`,\n ),\n value: String(r.id),\n })),\n );\n if (!id) return null;\n target = { [group as \"entity\" | \"bank\" | \"owner\"]: Number(id) };\n }\n const choice = await prompter.menu(\n `${stepName(step)}: which answer?`,\n slots.map((s, i) => {\n const def = fieldFor(s.field)!;\n const saved = display(s.field, savedValue(snapshot, { ...s, target }));\n return {\n title: `${def.label}${saved ? ` — ${saved}` : \" — (empty)\"}`,\n value: String(i),\n };\n }),\n );\n if (choice === null) return null;\n return { ...slots[Number(choice)]!, ...(target ? { target } : {}) };\n };\n\n /** The menu: jump to a step, change an answer, submit, or stop. */\n const openMenu = async (): Promise<\"stay\" | \"moved\" | \"quit\"> => {\n const missing = missingFields(snapshot);\n const action = await prompter.menu(\"What next?\", [\n { title: \"Continue\", value: \"continue\" },\n { title: \"Back to the previous question\", value: \"back\", disabled: history.length === 0 },\n { title: \"Go to a step\", value: \"step\" },\n { title: \"Add a country\", value: \"country\" },\n { title: \"Submit\", value: \"submit\", disabled: missing.length > 0 },\n { title: \"Stop for now (answers are saved)\", value: \"quit\" },\n ]);\n if (action === null || action === \"quit\") return \"quit\";\n if (action === \"back\") return goBack() ? \"moved\" : \"stay\";\n if (action === \"country\") {\n // Ask which country, then its questions, as for a new form's first one.\n forced = { field: \"country.<ISO>.currency\" };\n return \"moved\";\n }\n if (action === \"step\") {\n const step = await prompter.menu(\n \"Which step?\",\n STEPS.filter((s) => s.id !== \"terms-and-conditions\").map((s) => {\n const left = missing.filter((m) => m.step === s.id).length;\n return {\n title: `${left === 0 ? \"✓\" : `${left} left`} ${s.name}`,\n value: s.id,\n };\n }),\n );\n if (step) {\n const left = missing.filter((m) => m.step === step && !skipped.has(slotKey(fromMissing(m))));\n if (left.length > 0) {\n focus = step;\n return \"moved\";\n }\n const slot = await pickInStep(step);\n if (slot) {\n forced = slot;\n return \"moved\";\n }\n }\n }\n if (action === \"submit\" && (await offerSubmit())) return \"quit\";\n return \"stay\";\n };\n\n /** True when the walk is over: submitted, or handed to the admin form. */\n const offerSubmit = async (): Promise<boolean> => {\n if (!(await signedInAsPerson(api))) {\n submitUrl = onboardingFormUrl() ?? undefined;\n prompter.note(\n `Everything is filled in. Submitting records the person who accepts Fluid's terms, so a person has to submit at ${onboardingFormLocation()}, or sign in with \\`fluid login\\` and run this again.`,\n );\n return true;\n }\n const url = await termsUrl(api, companyId);\n const choice = await prompter.menu(\n `Submitting accepts Fluid's payments terms & conditions for the company${url ? ` (${url})` : \"\"}.`,\n [\n { title: \"I've read the terms. Submit\", value: \"submit\" },\n { title: \"Not now\", value: \"later\" },\n ],\n );\n if (choice !== \"submit\") return false;\n try {\n await submitOnboarding(api, snapshot);\n } catch (error) {\n const status = (error as { status?: number }).status;\n if (typeof status === \"number\" && status >= 500) {\n submitUrl = onboardingFormUrl() ?? undefined;\n prompter.note(`The API couldn't record the acceptance. Submit at ${onboardingFormLocation()}.`);\n return true;\n }\n throw error;\n }\n snapshot = await loadSnapshot(api, companyId);\n submitted = true;\n prompter.note(\"Submitted. Fluid's team will review it.\");\n return true;\n };\n\n for (;;) {\n const missing = missingFields(snapshot);\n let slot = forced;\n forced = undefined;\n if (!slot) {\n const open = missing.filter((m) => !skipped.has(slotKey(fromMissing(m))));\n let pool = focus ? open.filter((m) => m.step === focus) : open;\n if (focus && pool.length === 0) {\n prompter.note(`${stepName(focus)} is done.`);\n focus = undefined;\n pool = open;\n }\n slot = pool[0] ? fromMissing(pool[0]) : undefined;\n }\n\n if (!slot) {\n if (missing.length === 0) {\n const choice = await prompter.menu(\"Every required answer is in.\", [\n { title: \"Submit\", value: \"submit\" },\n { title: \"Change an answer\", value: \"menu\" },\n { title: \"Stop for now\", value: \"quit\" },\n ]);\n if (choice === \"submit\" && (await offerSubmit())) break;\n if (choice === \"menu\" && (await openMenu()) !== \"quit\") continue;\n if (choice === \"submit\") continue;\n break;\n }\n const choice = await prompter.menu(\n `${skipped.size} skipped question(s) left.`,\n [\n { title: \"Go through the skipped questions\", value: \"again\" },\n { title: \"Menu…\", value: \"menu\" },\n { title: \"Stop for now\", value: \"quit\" },\n ],\n );\n if (choice === \"again\") {\n skipped.clear();\n continue;\n }\n if (choice === \"menu\" && (await openMenu()) !== \"quit\") continue;\n break;\n }\n\n // A form with no countries yet asks for `country.<ISO>.…`: pick the\n // country first, then ask the real question for it.\n if (slot.field.includes(\"<ISO>\")) {\n // Countries already on the form are changed from their own step, so\n // adding one never lands on (and overwrites) an existing country.\n const existing = new Set(\n (snapshot.info.countries_info ?? []).map((c) => c.country_iso.toUpperCase()),\n );\n const countries = (await countryChoices()).filter((c) => !existing.has(c.value));\n const reply = await prompter.ask({\n section: stepName(\"countries\"),\n message: \"Which country do you sell in? (add more any time with ? → Add a country)\",\n kind: countries.length > 0 ? \"search\" : \"text\",\n ...(countries.length > 0\n ? { choices: countries, hint: \"type to filter\" }\n : { hint: \"two-letter code, e.g. US\" }),\n canGoBack: history.length > 0,\n });\n if (\"nav\" in reply) {\n if (reply.nav === \"quit\") break;\n if (reply.nav === \"back\") {\n if (!goBack()) forced = slot;\n } else if (reply.nav === \"skip\") {\n skipped.add(slotKey(slot));\n history.push(slot);\n } else {\n const after = await openMenu();\n if (after === \"quit\") break;\n if (after === \"stay\") forced = slot;\n }\n continue;\n }\n const iso = reply.value.trim().toUpperCase();\n if (!/^[A-Z]{2}$/.test(iso)) {\n prompter.note(\"Pick a country, or type its two-letter code.\");\n forced = slot;\n continue;\n }\n if (existing.has(iso)) {\n prompter.note(\n `${iso} is already on the form. To change it, open the menu and go to the Countries step.`,\n );\n forced = slot;\n continue;\n }\n forced = { ...slot, field: slot.field.replace(\"<ISO>\", iso) };\n continue;\n }\n\n const field = fieldFor(slot.field);\n if (!field) {\n skipped.add(slotKey(slot));\n continue;\n }\n const step = field.step;\n const left = missing.filter((m) => m.step === step).length;\n const current = display(slot.field, savedValue(snapshot, slot));\n const question = await questionFor(\n slot,\n field,\n current,\n await options(field),\n `${stepName(step)}${left > 0 ? ` · ${left} left` : \"\"}`,\n history.length > 0,\n );\n const reply = await prompter.ask(question);\n\n if (\"nav\" in reply) {\n if (reply.nav === \"quit\") break;\n if (reply.nav === \"back\") {\n if (!goBack()) forced = slot;\n continue;\n }\n if (reply.nav === \"skip\") {\n skipped.add(slotKey(slot));\n history.push(slot);\n continue;\n }\n // menu: come back to this question unless the menu moved elsewhere\n const after = await openMenu();\n if (after === \"quit\") break;\n if (after === \"stay\") forced = slot;\n continue;\n }\n\n if (reply.value.trim() === \"\") {\n if (current !== undefined) {\n history.push(slot); // Enter keeps the saved answer\n } else {\n prompter.note(\"Type an answer, or > to skip.\");\n forced = slot;\n }\n continue;\n }\n if (await save(slot, field, reply.value)) {\n answered += 1;\n history.push(slot);\n } else {\n forced = slot;\n }\n }\n\n const after = summarize(snapshot);\n return {\n answered,\n skipped: [...skipped].map((k) => k.split(\"|\")[0]!),\n status: after.status,\n readyToSubmit: after.readyToSubmit,\n missingCount: after.missingCount,\n submitted,\n ...(submitUrl ? { submitUrl } : {}),\n };\n}\n","import type { Command } from \"commander\";\nimport prompts from \"prompts\";\nimport type { CommandContext, FluidPlugin } from \"@fluid-app/fluid-cli\";\nimport { createDomainCommand } from \"@fluid-app/fluid-cli\";\n\nimport {\n applyPlan,\n currentCompanyId,\n listOptions,\n loadSnapshot,\n OPTION_LISTS,\n parseTarget,\n providerStatuses,\n removeRecord,\n submitOnboarding,\n termsUrl,\n assertComplete,\n onboardingFormLocation,\n onboardingFormUrl,\n signedInAsPerson,\n type OnboardingClient,\n type OptionList,\n type RemovableRecord,\n} from \"./api.js\";\nimport { buildPlan, describePlan, isEmptyPlan, parseIdType } from \"./assign.js\";\nimport {\n FIELDS,\n ID_TYPES,\n MAX_UPLOAD_BYTES,\n STEPS,\n type Group,\n type StepId,\n} from \"./fields.js\";\nimport { assertInteractive, terminalPrompter } from \"@fluid-app/fluid-cli\";\nimport { summarize } from \"./summary.js\";\nimport { walkOnboarding } from \"./walk.js\";\nimport { OnboardingError } from \"./types.js\";\n\nasync function client(ctx: CommandContext): Promise<OnboardingClient> {\n return (await ctx.getClient()) as unknown as OnboardingClient;\n}\n\n/**\n * Changes to the onboarding form need an explicit yes. Scripts and agents\n * pass `--yes`; an interactive terminal is asked. With neither, nothing runs.\n */\nexport async function confirmChange(\n question: string,\n yes: boolean,\n interactive: boolean = Boolean(process.stdin.isTTY),\n): Promise<void> {\n if (yes) return;\n if (!interactive)\n throw new OnboardingError(`${question} Pass --yes to confirm.`);\n const answer = await prompts({\n type: \"confirm\",\n name: \"ok\",\n message: question,\n initial: false,\n });\n if (!answer.ok) throw new OnboardingError(\"Cancelled.\");\n}\n\n/**\n * Print a failure as JSON on stderr and exit non-zero. The API's error body\n * names fields and reasons, never the submitted values, so its `errors` are\n * passed through as `details`.\n */\nexport function fail(\n err: unknown,\n write: (text: string) => void = (t) => process.stderr.write(t),\n): void {\n const status =\n typeof (err as { status?: unknown }).status === \"number\"\n ? (err as { status: number }).status\n : undefined;\n const body = (err as { body?: Record<string, unknown> | null }).body;\n const apiDetail =\n body && (body[\"errors\"] ?? body[\"error\"] ?? body[\"error_message\"]);\n const message =\n typeof body?.[\"error_message\"] === \"string\"\n ? (body[\"error_message\"] as string)\n : typeof apiDetail === \"string\"\n ? apiDetail\n : err instanceof Error\n ? err.message\n : String(err);\n const details =\n err instanceof OnboardingError && err.details !== undefined\n ? err.details\n : apiDetail && typeof apiDetail === \"object\"\n ? apiDetail\n : undefined;\n write(\n JSON.stringify({\n error: message,\n ...(status ? { status } : {}),\n ...(details !== undefined ? { details } : {}),\n }) + \"\\n\",\n );\n process.exitCode = 1;\n}\n\nfunction run(action: () => Promise<void>): Promise<void> {\n return action().catch((err) => fail(err));\n}\n\nconst collect = (value: string, previous: string[] = []): string[] => [\n ...previous,\n value,\n];\n\nconst GROUPS: readonly Group[] = [\n \"info\",\n \"entity\",\n \"bank\",\n \"owner\",\n \"country\",\n \"underwriting\",\n];\n\nexport function registerOnboardingCommands(\n parent: Command,\n ctx: CommandContext,\n): void {\n const onboarding = parent\n .command(\"onboarding\")\n .description(\n \"Payments onboarding (KYC): see what's missing, fill it in, and submit\",\n );\n\n onboarding\n .command(\"show\")\n .description(\n \"Status, each step, the required fields still missing, and the records on the form (sensitive values masked)\",\n )\n .option(\n \"--step <id>\",\n `Only list what's missing in one step: ${STEPS.map((s) => s.id).join(\", \")}`,\n )\n .action((opts: { step?: string }) =>\n run(async () => {\n if (opts.step && !STEPS.some((s) => s.id === opts.step)) {\n throw new OnboardingError(\n `--step must be one of ${STEPS.map((s) => s.id).join(\", \")}.`,\n );\n }\n const api = await client(ctx);\n const companyId = await currentCompanyId(api);\n const snapshot = await loadSnapshot(api, companyId);\n const summary = summarize(snapshot);\n const missing = opts.step\n ? summary.missing.filter((m) => m.step === (opts.step as StepId))\n : summary.missing;\n ctx.output({\n ...summary,\n missing,\n termsUrl: summary.termsAgreed\n ? undefined\n : await termsUrl(api, companyId),\n providers: summary.submitted\n ? await providerStatuses(api, companyId)\n : undefined,\n });\n }),\n );\n\n onboarding\n .command(\"fields\")\n .description(\n \"The full field schema: keys for --set/--file, types, options, and when each is required\",\n )\n .option(\"--group <group>\", `Only one group: ${GROUPS.join(\", \")}`)\n .option(\n \"--required\",\n \"Only fields that are always or conditionally required\",\n false,\n )\n .action((opts: { group?: string; required: boolean }) =>\n run(async () => {\n if (opts.group && !(GROUPS as readonly string[]).includes(opts.group)) {\n throw new OnboardingError(\n `--group must be one of ${GROUPS.join(\", \")}.`,\n );\n }\n const fields = FIELDS.filter(\n (f) =>\n (!opts.group || f.group === opts.group) &&\n (!opts.required || f.required !== \"optional\"),\n );\n ctx.output({\n steps: STEPS,\n targets: {\n entity:\n \"--entity <id|new>; defaults to the primary legal entity, created if there is none\",\n bank: \"--bank <id|new>; defaults to the primary bank account, created if there is none\",\n owner:\n \"--owner <id|new>; defaults to the onboarding contact (you), created if there is none\",\n country:\n \"country.<ISO>.<field>, e.g. country.US.currency=USD; adds the country if it's new\",\n },\n documents: {\n flag: \"--file <key>=<path>\",\n maxBytes: MAX_UPLOAD_BYTES,\n multiFile:\n \"files-type documents add to what's there; pass --replace-files to start over\",\n governmentIdTypes: ID_TYPES,\n linkOrFile:\n \"link_or_file documents take a URL with --set <key>.link=<url> or a file with --file\",\n },\n fields,\n });\n }),\n );\n\n onboarding\n .command(\"options <list>\")\n .description(`Values for choice fields: ${OPTION_LISTS.join(\", \")}`)\n .option(\"--country <iso>\", \"business-types: the types for one country\")\n .action((list: string, opts: { country?: string }) =>\n run(async () => {\n if (!(OPTION_LISTS as readonly string[]).includes(list)) {\n throw new OnboardingError(\n `List must be one of ${OPTION_LISTS.join(\", \")}.`,\n );\n }\n ctx.output(\n await listOptions(\n await client(ctx),\n list as OptionList,\n opts.country,\n ),\n );\n }),\n );\n\n onboarding\n .command(\"set\")\n .description(\n \"Save fields and upload documents, then print what's still missing (changes live data)\",\n )\n .option(\n \"--set <key=value>\",\n \"A field from `fields`, e.g. entity.legal_name=Acme Inc (repeatable)\",\n collect,\n [],\n )\n .option(\n \"--file <key=path>\",\n \"Upload a document, e.g. entity.business_license=./license.pdf (repeatable)\",\n collect,\n [],\n )\n .option(\"--entity <id|new>\", \"Which legal entity entity.* fields go to\")\n .option(\"--bank <id|new>\", \"Which bank account bank.* fields go to\")\n .option(\"--owner <id|new>\", \"Which person owner.* fields go to\")\n .option(\n \"--id-type <type>\",\n `Government ID type for owner.government_issued_ids: ${ID_TYPES.join(\", \")}`,\n )\n .option(\n \"--replace-files\",\n \"Replace a multi-file document's files instead of adding to them\",\n false,\n )\n .option(\"--yes\", \"Confirm without a prompt\", false)\n .action(\n (opts: {\n set: string[];\n file: string[];\n entity?: string;\n bank?: string;\n owner?: string;\n idType?: string;\n replaceFiles: boolean;\n yes: boolean;\n }) =>\n run(async () => {\n const plan = buildPlan(opts.set, opts.file);\n if (isEmptyPlan(plan)) {\n throw new OnboardingError(\n \"Pass fields with --set key=value or documents with --file key=path.\",\n );\n }\n const targets = {\n entity: parseTarget(\"--entity\", opts.entity),\n bank: parseTarget(\"--bank\", opts.bank),\n owner: parseTarget(\"--owner\", opts.owner),\n idType: parseIdType(opts.idType),\n replaceFiles: opts.replaceFiles,\n };\n const api = await client(ctx);\n const companyId = await currentCompanyId(api);\n const snapshot = await loadSnapshot(api, companyId);\n const count = opts.set.length + opts.file.length;\n await confirmChange(\n `Save ${count} onboarding change(s) for company ${companyId}?`,\n opts.yes,\n );\n const saved = await applyPlan(api, snapshot, plan, targets);\n const after = summarize(await loadSnapshot(api, companyId));\n ctx.output({\n saved,\n changed: describePlan(plan),\n status: after.status,\n readyToSubmit: after.readyToSubmit,\n missingCount: after.missingCount,\n steps: after.steps,\n missing: after.missing,\n });\n }),\n );\n\n onboarding\n .command(\"walk\")\n .description(\n \"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)\",\n )\n .option(\"--step <id>\", `Start at a step: ${STEPS.map((s) => s.id).join(\", \")}`)\n .action((opts: { step?: string }) =>\n run(async () => {\n assertInteractive(\"`show` to see what's missing and `set` to fill it in\");\n const step = opts.step as StepId | undefined;\n if (step && !STEPS.some((s) => s.id === step)) {\n throw new OnboardingError(\n `Unknown step \"${step}\". Use one of: ${STEPS.map((s) => s.id).join(\", \")}.`,\n );\n }\n const api = await client(ctx);\n const companyId = await currentCompanyId(api);\n ctx.output(\n await walkOnboarding(\n { api, companyId, prompter: terminalPrompter() },\n { step },\n ),\n );\n }),\n );\n\n onboarding\n .command(\"remove <record> <id>\")\n .description(\n \"Remove a legal entity, bank account, or person by id, or a country by ISO code (changes live data)\",\n )\n .option(\"--yes\", \"Confirm without a prompt\", false)\n .action((record: string, id: string, opts: { yes: boolean }) =>\n run(async () => {\n const records: readonly RemovableRecord[] = [\n \"entity\",\n \"bank\",\n \"owner\",\n \"country\",\n ];\n if (!(records as readonly string[]).includes(record)) {\n throw new OnboardingError(\n `Record must be one of ${records.join(\", \")}.`,\n );\n }\n const api = await client(ctx);\n const snapshot = await loadSnapshot(api, await currentCompanyId(api));\n await confirmChange(\n `Remove ${record} ${id} from the onboarding form?`,\n opts.yes,\n );\n ctx.output(\n await removeRecord(api, snapshot, record as RemovableRecord, id),\n );\n }),\n );\n\n onboarding\n .command(\"submit\")\n .description(\n \"Accept Fluid's terms and submit the form for review; refused while anything is missing (changes live data)\",\n )\n .option(\n \"--accept-terms\",\n \"Accept Fluid's payments terms & conditions for the company (required)\",\n false,\n )\n .option(\"--yes\", \"Confirm without a prompt\", false)\n .action((opts: { acceptTerms: boolean; yes: boolean }) =>\n run(async () => {\n const api = await client(ctx);\n const companyId = await currentCompanyId(api);\n const snapshot = await loadSnapshot(api, companyId);\n const before = summarize(snapshot);\n if (before.submitted) {\n ctx.output({\n status: \"submitted\",\n alreadySubmitted: true,\n providers: await providerStatuses(api, companyId),\n });\n return;\n }\n assertComplete(snapshot);\n if (!(await signedInAsPerson(api))) {\n // Submitting records who accepted the terms. A company API token\n // has no person behind it, so hand the last step to the admin form.\n ctx.output({\n status: \"ready_to_submit\",\n submitted: false,\n submitUrl: onboardingFormUrl(),\n submitAt: onboardingFormLocation(),\n reason:\n \"Every required field is filled in. Submitting records the person who accepts Fluid's terms, so a person has to submit: open the form at submitAt and submit there, or sign in with `fluid login` (email) and run this again.\",\n });\n return;\n }\n if (!opts.acceptTerms) {\n const url = await termsUrl(api, companyId);\n throw new OnboardingError(\n `Submitting accepts Fluid's payments terms & conditions for the company${url ? ` (${url})` : \"\"}. Read them, then pass --accept-terms.`,\n );\n }\n await confirmChange(\n `Accept the terms and submit payments onboarding for company ${companyId}?`,\n opts.yes,\n );\n try {\n await submitOnboarding(api, snapshot);\n } catch (error) {\n const status = (error as { status?: number }).status;\n if (typeof status === \"number\" && status >= 500) {\n throw new OnboardingError(\n `The API couldn't record the acceptance. Submit from the onboarding form instead: ${onboardingFormLocation()}`,\n );\n }\n throw error;\n }\n ctx.output({\n status: \"submitted\",\n submitted: true,\n providers: await providerStatuses(api, companyId),\n });\n }),\n );\n}\n\nconst plugin: FluidPlugin = {\n name: \"@fluid-app/fluid-cli-payments\",\n version: \"0.1.0\",\n register(ctx) {\n ctx.program.addCommand(\n createDomainCommand(\n \"payments\",\n \"Payments onboarding: what's missing, fill it in, and submit\",\n registerOnboardingCommands,\n ),\n );\n },\n};\n\nexport default plugin;\n"],"mappings":";;;;;AAwBA,MAAa,QAAqD;CAChE;EAAE,IAAI;EAAiB,MAAM;EAAc;CAC3C;EAAE,IAAI;EAAiB,MAAM;EAAiB;CAC9C;EAAE,IAAI;EAAkB,MAAM;EAAkB;CAChD;EAAE,IAAI;EAAiB,MAAM;EAAiB;CAC9C;EAAE,IAAI;EAAiB,MAAM;EAAiB;CAC9C;EAAE,IAAI;EAAoB,MAAM;EAAoB;CACpD;EAAE,IAAI;EAAa,MAAM;EAAa;CACtC;EAAE,IAAI;EAAgB,MAAM;EAAgB;CAC5C;EAAE,IAAI;EAAwB,MAAM;EAAsB;CAC3D;AAyCD,MAAM,KACJ,KACA,MACA,OACA,MACA,WAAwB,UACxB,QAA2B,EAAE,MACf;CACd;CACA,OAAO,IAAI,MAAM,IAAI,CAAC;CACtB;CACA;CACA;CACA;CACA,GAAG;CACJ;AAED,MAAM,MAAM;AACZ,MAAM,SAAS;AAEf,MAAM,cAAc;CAClB,CAAC,UAAU,SAAS;CACpB,CAAC,WAAW,UAAU;CACtB,CAAC,YAAY,WAAW;CACxB,CAAC,OAAO,MAAM;CACd,CAAC,gBAAgB,eAAe;CAChC,CAAC,aAAa,YAAY;CAC3B;AAED,MAAM,iBAAiB;CACrB,CAAC,UAAU,SAAS;CACpB,CAAC,aAAa,YAAY;CAC1B,CAAC,cAAc,cAAc;CAC7B,CAAC,eAAe,cAAc;CAC/B;AAED,MAAa,SAA8B;CAEzC,EACE,oCACA,WACA,wDACA,gBACD;CACD,EACE,sBACA,WACA,gCACA,iBACA,eACA,EAAE,MAAM,4CAA4C,CACrD;CACD,EACE,kCACA,WACA,0DACA,gBACD;CACD,EACE,6BACA,WACA,iEACA,gBACD;CACD,EACE,2BACA,WACA,+CACA,gBACD;CACD,EACE,0BACA,WACA,oCACA,gBACD;CACD,EACE,iCACA,WACA,oDACA,iBACA,WACD;CACD,EACE,sCACA,QACA,uBACA,iBACA,YACA,EAAE,SAAS,CAAC,UAAU,UAAU,EAAE,CACnC;CACD,EACE,+BACA,WACA,6EACA,iBACA,WACD;CAGD,EAAE,qBAAqB,UAAU,sBAAsB,gBAAgB;CACvE,EACE,uBACA,UACA,sBACA,iBACA,WACD;CACD,EACE,yBACA,iBACA,gDACA,gBACD;CACD,EACE,yCACA,UACA,2DACA,iBACA,UACA,EAAE,WAAW,MAAM,CACpB;CACD,EACE,8BACA,UACA,gCACA,gBACD;CACD,EACE,gCACA,QACA,sCACA,gBACD;CACD,EACE,gBACA,SACA,qCACA,gBACD;CACD,EACE,6BACA,UACA,+BACA,iBACA,WACD;CACD,EACE,kBACA,OACA,8CACA,gBACD;CACD,EACE,sBACA,OACA,4DACA,gBACD;CACD,EACE,wBACA,OACA,oCACA,iBACA,WACD;CACD,EAAE,mBAAmB,UAAU,6BAA6B,gBAAgB;CAC5E,EACE,mBACA,UACA,6BACA,iBACA,WACD;CACD,EAAE,eAAe,UAAU,mBAAmB,gBAAgB;CAC9D,EACE,mBACA,UACA,gCACA,gBACD;CACD,EAAE,sBAAsB,UAAU,0BAA0B,gBAAgB;CAC5E,EACE,sBACA,WACA,0CACA,gBACD;CACD,EACE,4CACA,QACA,qCACA,gBACD;CACD,EAAE,2BAA2B,QAAQ,oBAAoB,gBAAgB;CACzE,EACE,oCACA,QACA,6BACA,gBACD;CACD,EAAE,cAAc,QAAQ,gBAAgB,iBAAiB,eAAe,EACtE,MAAM,4BACP,CAAC;CACF,EACE,8CACA,SACA,mDACA,iBACA,WACD;CAGD,EAAE,kBAAkB,UAAU,aAAa,gBAAgB;CAC3D,EAAE,oBAAoB,UAAU,uBAAuB,gBAAgB;CACvE,EACE,uBACA,UACA,0BACA,iBACA,UACA,EAAE,WAAW,MAAM,CACpB;CACD,EACE,uBACA,UACA,kBACA,iBACA,eACA;EAAE,MAAM;EAA0B,WAAW;EAAM,CACpD;CACD,EACE,kBACA,UACA,kBACA,iBACA,eACA,EAAE,MAAM,8BAA8B,CACvC;CACD,EAAE,oBAAoB,WAAW,2BAA2B,gBAAgB;CAC5E,EACE,qBACA,YACA,yCACA,gBACD;CACD,EAAE,aAAa,UAAU,aAAa,gBAAgB;CACtD,EACE,kBACA,UACA,wEACA,iBACA,WACD;CACD,EACE,sCACA,SACA,wCACA,gBACD;CACD,EACE,oCACA,QACA,+BACA,gBACD;CAGD,EAAE,mBAAmB,UAAU,mBAAmB,gBAAgB;CAClE,EAAE,oBAAoB,SAAS,cAAc,gBAAgB;CAC7D,EACE,uBACA,QACA,8BACA,iBACA,UACA,EAAE,WAAW,MAAM,CACpB;CACD,EAAE,wBAAwB,UAAU,kBAAkB,gBAAgB;CACtE,EAAE,qBAAqB,WAAW,0BAA0B,gBAAgB;CAC5E,EACE,qBACA,WACA,mCACA,gBACD;CACD,EAAE,wBAAwB,UAAU,uBAAuB,gBAAgB;CAC3E,EAAE,cAAc,UAAU,aAAa,gBAAgB;CACvD,EAAE,eAAe,UAAU,0BAA0B,gBAAgB;CACrE,EAAE,kBAAkB,UAAU,iBAAiB,gBAAgB;CAC/D,EAAE,eAAe,SAAS,SAAS,gBAAgB;CACnD,EACE,+BACA,UACA,sCACA,iBACA,UACA,EAAE,WAAW,MAAM,CACpB;CACD,EAAE,kBAAkB,UAAU,aAAa,gBAAgB;CAC3D,EACE,qBACA,UACA,yBACA,iBACA,WACD;CACD,EACE,8BACA,WACA,qBACA,oBACA,WACD;CACD,EACE,6BACA,WACA,oBACA,oBACA,WACD;CACD,EACE,2BACA,WACA,2DACA,oBACA,eACA,EAAE,MAAM,qCAAqC,CAC9C;CACD,EACE,iCACA,WACA,wBACA,oBACA,WACD;CACD,EACE,4BACA,WACA,oDACA,iBACA,WACD;CACD,EACE,mBACA,UACA,uEACA,oBACA,WACD;CACD,EACE,+BACA,SACA,mHACA,gBACD;CACD,EACE,4BACA,QACA,8CACA,gBACD;CAGD,EACE,0BACA,YACA,8CACA,YACD;CACD,EACE,qCACA,YACA,8BACA,YACD;CACD,EACE,2BACA,UACA,4EACA,YACD;CACD,EACE,2CACA,WACA,gEACA,YACD;CAGD,EACE,oCACA,QACA,yBACA,eACD;CACD,EACE,qCACA,QACA,kDACA,eACD;CACD,EACE,4CACA,UACA,6DACA,eACD;CACD,EACE,mCACA,WACA,2GACA,eACD;CACD,EACE,8CACA,UACA,iCACA,eACD;CACD,EACE,oCACA,UACA,uBACA,eACD;CACD,EACE,qCACA,WACA,iEACA,eACD;CACD,EACE,qCACA,WACA,4DACA,eACD;CACD,EACE,oCACA,QACA,mCACA,eACD;CACD,EACE,oCACA,QACA,gCACA,eACD;CACD,EACE,uCACA,QACA,sCACA,eACD;CACD,EACE,uCACA,QACA,mCACA,eACD;CACD,EACE,gCACA,QACA,gDACA,eACD;CACD,EACE,gCACA,QACA,6CACA,eACD;CACD,EACE,uCACA,UACA,8CACA,eACD;CACD,EACE,oDACA,QACA,6CACA,eACD;CACD,EACE,gDACA,QACA,kDACA,eACD;CACD,EACE,uDACA,QACA,wCACA,eACD;CACD,EACE,8CACA,UACA,mDACA,eACD;CACD,EACE,2CACA,QACA,0DACA,eACD;CACD,EACE,sCACA,QACA,wCACA,eACD;CACD,EACE,2BACA,UACA,6CACA,eACD;CACD,EACE,kCACA,UACA,iCACA,eACD;CACD,EACE,qCACA,gBACA,0DACA,eACD;CACD,EACE,wCACA,gBACA,oDACA,eACD;CACD,EACE,+BACA,gBACA,2CACA,eACD;CAGD,EACE,wCACA,QACA,4CACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,6CACA,QACA,mBACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,0CACA,QACA,4BACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,4CACA,QACA,yCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,6CACA,QACA,qCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,kCACA,SACA,qBACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,oDACA,UACA,oEACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,4CACA,UACA,gDACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,qDACA,UACA,uDACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,4CACA,gBACA,+BACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,wDACA,QACA,yCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,0CACA,QACA,wCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,0CACA,QACA,gCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,iDACA,QACA,wCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,wDACA,QACA,8CACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,+CACA,UACA,yDACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,iDACA,QACA,6BACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,qCACA,gBACA,kCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,6CACA,gBACA,2BACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,iDACA,gBACA,oCACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,sCACA,gBACA,yBACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,wCACA,gBACA,2BACA,gBACA,eACA,EAAE,MAAM,KAAK,CACd;CACD,EACE,qDACA,QACA,uCACA,gBACA,WACD;CACD,EACE,uCACA,QACA,yBACA,gBACA,WACD;CACD,EACE,4CACA,QACA,8BACA,gBACA,WACD;CACD,EACE,mDACA,WACA,gCACA,gBACA,YACA,EAAE,YAAY,MAAM,CACrB;CACD,EACE,gDACA,WACA,iCACA,gBACA,YACA,EAAE,YAAY,MAAM,CACrB;CACD,EACE,yDACA,WACA,oDACA,gBACA,YACA,EAAE,YAAY,MAAM,CACrB;CACD,EACE,gDACA,QACA,mCACA,gBACA,WACD;CACD,EACE,wCACA,QACA,gBACA,gBACA,WACD;CACD,EACE,2CACA,QACA,6BACA,gBACA,WACD;CACD,EACE,kDACA,QACA,qCACA,gBACA,WACD;CACD,EACE,2CACA,QACA,8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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,84 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-app/fluid-cli-payments",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Fluid CLI plugin for payments onboarding — see what is missing, fill in fields and documents, and submit",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"README.md"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.mts",
|
|
16
|
+
"default": "./dist/index.mjs"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@fluid-app/fluid-cli": "0.1.35",
|
|
25
|
+
"commander": "^12.0.0",
|
|
26
|
+
"prompts": "^2.4.2"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@fluid-app/typescript-config": "0.0.0",
|
|
30
|
+
"@swc/core": "^1.15.18",
|
|
31
|
+
"@swc/jest": "^0.2.39",
|
|
32
|
+
"@types/jest": "^29.5.14",
|
|
33
|
+
"@types/node": "24.10.12",
|
|
34
|
+
"@types/prompts": "^2.4.9",
|
|
35
|
+
"jest": "^29.7.0",
|
|
36
|
+
"tsdown": "^0.21.0",
|
|
37
|
+
"typescript": "^5"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=24.0.0"
|
|
41
|
+
},
|
|
42
|
+
"nx": {
|
|
43
|
+
"targets": {
|
|
44
|
+
"typecheck": {
|
|
45
|
+
"dependsOn": [
|
|
46
|
+
{
|
|
47
|
+
"target": "build",
|
|
48
|
+
"projects": [
|
|
49
|
+
"@fluid-app/fluid-cli"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"test": {
|
|
55
|
+
"dependsOn": [
|
|
56
|
+
{
|
|
57
|
+
"target": "build",
|
|
58
|
+
"projects": [
|
|
59
|
+
"@fluid-app/fluid-cli"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"build": {
|
|
65
|
+
"dependsOn": [
|
|
66
|
+
"typecheck",
|
|
67
|
+
{
|
|
68
|
+
"target": "build",
|
|
69
|
+
"projects": [
|
|
70
|
+
"@fluid-app/fluid-cli"
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"build": "tsdown",
|
|
79
|
+
"dev": "tsdown --watch",
|
|
80
|
+
"typecheck": "tsgo --noEmit",
|
|
81
|
+
"lint": "oxlint",
|
|
82
|
+
"test": "jest"
|
|
83
|
+
}
|
|
6
84
|
}
|