fresh-squeezy 0.1.20 → 0.2.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/dist/cli.js +186 -75
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/main.ts","../src/cli/commands/augment.ts","../src/core/errors.ts","../src/core/config.ts","../src/core/http.ts","../src/resources/affiliates.ts","../src/resources/checkouts.ts","../src/resources/customers.ts","../src/resources/discountRedemptions.ts","../src/resources/discounts.ts","../src/resources/files.ts","../src/resources/licenseKeyInstances.ts","../src/resources/licenseKeys.ts","../src/resources/orderItems.ts","../src/resources/orders.ts","../src/resources/prices.ts","../src/resources/products.ts","../src/resources/registry.ts","../src/resources/stores.ts","../src/resources/subscriptionInvoices.ts","../src/resources/subscriptionItems.ts","../src/resources/subscriptions.ts","../src/resources/usageRecords.ts","../src/resources/users.ts","../src/resources/variants.ts","../src/resources/webhooks.ts","../src/resources/invokeOp.ts","../src/core/mode.ts","../src/validate/rules.ts","../src/validate/probe.ts","../src/validate/connection.ts","../src/validate/discount.ts","../src/validate/licenseKey.ts","../src/validate/product.ts","../src/validate/store.ts","../src/validate/subscriptionPlan.ts","../src/core/equality.ts","../src/support/manifest.ts","../src/validate/webhook.ts","../src/validate/doctor.ts","../src/createFreshSqueezy.ts","../src/cli/errors.ts","../src/cli/render.ts","../src/cli/prompts.ts","../src/cli/resourceDiscovery.ts","../src/cli/resolveStores.ts","../src/cli/commands/doctor.ts","../src/cli/commands/init.ts","../src/cli/brand.ts","../src/cli/commands/launcher.ts","../src/cli/projectInstall.ts","../src/cli/commands/resourceOps.ts","../src/cli/commands/bulkOps.ts","../src/cli/commands/validate.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { Command } from \"commander\";\nimport dotenv from \"dotenv\";\nimport type { Mode } from \"../core/types.js\";\nimport type { OpVerb } from \"../resources/registry.js\";\nimport { runAugmentCommand } from \"./commands/augment.js\";\nimport { runDoctorCommand } from \"./commands/doctor.js\";\nimport { runInitCommand } from \"./commands/init.js\";\nimport { runLauncherCommand } from \"./commands/launcher.js\";\nimport { runResourceOpCommand } from \"./commands/resourceOps.js\";\nimport { type ValidateTarget, runValidateCommand } from \"./commands/validate.js\";\nimport { renderCliError } from \"./errors.js\";\n\n/**\n * CLI entry. Wires commander subcommands to their handlers. Each handler\n * returns an exit code; the wrapper below forwards it to `process.exit`.\n *\n * Store resolution is a CLI concern: `--store-ids 1,2,3` (CSV) for scripts,\n * `--all-stores` for \"run against every reachable store\", or interactive\n * multi-select when stdin is a TTY and neither flag is supplied. The library\n * API deliberately stays single-store-per-call.\n */\n\ndotenv.config();\n\nconst OP_VERBS: OpVerb[] = [\n \"get\",\n \"list\",\n \"create\",\n \"update\",\n \"delete\",\n \"cancel\",\n \"refund\",\n \"generate-invoice\",\n \"current-usage\",\n];\n\nconst parseMode = (value: string): Mode => {\n if (value === \"test\" || value === \"live\") return value;\n throw new Error(`Mode must be \"test\" or \"live\", got \"${value}\"`);\n};\n\nconst parseCsv = (value: string): string[] =>\n value\n .split(\",\")\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0);\n\nconst readPackageVersion = (): string => {\n const candidates = [\n new URL(\"../package.json\", import.meta.url),\n new URL(\"../../package.json\", import.meta.url),\n ];\n\n for (const candidate of candidates) {\n try {\n const pkg = JSON.parse(readFileSync(candidate, \"utf8\")) as { version?: unknown };\n if (typeof pkg.version === \"string\") return pkg.version;\n } catch {\n // Source runs from src/cli; the built binary runs from dist.\n }\n }\n\n return \"0.0.0\";\n};\n\nconst isInteractive = Boolean(process.stdin.isTTY);\nconst packageVersion = readPackageVersion();\n\ninterface SharedCliOpts {\n mode?: Mode;\n storeIds?: string[];\n allStores?: boolean;\n productId?: string;\n webhookUrl?: string;\n discountId?: string;\n licenseKeyId?: string;\n variantId?: string;\n json?: boolean;\n}\n\ninterface DoctorCliOpts extends SharedCliOpts {\n allResources?: boolean;\n}\n\ninterface ResourceOpCliOpts {\n mode?: Mode;\n id?: string;\n storeIds?: string[];\n parentId?: string;\n body?: string;\n bodyFile?: string;\n yes?: boolean;\n json?: boolean;\n all?: boolean;\n ids?: string[];\n match?: string;\n dryRun?: boolean;\n}\n\n/** Store-flag shapes reused by validate targets. */\ntype StoreFlagKind = \"none\" | \"multi\" | \"ownership\";\n\ninterface ValidateCommandSpec {\n name: ValidateTarget;\n description: string;\n stores: StoreFlagKind;\n required?: [flag: string, description: string];\n /** Extra store-ids help text when `stores` is multi/ownership. */\n storeIdsHelp?: string;\n}\n\nconst VALIDATE_COMMANDS: ValidateCommandSpec[] = [\n {\n name: \"connection\",\n description: \"Check that the API key authenticates\",\n stores: \"none\",\n },\n {\n name: \"store\",\n description: \"Check one or more stores are reachable\",\n stores: \"multi\",\n storeIdsHelp: \"Comma-separated store IDs\",\n },\n {\n name: \"product\",\n description: \"Check a product is published with at least one variant\",\n stores: \"ownership\",\n required: [\"--product-id <id>\", \"Product ID to validate\"],\n storeIdsHelp: \"Expected owning store IDs (first is used for cross-check)\",\n },\n {\n name: \"webhook\",\n description: \"Check a webhook is registered with the recommended events\",\n stores: \"multi\",\n required: [\"--webhook-url <url>\", \"Public webhook URL\"],\n storeIdsHelp: \"Comma-separated store IDs\",\n },\n {\n name: \"discount\",\n description: \"Check a discount code is valid and redeemable\",\n stores: \"ownership\",\n required: [\"--discount-id <id>\", \"Discount ID to validate\"],\n storeIdsHelp: \"Store ID for ownership check (first ID used)\",\n },\n {\n name: \"license-key\",\n description: \"Check a license key is active and not at its activation limit\",\n stores: \"ownership\",\n required: [\"--license-key-id <id>\", \"License key ID to validate\"],\n storeIdsHelp: \"Store ID for ownership check (first ID used)\",\n },\n {\n name: \"subscription-plan\",\n description: \"Check a subscription plan variant has valid billing interval and trial config\",\n stores: \"ownership\",\n required: [\"--variant-id <id>\", \"Variant ID of the subscription plan\"],\n storeIdsHelp: \"Store ID for ownership check (first ID used)\",\n },\n];\n\nconst exitWith = async (code: Promise<number> | number): Promise<void> => {\n process.exit(await code);\n};\n\nconst toValidateOptions = (opts: SharedCliOpts) => ({\n mode: opts.mode,\n storeIds: opts.storeIds,\n allStores: Boolean(opts.allStores),\n productId: opts.productId,\n webhookUrl: opts.webhookUrl,\n discountId: opts.discountId,\n licenseKeyId: opts.licenseKeyId,\n variantId: opts.variantId,\n json: Boolean(opts.json),\n isInteractive,\n});\n\nconst attachModeJson = (cmd: Command): Command =>\n cmd\n .option(\"-m, --mode <mode>\", \"test or live\", parseMode)\n .option(\"--json\", \"Emit machine-readable JSON\");\n\nconst attachValidateFlags = (cmd: Command, spec: ValidateCommandSpec): Command => {\n if (spec.required) cmd.requiredOption(spec.required[0], spec.required[1]);\n\n if (spec.stores === \"multi\") {\n cmd\n .option(\"--store-ids <ids>\", spec.storeIdsHelp ?? \"Comma-separated store IDs\", parseCsv)\n .option(\"--all-stores\", \"Run against every reachable store\");\n } else if (spec.stores === \"ownership\") {\n cmd.option(\n \"--store-ids <ids>\",\n spec.storeIdsHelp ?? \"Store ID for ownership check (first ID used)\",\n parseCsv,\n );\n }\n\n return attachModeJson(cmd);\n};\n\nconst program = new Command();\n\nprogram\n .name(\"fresh-squeezy\")\n .description(\n \"Dual-mode Lemon Squeezy CLI: doctor/validate pre-flight + docs-backed resource ops (get/list/create/…)\",\n )\n .version(packageVersion)\n .option(\"--no-install\", \"Skip adding fresh-squeezy to devDependencies before guided setup\")\n .showSuggestionAfterError()\n .showHelpAfterError(\"\\nRun `fresh-squeezy --help` for examples.\");\n\nprogram.addHelpText(\n \"after\",\n `\nStart (doctor setup):\n fresh-squeezy add as a dev dependency, then run guided setup\n fresh-squeezy --no-install run guided setup without editing package.json\n fresh-squeezy doctor --all-stores --all-resources\n fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\n\nOps (docs-backed Lemon Squeezy API only — products/variants are read-only):\n fresh-squeezy ops --list\n fresh-squeezy get product --id 42 --json\n fresh-squeezy list webhook --store-ids 12\n fresh-squeezy create webhook --body-file webhook.json --yes\n fresh-squeezy cancel subscription --id 9 --yes\n fresh-squeezy refund order --id 100 --yes\n fresh-squeezy generate-invoice order --id 100 --yes\n\nSafety: delete/cancel/refund always need --yes (or TTY confirm); live-mode writes need --yes too.\nBodies are JSON:API documents via --body or --body-file (not flat flags).\n\nStore selection:\n Use --store-ids 12,34 for explicit stores, --all-stores for automation, or run in a TTY to pick stores interactively.\n`,\n);\n\nprogram.action(async (opts: { install?: boolean }) => {\n if (!isInteractive) {\n process.stderr.write(\n renderCliError(\"`fresh-squeezy` guided setup requires an interactive terminal.\", [\n \"fresh-squeezy doctor --all-stores\",\n \"fresh-squeezy validate connection\",\n ]),\n );\n process.exit(2);\n }\n\n await exitWith(\n runLauncherCommand({\n isInteractive,\n install: opts.install,\n packageVersion,\n }),\n );\n});\n\nconst doctor = program\n .command(\"doctor\")\n .description(\"Run the full integration doctor\")\n .option(\"-m, --mode <mode>\", \"test or live\", parseMode)\n .option(\"--store-ids <ids>\", \"Comma-separated store IDs (e.g. 1,2,3)\", parseCsv)\n .option(\"--all-stores\", \"Run against every reachable store, no prompt\")\n .option(\n \"--all-resources\",\n \"Discover and validate every supported resource in each selected store\",\n )\n .option(\"--product-id <id>\", \"Product to validate\")\n .option(\"--webhook-url <url>\", \"Webhook URL to validate\")\n .option(\"--discount-id <id>\", \"Discount to validate\")\n .option(\"--license-key-id <id>\", \"License key to validate\")\n .option(\"--variant-id <id>\", \"Subscription plan variant to validate\")\n .option(\"--json\", \"Emit machine-readable JSON\")\n .action(async (opts: DoctorCliOpts) => {\n await exitWith(\n runDoctorCommand({\n ...toValidateOptions(opts),\n allResources: Boolean(opts.allResources),\n }),\n );\n });\n\ndoctor.addHelpText(\n \"after\",\n `\nExamples:\n fresh-squeezy doctor\n fresh-squeezy doctor --all-stores\n fresh-squeezy doctor --all-stores --all-resources\n fresh-squeezy doctor --store-ids 12 --product-id 987 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\n fresh-squeezy doctor --all-stores --all-resources --json\n`,\n);\n\nconst validate = program.command(\"validate\").description(\"Run a single validator\");\n\nvalidate.addHelpText(\n \"after\",\n `\nExamples:\n fresh-squeezy validate connection\n fresh-squeezy validate store --all-stores\n fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\n\nTargets:\n connection, store, product, webhook, discount, license-key, subscription-plan\n`,\n);\n\nfor (const spec of VALIDATE_COMMANDS) {\n attachValidateFlags(validate.command(spec.name).description(spec.description), spec).action(\n async (opts: SharedCliOpts) => {\n await exitWith(runValidateCommand(spec.name, toValidateOptions(opts)));\n },\n );\n}\n\nprogram\n .command(\"init\")\n .description(\"Interactive setup: ask for credentials, pick a store, run doctor\")\n .option(\"--env-file <path>\", \"Where to write credentials (default: .env)\")\n .action(async (opts: { envFile?: string }) => {\n await exitWith(runInitCommand({ envFile: opts.envFile, isInteractive }));\n });\n\nconst types = program\n .command(\"types\")\n .description(\n \"Type-augmentation utilities for the official Lemon Squeezy SDK and hand-rolled types\",\n );\n\ntypes\n .command(\"augment\")\n .description(\n \"Generate a .d.ts that intersects your Lemon Squeezy resource types with changelog fields fresh-squeezy tracks.\",\n )\n .option(\"--out <path>\", \"Output path (default: lemonsqueezy.augment.d.ts in CWD)\")\n .option(\"--force\", \"Emit the generic file even when @lemonsqueezy/lemonsqueezy.js is detected\")\n .action(async (opts: { out?: string; force?: boolean }) => {\n await exitWith(runAugmentCommand({ out: opts.out, force: Boolean(opts.force) }));\n });\n\nprogram\n .command(\"ops\")\n .description(\"List docs-backed resource ops (Lemon Squeezy official API matrix)\")\n .option(\"--list\", \"Print the full verb matrix\", true)\n .option(\"--json\", \"Emit machine-readable JSON\")\n .action(async (opts: { json?: boolean }) => {\n await exitWith(\n runResourceOpCommand({\n resource: \"\",\n verb: \"get\",\n listCatalog: true,\n json: Boolean(opts.json),\n }),\n );\n });\n\nconst BULK_VERBS: readonly OpVerb[] = [\"delete\", \"cancel\", \"refund\"];\n\n/** Per-verb `--help` footer; bulk verbs get --all/--ids/--dry-run examples. */\nconst opHelpText = (verb: OpVerb): string => {\n if (!BULK_VERBS.includes(verb)) {\n return `\\nExample:\\n fresh-squeezy ${verb} <resource> --id 42 --json\\n`;\n }\n const r = verb === \"delete\" ? \"discount\" : verb === \"cancel\" ? \"subscription\" : \"order\";\n return `\nExamples:\n fresh-squeezy ${verb} ${r} --id 42 --yes\n fresh-squeezy ${verb} ${r} --ids 1,2,3 --yes\n fresh-squeezy ${verb} ${r} --all --store-ids 12 --dry-run\n fresh-squeezy ${verb} ${r} --all --store-ids 12 --match TEST --yes --json\n\nBulk notes:\n --all lists every page first, then asks once (TTY) or needs --yes (non-TTY).\n Store falls back to LEMON_SQUEEZY_STORE_ID when --store-ids is omitted.\n Exit codes: 0 ok, 1 some items failed, 2 usage error / declined.\n`;\n};\n\nfor (const verb of OP_VERBS) {\n program\n .command(`${verb} <resource>`)\n .description(`Docs-backed ${verb} for a Lemon Squeezy resource`)\n .option(\"-m, --mode <mode>\", \"test or live\", parseMode)\n .option(\"--id <id>\", \"Resource id\")\n .option(\n \"--store-ids <ids>\",\n \"Comma-separated store IDs (first used for list filters)\",\n parseCsv,\n )\n .option(\n \"--parent-id <id>\",\n \"Parent resource id for nested lists (product, order, subscription, …)\",\n )\n .option(\"--body <json>\", \"JSON:API body string\")\n .option(\"--body-file <path>\", \"Path to JSON:API body file\")\n .option(\"--yes\", \"Skip confirm; required for live writes and destructive ops when non-TTY\")\n .option(\"--json\", \"Emit machine-readable JSON\")\n .option(\"--all\", \"Bulk: apply to every item from `list` (delete, cancel, refund)\")\n .option(\"--ids <ids>\", \"Bulk: comma-separated ids (delete, cancel, refund)\", parseCsv)\n .option(\"--match <text>\", \"Bulk: with --all, only items whose name/code/url contain <text>\")\n .option(\"--dry-run\", \"Bulk: show what would be affected; send nothing\")\n .addHelpText(\"after\", opHelpText(verb))\n .action(async (resource: string, opts: ResourceOpCliOpts) => {\n await exitWith(\n runResourceOpCommand({\n verb,\n resource,\n mode: opts.mode,\n id: opts.id,\n storeIds: opts.storeIds,\n parentId: opts.parentId,\n body: opts.body,\n bodyFile: opts.bodyFile,\n yes: Boolean(opts.yes),\n json: Boolean(opts.json),\n isInteractive,\n all: Boolean(opts.all),\n ids: opts.ids,\n match: opts.match,\n dryRun: Boolean(opts.dryRun),\n }),\n );\n });\n}\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n const hints = message.includes(\"Mode must be\")\n ? [\"fresh-squeezy doctor --mode test\", \"fresh-squeezy doctor --mode live\"]\n : [\"fresh-squeezy --help\"];\n process.stderr.write(renderCliError(message, hints));\n process.exit(2);\n});\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\n\n/**\n * Options for `fresh-squeezy types:augment`.\n *\n * All paths are CLI-friendly defaults: the command runs in the consumer's\n * CWD, reads their `package.json`, and writes the augmentation `.d.ts`\n * next to it (or wherever they redirect with `--out`).\n */\nexport interface AugmentCommandOptions {\n /** Project root. Defaults to `process.cwd()`. */\n cwd?: string;\n /** Output path for the augmentation file. Defaults to `lemonsqueezy.augment.d.ts`. */\n out?: string;\n /** Suppress \"no SDK detected\" message and emit the generic file anyway. */\n force?: boolean;\n}\n\n/**\n * Two flavours of file we emit.\n *\n * - `with-sdk` — the consumer has `@lemonsqueezy/lemonsqueezy.js` installed.\n * The file imports types from the SDK and intersects them with our\n * `Latest*Fields`. Consumers reach the augmented type via\n * `LemonSqueezyAugmented[\"subscription\"]`.\n *\n * - `generic` — the consumer's resource types are home-rolled or come from\n * another SDK. The file re-exports `WithLatestLemonSqueezyFields<T, R>`\n * so consumers can wire their own base type.\n */\ntype Flavour = \"with-sdk\" | \"generic\";\n\n/**\n * Generate a `.d.ts` file in the consumer's project so their existing\n * Lemon Squeezy resource types pick up fields fresh-squeezy already knows\n * about (per the changelog audit in `src/support/manifest.ts`).\n *\n * Writes a single file. Idempotent: re-running overwrites with the\n * current version, so a CI step can safely regenerate after each\n * fresh-squeezy upgrade. Returns 0 on success, 2 on I/O failure.\n */\nexport const runAugmentCommand = async (options: AugmentCommandOptions = {}): Promise<number> => {\n const cwd = options.cwd ?? process.cwd();\n const outPath = resolve(cwd, options.out ?? \"lemonsqueezy.augment.d.ts\");\n\n try {\n const flavour = await detectFlavour(cwd, options.force ?? false);\n const contents = renderAugmentationFile(flavour);\n await mkdir(dirname(outPath), { recursive: true });\n await writeFile(outPath, contents, \"utf8\");\n\n process.stdout.write(`fresh-squeezy: wrote ${outPath} (${flavour}).\\n`);\n if (flavour === \"with-sdk\") {\n process.stdout.write(\n `Use it via: import type { LemonSqueezyAugmented } from \"./lemonsqueezy.augment\";\\n`,\n );\n } else {\n process.stdout.write(\n `Use it via: import type { WithLatestLemonSqueezyFields } from \"./lemonsqueezy.augment\";\\n`,\n );\n }\n return 0;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`fresh-squeezy: ${message}\\n`);\n return 2;\n }\n};\n\nconst detectFlavour = async (cwd: string, force: boolean): Promise<Flavour> => {\n if (force) return \"generic\";\n const pkgPath = resolve(cwd, \"package.json\");\n if (!existsSync(pkgPath)) return \"generic\";\n\n const raw = await readFile(pkgPath, \"utf8\");\n const pkg = JSON.parse(raw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n };\n\n const deps = {\n ...(pkg.dependencies ?? {}),\n ...(pkg.devDependencies ?? {}),\n ...(pkg.peerDependencies ?? {}),\n };\n\n return \"@lemonsqueezy/lemonsqueezy.js\" in deps ? \"with-sdk\" : \"generic\";\n};\n\nconst renderAugmentationFile = (flavour: Flavour): string => {\n const header = `/**\n * Generated by \\`fresh-squeezy types:augment\\` — re-run after upgrading\n * fresh-squeezy to refresh the field set.\n *\n * Why this file exists: the live Lemon Squeezy API has acquired fields\n * since the SDK / hand-rolled types in this repo were last updated\n * (e.g. \\`payment_processor\\`, \\`tax_inclusive\\`, \\`refunded_amount*\\`,\n * \\`setup_fee*\\`, \\`unit_price_decimal\\`, checkout color options,\n * \\`skip_trial\\`, \\`variant_quantities\\`, subscription item proration\n * flags, and order item \\`quantity\\`). fresh-squeezy also generates a\n * broad resource map from Lemon Squeezy's object docs, so newly documented\n * attributes can flow in after \\`npm run generate:api-types\\`.\n *\n * To wire it in:\n * 1. Make sure your tsconfig.json's \"include\" covers this file (most\n * do by default if it's in the project root or under \"src\").\n * 2. Import the augmented type from this file instead of the raw SDK\n * type — see the example at the bottom of this file.\n */\n\n`;\n\n if (flavour === \"with-sdk\") {\n return `${header}import type {\n Subscription,\n SubscriptionInvoice,\n Order,\n OrderItem,\n Variant,\n Price,\n Checkout,\n} from \"@lemonsqueezy/lemonsqueezy.js\";\nimport type {\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n WithLatestLemonSqueezyFields,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n} from \"fresh-squeezy\";\n\n/**\n * One-stop reference for resources fresh-squeezy has wider knowledge of\n * than the official SDK. The shape mirrors the SDK's response envelope\n * (\\`{ data: { attributes: ... } }\\`) — only the inner attributes are\n * widened. Request-only field sets (e.g. subscription-item update params)\n * are not response documents, so they ship as standalone \\`Latest*Fields\\`\n * exports below rather than as entries here.\n */\nexport interface LemonSqueezyAugmented {\n subscription: AugmentResponse<Subscription, LatestSubscriptionFields>;\n subscriptionInvoice: AugmentResponse<SubscriptionInvoice, LatestSubscriptionInvoiceFields>;\n order: AugmentResponse<Order, LatestOrderFields>;\n orderItem: AugmentResponse<OrderItem, LatestOrderItemFields>;\n variant: AugmentResponse<Variant, LatestVariantFields>;\n price: AugmentResponse<Price, LatestPriceFields>;\n checkout: AugmentResponse<Checkout, LatestCheckoutFields>;\n}\n\nexport type {\n WithLatestLemonSqueezyFields,\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n};\n\n/**\n * Helper that walks the official SDK's response envelope and intersects\n * the inner \\`attributes\\` record with the supplied field set.\n */\ntype AugmentResponse<T, Fields> = T extends {\n data: infer Data;\n}\n ? Data extends { attributes: infer Attrs }\n ? Omit<T, \"data\"> & {\n data: Omit<Data, \"attributes\"> & { attributes: Attrs & Fields };\n }\n : T\n : T;\n\n/* Example:\n *\n * import type { LemonSqueezyAugmented } from \"./lemonsqueezy.augment\";\n *\n * function describe(sub: LemonSqueezyAugmented[\"subscription\"]) {\n * const attrs = sub.data.attributes;\n * console.log(attrs.payment_processor); // ← typed, no manual extension\n * console.log(attrs.urls?.update_customer_portal);\n * }\n */\n`;\n }\n\n return `${header}import type {\n WithLatestLemonSqueezyFields,\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n} from \"fresh-squeezy\";\n\nexport type {\n WithLatestLemonSqueezyFields,\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n};\n\n/* Example with a hand-rolled or third-party type:\n *\n * import type { WithLatestLemonSqueezyFields } from \"./lemonsqueezy.augment\";\n *\n * type MySubscription = WithLatestLemonSqueezyFields<MyExistingSubscription, \"subscription\">;\n *\n * function describe(sub: MySubscription) {\n * console.log(sub.payment_processor); // typed\n * type MyCheckout = WithLatestLemonSqueezyFields<MyExistingCheckout, \"checkout\">;\n * }\n */\n`;\n};\n","/**\n * Unified error type for fresh-squeezy. All HTTP and validation failures that\n * bubble up to consumers pass through this class so caller code can branch on\n * a single `instanceof` check.\n *\n * Why a class over a discriminated union: Node's `fetch` rejections interleave\n * with library errors in user stack traces. A class keeps the stack readable\n * and gives one stable prototype chain for consumer `catch` blocks.\n */\nexport class FreshSqueezyError extends Error {\n public readonly code: string;\n public readonly status?: number;\n public readonly detail?: unknown;\n\n constructor(opts: { code: string; message: string; status?: number; detail?: unknown }) {\n super(opts.message);\n this.name = \"FreshSqueezyError\";\n this.code = opts.code;\n this.status = opts.status;\n this.detail = opts.detail;\n Object.setPrototypeOf(this, FreshSqueezyError.prototype);\n }\n}\n","import { FreshSqueezyError } from \"./errors.js\";\nimport type { FreshSqueezyConfig, Mode, ResolvedConfig } from \"./types.js\";\n\n/**\n * Lemon Squeezy API root. Test and live share the same host — mode is determined\n * by which API key is used. Documented at https://docs.lemonsqueezy.com/api.\n */\nconst DEFAULT_BASE_URL = \"https://api.lemonsqueezy.com\";\n\n/**\n * Env variable names read when a field is not passed explicitly. Consuming\n * products rely on these names being stable — treat them as public API.\n */\nexport const ENV_KEYS = {\n apiKey: \"LEMON_SQUEEZY_API_KEY\",\n storeId: \"LEMON_SQUEEZY_STORE_ID\",\n mode: \"LEMON_SQUEEZY_MODE\",\n} as const;\n\n/**\n * Resolve the user-supplied config against environment variables and defaults.\n *\n * Precedence (highest → lowest): explicit argument → env var → built-in default.\n * Throws `FreshSqueezyError` only for fields that cannot be defaulted (currently\n * just `apiKey`), so callers can surface a clear setup error at construction\n * time rather than at first request.\n */\nexport const resolveConfig = (input: FreshSqueezyConfig = {}): ResolvedConfig => {\n const apiKey = input.apiKey ?? process.env[ENV_KEYS.apiKey];\n if (!apiKey) {\n throw new FreshSqueezyError({\n code: \"MISSING_API_KEY\",\n message: `No API key provided. Pass \\`apiKey\\` or set ${ENV_KEYS.apiKey}.`,\n });\n }\n\n const mode = normalizeMode(input.mode ?? process.env[ENV_KEYS.mode] ?? \"test\");\n const storeIdRaw = input.storeId ?? process.env[ENV_KEYS.storeId];\n\n return {\n apiKey,\n storeId: storeIdRaw == null ? undefined : String(storeIdRaw),\n mode,\n baseUrl: input.baseUrl ?? DEFAULT_BASE_URL,\n fetch: input.fetch ?? globalThis.fetch,\n };\n};\n\nconst normalizeMode = (value: string): Mode => {\n if (value === \"test\" || value === \"live\") return value;\n throw new FreshSqueezyError({\n code: \"INVALID_MODE\",\n message: `Mode must be \"test\" or \"live\", got \"${value}\".`,\n });\n};\n","import { FreshSqueezyError } from \"./errors.js\";\nimport type {\n JsonApiCollection,\n JsonApiDocument,\n JsonApiResource,\n ResolvedConfig,\n} from \"./types.js\";\n\n/**\n * Stable FreshSqueezyError.code values for common HTTP status codes.\n * Unlisted statuses fall through to the JSON:API error `code` or `HTTP_<status>`.\n */\nconst HTTP_STATUS_CODES = {\n 401: \"UNAUTHORIZED\",\n 404: \"NOT_FOUND\",\n 429: \"RATE_LIMITED\",\n} as const;\n\n/**\n * Options for a single HTTP request.\n *\n * `path` is a Lemon Squeezy API path starting with `/v1/...`. The `query`\n * record is serialized via `URLSearchParams` (JSON:API bracket keys such as\n * `filter[store_id]` are accepted as-is and percent-encoded in the final URL).\n */\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n path: string;\n query?: Record<string, string | number | undefined>;\n /** JSON:API document or other request body; stringified when present. */\n body?: unknown;\n signal?: AbortSignal;\n}\n\n/**\n * Lemon Squeezy JSON:API error object. Kept loose because the API occasionally\n * includes extra keys; the fields we surface are the stable ones.\n */\ninterface JsonApiError {\n status?: string;\n code?: string;\n title?: string;\n detail?: string;\n}\n\n/**\n * Low-level HTTP client. Callers usually go through resource/validator helpers,\n * but this is also exposed as the public escape hatch so consumers can reach\n * endpoints fresh-squeezy does not wrap yet.\n *\n * Responsibilities kept in this one place (per plan.md \"one source of truth\n * for transport\"):\n * - auth header injection\n * - query string serialization (JSON:API bracket keys via URLSearchParams)\n * - response parsing + error normalization\n * - surfacing HTTP status in `FreshSqueezyError`\n *\n * Retries, pagination helpers, and rate-limit handling live in separate files\n * so this layer stays small and obvious.\n */\nexport class HttpClient {\n constructor(private readonly config: ResolvedConfig) {}\n\n async request<T>(options: RequestOptions): Promise<T> {\n const url = this.requestUrl(options.path, options.query);\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.config.apiKey}`,\n Accept: \"application/vnd.api+json\",\n };\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/vnd.api+json\";\n }\n\n let httpResponse: Response;\n try {\n httpResponse = await this.config.fetch(url, {\n method: options.method ?? \"GET\",\n headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n signal: options.signal,\n });\n } catch (cause) {\n throw new FreshSqueezyError({\n code: \"NETWORK_ERROR\",\n message: cause instanceof Error ? cause.message : \"Network request failed\",\n detail: cause,\n });\n }\n\n const text = await httpResponse.text();\n const parsed = text.length > 0 ? parseJsonBody(text) : undefined;\n\n if (!httpResponse.ok) {\n throw apiError(httpResponse.status, parsed);\n }\n\n return parsed as T;\n }\n\n /**\n * Fetch a single JSON:API resource and return its `data` object.\n */\n async getResource<TAttr>(path: string): Promise<JsonApiResource<TAttr>> {\n const doc = await this.request<JsonApiDocument<TAttr>>({ path });\n return doc.data;\n }\n\n /**\n * POST a JSON:API document and return the created `data` resource.\n *\n * @param path - API path starting with `/v1/...`.\n * @param body - JSON:API create document.\n * @returns The created resource.\n */\n async postResource<TAttr>(path: string, body: unknown): Promise<JsonApiResource<TAttr>> {\n const doc = await this.request<JsonApiDocument<TAttr>>({ method: \"POST\", path, body });\n return doc.data;\n }\n\n /**\n * PATCH a JSON:API document and return the updated `data` resource.\n *\n * @param path - API path starting with `/v1/...`.\n * @param body - JSON:API update document.\n * @returns The updated resource.\n */\n async patchResource<TAttr>(path: string, body: unknown): Promise<JsonApiResource<TAttr>> {\n const doc = await this.request<JsonApiDocument<TAttr>>({ method: \"PATCH\", path, body });\n return doc.data;\n }\n\n /**\n * DELETE a resource. Lemon Squeezy often returns an empty body on success.\n *\n * @param path - API path starting with `/v1/...`.\n * @returns Nothing — single void return, not a multi-field bag.\n */\n async deleteResource(path: string): Promise<void> {\n await this.request({ method: \"DELETE\", path });\n }\n\n /**\n * Fetch a single page of a JSON:API collection. Most callers want\n * `paginate()` instead — this method is kept for one-shot lookups where\n * the caller knows the result fits in a single page.\n */\n async getCollection<TAttr>(\n path: string,\n query?: RequestOptions[\"query\"],\n ): Promise<JsonApiResource<TAttr>[]> {\n const doc = await this.request<JsonApiCollection<TAttr>>({ path, query });\n return doc.data;\n }\n\n /**\n * Walk a JSON:API collection across every page and concatenate the\n * results. Lemon Squeezy returns 25 items per page by default; without\n * pagination, validators silently miss anything past the first page (e.g.\n * `validateWebhook` on a store with 26+ webhooks would falsely report\n * `WEBHOOK_NOT_FOUND` for any webhook on page 2).\n *\n * Stops as soon as `meta.page.lastPage` is reached. Falls back to a\n * single-page fetch if the API does not surface page metadata.\n *\n * Caller-supplied `page[number]` is honored as the starting page; we\n * advance from there. `page[size]` is left untouched so callers can tune\n * batch size (max 100 per Lemon Squeezy docs).\n */\n async paginate<TAttr>(\n path: string,\n query?: RequestOptions[\"query\"],\n ): Promise<JsonApiResource<TAttr>[]> {\n const startPage = Number(query?.[\"page[number]\"] ?? 1);\n const all: JsonApiResource<TAttr>[] = [];\n\n let pageNumber = startPage;\n while (true) {\n const pagedQuery = { ...(query ?? {}), \"page[number]\": pageNumber };\n const doc = await this.request<JsonApiCollection<TAttr>>({ path, query: pagedQuery });\n all.push(...doc.data);\n\n const lastPage = doc.meta?.page?.lastPage;\n if (lastPage === undefined || pageNumber >= lastPage) return all;\n pageNumber += 1;\n }\n }\n\n private requestUrl(path: string, query?: RequestOptions[\"query\"]): string {\n const url = new URL(path, this.config.baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) continue;\n url.searchParams.append(key, String(value));\n }\n }\n return url.toString();\n }\n}\n\nconst parseJsonBody = (text: string): unknown => {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n};\n\nconst apiError = (status: number, responseBody: unknown): FreshSqueezyError => {\n const errors = extractJsonApiErrors(responseBody);\n const first = errors[0];\n const mapped = HTTP_STATUS_CODES[status as keyof typeof HTTP_STATUS_CODES];\n const code = mapped ?? first?.code ?? `HTTP_${status}`;\n const message =\n first?.detail ?? first?.title ?? `Lemon Squeezy request failed with status ${status}`;\n return new FreshSqueezyError({ code, status, message, detail: responseBody });\n};\n\nconst extractJsonApiErrors = (responseBody: unknown): JsonApiError[] => {\n if (!responseBody || typeof responseBody !== \"object\") return [];\n const errors = (responseBody as { errors?: unknown }).errors;\n if (!Array.isArray(errors)) return [];\n return errors.filter(\n (entry): entry is JsonApiError => typeof entry === \"object\" && entry !== null,\n );\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedAffiliateAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type AffiliateStatus = \"active\" | \"pending\" | \"disabled\";\n\n/**\n * Affiliate attributes added with the 2025-01-21 Affiliates API surface.\n * No validator consumes these yet; the helpers give typed access while\n * preserving the raw request escape hatch for mutations and includes.\n */\nexport interface AffiliateAttributes extends GeneratedAffiliateAttributes {\n store_id: number;\n user_id: number;\n user_name: string;\n user_email: string;\n share_domain: string;\n status: AffiliateStatus;\n application_note?: string | null;\n products?: unknown;\n total_earnings: number;\n unpaid_earnings: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getAffiliate = async (\n http: HttpClient,\n affiliateId: string | number,\n): Promise<JsonApiResource<AffiliateAttributes>> => {\n return http.getResource<AffiliateAttributes>(`/v1/affiliates/${affiliateId}`);\n};\n\nexport const listAffiliatesForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<AffiliateAttributes>[]> => {\n return http.paginate<AffiliateAttributes>(\"/v1/affiliates\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedCheckoutAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type CheckoutLocale =\n | \"bg\"\n | \"hr\"\n | \"cs\"\n | \"da\"\n | \"nl\"\n | \"en\"\n | \"et\"\n | \"fil\"\n | \"fi\"\n | \"fr\"\n | \"de\"\n | \"el\"\n | \"hu\"\n | \"id\"\n | \"it\"\n | \"ja\"\n | \"ko\"\n | \"lv\"\n | \"lt\"\n | \"ms\"\n | \"mt\"\n | \"pl\"\n | \"pt\"\n | \"ro\"\n | \"ru\"\n | \"zh-CN\"\n | \"sk\"\n | \"sl\"\n | \"es\"\n | \"sv\"\n | \"th\"\n | \"tr\"\n | \"vi\";\n\nexport interface CheckoutProductOptions {\n name?: string;\n description?: string;\n media?: string[];\n redirect_url?: string;\n receipt_button_text?: string;\n receipt_link_url?: string;\n receipt_thank_you_note?: string;\n enabled_variants?: number[];\n}\n\nexport interface CheckoutOptions {\n embed?: boolean;\n media?: boolean;\n logo?: boolean;\n desc?: boolean;\n discount?: boolean;\n subscription_preview?: boolean;\n /** Added 2024-03-28. */\n skip_trial?: boolean;\n /** Deprecated 2024-09-04; keep typed so old payloads still compile. */\n dark?: boolean;\n background_color?: string;\n headings_color?: string;\n primary_text_color?: string;\n secondary_text_color?: string;\n links_color?: string;\n borders_color?: string;\n checkbox_color?: string;\n active_state_color?: string;\n button_color?: string;\n button_text_color?: string;\n terms_privacy_color?: string;\n locale?: CheckoutLocale | string | null;\n}\n\nexport interface CheckoutVariantQuantity {\n variant_id: number;\n quantity: number;\n}\n\nexport interface CheckoutData {\n email?: string;\n name?: string;\n billing_address?: {\n country?: string;\n zip?: string;\n };\n tax_number?: string;\n discount_code?: string;\n custom?: Record<string, unknown>;\n /** Added 2023-08-23 for multi-variant checkout quantities. */\n variant_quantities?: CheckoutVariantQuantity[];\n}\n\nexport interface CheckoutPreview {\n currency: string;\n currency_rate: number | string;\n subtotal: number;\n discount_total: number;\n tax: number;\n total: number;\n subtotal_usd: number;\n discount_total_usd: number;\n tax_usd: number;\n total_usd: number;\n subtotal_formatted: string;\n discount_total_formatted: string;\n tax_formatted: string;\n total_formatted: string;\n}\n\nexport interface CheckoutAttributes extends GeneratedCheckoutAttributes {\n store_id: number;\n variant_id: number;\n custom_price?: number | null;\n product_options?: CheckoutProductOptions;\n checkout_options?: CheckoutOptions;\n checkout_data?: CheckoutData;\n preview?: CheckoutPreview;\n expires_at?: string | null;\n url?: string;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve a checkout (GET /v1/checkouts/:id).\n *\n * @param http - Shared API client.\n * @param checkoutId - Checkout id.\n * @returns The checkout resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const checkout = await getCheckout(http, 1);\n * ```\n */\nexport const getCheckout = async (\n http: HttpClient,\n checkoutId: string | number,\n): Promise<JsonApiResource<CheckoutAttributes>> => {\n return http.getResource<CheckoutAttributes>(`/v1/checkouts/${checkoutId}`);\n};\n\n/**\n * List checkouts for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Checkout resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const checkouts = await listCheckoutsForStore(http, 1);\n * ```\n */\nexport const listCheckoutsForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<CheckoutAttributes>[]> => {\n return http.paginate<CheckoutAttributes>(\"/v1/checkouts\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a checkout (POST /v1/checkouts).\n * Docs: https://docs.lemonsqueezy.com/api/checkouts/create-checkout\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document (store + variant relationships).\n * @returns The created checkout (includes `url` for the hosted checkout).\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const checkout = await createCheckout(http, {\n * data: {\n * type: \"checkouts\",\n * attributes: { checkout_data: { email: \"buyer@example.com\" } },\n * relationships: {\n * store: { data: { type: \"stores\", id: \"1\" } },\n * variant: { data: { type: \"variants\", id: \"1\" } },\n * },\n * },\n * });\n * ```\n */\nexport const createCheckout = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<CheckoutAttributes>> => {\n return http.postResource<CheckoutAttributes>(\"/v1/checkouts\", body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedCustomerAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type CustomerStatus =\n | \"subscribed\"\n | \"unsubscribed\"\n | \"archived\"\n | \"requires_verification\"\n | \"invalid_email\"\n | \"bounced\";\n\nexport interface CustomerUrls {\n customer_portal?: string | null;\n}\n\n/**\n * Lemon Squeezy customer attributes. The customer portal URL was called out\n * in the 2023-09-19 changelog and is useful for apps linking users back to\n * billing without another API shape.\n */\nexport interface CustomerAttributes extends GeneratedCustomerAttributes {\n store_id: number;\n name: string;\n email: string;\n status: CustomerStatus;\n city?: string | null;\n region?: string | null;\n country?: string | null;\n total_revenue_currency: number;\n mrr: number;\n status_formatted: string;\n country_formatted?: string | null;\n total_revenue_currency_formatted: string;\n mrr_formatted: string;\n urls?: CustomerUrls;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve a customer (GET /v1/customers/:id).\n *\n * @param http - Shared API client.\n * @param customerId - Customer id.\n * @returns The customer resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customer = await getCustomer(http, 1);\n * ```\n */\nexport const getCustomer = async (\n http: HttpClient,\n customerId: string | number,\n): Promise<JsonApiResource<CustomerAttributes>> => {\n return http.getResource<CustomerAttributes>(`/v1/customers/${customerId}`);\n};\n\n/**\n * List customers for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Customer resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customers = await listCustomersForStore(http, 1);\n * ```\n */\nexport const listCustomersForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<CustomerAttributes>[]> => {\n return http.paginate<CustomerAttributes>(\"/v1/customers\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a customer (POST /v1/customers).\n * Docs: https://docs.lemonsqueezy.com/api/customers/create-customer\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created customer.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customer = await createCustomer(http, {\n * data: {\n * type: \"customers\",\n * attributes: { name: \"Ada\", email: \"ada@example.com\" },\n * relationships: { store: { data: { type: \"stores\", id: \"1\" } } },\n * },\n * });\n * ```\n */\nexport const createCustomer = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<CustomerAttributes>> => {\n return http.postResource<CustomerAttributes>(\"/v1/customers\", body);\n};\n\n/**\n * Update a customer (PATCH /v1/customers/:id).\n * Docs: https://docs.lemonsqueezy.com/api/customers/update-customer\n *\n * @param http - Shared API client.\n * @param customerId - Customer id.\n * @param body - JSON:API update document.\n * @returns The updated customer.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customer = await updateCustomer(http, 1, {\n * data: { type: \"customers\", id: \"1\", attributes: { name: \"Ada Lovelace\" } },\n * });\n * ```\n */\nexport const updateCustomer = async (\n http: HttpClient,\n customerId: string | number,\n body: unknown,\n): Promise<JsonApiResource<CustomerAttributes>> => {\n return http.patchResource<CustomerAttributes>(`/v1/customers/${customerId}`, body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedDiscountRedemptionAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface DiscountRedemptionAttributes extends GeneratedDiscountRedemptionAttributes {\n discount_id: number;\n order_id: number;\n discount_name: string;\n discount_code: string;\n discount_amount: number;\n discount_amount_type: \"percent\" | \"fixed\";\n amount: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getDiscountRedemption = async (\n http: HttpClient,\n discountRedemptionId: string | number,\n): Promise<JsonApiResource<DiscountRedemptionAttributes>> => {\n return http.getResource<DiscountRedemptionAttributes>(\n `/v1/discount-redemptions/${discountRedemptionId}`,\n );\n};\n\nexport const listDiscountRedemptionsForDiscount = async (\n http: HttpClient,\n discountId: string | number,\n): Promise<JsonApiResource<DiscountRedemptionAttributes>[]> => {\n return http.paginate<DiscountRedemptionAttributes>(\"/v1/discount-redemptions\", {\n \"filter[discount_id]\": String(discountId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedDiscountAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of Lemon Squeezy discount attributes used by the discount validator.\n * Full schema at https://docs.lemonsqueezy.com/api/discounts.\n */\nexport interface DiscountAttributes extends GeneratedDiscountAttributes {\n name: string;\n code: string;\n amount: number;\n amount_type: \"percent\" | \"fixed\";\n is_limited_to_products: boolean;\n is_limited_redemptions: boolean;\n max_redemptions: number;\n starts_at: string | null;\n expires_at: string | null;\n status: \"draft\" | \"published\";\n duration: \"once\" | \"repeating\" | \"forever\";\n store_id: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Fetch a single discount by ID. The validator uses the discount's\n * `relationships.store` to confirm ownership against the caller's storeId.\n *\n * @param http - Shared API client.\n * @param discountId - Discount id.\n * @returns The discount resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const discount = await getDiscount(http, 1);\n * ```\n */\nexport const getDiscount = async (\n http: HttpClient,\n discountId: string | number,\n): Promise<JsonApiResource<DiscountAttributes>> => {\n return http.getResource<DiscountAttributes>(`/v1/discounts/${discountId}`);\n};\n\n/**\n * List discounts for a store (GET /v1/discounts?filter[store_id]=…).\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Discount resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const discounts = await listDiscountsForStore(http, 1);\n * ```\n */\nexport const listDiscountsForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<DiscountAttributes>[]> => {\n return http.paginate<DiscountAttributes>(\"/v1/discounts\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a discount (POST /v1/discounts). No update endpoint exists in the API.\n * Docs: https://docs.lemonsqueezy.com/api/discounts/create-discount\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created discount.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const discount = await createDiscount(http, {\n * data: {\n * type: \"discounts\",\n * attributes: { name: \"Launch\", code: \"LAUNCH10\", amount: 10, amount_type: \"percent\" },\n * relationships: { store: { data: { type: \"stores\", id: \"1\" } } },\n * },\n * });\n * ```\n */\nexport const createDiscount = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<DiscountAttributes>> => {\n return http.postResource<DiscountAttributes>(\"/v1/discounts\", body);\n};\n\n/**\n * Delete a discount (DELETE /v1/discounts/:id).\n * Docs: https://docs.lemonsqueezy.com/api/discounts/delete-discount\n *\n * @param http - Shared API client.\n * @param discountId - Discount id.\n * @returns Nothing on success.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * await deleteDiscount(http, 1);\n * ```\n */\nexport const deleteDiscount = async (\n http: HttpClient,\n discountId: string | number,\n): Promise<void> => {\n await http.deleteResource(`/v1/discounts/${discountId}`);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedFileAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Lemon Squeezy file attributes, generated from the public object docs.\n * Exposed so consumers can type file-resource escape-hatch calls without\n * waiting for a hand-written validator.\n */\nexport interface FileAttributes extends GeneratedFileAttributes {}\n\nexport const getFile = async (\n http: HttpClient,\n fileId: string | number,\n): Promise<JsonApiResource<FileAttributes>> => {\n return http.getResource<FileAttributes>(`/v1/files/${fileId}`);\n};\n\nexport const listFilesForVariant = async (\n http: HttpClient,\n variantId: string | number,\n): Promise<JsonApiResource<FileAttributes>[]> => {\n return http.paginate<FileAttributes>(\"/v1/files\", {\n \"filter[variant_id]\": String(variantId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedLicenseKeyInstanceAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface LicenseKeyInstanceAttributes extends GeneratedLicenseKeyInstanceAttributes {\n license_key_id: number;\n identifier: string;\n name: string;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getLicenseKeyInstance = async (\n http: HttpClient,\n licenseKeyInstanceId: string | number,\n): Promise<JsonApiResource<LicenseKeyInstanceAttributes>> => {\n return http.getResource<LicenseKeyInstanceAttributes>(\n `/v1/license-key-instances/${licenseKeyInstanceId}`,\n );\n};\n\nexport const listLicenseKeyInstancesForLicenseKey = async (\n http: HttpClient,\n licenseKeyId: string | number,\n): Promise<JsonApiResource<LicenseKeyInstanceAttributes>[]> => {\n return http.paginate<LicenseKeyInstanceAttributes>(\"/v1/license-key-instances\", {\n \"filter[license_key_id]\": String(licenseKeyId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedLicenseKeyAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of Lemon Squeezy license-key attributes used by the license key\n * validator. Full schema at https://docs.lemonsqueezy.com/api/license-keys.\n */\nexport interface LicenseKeyAttributes extends GeneratedLicenseKeyAttributes {\n key_short: string;\n status: \"active\" | \"inactive\" | \"expired\" | \"disabled\";\n expires_at: string | null;\n activation_limit: number | null;\n instances_count: number;\n disabled: boolean;\n store_id: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Fetch a single license key by ID. Used by the license key validator to\n * check activation limits, expiration, and store ownership.\n *\n * @param http - Shared API client.\n * @param licenseKeyId - License key id.\n * @returns The license key resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const key = await getLicenseKey(http, 1);\n * ```\n */\nexport const getLicenseKey = async (\n http: HttpClient,\n licenseKeyId: string | number,\n): Promise<JsonApiResource<LicenseKeyAttributes>> => {\n return http.getResource<LicenseKeyAttributes>(`/v1/license-keys/${licenseKeyId}`);\n};\n\n/**\n * List license keys for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns License key resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const keys = await listLicenseKeysForStore(http, 1);\n * ```\n */\nexport const listLicenseKeysForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<LicenseKeyAttributes>[]> => {\n return http.paginate<LicenseKeyAttributes>(\"/v1/license-keys\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Update a license key (PATCH /v1/license-keys/:id) — e.g. `expires_at`, disabled.\n * Docs: https://docs.lemonsqueezy.com/api/license-keys/update-license-key\n *\n * @param http - Shared API client.\n * @param licenseKeyId - License key id.\n * @param body - JSON:API update document.\n * @returns The updated license key.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const key = await updateLicenseKey(http, 1, {\n * data: { type: \"license-keys\", id: \"1\", attributes: { disabled: true } },\n * });\n * ```\n */\nexport const updateLicenseKey = async (\n http: HttpClient,\n licenseKeyId: string | number,\n body: unknown,\n): Promise<JsonApiResource<LicenseKeyAttributes>> => {\n return http.patchResource<LicenseKeyAttributes>(`/v1/license-keys/${licenseKeyId}`, body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedOrderItemAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Order item attributes. `quantity` was added to the documented object in\n * the 2024-12-06 changelog and is needed for multi-quantity reconciliation.\n */\nexport interface OrderItemAttributes extends GeneratedOrderItemAttributes {\n order_id: number;\n product_id: number;\n variant_id: number;\n product_name: string;\n variant_name: string;\n price: number;\n quantity: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getOrderItem = async (\n http: HttpClient,\n orderItemId: string | number,\n): Promise<JsonApiResource<OrderItemAttributes>> => {\n return http.getResource<OrderItemAttributes>(`/v1/order-items/${orderItemId}`);\n};\n\nexport const listOrderItemsForOrder = async (\n http: HttpClient,\n orderId: string | number,\n): Promise<JsonApiResource<OrderItemAttributes>[]> => {\n return http.paginate<OrderItemAttributes>(\"/v1/order-items\", {\n \"filter[order_id]\": String(orderId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedOrderAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface OrderUrls {\n receipt?: string;\n}\n\nexport interface OrderFirstItem {\n id: number;\n order_id?: number;\n product_id: number;\n variant_id: number;\n product_name: string;\n variant_name: string;\n price: number;\n quantity?: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Subset of Lemon Squeezy order attributes fresh-squeezy understands.\n *\n * fresh-squeezy does not (yet) validate orders — the type is exported so\n * consumers using the raw `client.request<OrderAttributes>()` escape hatch\n * get a typed response that includes platform additions the official SDK\n * has not yet picked up.\n *\n * Field provenance against the changelog\n * (https://docs.lemonsqueezy.com/api/getting-started/changelog):\n *\n * - `status: \"fraudulent\"` — added 2024-09-10. Indicates a manual fraud\n * flag; treat as terminal and refund or chargeback as appropriate.\n * - `refunded_amount`, `refunded_amount_usd`, `refunded_amount_formatted`\n * — added 2024-08-07. Useful for consumers reconciling partial refunds.\n * - `tax_inclusive` — added 2024-02-05.\n */\nexport interface OrderAttributes extends GeneratedOrderAttributes {\n store_id: number;\n customer_id?: number;\n identifier: string;\n order_number: number;\n user_name: string;\n user_email: string;\n currency: string;\n currency_rate: string;\n subtotal: number;\n setup_fee?: number;\n discount_total: number;\n tax: number;\n tax_inclusive?: boolean;\n total: number;\n refunded_amount?: number;\n subtotal_usd?: number;\n setup_fee_usd?: number;\n discount_total_usd?: number;\n tax_usd?: number;\n total_usd?: number;\n refunded_amount_usd?: number | null;\n tax_name?: string | null;\n tax_rate?: number | string | null;\n refunded_amount_formatted?: string | null;\n refunded?: boolean;\n refunded_at?: string | null;\n status: \"pending\" | \"failed\" | \"paid\" | \"refunded\" | \"fraudulent\" | \"partial_refund\";\n status_formatted: string;\n subtotal_formatted?: string;\n setup_fee_formatted?: string;\n discount_total_formatted?: string;\n tax_formatted?: string;\n total_formatted?: string;\n first_order_item?: OrderFirstItem | null;\n urls?: OrderUrls;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Fetch a single order by ID.\n *\n * @param http - Shared API client.\n * @param orderId - Order id.\n * @returns The order resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const order = await getOrder(http, 1);\n * ```\n */\nexport const getOrder = async (\n http: HttpClient,\n orderId: string | number,\n): Promise<JsonApiResource<OrderAttributes>> => {\n return http.getResource<OrderAttributes>(`/v1/orders/${orderId}`);\n};\n\n/**\n * List orders for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Order resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const orders = await listOrdersForStore(http, 1);\n * ```\n */\nexport const listOrdersForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<OrderAttributes>[]> => {\n return http.paginate<OrderAttributes>(\"/v1/orders\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Issue a full or partial order refund (POST /v1/orders/:id/refund).\n * Docs: https://docs.lemonsqueezy.com/api/orders/issue-refund\n *\n * @param http - Shared API client.\n * @param orderId - Order to refund.\n * @param body - Optional JSON:API body (`attributes.amount` for partial).\n * @returns The updated order after refund.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const order = await refundOrder(http, 1);\n * ```\n */\nexport const refundOrder = async (\n http: HttpClient,\n orderId: string | number,\n body?: unknown,\n): Promise<JsonApiResource<OrderAttributes>> => {\n return http.postResource<OrderAttributes>(`/v1/orders/${orderId}/refund`, body ?? {});\n};\n\n/**\n * Generate an order invoice (POST /v1/orders/:id/generate-invoice).\n * Docs: https://docs.lemonsqueezy.com/api/orders/generate-order-invoice\n *\n * @param http - Shared API client.\n * @param orderId - Order id.\n * @param body - Optional locale/name attributes document.\n * @returns API response document (invoice URL payload).\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoice = await generateOrderInvoice(http, 1);\n * ```\n */\nexport const generateOrderInvoice = async (\n http: HttpClient,\n orderId: string | number,\n body?: unknown,\n): Promise<unknown> => {\n return http.request({\n method: \"POST\",\n path: `/v1/orders/${orderId}/generate-invoice`,\n body: body ?? {},\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedPriceAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of Lemon Squeezy price attributes. Prices are nested under\n * variants in the API surface; consumers that read them directly via\n * `client.request<PriceAttributes>()` get a typed response that includes\n * the setup-fee fields the official SDK does not yet surface.\n *\n * Field provenance:\n * - `setup_fee_enabled`, `setup_fee` — added 2024-01-21.\n * - `unit_price_decimal` — added 2024-01-15.\n */\nexport interface PriceAttributes extends GeneratedPriceAttributes {\n variant_id: number;\n category: \"one_time\" | \"subscription\" | \"lead_magnet\" | \"pwyw\";\n scheme: \"standard\" | \"package\" | \"graduated\" | \"volume\";\n usage_aggregation?: string | null;\n unit_price?: number;\n /** Added 2024-01-15. Decimal string for sub-cent accuracy. */\n unit_price_decimal?: string | null;\n package_size?: number;\n tiers?: unknown;\n renewal_interval_unit?: \"day\" | \"week\" | \"month\" | \"year\" | null;\n renewal_interval_quantity?: number | null;\n trial_interval_unit?: \"day\" | \"week\" | \"month\" | \"year\" | null;\n trial_interval_quantity?: number | null;\n min_price?: number | null;\n suggested_price?: number | null;\n tax_code?: string;\n /** Added 2024-01-21. */\n setup_fee_enabled?: boolean | null;\n /** Added 2024-01-21. Setup fee in cents, paired with `setup_fee_enabled`. */\n setup_fee?: number | null;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Fetch a single price by ID (read-only — no create/update/delete in LS API).\n *\n * @param http - Shared API client.\n * @param priceId - Price id.\n * @returns The price resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const price = await getPrice(http, 1);\n * ```\n */\nexport const getPrice = async (\n http: HttpClient,\n priceId: string | number,\n): Promise<JsonApiResource<PriceAttributes>> => {\n return http.getResource<PriceAttributes>(`/v1/prices/${priceId}`);\n};\n\n/**\n * List prices for a variant.\n *\n * @param http - Shared API client.\n * @param variantId - Variant filter.\n * @returns Price resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const prices = await listPricesForVariant(http, 1);\n * ```\n */\nexport const listPricesForVariant = async (\n http: HttpClient,\n variantId: string | number,\n): Promise<JsonApiResource<PriceAttributes>[]> => {\n return http.paginate<PriceAttributes>(\"/v1/prices\", {\n \"filter[variant_id]\": String(variantId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedProductAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of product attributes we need for validation. `status` drives the\n * \"unpublished product\" check; `store_id` drives ownership checks.\n */\nexport interface ProductAttributes extends GeneratedProductAttributes {\n name: string;\n slug: string;\n description?: string | null;\n status: \"draft\" | \"published\";\n status_formatted?: string;\n store_id: number;\n buy_now_url?: string | null;\n from_price?: number | null;\n to_price?: number | null;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getProduct = async (\n http: HttpClient,\n productId: string | number,\n): Promise<JsonApiResource<ProductAttributes>> => {\n return http.getResource<ProductAttributes>(`/v1/products/${productId}`);\n};\n\n/**\n * List every product in the store, paginated. Used by the CLI's\n * interactive product picker; without pagination only the first 25\n * products are offered.\n */\nexport const listProducts = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<ProductAttributes>[]> => {\n return http.paginate<ProductAttributes>(\"/v1/products\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n","/**\n * Docs-backed ops matrix for Lemon Squeezy.\n *\n * Only verbs that exist at https://docs.lemonsqueezy.com/api are listed.\n * Catalog resources (products, variants, prices, files, stores, …) are\n * read-only. CI changelog scrape may propose gaps; this registry is what ships.\n */\n\n/** CLI / client verb tokens, including non-CRUD LS actions. */\nexport type OpVerb =\n | \"get\"\n | \"list\"\n | \"create\"\n | \"update\"\n | \"delete\"\n | \"cancel\"\n | \"refund\"\n | \"generate-invoice\"\n | \"current-usage\";\n\n/**\n * One implemented, documented operation.\n *\n * @remarks `docsPath` is the path under `/api/` on the LS docs site.\n */\nexport interface ResourceVerbSpec {\n /** CLI resource token (singular), e.g. `webhook`. */\n resource: string;\n verb: OpVerb;\n /** Docs path fragment, e.g. `webhooks/create-webhook`. */\n docsPath: string;\n /** Requires --yes or TTY confirm always (delete/cancel/refund). */\n destructive?: boolean;\n body?: \"required\" | \"optional\" | \"none\";\n /**\n * How list/get resolve the primary id filter.\n * - `id` — --id\n * - `store` — --store-ids (first) or store filter\n * - `parent` — --parent-id (subscription, order, product, …)\n */\n idRole?: \"id\" | \"store\" | \"parent\" | \"none\";\n}\n\n/**\n * Implemented ops. Keep in sync with exports in `src/resources/*` and the\n * CLI dispatcher. Do not register fantasy endpoints (e.g. product create).\n */\nexport const resourceRegistry: readonly ResourceVerbSpec[] = [\n // users\n { resource: \"user\", verb: \"get\", docsPath: \"users/retrieve-user\", body: \"none\", idRole: \"none\" },\n\n // stores (read-only)\n { resource: \"store\", verb: \"get\", docsPath: \"stores/retrieve-store\", body: \"none\", idRole: \"id\" },\n {\n resource: \"store\",\n verb: \"list\",\n docsPath: \"stores/list-all-stores\",\n body: \"none\",\n idRole: \"none\",\n },\n\n // products (read-only)\n {\n resource: \"product\",\n verb: \"get\",\n docsPath: \"products/retrieve-product\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"product\",\n verb: \"list\",\n docsPath: \"products/list-all-products\",\n body: \"none\",\n idRole: \"store\",\n },\n\n // variants (read-only)\n {\n resource: \"variant\",\n verb: \"get\",\n docsPath: \"variants/retrieve-variant\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"variant\",\n verb: \"list\",\n docsPath: \"variants/list-all-variants\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // prices (read-only)\n { resource: \"price\", verb: \"get\", docsPath: \"prices/retrieve-price\", body: \"none\", idRole: \"id\" },\n {\n resource: \"price\",\n verb: \"list\",\n docsPath: \"prices/list-all-prices\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // files (read-only)\n { resource: \"file\", verb: \"get\", docsPath: \"files/retrieve-file\", body: \"none\", idRole: \"id\" },\n {\n resource: \"file\",\n verb: \"list\",\n docsPath: \"files/list-all-files\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // customers\n {\n resource: \"customer\",\n verb: \"get\",\n docsPath: \"customers/retrieve-customer\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"customer\",\n verb: \"list\",\n docsPath: \"customers/list-all-customers\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"customer\",\n verb: \"create\",\n docsPath: \"customers/create-customer\",\n body: \"required\",\n idRole: \"none\",\n },\n {\n resource: \"customer\",\n verb: \"update\",\n docsPath: \"customers/update-customer\",\n body: \"required\",\n idRole: \"id\",\n },\n\n // orders\n { resource: \"order\", verb: \"get\", docsPath: \"orders/retrieve-order\", body: \"none\", idRole: \"id\" },\n {\n resource: \"order\",\n verb: \"list\",\n docsPath: \"orders/list-all-orders\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"order\",\n verb: \"refund\",\n docsPath: \"orders/issue-refund\",\n body: \"optional\",\n destructive: true,\n idRole: \"id\",\n },\n {\n resource: \"order\",\n verb: \"generate-invoice\",\n docsPath: \"orders/generate-order-invoice\",\n body: \"optional\",\n idRole: \"id\",\n },\n\n // order-items (read-only)\n {\n resource: \"order-item\",\n verb: \"get\",\n docsPath: \"order-items/retrieve-order-item\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"order-item\",\n verb: \"list\",\n docsPath: \"order-items/list-all-order-items\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // subscriptions\n {\n resource: \"subscription\",\n verb: \"get\",\n docsPath: \"subscriptions/retrieve-subscription\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"subscription\",\n verb: \"list\",\n docsPath: \"subscriptions/list-all-subscriptions\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"subscription\",\n verb: \"update\",\n docsPath: \"subscriptions/update-subscription\",\n body: \"required\",\n idRole: \"id\",\n },\n {\n resource: \"subscription\",\n verb: \"cancel\",\n docsPath: \"subscriptions/cancel-subscription\",\n body: \"none\",\n destructive: true,\n idRole: \"id\",\n },\n\n // subscription-items\n {\n resource: \"subscription-item\",\n verb: \"get\",\n docsPath: \"subscription-items/retrieve-subscription-item\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"subscription-item\",\n verb: \"list\",\n docsPath: \"subscription-items/list-all-subscription-items\",\n body: \"none\",\n idRole: \"parent\",\n },\n {\n resource: \"subscription-item\",\n verb: \"update\",\n docsPath: \"subscription-items/update-subscription-item\",\n body: \"required\",\n idRole: \"id\",\n },\n {\n resource: \"subscription-item\",\n verb: \"current-usage\",\n docsPath: \"subscription-items/retrieve-subscription-item-current-usage\",\n body: \"none\",\n idRole: \"id\",\n },\n\n // subscription-invoices\n {\n resource: \"subscription-invoice\",\n verb: \"get\",\n docsPath: \"subscription-invoices/retrieve-subscription-invoice\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"subscription-invoice\",\n verb: \"list\",\n docsPath: \"subscription-invoices/list-all-subscription-invoices\",\n body: \"none\",\n idRole: \"parent\",\n },\n {\n resource: \"subscription-invoice\",\n verb: \"refund\",\n docsPath: \"subscription-invoices/issue-refund\",\n body: \"optional\",\n destructive: true,\n idRole: \"id\",\n },\n {\n resource: \"subscription-invoice\",\n verb: \"generate-invoice\",\n docsPath: \"subscription-invoices/generate-subscription-invoice\",\n body: \"optional\",\n idRole: \"id\",\n },\n\n // usage-records\n {\n resource: \"usage-record\",\n verb: \"get\",\n docsPath: \"usage-records/retrieve-usage-record\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"usage-record\",\n verb: \"list\",\n docsPath: \"usage-records/list-all-usage-records\",\n body: \"none\",\n idRole: \"parent\",\n },\n {\n resource: \"usage-record\",\n verb: \"create\",\n docsPath: \"usage-records/create-usage-record\",\n body: \"required\",\n idRole: \"none\",\n },\n\n // discounts\n {\n resource: \"discount\",\n verb: \"get\",\n docsPath: \"discounts/retrieve-discount\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"discount\",\n verb: \"list\",\n docsPath: \"discounts/list-all-discounts\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"discount\",\n verb: \"create\",\n docsPath: \"discounts/create-discount\",\n body: \"required\",\n idRole: \"none\",\n },\n {\n resource: \"discount\",\n verb: \"delete\",\n docsPath: \"discounts/delete-discount\",\n body: \"none\",\n destructive: true,\n idRole: \"id\",\n },\n\n // discount-redemptions (read-only)\n {\n resource: \"discount-redemption\",\n verb: \"get\",\n docsPath: \"discount-redemptions/retrieve-discount-redemption\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"discount-redemption\",\n verb: \"list\",\n docsPath: \"discount-redemptions/list-all-discount-redemptions\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // license-keys\n {\n resource: \"license-key\",\n verb: \"get\",\n docsPath: \"license-keys/retrieve-license-key\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"license-key\",\n verb: \"list\",\n docsPath: \"license-keys/list-all-license-keys\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"license-key\",\n verb: \"update\",\n docsPath: \"license-keys/update-license-key\",\n body: \"required\",\n idRole: \"id\",\n },\n\n // license-key-instances (read-only)\n {\n resource: \"license-key-instance\",\n verb: \"get\",\n docsPath: \"license-key-instances/retrieve-license-key-instance\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"license-key-instance\",\n verb: \"list\",\n docsPath: \"license-key-instances/list-all-license-key-instances\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // checkouts\n {\n resource: \"checkout\",\n verb: \"get\",\n docsPath: \"checkouts/retrieve-checkout\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"checkout\",\n verb: \"list\",\n docsPath: \"checkouts/list-all-checkouts\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"checkout\",\n verb: \"create\",\n docsPath: \"checkouts/create-checkout\",\n body: \"required\",\n idRole: \"none\",\n },\n\n // webhooks\n {\n resource: \"webhook\",\n verb: \"get\",\n docsPath: \"webhooks/retrieve-webhook\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"webhook\",\n verb: \"list\",\n docsPath: \"webhooks/list-all-webhooks\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"webhook\",\n verb: \"create\",\n docsPath: \"webhooks/create-webhook\",\n body: \"required\",\n idRole: \"none\",\n },\n {\n resource: \"webhook\",\n verb: \"update\",\n docsPath: \"webhooks/update-webhook\",\n body: \"required\",\n idRole: \"id\",\n },\n {\n resource: \"webhook\",\n verb: \"delete\",\n docsPath: \"webhooks/delete-webhook\",\n body: \"none\",\n destructive: true,\n idRole: \"id\",\n },\n\n // affiliates (read-only)\n {\n resource: \"affiliate\",\n verb: \"get\",\n docsPath: \"affiliates/retrieve-affiliate\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"affiliate\",\n verb: \"list\",\n docsPath: \"affiliates/list-all-affiliates\",\n body: \"none\",\n idRole: \"store\",\n },\n] as const;\n\n/**\n * Plural CLI tokens → singular registry keys.\n * Lookups run after `_` → `-` normalization, so only kebab forms live here.\n */\nconst RESOURCE_ALIASES: Record<string, string> = {\n products: \"product\",\n stores: \"store\",\n customers: \"customer\",\n orders: \"order\",\n \"order-items\": \"order-item\",\n subscriptions: \"subscription\",\n \"subscription-items\": \"subscription-item\",\n \"subscription-invoices\": \"subscription-invoice\",\n \"usage-records\": \"usage-record\",\n discounts: \"discount\",\n \"discount-redemptions\": \"discount-redemption\",\n \"license-keys\": \"license-key\",\n \"license-key-instances\": \"license-key-instance\",\n checkouts: \"checkout\",\n webhooks: \"webhook\",\n affiliates: \"affiliate\",\n variants: \"variant\",\n prices: \"price\",\n files: \"file\",\n users: \"user\",\n};\n\n/**\n * Normalize a CLI resource token to the singular registry key.\n *\n * @param resource - Raw token (`products`, `order_items`, `webhook`).\n * @returns Canonical singular resource name used in `resourceRegistry`.\n */\nexport const normalizeResourceName = (resource: string): string => {\n const normalized = resource.replace(/_/g, \"-\").toLowerCase();\n if (RESOURCE_ALIASES[normalized]) {\n return RESOURCE_ALIASES[normalized];\n }\n // naive singular for simple plurals; leave tokens like \"status\" alone\n if (normalized.endsWith(\"s\") && normalized !== \"status\") {\n return normalized.slice(0, -1);\n }\n return normalized;\n};\n\n/**\n * Look up a registry entry.\n *\n * @param resource - CLI resource token.\n * @param verb - Op verb.\n * @returns The spec, or undefined when not implemented / not in LS API.\n */\nexport const findResourceVerb = (resource: string, verb: string): ResourceVerbSpec | undefined => {\n const key = normalizeResourceName(resource);\n return resourceRegistry.find((entry) => entry.resource === key && entry.verb === verb);\n};\n\n/**\n * Unique resource names that have at least one verb.\n *\n * @returns Sorted resource tokens for help text / menus.\n */\nexport const listRegisteredResources = (): string[] => {\n return [...new Set(resourceRegistry.map((entry) => entry.resource))].sort();\n};\n\n/**\n * All verbs registered for a resource (empty when unknown).\n *\n * @param resource - CLI resource token (plural or singular).\n * @returns Sorted verb list for help / menus.\n */\nexport const listRegisteredVerbs = (resource: string): OpVerb[] => {\n const key = normalizeResourceName(resource);\n return resourceRegistry\n .filter((entry) => entry.resource === key)\n .map((entry) => entry.verb)\n .sort();\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedStoreAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of store attributes fresh-squeezy reads.\n * Full schema at https://docs.lemonsqueezy.com/api/stores.\n */\nexport interface StoreAttributes extends GeneratedStoreAttributes {\n name: string;\n slug: string;\n domain?: string | null;\n url?: string | null;\n country?: string;\n currency?: string;\n plan?: string;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<StoreAttributes>> => {\n return http.getResource<StoreAttributes>(`/v1/stores/${storeId}`);\n};\n\n/**\n * List every store reachable with the configured API key, paginated.\n * Used by `validateConnection` to populate the connection summary, and by\n * the CLI's `--all-stores` flag. Pagination matters here for accounts that\n * own a large catalogue of stores.\n */\nexport const listStores = async (http: HttpClient): Promise<JsonApiResource<StoreAttributes>[]> => {\n return http.paginate<StoreAttributes>(\"/v1/stores\");\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedSubscriptionInvoiceAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type SubscriptionInvoiceStatus = \"pending\" | \"paid\" | \"void\" | \"refunded\" | \"partial_refund\";\n\nexport type SubscriptionInvoiceBillingReason = \"initial\" | \"renewal\" | \"updated\";\n\nexport interface SubscriptionInvoiceUrls {\n invoice_url?: string;\n}\n\n/**\n * Subscription invoice attributes, including fields added across the\n * changelog: customer identity, tax inclusion, and partial refund amounts.\n */\nexport interface SubscriptionInvoiceAttributes extends GeneratedSubscriptionInvoiceAttributes {\n store_id: number;\n subscription_id: number;\n customer_id: number;\n user_name: string;\n user_email: string;\n billing_reason: SubscriptionInvoiceBillingReason | string;\n card_brand?: string | null;\n card_last_four?: string | null;\n currency: string;\n currency_rate: string;\n status: SubscriptionInvoiceStatus;\n status_formatted: string;\n refunded: boolean;\n refunded_at: string | null;\n subtotal: number;\n discount_total: number;\n tax: number;\n tax_inclusive: boolean;\n total: number;\n refunded_amount: number;\n subtotal_usd: number;\n discount_total_usd: number;\n tax_usd: number;\n total_usd: number;\n refunded_amount_usd: number;\n subtotal_formatted: string;\n discount_total_formatted: string;\n tax_formatted: string;\n total_formatted: string;\n refunded_amount_formatted: string;\n urls?: SubscriptionInvoiceUrls;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve a subscription invoice.\n *\n * @param http - Shared API client.\n * @param subscriptionInvoiceId - Invoice id.\n * @returns The invoice resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoice = await getSubscriptionInvoice(http, 1);\n * ```\n */\nexport const getSubscriptionInvoice = async (\n http: HttpClient,\n subscriptionInvoiceId: string | number,\n): Promise<JsonApiResource<SubscriptionInvoiceAttributes>> => {\n return http.getResource<SubscriptionInvoiceAttributes>(\n `/v1/subscription-invoices/${subscriptionInvoiceId}`,\n );\n};\n\n/**\n * List invoices for a subscription.\n *\n * @param http - Shared API client.\n * @param subscriptionId - Parent subscription id.\n * @returns Invoice resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoices = await listSubscriptionInvoicesForSubscription(http, 1);\n * ```\n */\nexport const listSubscriptionInvoicesForSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionInvoiceAttributes>[]> => {\n return http.paginate<SubscriptionInvoiceAttributes>(\"/v1/subscription-invoices\", {\n \"filter[subscription_id]\": String(subscriptionId),\n });\n};\n\n/**\n * Refund a subscription invoice (POST /v1/subscription-invoices/:id/refund).\n * Docs: https://docs.lemonsqueezy.com/api/subscription-invoices/issue-refund\n *\n * @param http - Shared API client.\n * @param subscriptionInvoiceId - Invoice id.\n * @param body - Optional partial-refund document.\n * @returns The updated invoice.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoice = await refundSubscriptionInvoice(http, 1);\n * ```\n */\nexport const refundSubscriptionInvoice = async (\n http: HttpClient,\n subscriptionInvoiceId: string | number,\n body?: unknown,\n): Promise<JsonApiResource<SubscriptionInvoiceAttributes>> => {\n return http.postResource<SubscriptionInvoiceAttributes>(\n `/v1/subscription-invoices/${subscriptionInvoiceId}/refund`,\n body ?? {},\n );\n};\n\n/**\n * Generate a subscription invoice PDF/URL.\n * Docs: https://docs.lemonsqueezy.com/api/subscription-invoices/generate-subscription-invoice\n *\n * @param http - Shared API client.\n * @param subscriptionInvoiceId - Invoice id.\n * @param body - Optional generation attributes.\n * @returns API response document.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const doc = await generateSubscriptionInvoice(http, 1);\n * ```\n */\nexport const generateSubscriptionInvoice = async (\n http: HttpClient,\n subscriptionInvoiceId: string | number,\n body?: unknown,\n): Promise<unknown> => {\n return http.request({\n method: \"POST\",\n path: `/v1/subscription-invoices/${subscriptionInvoiceId}/generate-invoice`,\n body: body ?? {},\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedSubscriptionItemAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface SubscriptionItemAttributes extends GeneratedSubscriptionItemAttributes {\n subscription_id: number;\n price_id: number;\n quantity: number;\n is_usage_based: boolean;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Attributes accepted by the update subscription item endpoint. The proration\n * controls were added in the 2024-02-12 changelog.\n */\nexport interface SubscriptionItemUpdateAttributes {\n quantity?: number;\n invoice_immediately?: boolean;\n disable_prorations?: boolean;\n}\n\n/**\n * Retrieve a subscription item.\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Item id.\n * @returns The subscription item resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const item = await getSubscriptionItem(http, 1);\n * ```\n */\nexport const getSubscriptionItem = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n): Promise<JsonApiResource<SubscriptionItemAttributes>> => {\n return http.getResource<SubscriptionItemAttributes>(\n `/v1/subscription-items/${subscriptionItemId}`,\n );\n};\n\n/**\n * List subscription items for a subscription.\n *\n * @param http - Shared API client.\n * @param subscriptionId - Parent subscription id.\n * @returns Subscription item resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const items = await listSubscriptionItemsForSubscription(http, 1);\n * ```\n */\nexport const listSubscriptionItemsForSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionItemAttributes>[]> => {\n return http.paginate<SubscriptionItemAttributes>(\"/v1/subscription-items\", {\n \"filter[subscription_id]\": String(subscriptionId),\n });\n};\n\n/**\n * Build a JSON:API update body for a subscription item (quantity / proration).\n *\n * @param subscriptionItemId - Item id embedded in the document.\n * @param attributes - Fields accepted by the update endpoint.\n * @returns A single JSON:API document (not multiple loose objects).\n *\n * @example\n * ```ts\n * const body = buildSubscriptionItemUpdateBody(1, { quantity: 3 });\n * await updateSubscriptionItem(http, 1, body);\n * ```\n */\nexport const buildSubscriptionItemUpdateBody = (\n subscriptionItemId: string | number,\n attributes: SubscriptionItemUpdateAttributes,\n): unknown => {\n return {\n data: {\n type: \"subscription-items\",\n id: String(subscriptionItemId),\n attributes,\n },\n };\n};\n\n/**\n * Update a subscription item (PATCH /v1/subscription-items/:id).\n * Docs: https://docs.lemonsqueezy.com/api/subscription-items/update-subscription-item\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Item id.\n * @param body - JSON:API update document.\n * @returns The updated subscription item.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const item = await updateSubscriptionItem(\n * http,\n * 1,\n * buildSubscriptionItemUpdateBody(1, { quantity: 2 }),\n * );\n * ```\n */\nexport const updateSubscriptionItem = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n body: unknown,\n): Promise<JsonApiResource<SubscriptionItemAttributes>> => {\n return http.patchResource<SubscriptionItemAttributes>(\n `/v1/subscription-items/${subscriptionItemId}`,\n body,\n );\n};\n\n/**\n * Current-period usage for a usage-based subscription item.\n * Docs: https://docs.lemonsqueezy.com/api/subscription-items/retrieve-subscription-item-current-usage\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Item id.\n * @returns Usage payload for the current billing period.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const usage = await getSubscriptionItemCurrentUsage(http, 1);\n * ```\n */\nexport const getSubscriptionItemCurrentUsage = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n): Promise<unknown> => {\n return http.request({\n path: `/v1/subscription-items/${subscriptionItemId}/current-usage`,\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedSubscriptionAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * URLs Lemon Squeezy attaches to a subscription so consumers can deep-link\n * users to billing pages. The set has grown over time; we keep optional\n * fields for forward-compatibility.\n */\nexport interface SubscriptionUrls {\n update_payment_method?: string;\n customer_portal?: string;\n /** Added 2024-02-20: lets consumers offer \"manage subscription\" without an extra round-trip. */\n update_customer_portal?: string | null;\n /** Current API examples also surface this key name for PayPal update flows. */\n customer_portal_update_subscription?: string | null;\n}\n\nexport interface SubscriptionPause {\n mode: \"void\" | \"free\" | string;\n resumes_at?: string | null;\n}\n\nexport interface SubscriptionItemSummary {\n id: number;\n subscription_id: number;\n price_id: number;\n quantity: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Subset of subscription attributes. fresh-squeezy does not (yet) validate\n * subscriptions — this type is exported so consumers using the raw\n * `client.request<SubscriptionAttributes>()` escape hatch get a typed\n * response that includes platform additions the official SDK has not yet\n * picked up.\n *\n * Field provenance against the changelog:\n * - `payment_processor` — added 2025-06-11.\n * - `urls.update_customer_portal` — added 2024-02-20.\n * - `tax_inclusive` — invoice-only in current API docs; retained here as\n * a compatibility field for consumers that previously normalised\n * subscription and subscription invoice payloads together.\n */\nexport interface SubscriptionAttributes extends GeneratedSubscriptionAttributes {\n store_id: number;\n customer_id: number;\n order_id?: number;\n order_item_id?: number;\n product_id: number;\n variant_id: number;\n product_name: string;\n variant_name: string;\n user_name: string;\n user_email: string;\n status: \"on_trial\" | \"active\" | \"paused\" | \"past_due\" | \"unpaid\" | \"cancelled\" | \"expired\";\n status_formatted: string;\n card_brand?: string | null;\n card_last_four?: string | null;\n /** Added 2025-06-11. Identifies which payment provider processed the transaction. */\n payment_processor?: \"stripe\" | \"lemonsqueezy\" | \"paypal\" | string;\n pause?: SubscriptionPause | null;\n cancelled?: boolean;\n trial_ends_at?: string | null;\n billing_anchor?: number;\n first_subscription_item?: SubscriptionItemSummary | null;\n urls?: SubscriptionUrls;\n renews_at?: string | null;\n ends_at?: string | null;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n /** Compatibility field for older fresh-squeezy consumers; prefer SubscriptionInvoiceAttributes.tax_inclusive. */\n tax_inclusive?: boolean;\n}\n\n/**\n * Fetch a single subscription by ID.\n *\n * @param http - Shared API client.\n * @param subscriptionId - Subscription id.\n * @returns The subscription resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const sub = await getSubscription(http, 1);\n * ```\n */\nexport const getSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionAttributes>> => {\n return http.getResource<SubscriptionAttributes>(`/v1/subscriptions/${subscriptionId}`);\n};\n\n/**\n * List subscriptions for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Subscription resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const subs = await listSubscriptionsForStore(http, 1);\n * ```\n */\nexport const listSubscriptionsForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<SubscriptionAttributes>[]> => {\n return http.paginate<SubscriptionAttributes>(\"/v1/subscriptions\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Update a subscription (PATCH /v1/subscriptions/:id) — plan change, pause, etc.\n * Docs: https://docs.lemonsqueezy.com/api/subscriptions/update-subscription\n *\n * @param http - Shared API client.\n * @param subscriptionId - Subscription id.\n * @param body - JSON:API update document.\n * @returns The updated subscription.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const sub = await updateSubscription(http, 1, {\n * data: { type: \"subscriptions\", id: \"1\", attributes: { variant_id: 2 } },\n * });\n * ```\n */\nexport const updateSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n body: unknown,\n): Promise<JsonApiResource<SubscriptionAttributes>> => {\n return http.patchResource<SubscriptionAttributes>(`/v1/subscriptions/${subscriptionId}`, body);\n};\n\n/**\n * Cancel a subscription (DELETE /v1/subscriptions/:id).\n * Docs: https://docs.lemonsqueezy.com/api/subscriptions/cancel-subscription\n *\n * @param http - Shared API client.\n * @param subscriptionId - Subscription id.\n * @returns The cancelled subscription resource when the API returns one.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const sub = await cancelSubscription(http, 1);\n * ```\n */\nexport const cancelSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionAttributes> | undefined> => {\n const doc = await http.request<{ data?: JsonApiResource<SubscriptionAttributes> }>({\n method: \"DELETE\",\n path: `/v1/subscriptions/${subscriptionId}`,\n });\n return doc?.data;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedUsageRecordAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type UsageRecordAction = \"increment\" | \"set\";\n\nexport interface UsageRecordAttributes extends GeneratedUsageRecordAttributes {\n subscription_item_id: number;\n quantity: number;\n action: UsageRecordAction;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Retrieve a usage record.\n *\n * @param http - Shared API client.\n * @param usageRecordId - Usage record id.\n * @returns The usage record resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const record = await getUsageRecord(http, 1);\n * ```\n */\nexport const getUsageRecord = async (\n http: HttpClient,\n usageRecordId: string | number,\n): Promise<JsonApiResource<UsageRecordAttributes>> => {\n return http.getResource<UsageRecordAttributes>(`/v1/usage-records/${usageRecordId}`);\n};\n\n/**\n * List usage records for a subscription item.\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Parent subscription item id.\n * @returns Usage record resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const records = await listUsageRecordsForSubscriptionItem(http, 1);\n * ```\n */\nexport const listUsageRecordsForSubscriptionItem = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n): Promise<JsonApiResource<UsageRecordAttributes>[]> => {\n return http.paginate<UsageRecordAttributes>(\"/v1/usage-records\", {\n \"filter[subscription_item_id]\": String(subscriptionItemId),\n });\n};\n\n/**\n * Create a usage record (POST /v1/usage-records).\n * Docs: https://docs.lemonsqueezy.com/api/usage-records/create-usage-record\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created usage record.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const record = await createUsageRecord(http, {\n * data: {\n * type: \"usage-records\",\n * attributes: { quantity: 5, action: \"increment\" },\n * relationships: {\n * \"subscription-item\": { data: { type: \"subscription-items\", id: \"1\" } },\n * },\n * },\n * });\n * ```\n */\nexport const createUsageRecord = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<UsageRecordAttributes>> => {\n return http.postResource<UsageRecordAttributes>(\"/v1/usage-records\", body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiDocument } from \"../core/types.js\";\nimport type { GeneratedUserAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of the Lemon Squeezy `users` resource attributes we rely on.\n * Full schema at https://docs.lemonsqueezy.com/api/users.\n */\nexport interface UserAttributes extends GeneratedUserAttributes {\n name: string;\n email: string;\n color?: string;\n avatar_url?: string | null;\n has_custom_avatar?: boolean;\n createdAt?: string;\n updatedAt?: string;\n}\n\n/**\n * Document-level metadata on `/v1/users/me`.\n *\n * `test_mode` was added to the endpoint on 2024-01-05 (per the Lemon Squeezy\n * API changelog: https://docs.lemonsqueezy.com/api/getting-started/changelog).\n * It reports whether the *key* being used is a test-mode key, independent of\n * what the caller declared. The connection validator compares this against\n * the caller's declared mode to catch the common \"prod key in staging\"\n * (or vice versa) misconfiguration.\n */\nexport interface UserMeta {\n test_mode?: boolean;\n}\n\n/**\n * Authenticated-user document with the `data` + `meta` block preserved.\n * The connection validator needs the meta flag, so we return the full\n * document here rather than just `data` as the collection helpers do.\n */\nexport type AuthenticatedUserDocument = JsonApiDocument<UserAttributes> & { meta?: UserMeta };\n\n/**\n * Fetch the user associated with the API key. Primary use is the connection\n * validator: a successful call confirms the key is valid, surfaces the\n * account identity for logs, and exposes `meta.test_mode` for mode\n * mismatch detection.\n *\n * @param http - Shared API client.\n * @returns Full `/v1/users/me` document including `meta.test_mode`.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const doc = await getAuthenticatedUser(http);\n * const mode = doc.meta?.test_mode ? \"test\" : \"live\";\n * ```\n */\nexport const getAuthenticatedUser = async (\n http: HttpClient,\n): Promise<AuthenticatedUserDocument> => {\n return http.request<AuthenticatedUserDocument>({ path: \"/v1/users/me\" });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedVariantAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface VariantLink {\n title: string;\n url: string;\n}\n\n/**\n * Variant attributes used by the product validator to detect\n * variant/price drift from the product they belong to.\n */\nexport interface VariantAttributes extends GeneratedVariantAttributes {\n product_id: number;\n name: string;\n slug: string;\n description?: string | null;\n has_license_keys?: boolean;\n license_activation_limit?: number | null;\n is_license_limit_unlimited?: boolean;\n license_length_value?: number | null;\n license_length_unit?: \"day\" | \"week\" | \"month\" | \"year\" | null;\n is_license_length_unlimited?: boolean;\n status: \"pending\" | \"draft\" | \"published\";\n status_formatted?: string;\n is_subscription?: boolean;\n interval?: string | null;\n interval_count?: number | null;\n sort?: number;\n /**\n * Hosted-checkout-style links keyed by purpose. Added 2024-06-09 — older\n * SDK and validator versions don't surface this field, so consumers had\n * to read `meta.product_links` manually before. Optional because the\n * field is absent on older variants.\n */\n links?: VariantLink[] | Record<string, string>;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Extended variant attributes for subscription plan validation. In Lemon\n * Squeezy, \"subscription plans\" live as variants with `is_subscription: true`.\n * These fields are only present on subscription variants and are checked by\n * the subscription plan validator to catch misconfigured trial periods,\n * zero-price plans, and invalid billing intervals.\n */\nexport interface SubscriptionVariantAttributes extends VariantAttributes {\n is_subscription: boolean;\n interval: string | null;\n interval_count: number | null;\n has_free_trial: boolean;\n trial_interval: string | null;\n trial_interval_count: number | null;\n price: number;\n}\n\n/**\n * Fetch a single variant by ID. Used by the subscription plan validator to\n * inspect subscription-specific fields (interval, trial, price).\n */\nexport const getVariant = async <TAttr = VariantAttributes>(\n http: HttpClient,\n variantId: string | number,\n): Promise<JsonApiResource<TAttr>> => {\n return http.getResource<TAttr>(`/v1/variants/${variantId}`);\n};\n\n/**\n * List every variant of the product, paginated so products with more than\n * one page of variants don't trip the `VARIANT_UNPUBLISHED` heuristic when\n * the only published variants happen to live past page 1.\n */\nexport const listVariantsForProduct = async (\n http: HttpClient,\n productId: string | number,\n): Promise<JsonApiResource<VariantAttributes>[]> => {\n return http.paginate<VariantAttributes>(\"/v1/variants\", {\n \"filter[product_id]\": String(productId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedWebhookAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of webhook attributes we read. `events` is an ordered list of\n * subscribed event names; the validator cross-references these against the\n * support manifest to catch missing subscriptions.\n */\nexport interface WebhookAttributes extends GeneratedWebhookAttributes {\n store_id: number;\n url: string;\n events: string[];\n last_sent_at?: string | null;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve one webhook by id.\n *\n * @param http - Shared API client.\n * @param webhookId - Webhook id.\n * @returns The webhook resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhook = await getWebhook(http, 1);\n * ```\n */\nexport const getWebhook = async (\n http: HttpClient,\n webhookId: string | number,\n): Promise<JsonApiResource<WebhookAttributes>> => {\n return http.getResource<WebhookAttributes>(`/v1/webhooks/${webhookId}`);\n};\n\n/**\n * List every webhook registered on the store, walking pagination so a store\n * with more than one page of webhooks doesn't produce a false\n * `WEBHOOK_NOT_FOUND` from `validateWebhook`.\n *\n * @param http - Shared API client.\n * @param storeId - Store to filter.\n * @returns All webhook resources for the store.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhooks = await listWebhooksForStore(http, 1);\n * ```\n */\nexport const listWebhooksForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<WebhookAttributes>[]> => {\n return http.paginate<WebhookAttributes>(\"/v1/webhooks\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a webhook (POST /v1/webhooks).\n * Docs: https://docs.lemonsqueezy.com/api/webhooks/create-webhook\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created webhook.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhook = await createWebhook(http, {\n * data: {\n * type: \"webhooks\",\n * attributes: { url: \"https://app.example.com/hook\", events: [\"order_created\"] },\n * relationships: { store: { data: { type: \"stores\", id: \"1\" } } },\n * },\n * });\n * ```\n */\nexport const createWebhook = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<WebhookAttributes>> => {\n return http.postResource<WebhookAttributes>(\"/v1/webhooks\", body);\n};\n\n/**\n * Update a webhook (PATCH /v1/webhooks/:id).\n * Docs: https://docs.lemonsqueezy.com/api/webhooks/update-webhook\n *\n * @param http - Shared API client.\n * @param webhookId - Webhook id.\n * @param body - JSON:API update document.\n * @returns The updated webhook.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhook = await updateWebhook(http, 1, {\n * data: { type: \"webhooks\", id: \"1\", attributes: { events: [\"order_created\"] } },\n * });\n * ```\n */\nexport const updateWebhook = async (\n http: HttpClient,\n webhookId: string | number,\n body: unknown,\n): Promise<JsonApiResource<WebhookAttributes>> => {\n return http.patchResource<WebhookAttributes>(`/v1/webhooks/${webhookId}`, body);\n};\n\n/**\n * Delete a webhook (DELETE /v1/webhooks/:id).\n * Docs: https://docs.lemonsqueezy.com/api/webhooks/delete-webhook\n *\n * @param http - Shared API client.\n * @param webhookId - Webhook id.\n * @returns Nothing on success.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * await deleteWebhook(http, 1);\n * ```\n */\nexport const deleteWebhook = async (\n http: HttpClient,\n webhookId: string | number,\n): Promise<void> => {\n await http.deleteResource(`/v1/webhooks/${webhookId}`);\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { HttpClient } from \"../core/http.js\";\nimport { getAffiliate, listAffiliatesForStore } from \"./affiliates.js\";\nimport { createCheckout, getCheckout, listCheckoutsForStore } from \"./checkouts.js\";\nimport { createCustomer, getCustomer, listCustomersForStore, updateCustomer } from \"./customers.js\";\nimport {\n getDiscountRedemption,\n listDiscountRedemptionsForDiscount,\n} from \"./discountRedemptions.js\";\nimport { createDiscount, deleteDiscount, getDiscount, listDiscountsForStore } from \"./discounts.js\";\nimport { getFile, listFilesForVariant } from \"./files.js\";\nimport {\n getLicenseKeyInstance,\n listLicenseKeyInstancesForLicenseKey,\n} from \"./licenseKeyInstances.js\";\nimport { getLicenseKey, listLicenseKeysForStore, updateLicenseKey } from \"./licenseKeys.js\";\nimport { getOrderItem, listOrderItemsForOrder } from \"./orderItems.js\";\nimport { generateOrderInvoice, getOrder, listOrdersForStore, refundOrder } from \"./orders.js\";\nimport { getPrice, listPricesForVariant } from \"./prices.js\";\nimport { getProduct, listProducts } from \"./products.js\";\nimport { type OpVerb, findResourceVerb } from \"./registry.js\";\nimport { getStore, listStores } from \"./stores.js\";\nimport {\n generateSubscriptionInvoice,\n getSubscriptionInvoice,\n listSubscriptionInvoicesForSubscription,\n refundSubscriptionInvoice,\n} from \"./subscriptionInvoices.js\";\nimport {\n getSubscriptionItem,\n getSubscriptionItemCurrentUsage,\n listSubscriptionItemsForSubscription,\n updateSubscriptionItem,\n} from \"./subscriptionItems.js\";\nimport {\n cancelSubscription,\n getSubscription,\n listSubscriptionsForStore,\n updateSubscription,\n} from \"./subscriptions.js\";\nimport {\n createUsageRecord,\n getUsageRecord,\n listUsageRecordsForSubscriptionItem,\n} from \"./usageRecords.js\";\nimport { getAuthenticatedUser } from \"./users.js\";\nimport { getVariant, listVariantsForProduct } from \"./variants.js\";\nimport {\n createWebhook,\n deleteWebhook,\n getWebhook,\n listWebhooksForStore,\n updateWebhook,\n} from \"./webhooks.js\";\n\n/**\n * Arguments for a single resource op invocation.\n *\n * One named input type — not a bag of unrelated returns.\n */\nexport interface InvokeOpArgs {\n id?: string | number;\n storeId?: string | number;\n parentId?: string | number;\n body?: unknown;\n}\n\n/**\n * Dispatch a docs-backed resource verb through the thin resource helpers.\n *\n * @param http - Shared API client.\n * @param resource - CLI resource token (`webhook`, `product`, …).\n * @param verb - Op verb (`get`, `create`, `refund`, …).\n * @param args - Ids / body for the call.\n * @returns A single JSON:API resource, list, void, or action payload.\n * @throws {FreshSqueezyError} When the verb is unknown or HTTP fails.\n *\n * @example\n * ```ts\n * const product = await invokeOp(http, \"product\", \"get\", { id: 42 });\n * ```\n */\nexport const invokeOp = async (\n http: HttpClient,\n resource: string,\n verb: OpVerb | string,\n args: InvokeOpArgs = {},\n): Promise<unknown> => {\n const spec = findResourceVerb(resource, verb);\n if (!spec) {\n throw new FreshSqueezyError({\n code: \"UNKNOWN_OP\",\n message: `Unknown or unsupported op: ${verb} ${resource}. Run \\`fresh-squeezy ops --list\\`.`,\n });\n }\n\n const key = `${spec.resource}:${spec.verb}` as const;\n switch (key) {\n case \"user:get\": {\n const doc = await getAuthenticatedUser(http);\n return doc.data;\n }\n\n case \"store:get\":\n return getStore(http, requireId(args, \"store\"));\n case \"store:list\":\n return listStores(http);\n\n case \"product:get\":\n return getProduct(http, requireId(args, \"product\"));\n case \"product:list\":\n return listProducts(http, requireStore(args));\n\n case \"variant:get\":\n return getVariant(http, requireId(args, \"variant\"));\n case \"variant:list\":\n return listVariantsForProduct(http, requireParent(args, \"product\"));\n\n case \"price:get\":\n return getPrice(http, requireId(args, \"price\"));\n case \"price:list\":\n return listPricesForVariant(http, requireParent(args, \"variant\"));\n\n case \"file:get\":\n return getFile(http, requireId(args, \"file\"));\n case \"file:list\":\n return listFilesForVariant(http, requireParent(args, \"variant\"));\n\n case \"customer:get\":\n return getCustomer(http, requireId(args, \"customer\"));\n case \"customer:list\":\n return listCustomersForStore(http, requireStore(args));\n case \"customer:create\":\n return createCustomer(http, requireBody(args));\n case \"customer:update\":\n return updateCustomer(http, requireId(args, \"customer\"), requireBody(args));\n\n case \"order:get\":\n return getOrder(http, requireId(args, \"order\"));\n case \"order:list\":\n return listOrdersForStore(http, requireStore(args));\n case \"order:refund\":\n return refundOrder(http, requireId(args, \"order\"), args.body);\n case \"order:generate-invoice\":\n return generateOrderInvoice(http, requireId(args, \"order\"), args.body);\n\n case \"order-item:get\":\n return getOrderItem(http, requireId(args, \"order-item\"));\n case \"order-item:list\":\n return listOrderItemsForOrder(http, requireParent(args, \"order\"));\n\n case \"subscription:get\":\n return getSubscription(http, requireId(args, \"subscription\"));\n case \"subscription:list\":\n return listSubscriptionsForStore(http, requireStore(args));\n case \"subscription:update\":\n return updateSubscription(http, requireId(args, \"subscription\"), requireBody(args));\n case \"subscription:cancel\":\n return cancelSubscription(http, requireId(args, \"subscription\"));\n\n case \"subscription-item:get\":\n return getSubscriptionItem(http, requireId(args, \"subscription-item\"));\n case \"subscription-item:list\":\n return listSubscriptionItemsForSubscription(http, requireParent(args, \"subscription\"));\n case \"subscription-item:update\":\n return updateSubscriptionItem(http, requireId(args, \"subscription-item\"), requireBody(args));\n case \"subscription-item:current-usage\":\n return getSubscriptionItemCurrentUsage(http, requireId(args, \"subscription-item\"));\n\n case \"subscription-invoice:get\":\n return getSubscriptionInvoice(http, requireId(args, \"subscription-invoice\"));\n case \"subscription-invoice:list\":\n return listSubscriptionInvoicesForSubscription(http, requireParent(args, \"subscription\"));\n case \"subscription-invoice:refund\":\n return refundSubscriptionInvoice(http, requireId(args, \"subscription-invoice\"), args.body);\n case \"subscription-invoice:generate-invoice\":\n return generateSubscriptionInvoice(http, requireId(args, \"subscription-invoice\"), args.body);\n\n case \"usage-record:get\":\n return getUsageRecord(http, requireId(args, \"usage-record\"));\n case \"usage-record:list\":\n return listUsageRecordsForSubscriptionItem(http, requireParent(args, \"subscription-item\"));\n case \"usage-record:create\":\n return createUsageRecord(http, requireBody(args));\n\n case \"discount:get\":\n return getDiscount(http, requireId(args, \"discount\"));\n case \"discount:list\":\n return listDiscountsForStore(http, requireStore(args));\n case \"discount:create\":\n return createDiscount(http, requireBody(args));\n case \"discount:delete\":\n await deleteDiscount(http, requireId(args, \"discount\"));\n return undefined;\n\n case \"discount-redemption:get\":\n return getDiscountRedemption(http, requireId(args, \"discount-redemption\"));\n case \"discount-redemption:list\":\n return listDiscountRedemptionsForDiscount(http, requireParent(args, \"discount\"));\n\n case \"license-key:get\":\n return getLicenseKey(http, requireId(args, \"license-key\"));\n case \"license-key:list\":\n return listLicenseKeysForStore(http, requireStore(args));\n case \"license-key:update\":\n return updateLicenseKey(http, requireId(args, \"license-key\"), requireBody(args));\n\n case \"license-key-instance:get\":\n return getLicenseKeyInstance(http, requireId(args, \"license-key-instance\"));\n case \"license-key-instance:list\":\n return listLicenseKeyInstancesForLicenseKey(http, requireParent(args, \"license-key\"));\n\n case \"checkout:get\":\n return getCheckout(http, requireId(args, \"checkout\"));\n case \"checkout:list\":\n return listCheckoutsForStore(http, requireStore(args));\n case \"checkout:create\":\n return createCheckout(http, requireBody(args));\n\n case \"webhook:get\":\n return getWebhook(http, requireId(args, \"webhook\"));\n case \"webhook:list\":\n return listWebhooksForStore(http, requireStore(args));\n case \"webhook:create\":\n return createWebhook(http, requireBody(args));\n case \"webhook:update\":\n return updateWebhook(http, requireId(args, \"webhook\"), requireBody(args));\n case \"webhook:delete\":\n await deleteWebhook(http, requireId(args, \"webhook\"));\n return undefined;\n\n case \"affiliate:get\":\n return getAffiliate(http, requireId(args, \"affiliate\"));\n case \"affiliate:list\":\n return listAffiliatesForStore(http, requireStore(args));\n\n default:\n throw new FreshSqueezyError({\n code: \"UNKNOWN_OP\",\n message: `Op registered but not wired: ${key}`,\n });\n }\n};\n\nconst requireId = (args: InvokeOpArgs, label: string): string | number => {\n if (args.id === undefined || args.id === \"\") {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--id is required for this ${label} operation.`,\n });\n }\n return args.id;\n};\n\nconst requireStore = (args: InvokeOpArgs): string | number => {\n if (args.storeId === undefined || args.storeId === \"\") {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"--store-ids (or store id) is required for this list operation.\",\n });\n }\n return args.storeId;\n};\n\nconst requireParent = (args: InvokeOpArgs, label: string): string | number => {\n if (args.parentId === undefined || args.parentId === \"\") {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--parent-id (${label} id) is required for this list operation.`,\n });\n }\n return args.parentId;\n};\n\nconst requireBody = (args: InvokeOpArgs): unknown => {\n if (args.body === undefined) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"A JSON body is required (--body, --body-file, or stdin).\",\n });\n }\n return args.body;\n};\n","import type { Mode } from \"./types.js\";\n\n/**\n * Map the boolean `meta.test_mode` flag from `/v1/users/me` to our `Mode` type.\n *\n * Returns `undefined` when the field is absent so older accounts and proxies\n * that don't surface the flag don't produce spurious mode mismatches. Lemon\n * Squeezy added `meta.test_mode` to the endpoint on 2024-01-05 (see API\n * changelog: https://docs.lemonsqueezy.com/api/getting-started/changelog).\n *\n * Pure function — exposed publicly so consumers can resolve a key's true mode\n * from a `/v1/users/me` document they already have, without re-running the\n * full connection validator. Keeping it free of any resource import is what\n * lets `core/` stay foundational (it never reaches up into `resources/`); the\n * I/O counterpart `fetchActualMode` lives in `validate/connection.ts`.\n */\nexport const resolveActualMode = (testMode: boolean | undefined): Mode | undefined => {\n if (testMode === true) return \"test\";\n if (testMode === false) return \"live\";\n return undefined;\n};\n","import type {\n ValidationIssue,\n ValidationResult,\n ValidationSeverity,\n ValidationTarget,\n} from \"../core/types.js\";\n\n/**\n * Stable issue codes. Consumers may switch on these in CI — do not rename\n * without a major version bump.\n */\nexport const ISSUE_CODES = {\n AUTH_FAILED: \"AUTH_FAILED\",\n MODE_MISMATCH: \"MODE_MISMATCH\",\n STORE_NOT_FOUND: \"STORE_NOT_FOUND\",\n STORE_NOT_OWNED: \"STORE_NOT_OWNED\",\n PRODUCT_NOT_FOUND: \"PRODUCT_NOT_FOUND\",\n PRODUCT_WRONG_STORE: \"PRODUCT_WRONG_STORE\",\n PRODUCT_UNPUBLISHED: \"PRODUCT_UNPUBLISHED\",\n PRODUCT_NO_BUY_URL: \"PRODUCT_NO_BUY_URL\",\n VARIANT_UNPUBLISHED: \"VARIANT_UNPUBLISHED\",\n VARIANT_MISSING: \"VARIANT_MISSING\",\n WEBHOOK_NOT_FOUND: \"WEBHOOK_NOT_FOUND\",\n WEBHOOK_EVENTS_MISSING: \"WEBHOOK_EVENTS_MISSING\",\n WEBHOOK_OPTIONAL_EVENTS: \"WEBHOOK_OPTIONAL_EVENTS\",\n DISCOUNT_NOT_FOUND: \"DISCOUNT_NOT_FOUND\",\n DISCOUNT_DRAFT: \"DISCOUNT_DRAFT\",\n DISCOUNT_EXPIRED: \"DISCOUNT_EXPIRED\",\n DISCOUNT_NOT_STARTED: \"DISCOUNT_NOT_STARTED\",\n DISCOUNT_REDEMPTIONS_EXHAUSTED: \"DISCOUNT_REDEMPTIONS_EXHAUSTED\",\n DISCOUNT_INVALID_AMOUNT: \"DISCOUNT_INVALID_AMOUNT\",\n DISCOUNT_STORE_MISMATCH: \"DISCOUNT_STORE_MISMATCH\",\n LICENSE_KEY_NOT_FOUND: \"LICENSE_KEY_NOT_FOUND\",\n LICENSE_KEY_DISABLED: \"LICENSE_KEY_DISABLED\",\n LICENSE_KEY_EXPIRED: \"LICENSE_KEY_EXPIRED\",\n LICENSE_KEY_AT_ACTIVATION_LIMIT: \"LICENSE_KEY_AT_ACTIVATION_LIMIT\",\n LICENSE_KEY_STORE_MISMATCH: \"LICENSE_KEY_STORE_MISMATCH\",\n PLAN_VARIANT_NOT_FOUND: \"PLAN_VARIANT_NOT_FOUND\",\n PLAN_NOT_SUBSCRIPTION: \"PLAN_NOT_SUBSCRIPTION\",\n PLAN_INVALID_INTERVAL: \"PLAN_INVALID_INTERVAL\",\n PLAN_FREE_PRICE: \"PLAN_FREE_PRICE\",\n PLAN_TRIAL_INCONSISTENT: \"PLAN_TRIAL_INCONSISTENT\",\n PLAN_DRAFT: \"PLAN_DRAFT\",\n PLAN_STORE_MISMATCH: \"PLAN_STORE_MISMATCH\",\n NETWORK_ERROR: \"NETWORK_ERROR\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\n/**\n * Build a `ValidationIssue` with defaults for the common case.\n * Extracted so every validator produces consistently shaped issues.\n */\nexport const issue = (\n code: string,\n severity: ValidationSeverity,\n message: string,\n extras: { suggestedFix?: string; context?: ValidationIssue[\"context\"] } = {},\n): ValidationIssue => {\n const base: ValidationIssue = { code, severity, message };\n if (extras.suggestedFix !== undefined) base.suggestedFix = extras.suggestedFix;\n if (extras.context !== undefined) base.context = extras.context;\n return base;\n};\n\n/**\n * Fold an issue list into a boolean. Used by every validator so `ok` is\n * computed the same way everywhere.\n */\nexport const isOk = (issues: ValidationIssue[]): boolean => {\n return !issues.some((entry) => entry.severity === \"error\");\n};\n\n/**\n * Compose a `ValidationResult` with the `ok` flag derived from issues.\n */\nexport const buildResult = <T>(\n name: string,\n mode: ValidationResult[\"mode\"],\n issues: ValidationIssue[],\n resource?: T,\n target?: ValidationTarget,\n): ValidationResult<T> => {\n const result: ValidationResult<T> = {\n name,\n ok: isOk(issues),\n mode,\n issues,\n };\n if (resource !== undefined) result.resource = resource;\n if (target !== undefined) result.target = target;\n return result;\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { ValidationIssue } from \"../core/types.js\";\nimport { ISSUE_CODES, issue } from \"./rules.js\";\n\n/**\n * How a caller wants the error mapper to translate specific failure modes.\n * Every field is optional — omit a slot and that mode falls through to the\n * generic mappings (`NETWORK_ERROR`, `UNKNOWN`).\n */\nexport interface IssueMapping {\n /** Translate 401 / `UNAUTHORIZED` to a specific issue code (e.g. `AUTH_FAILED`). */\n unauthorized?: { code: string; message: string; suggestedFix?: string };\n /** Translate 404 to a resource-specific not-found issue. */\n notFound?: {\n code: string;\n message: string;\n suggestedFix?: string;\n context?: ValidationIssue[\"context\"];\n };\n}\n\n/**\n * Map any thrown error from a resource fetch to a `ValidationIssue`. The\n * single source of truth for \"how does this validator surface failures?\":\n *\n * - 401 → `mapping.unauthorized.code` if provided, else fall through\n * - 404 → `mapping.notFound.code` if provided, else fall through\n * - network failure → `NETWORK_ERROR`\n * - any other `FreshSqueezyError` → `UNKNOWN` (with status + code context)\n * - any other `Error` → `UNKNOWN`\n *\n * Public so validators that own a non-trivial composite call (e.g.\n * `validateConnection`, which fetches users + stores in one try-block) can\n * reuse the same mapper as `probeFetch` does for single-resource fetches.\n */\nexport const mapErrorToIssue = (err: unknown, mapping: IssueMapping = {}): ValidationIssue => {\n if (err instanceof FreshSqueezyError) {\n if (mapping.unauthorized && (err.status === 401 || err.code === \"UNAUTHORIZED\")) {\n return issue(mapping.unauthorized.code, \"error\", mapping.unauthorized.message, {\n suggestedFix: mapping.unauthorized.suggestedFix,\n context: { status: err.status ?? null },\n });\n }\n if (mapping.notFound && err.status === 404) {\n return issue(mapping.notFound.code, \"error\", mapping.notFound.message, {\n suggestedFix: mapping.notFound.suggestedFix,\n context: mapping.notFound.context,\n });\n }\n if (err.code === \"NETWORK_ERROR\") {\n return issue(\n ISSUE_CODES.NETWORK_ERROR,\n \"error\",\n `Could not reach Lemon Squeezy: ${err.message}`,\n );\n }\n return issue(ISSUE_CODES.UNKNOWN, \"error\", err.message, {\n context: { status: err.status ?? null, code: err.code },\n });\n }\n const message = err instanceof Error ? err.message : \"Unknown error\";\n return issue(ISSUE_CODES.UNKNOWN, \"error\", message);\n};\n\n/**\n * Per-validator metadata for the resource-fetch probe.\n *\n * `notFoundCode` and `notFoundMessage` are resource-specific so each validator\n * keeps its stable `ISSUE_CODES.*_NOT_FOUND` identifier in callsite-visible\n * code. Everything else (mapping `FreshSqueezyError` shapes, falling back to\n * `UNKNOWN`, attaching status/code context) is handled here so validators\n * stop re-implementing the same try/catch skeleton.\n */\nexport interface FetchProbeOptions {\n notFoundCode: string;\n notFoundMessage: string;\n notFoundFix?: string;\n notFoundContext?: ValidationIssue[\"context\"];\n}\n\n/**\n * Outcome of a probed resource fetch. Either the resource (caller continues\n * with assertions) or one normalized issue (caller bails with `buildResult`).\n */\nexport type FetchProbeOutcome<T> =\n | { ok: true; resource: T }\n | { ok: false; issue: ValidationIssue };\n\n/**\n * Run a resource fetch with the same error mapping every single-resource\n * validator needs. Delegates to `mapErrorToIssue` so the rules live in\n * exactly one place.\n *\n * Validators keep their resource-specific assertion logic; only the I/O\n * scaffolding lives here. The deletion test: if this module disappeared every\n * validator would grow back the same try/catch skeleton.\n */\nexport const probeFetch = async <T>(\n fetcher: () => Promise<T>,\n options: FetchProbeOptions,\n): Promise<FetchProbeOutcome<T>> => {\n return probeCollection(fetcher, {\n notFound: {\n code: options.notFoundCode,\n message: options.notFoundMessage,\n suggestedFix: options.notFoundFix,\n context: options.notFoundContext,\n },\n });\n};\n\n/**\n * Run a fetch — typically a list/collection endpoint — through the shared\n * error mapper without `probeFetch`'s single-resource `notFound` slot. Pass an\n * `IssueMapping` to translate specific statuses (e.g. 401 → `AUTH_FAILED` for\n * the connection validator); omit it and every failure normalizes to\n * `NETWORK_ERROR` / `UNKNOWN`.\n *\n * The deletion test: without this, `validateWebhook` and `validateConnection`\n * would each hand-roll the same try/catch → `mapErrorToIssue` skeleton that\n * `probeFetch` already centralizes for single-resource fetches.\n */\nexport const probeCollection = async <T>(\n fetcher: () => Promise<T>,\n mapping: IssueMapping = {},\n): Promise<FetchProbeOutcome<T>> => {\n try {\n return { ok: true, resource: await fetcher() };\n } catch (err) {\n return { ok: false, issue: mapErrorToIssue(err, mapping) };\n }\n};\n\n/**\n * Inputs for a store-ownership cross-check.\n *\n * `code` and `label` are resource-specific so the issue stays informative\n * (\"Discount belongs to store …\" vs \"Product belongs to store …\"). `id` and\n * `extraContext` let validators describe which resource was inspected so\n * downstream tooling can correlate the mismatch with the request that\n * produced it.\n */\nexport interface OwnershipCheck {\n expectedStoreId: string | number;\n actualStoreId: string | number;\n /** Stable issue code (e.g. `ISSUE_CODES.DISCOUNT_STORE_MISMATCH`). */\n code: string;\n /** Resource label used in the issue message (e.g. `\"Discount\"`). */\n label: string;\n suggestedFix?: string;\n /** Extra context fields merged in alongside `expectedStoreId` / `actualStoreId`. */\n extraContext?: ValidationIssue[\"context\"];\n}\n\n/**\n * Compare an expected store ID against the value Lemon Squeezy returned on\n * the resource. Returns a `ValidationIssue` if they don't match, or `null` if\n * ownership is fine. Validators add the issue to their issue list — this\n * helper does not push for them.\n *\n * Both inputs are coerced via `String(...)` so a numeric `store_id` from JSON\n * compares correctly against a string-typed `storeId` from the CLI / env.\n */\nexport const checkStoreOwnership = (check: OwnershipCheck): ValidationIssue | null => {\n const expected = String(check.expectedStoreId);\n const actual = String(check.actualStoreId);\n if (expected === actual) return null;\n\n return issue(\n check.code,\n \"error\",\n `${check.label} belongs to store ${actual}, expected ${expected}.`,\n {\n suggestedFix: check.suggestedFix,\n context: {\n expectedStoreId: expected,\n actualStoreId: actual,\n ...(check.extraContext ?? {}),\n },\n },\n );\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport { resolveActualMode } from \"../core/mode.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { listStores } from \"../resources/stores.js\";\nimport { type UserAttributes, getAuthenticatedUser } from \"../resources/users.js\";\nimport { probeCollection } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\n/**\n * Connection validator summary attached to the `resource` field. Keeps the\n * validator self-contained — consumers need not call `users/me` again.\n *\n * `actualMode` is derived from the `meta.test_mode` field Lemon Squeezy added\n * to `/v1/users/me` on 2024-01-05 (API changelog). When the caller declared\n * one mode but the key actually belongs to the other, the validator fires a\n * `MODE_MISMATCH` error — the single misconfiguration most likely to cause a\n * prod-in-staging (or vice versa) incident.\n */\nexport interface ConnectionSummary {\n user: UserAttributes;\n storeCount: number;\n storeIds: string[];\n /** The mode the API key actually belongs to (per `/v1/users/me` meta). */\n actualMode?: Mode;\n /** The mode the caller asked for at construction time. */\n declaredMode: Mode;\n}\n\n/**\n * Verify that the API key works, surface the account identity + reachable\n * stores, and cross-check declared mode vs the key's true mode.\n *\n * This is the first check every `doctor()` run performs; if it fails,\n * no downstream validator has anything useful to report.\n */\nexport const validateConnection = async (\n http: HttpClient,\n mode: Mode,\n): Promise<ValidationResult<ConnectionSummary>> => {\n const fetched = await probeCollection(\n async () => {\n const userDoc = await getAuthenticatedUser(http);\n const stores = await listStores(http);\n return { userDoc, stores };\n },\n {\n unauthorized: {\n code: ISSUE_CODES.AUTH_FAILED,\n message: \"API key rejected by Lemon Squeezy.\",\n suggestedFix: \"Regenerate the key at https://app.lemonsqueezy.com/settings/api.\",\n },\n },\n );\n\n if (!fetched.ok) {\n return buildResult(\"connection\", mode, [fetched.issue]);\n }\n\n const { userDoc, stores } = fetched.resource;\n const actualMode = resolveActualMode(userDoc.meta?.test_mode);\n const summary: ConnectionSummary = {\n user: userDoc.data.attributes,\n storeCount: stores.length,\n storeIds: stores.map((store) => store.id),\n declaredMode: mode,\n ...(actualMode ? { actualMode } : {}),\n };\n\n const issues: ValidationIssue[] = [];\n\n if (actualMode && actualMode !== mode) {\n issues.push(\n issue(\n ISSUE_CODES.MODE_MISMATCH,\n \"error\",\n `API key is a ${actualMode}-mode key but was run with --mode ${mode}.`,\n {\n suggestedFix: `Either pass --mode ${actualMode} or use a ${mode}-mode key from https://app.lemonsqueezy.com/settings/api.`,\n context: { declared: mode, actual: actualMode },\n },\n ),\n );\n }\n\n if (stores.length === 0) {\n issues.push(\n issue(\n ISSUE_CODES.STORE_NOT_FOUND,\n \"warning\",\n \"API key authenticated but no stores are reachable.\",\n { suggestedFix: \"Confirm the API key belongs to an account that owns at least one store.\" },\n ),\n );\n }\n\n return buildResult(\"connection\", mode, issues, summary);\n};\n\n/**\n * Ask the Lemon Squeezy API which mode the configured key actually belongs to.\n *\n * Useful as a fail-fast check at app boot — e.g. refuse to start if a prod key\n * is loaded into a staging deployment — without paying for a full doctor run.\n * Returns `undefined` if the API doesn't surface `meta.test_mode` (older\n * proxies, partial responses).\n *\n * Lives here rather than in `core/mode.ts` so the foundational `core/` layer\n * never imports from `resources/`; the pure `resolveActualMode` it delegates to\n * still lives in `core/`. Throws `FreshSqueezyError` on auth or network\n * failure; callers that want a structured non-throwing result should use\n * `validateConnection` instead.\n */\nexport const fetchActualMode = async (http: HttpClient): Promise<Mode | undefined> => {\n const doc = await getAuthenticatedUser(http);\n return resolveActualMode(doc.meta?.test_mode);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type DiscountAttributes, getDiscount } from \"../resources/discounts.js\";\nimport { checkStoreOwnership, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface DiscountValidationOptions {\n storeId: string | number;\n discountId: string | number;\n}\n\n/**\n * Validate a Lemon Squeezy discount code. Catches the most common\n * misconfigurations: draft discounts that can't be redeemed, expired or\n * not-yet-active windows, invalid amounts (negative or >100% for percent\n * type), and store ownership mismatches.\n *\n * The redemption exhaustion check is deliberately conservative (v1): it only\n * flags when `is_limited_redemptions` is true and `max_redemptions` is zero,\n * because a full redemption count fetch against\n * `/v1/discount-redemptions?filter[discount_id]=` is YAGNI until a consumer\n * asks for it.\n */\nexport const validateDiscount = async (\n http: HttpClient,\n mode: Mode,\n options: DiscountValidationOptions,\n): Promise<ValidationResult<DiscountAttributes>> => {\n const target = {\n label: `discount ${options.discountId}`,\n id: String(options.discountId),\n };\n\n const fetched = await probeFetch(() => getDiscount(http, options.discountId), {\n notFoundCode: ISSUE_CODES.DISCOUNT_NOT_FOUND,\n notFoundMessage: `Discount ${options.discountId} not found.`,\n notFoundFix: \"Verify the discount ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { discountId: String(options.discountId) },\n });\n\n if (!fetched.ok) {\n return buildResult<DiscountAttributes>(\"discount\", mode, [fetched.issue], undefined, target);\n }\n\n const attrs = fetched.resource.attributes;\n return buildResult(\"discount\", mode, checkDiscount(attrs, { storeId: options.storeId }), attrs, {\n label: `${attrs.name} (${attrs.code})`,\n id: String(options.discountId),\n });\n};\n\n/**\n * Pure attribute assertions for a discount: store ownership, draft/expiry/\n * activation windows, redemption exhaustion, and amount validity. No I/O, so\n * the rules are unit-testable with plain data.\n */\nexport const checkDiscount = (\n attrs: DiscountAttributes,\n options: { storeId: string | number },\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.storeId,\n actualStoreId: attrs.store_id,\n code: ISSUE_CODES.DISCOUNT_STORE_MISMATCH,\n label: \"Discount\",\n suggestedFix: \"Use the correct store ID or discount ID — discounts should not cross stores.\",\n });\n if (mismatch) issues.push(mismatch);\n\n if (attrs.status === \"draft\") {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_DRAFT,\n \"warning\",\n `Discount \"${attrs.name}\" is in draft status — customers cannot redeem it.`,\n {\n suggestedFix:\n \"Publish the discount in the Lemon Squeezy dashboard before sharing the code.\",\n context: { name: attrs.name, code: attrs.code },\n },\n ),\n );\n }\n\n const now = new Date();\n if (attrs.expires_at && new Date(attrs.expires_at) < now) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_EXPIRED,\n \"error\",\n `Discount \"${attrs.name}\" expired at ${attrs.expires_at}.`,\n {\n suggestedFix: \"Extend the expiration date or create a new discount.\",\n context: { name: attrs.name, expiresAt: attrs.expires_at },\n },\n ),\n );\n }\n\n if (attrs.starts_at && new Date(attrs.starts_at) > now) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_NOT_STARTED,\n \"warning\",\n `Discount \"${attrs.name}\" starts at ${attrs.starts_at} — not yet active.`,\n {\n suggestedFix: \"Wait for the start date or adjust it in the dashboard.\",\n context: { name: attrs.name, startsAt: attrs.starts_at },\n },\n ),\n );\n }\n\n if (attrs.is_limited_redemptions && attrs.max_redemptions <= 0) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_REDEMPTIONS_EXHAUSTED,\n \"warning\",\n `Discount \"${attrs.name}\" has limited redemptions with max_redemptions ≤ 0.`,\n {\n suggestedFix: \"Increase max_redemptions or disable the redemption limit.\",\n context: { name: attrs.name, maxRedemptions: attrs.max_redemptions },\n },\n ),\n );\n }\n\n if (attrs.amount <= 0) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_INVALID_AMOUNT,\n \"error\",\n `Discount \"${attrs.name}\" has amount ${attrs.amount} — must be positive.`,\n {\n suggestedFix: \"Set a positive discount amount in the dashboard.\",\n context: { name: attrs.name, amount: attrs.amount },\n },\n ),\n );\n } else if (attrs.amount_type === \"percent\" && attrs.amount > 100) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_INVALID_AMOUNT,\n \"error\",\n `Discount \"${attrs.name}\" is ${attrs.amount}% — percent discounts cannot exceed 100%.`,\n {\n suggestedFix: \"Set the discount to 100% or less.\",\n context: { name: attrs.name, amount: attrs.amount, amountType: attrs.amount_type },\n },\n ),\n );\n }\n\n return issues;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type LicenseKeyAttributes, getLicenseKey } from \"../resources/licenseKeys.js\";\nimport { checkStoreOwnership, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface LicenseKeyValidationOptions {\n storeId: string | number;\n licenseKeyId: string | number;\n}\n\n/**\n * Validate a Lemon Squeezy license key. Surfaces disabled keys, expired\n * keys, keys at their activation limit, and store ownership mismatches — the\n * four states most likely to cause \"why can't my customer activate?\"\n * support tickets.\n */\nexport const validateLicenseKey = async (\n http: HttpClient,\n mode: Mode,\n options: LicenseKeyValidationOptions,\n): Promise<ValidationResult<LicenseKeyAttributes>> => {\n const target = {\n label: `license key ${options.licenseKeyId}`,\n id: String(options.licenseKeyId),\n };\n\n const fetched = await probeFetch(() => getLicenseKey(http, options.licenseKeyId), {\n notFoundCode: ISSUE_CODES.LICENSE_KEY_NOT_FOUND,\n notFoundMessage: `License key ${options.licenseKeyId} not found.`,\n notFoundFix: \"Verify the license key ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { licenseKeyId: String(options.licenseKeyId) },\n });\n\n if (!fetched.ok) {\n return buildResult<LicenseKeyAttributes>(\n \"licenseKey\",\n mode,\n [fetched.issue],\n undefined,\n target,\n );\n }\n\n const attrs = fetched.resource.attributes;\n return buildResult(\n \"licenseKey\",\n mode,\n checkLicenseKey(attrs, { storeId: options.storeId }),\n attrs,\n { label: attrs.key_short, id: String(options.licenseKeyId) },\n );\n};\n\n/**\n * Pure attribute assertions for a license key: store ownership, disabled/\n * expired state, and activation-limit exhaustion. No I/O, so the rules are\n * unit-testable with plain data.\n */\nexport const checkLicenseKey = (\n attrs: LicenseKeyAttributes,\n options: { storeId: string | number },\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.storeId,\n actualStoreId: attrs.store_id,\n code: ISSUE_CODES.LICENSE_KEY_STORE_MISMATCH,\n label: \"License key\",\n suggestedFix: \"Use the correct store ID or license key ID — keys should not cross stores.\",\n });\n if (mismatch) issues.push(mismatch);\n\n if (attrs.disabled) {\n issues.push(\n issue(\n ISSUE_CODES.LICENSE_KEY_DISABLED,\n \"error\",\n `License key ${attrs.key_short} is disabled.`,\n {\n suggestedFix: \"Re-enable the license key in the Lemon Squeezy dashboard.\",\n context: { keyShort: attrs.key_short },\n },\n ),\n );\n }\n\n if (attrs.expires_at && new Date(attrs.expires_at) < new Date()) {\n issues.push(\n issue(\n ISSUE_CODES.LICENSE_KEY_EXPIRED,\n \"error\",\n `License key ${attrs.key_short} expired at ${attrs.expires_at}.`,\n {\n suggestedFix: \"Extend the expiration date or issue a new license key.\",\n context: { keyShort: attrs.key_short, expiresAt: attrs.expires_at },\n },\n ),\n );\n }\n\n if (attrs.activation_limit !== null && attrs.instances_count >= attrs.activation_limit) {\n issues.push(\n issue(\n ISSUE_CODES.LICENSE_KEY_AT_ACTIVATION_LIMIT,\n \"warning\",\n `License key ${attrs.key_short} has reached its activation limit (${attrs.instances_count}/${attrs.activation_limit}).`,\n {\n suggestedFix: \"Increase the activation limit or deactivate unused instances.\",\n context: {\n keyShort: attrs.key_short,\n instancesCount: attrs.instances_count,\n activationLimit: attrs.activation_limit,\n },\n },\n ),\n );\n }\n\n return issues;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type ProductAttributes, getProduct } from \"../resources/products.js\";\nimport { listVariantsForProduct } from \"../resources/variants.js\";\nimport { checkStoreOwnership, probeCollection, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface ProductValidationOptions {\n productId: string | number;\n /** Optional: confirm the product belongs to this store. */\n expectedStoreId?: string | number;\n}\n\n/**\n * Validate a product's publish state, store ownership, and that it has at\n * least one published variant. Surfaces the most common misconfigurations\n * caught in the wild (unpublished product, wrong store, missing variants).\n */\nexport const validateProduct = async (\n http: HttpClient,\n mode: Mode,\n options: ProductValidationOptions,\n): Promise<ValidationResult<ProductAttributes>> => {\n const issues: ValidationIssue[] = [];\n const target = {\n label: `product ${options.productId}`,\n id: String(options.productId),\n };\n\n const fetched = await probeFetch(() => getProduct(http, options.productId), {\n notFoundCode: ISSUE_CODES.PRODUCT_NOT_FOUND,\n notFoundMessage: `Product ${options.productId} not found.`,\n notFoundFix: \"Verify the product ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { productId: String(options.productId) },\n });\n\n if (!fetched.ok) {\n return buildResult<ProductAttributes>(\"product\", mode, [fetched.issue], undefined, target);\n }\n\n const attrs = fetched.resource.attributes;\n issues.push(...checkProduct(attrs, { expectedStoreId: options.expectedStoreId }));\n\n // Variant population needs a second fetch, so it stays out of the pure check.\n // Listing is best-effort: map via probeCollection, then soft-fail as warning.\n const variantsProbed = await probeCollection(() =>\n listVariantsForProduct(http, options.productId),\n );\n if (!variantsProbed.ok) {\n issues.push({ ...variantsProbed.issue, severity: \"warning\" });\n } else if (variantsProbed.resource.length === 0) {\n issues.push(\n issue(\n ISSUE_CODES.VARIANT_MISSING,\n \"error\",\n \"Product has no variants. Customers cannot purchase it.\",\n { suggestedFix: \"Add at least one variant in the product configuration.\" },\n ),\n );\n } else if (\n !variantsProbed.resource.some((variant) => variant.attributes.status === \"published\")\n ) {\n issues.push(\n issue(\n ISSUE_CODES.VARIANT_UNPUBLISHED,\n \"error\",\n \"Product has variants but none are published.\",\n { suggestedFix: \"Publish at least one variant.\" },\n ),\n );\n }\n\n return buildResult(\"product\", mode, issues, attrs, {\n label: attrs.name,\n id: String(options.productId),\n });\n};\n\n/**\n * Pure attribute assertions for a product: store ownership, publish state, and\n * hosted-checkout availability. The variant-population rule needs a second\n * fetch and stays in `validateProduct`; everything here runs on plain data, so\n * the rules are unit-testable without a mock fetch.\n */\nexport const checkProduct = (\n attrs: ProductAttributes,\n options: { expectedStoreId?: string | number } = {},\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n if (options.expectedStoreId !== undefined) {\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.expectedStoreId,\n actualStoreId: attrs.store_id,\n code: ISSUE_CODES.PRODUCT_WRONG_STORE,\n label: \"Product\",\n suggestedFix:\n \"Either use the correct store ID or the correct product ID — IDs should not cross stores.\",\n });\n if (mismatch) issues.push(mismatch);\n }\n\n if (attrs.status !== \"published\") {\n issues.push(\n issue(\n ISSUE_CODES.PRODUCT_UNPUBLISHED,\n \"error\",\n `Product is in \"${attrs.status}\" state, not \"published\".`,\n {\n suggestedFix: \"Publish the product in the Lemon Squeezy dashboard before selling.\",\n context: { status: attrs.status },\n },\n ),\n );\n }\n\n if (!attrs.buy_now_url) {\n issues.push(\n issue(\n ISSUE_CODES.PRODUCT_NO_BUY_URL,\n \"warning\",\n \"Product has no buy-now URL. Hosted checkout may be disabled.\",\n { suggestedFix: \"Enable buy-now in product settings, or use a custom checkout flow.\" },\n ),\n );\n }\n\n return issues;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationResult } from \"../core/types.js\";\nimport { type StoreAttributes, getStore } from \"../resources/stores.js\";\nimport { probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult } from \"./rules.js\";\n\n/**\n * Verify a store exists and is reachable with the current API key. A 404\n * typically means the key belongs to a different account, not that the store\n * is gone — the suggested fix reflects that.\n */\nexport const validateStore = async (\n http: HttpClient,\n mode: Mode,\n storeId: string | number,\n): Promise<ValidationResult<StoreAttributes>> => {\n const target = { label: `store ${storeId}`, id: String(storeId) };\n\n const fetched = await probeFetch(() => getStore(http, storeId), {\n notFoundCode: ISSUE_CODES.STORE_NOT_FOUND,\n notFoundMessage: `Store ${storeId} not found with the current API key.`,\n notFoundFix: \"Check the store ID and confirm the API key belongs to the account that owns it.\",\n notFoundContext: { storeId: String(storeId) },\n });\n\n if (!fetched.ok) {\n return buildResult<StoreAttributes>(\"store\", mode, [fetched.issue], undefined, target);\n }\n\n return buildResult(\"store\", mode, [], fetched.resource.attributes, {\n label: fetched.resource.attributes.name,\n id: String(storeId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { getProduct } from \"../resources/products.js\";\nimport { type SubscriptionVariantAttributes, getVariant } from \"../resources/variants.js\";\nimport { checkStoreOwnership, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface SubscriptionPlanValidationOptions {\n storeId: string | number;\n variantId: string | number;\n}\n\n/** Summary of a subscription plan variant's validated state. */\nexport interface SubscriptionPlanSummary {\n variantId: string;\n interval: string | null;\n intervalCount: number | null;\n price: number;\n hasFreeTrial: boolean;\n status: string;\n}\n\nconst VALID_INTERVALS = new Set([\"day\", \"week\", \"month\", \"year\"]);\n\n/**\n * Validate a Lemon Squeezy \"subscription plan\", which is a variant with\n * `is_subscription: true`. Checks that the variant is actually a subscription,\n * has a valid billing interval, and that trial settings are consistent.\n *\n * Store cross-check requires fetching the parent product to read its\n * `store_id`. This is an extra network hop but catches the common mistake of\n * passing a variant ID from one store while targeting another. Accept the\n * `storeId` as advisory — if the product fetch fails the cross-check is\n * silently skipped rather than blocking the entire validation.\n */\nexport const validateSubscriptionPlan = async (\n http: HttpClient,\n mode: Mode,\n options: SubscriptionPlanValidationOptions,\n): Promise<ValidationResult<SubscriptionPlanSummary>> => {\n const target = {\n label: `variant ${options.variantId}`,\n id: String(options.variantId),\n };\n\n const fetched = await probeFetch(\n () => getVariant<SubscriptionVariantAttributes>(http, options.variantId),\n {\n notFoundCode: ISSUE_CODES.PLAN_VARIANT_NOT_FOUND,\n notFoundMessage: `Variant ${options.variantId} not found.`,\n notFoundFix: \"Verify the variant ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { variantId: String(options.variantId) },\n },\n );\n\n if (!fetched.ok) {\n return buildResult<SubscriptionPlanSummary>(\n \"subscriptionPlan\",\n mode,\n [fetched.issue],\n undefined,\n target,\n );\n }\n\n const variant = fetched.resource;\n const attrs = variant.attributes;\n const issues = checkSubscriptionPlan(attrs, { variantId: options.variantId });\n\n // Store cross-check needs a second fetch (parent product). Advisory only —\n // skip on failure rather than blocking the pure attribute checks above.\n const productProbed = await probeFetch(() => getProduct(http, attrs.product_id), {\n notFoundCode: ISSUE_CODES.PRODUCT_NOT_FOUND,\n notFoundMessage: `Product ${attrs.product_id} not found.`,\n });\n if (productProbed.ok) {\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.storeId,\n actualStoreId: productProbed.resource.attributes.store_id,\n code: ISSUE_CODES.PLAN_STORE_MISMATCH,\n label: `Subscription variant (via product ${attrs.product_id})`,\n suggestedFix: \"Use the correct store ID or variant ID — plans should not cross stores.\",\n extraContext: { productId: String(attrs.product_id) },\n });\n if (mismatch) issues.push(mismatch);\n }\n // product fetch failed: keep silent skip (advisory ownership only)\n\n const summary: SubscriptionPlanSummary = {\n variantId: variant.id,\n interval: attrs.interval,\n intervalCount: attrs.interval_count,\n price: attrs.price,\n hasFreeTrial: attrs.has_free_trial,\n status: attrs.status,\n };\n\n return buildResult(\"subscriptionPlan\", mode, issues, summary, {\n label: attrs.name,\n id: String(options.variantId),\n });\n};\n\n/**\n * Pure attribute assertions for a subscription variant: that it is actually a\n * subscription, has a valid interval / interval_count, is not free-priced, has\n * consistent trial settings, and is not a draft. The store cross-check needs a\n * second fetch and stays in `validateSubscriptionPlan`; everything here runs on\n * plain data, so the rules are unit-testable without a mock fetch.\n */\nexport const checkSubscriptionPlan = (\n attrs: SubscriptionVariantAttributes,\n options: { variantId: string | number },\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n if (!attrs.is_subscription) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_NOT_SUBSCRIPTION,\n \"error\",\n `Variant ${options.variantId} is not a subscription variant (is_subscription is false).`,\n {\n suggestedFix:\n \"Use a variant that has subscription billing enabled, or use the regular variant validator.\",\n context: { variantId: String(options.variantId) },\n },\n ),\n );\n }\n\n if (!attrs.interval || !VALID_INTERVALS.has(attrs.interval)) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_INVALID_INTERVAL,\n \"error\",\n `Subscription variant has invalid interval: \"${attrs.interval ?? \"missing\"}\". Expected one of: day, week, month, year.`,\n {\n suggestedFix: \"Set a valid billing interval in the variant configuration.\",\n context: { interval: attrs.interval ?? null },\n },\n ),\n );\n }\n\n if (attrs.interval_count === null || attrs.interval_count <= 0) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_INVALID_INTERVAL,\n \"error\",\n `Subscription variant has invalid interval_count: ${attrs.interval_count}. Must be a positive integer.`,\n {\n suggestedFix:\n \"Set interval_count to a positive value (e.g. 1 for monthly, 2 for biweekly).\",\n context: { intervalCount: attrs.interval_count },\n },\n ),\n );\n }\n\n if (attrs.price === 0 && attrs.is_subscription) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_FREE_PRICE,\n \"warning\",\n \"Subscription variant has a price of 0 — this is almost always a misconfiguration for paid plans.\",\n {\n suggestedFix:\n \"Set the variant price to the intended amount in cents, or confirm this is intentionally free.\",\n context: { price: attrs.price },\n },\n ),\n );\n }\n\n if (attrs.has_free_trial && (!attrs.trial_interval || (attrs.trial_interval_count ?? 0) <= 0)) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_TRIAL_INCONSISTENT,\n \"warning\",\n `Subscription variant has free trial enabled but trial interval is misconfigured (interval: \"${attrs.trial_interval ?? \"missing\"}\", count: ${attrs.trial_interval_count ?? 0}).`,\n {\n suggestedFix: \"Set a valid trial interval and count, or disable the free trial.\",\n context: {\n trialInterval: attrs.trial_interval ?? null,\n trialIntervalCount: attrs.trial_interval_count ?? null,\n },\n },\n ),\n );\n }\n\n if (attrs.status === \"draft\") {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_DRAFT,\n \"warning\",\n \"Subscription variant is in draft status — customers cannot subscribe.\",\n {\n suggestedFix: \"Publish the variant in the Lemon Squeezy dashboard.\",\n context: { status: attrs.status },\n },\n ),\n );\n }\n\n return issues;\n};\n","/**\n * Domain-equality primitives for fresh-squeezy.\n *\n * These helpers encode \"when are two values the same in our domain?\" — separate\n * from the validators that consume them so the rules are testable on their own\n * and reusable from any future surface (init, dedupe, repair, etc.).\n */\n\n/**\n * Compare two webhook URLs ignoring trailing slashes and casing.\n *\n * Lemon Squeezy strips trailing slashes when persisting a webhook, but users\n * often paste the trailing-slash form into their config. The webhook validator\n * relies on this rule to match a configured URL against the registered list.\n */\nexport const sameWebhookUrl = (a: string, b: string): boolean => {\n return normalizeWebhookUrl(a) === normalizeWebhookUrl(b);\n};\n\nconst normalizeWebhookUrl = (raw: string): string => {\n return raw.replace(/\\/+$/, \"\").toLowerCase();\n};\n","import { GENERATED_LEMON_SQUEEZY_RESOURCES } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Support manifest: the locally reviewed source of truth for what\n * fresh-squeezy explicitly understands on the Lemon Squeezy platform.\n *\n * Resource/type coverage is generated from Lemon Squeezy object docs with\n * `pnpm generate:api-types`. Validator policy remains reviewed here:\n * when the platform adds new webhook events or behavior, bump the entries\n * below and re-snapshot the changelog page with\n * `pnpm check:changelog -- --update`.\n *\n * Changelog source: https://docs.lemonsqueezy.com/api/getting-started/changelog\n * Last reviewed: 2026-05-07\n */\n\n/** Resources fresh-squeezy understands today, generated from object docs. */\nexport const SUPPORTED_RESOURCES = GENERATED_LEMON_SQUEEZY_RESOURCES;\n\n/**\n * Webhook events fresh-squeezy expects a production integration to subscribe to\n * at minimum. Consumers can still subscribe to more; the validator only flags\n * missing ones from this list.\n *\n * Rationale:\n * - `order_*` covers one-off purchases and refunds.\n * - `subscription_*` covers the recurring-billing lifecycle.\n * - `subscription_payment_*` covers dunning / retry loops.\n *\n * Confirmed present in the Lemon Squeezy webhook topic list as of 2026-04-24.\n */\nexport const RECOMMENDED_WEBHOOK_EVENTS = [\n \"order_created\",\n \"order_refunded\",\n \"subscription_created\",\n \"subscription_updated\",\n \"subscription_cancelled\",\n \"subscription_resumed\",\n \"subscription_expired\",\n \"subscription_payment_success\",\n \"subscription_payment_failed\",\n] as const;\n\n/**\n * Newer or integration-specific events surfaced as info-level suggestions\n * rather than errors. Missing these is common and not necessarily a\n * misconfiguration.\n *\n * Per-entry changelog provenance (source:\n * https://docs.lemonsqueezy.com/api/getting-started/changelog):\n *\n * - `customer_updated` — added 2026-02-25. Fires when a customer record\n * changes (e.g. email, marketing consent). Needed if the app mirrors\n * customer data locally.\n * - `affiliate_activated` — added 2025-01-21 alongside the affiliates\n * endpoints. Only relevant if the store has an affiliate program.\n * - `license_key_created` / `license_key_updated` — License API events.\n * Only relevant when variants have `has_license_keys: true`.\n */\nexport const OPTIONAL_WEBHOOK_EVENTS = [\n \"customer_updated\",\n \"affiliate_activated\",\n \"license_key_created\",\n \"license_key_updated\",\n] as const;\n\n/**\n * Platform additions we have read and decided *not* to validate against yet,\n * documented here so maintainers see the deliberate gap during review.\n *\n * Tracked so the drift workflow has an \"expected state\" to compare against:\n * if the changelog page changes and none of these items explain it, the diff\n * is probably something new that needs a manifest update.\n */\nexport const ACKNOWLEDGED_CHANGELOG_ENTRIES = [\n {\n date: \"2026-02-25\",\n summary: \"Added customer_updated webhook event.\",\n handledBy: \"OPTIONAL_WEBHOOK_EVENTS\",\n },\n {\n date: \"2025-06-11\",\n summary: \"Added payment_processor attribute to Subscription objects.\",\n handledBy:\n \"Surfaced as SubscriptionAttributes.payment_processor in src/resources/subscriptions.ts.\",\n },\n {\n date: \"2025-01-21\",\n summary: \"Added Affiliates endpoints and affiliate_activated webhook.\",\n handledBy: \"OPTIONAL_WEBHOOK_EVENTS (event only; resource stays v2 scope)\",\n },\n {\n date: \"2024-12-06\",\n summary: \"Added quantity parameter to OrderItem objects.\",\n handledBy: \"OrderItemAttributes.quantity (src/resources/orderItems.ts).\",\n },\n {\n date: \"2024-09-10\",\n summary: \"Added fraudulent Order status.\",\n handledBy: \"OrderAttributes.status union includes 'fraudulent' (src/resources/orders.ts).\",\n },\n {\n date: \"2024-09-04\",\n summary: \"Added Issue an Order refund and Issue a Subscription Invoice refund endpoints.\",\n handledBy:\n \"Not wrapped — reachable via client.request('/v1/orders/:id/refund'). Refund-amount fields surfaced on OrderAttributes.\",\n },\n {\n date: \"2024-08-07\",\n summary:\n \"Added refunded_amount, refunded_amount_usd, refunded_amount_formatted to Order and Subscription invoice objects.\",\n handledBy: \"OrderAttributes.refunded_amount*, SubscriptionInvoiceAttributes.refunded_amount*.\",\n },\n {\n date: \"2024-06-09\",\n summary: \"Added links property to Variant objects.\",\n handledBy: \"VariantAttributes.links (src/resources/variants.ts).\",\n },\n {\n date: \"2024-05-20\",\n summary: \"Added Generate order invoice endpoint.\",\n handledBy: \"Not wrapped — reachable via client.request('/v1/orders/:id/generate-invoice').\",\n },\n {\n date: \"2024-04-09\",\n summary: \"License Key expires_at is now mutable via the update endpoint.\",\n handledBy:\n \"Type unchanged (LicenseKeyAttributes.expires_at already nullable string). Mutation reachable via client.request('PATCH /v1/license-keys/:id').\",\n },\n {\n date: \"2024-03-28\",\n summary: \"Subscription trial_ends_at is now mutable via the update endpoint.\",\n handledBy:\n \"SubscriptionAttributes.trial_ends_at plus CheckoutOptions.skip_trial. Mutations remain reachable via client.request().\",\n },\n {\n date: \"2024-02-20\",\n summary: \"Added urls.update_customer_portal to Subscription objects.\",\n handledBy: \"SubscriptionUrls.update_customer_portal (src/resources/subscriptions.ts).\",\n },\n {\n date: \"2024-02-12\",\n summary:\n \"Added Generate subscription invoice endpoint and invoice_immediately / disable_prorations parameters.\",\n handledBy:\n \"SubscriptionItemUpdateAttributes.invoice_immediately / disable_prorations; invoice endpoint reachable via client.request().\",\n },\n {\n date: \"2024-02-05\",\n summary: \"Added tax_inclusive parameter to Order objects and Subscription invoice objects.\",\n handledBy: \"OrderAttributes.tax_inclusive, SubscriptionInvoiceAttributes.tax_inclusive.\",\n },\n {\n date: \"2024-01-21\",\n summary:\n \"Added setup_fee_enabled / setup_fee to Price objects; setup_fee* to Subscription invoice.\",\n handledBy: \"PriceAttributes.setup_fee*, OrderAttributes.setup_fee*.\",\n },\n {\n date: \"2024-01-15\",\n summary: \"Added unit_price_decimal to Price objects.\",\n handledBy: \"PriceAttributes.unit_price_decimal.\",\n },\n {\n date: \"2024-01-05\",\n summary: \"Added test_mode flag to /v1/users/me meta.\",\n handledBy:\n \"Read in validateConnection to emit MODE_MISMATCH when the key's true mode differs from the caller's declared mode.\",\n },\n {\n date: \"2023-09-19\",\n summary: \"Added customer_portal URLs to Subscription and Customer objects.\",\n handledBy: \"SubscriptionUrls.customer_portal and CustomerUrls.customer_portal.\",\n },\n {\n date: \"2023-08-23\",\n summary:\n \"Added checkout_data.variant_quantities, subscription items, prices, and usage-based billing.\",\n handledBy:\n \"CheckoutData.variant_quantities, SubscriptionItemAttributes, UsageRecordAttributes, PriceAttributes.\",\n },\n {\n date: \"2023-08-14\",\n summary: \"Added customer_id, user_name, user_email to Subscription invoice objects.\",\n handledBy: \"SubscriptionInvoiceAttributes customer fields.\",\n },\n {\n date: \"2023-03-30\",\n summary: \"Added receipt URL to Order objects.\",\n handledBy: \"OrderUrls.receipt.\",\n },\n] as const;\n\nexport type RecommendedEvent = (typeof RECOMMENDED_WEBHOOK_EVENTS)[number];\nexport type OptionalEvent = (typeof OPTIONAL_WEBHOOK_EVENTS)[number];\n","import { sameWebhookUrl } from \"../core/equality.js\";\nimport type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type WebhookAttributes, listWebhooksForStore } from \"../resources/webhooks.js\";\nimport { OPTIONAL_WEBHOOK_EVENTS, RECOMMENDED_WEBHOOK_EVENTS } from \"../support/manifest.js\";\nimport { probeCollection } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface WebhookValidationOptions {\n storeId: string | number;\n /** The public URL your app exposes for Lemon Squeezy to POST to. */\n url: string;\n}\n\n/**\n * Confirm a webhook matching `options.url` is registered against the given\n * store, and cross-reference its subscribed events against the support\n * manifest's recommended + optional lists.\n *\n * Missing recommended events = error. Missing optional events = info, because\n * not every integration needs them.\n */\nexport const validateWebhook = async (\n http: HttpClient,\n mode: Mode,\n options: WebhookValidationOptions,\n): Promise<ValidationResult<WebhookAttributes>> => {\n const target = { label: options.url, url: options.url };\n\n const fetched = await probeCollection(() => listWebhooksForStore(http, options.storeId));\n if (!fetched.ok) {\n return buildResult<WebhookAttributes>(\"webhook\", mode, [fetched.issue], undefined, target);\n }\n\n const match = fetched.resource.find((webhook) =>\n sameWebhookUrl(webhook.attributes.url, options.url),\n );\n if (!match) {\n return buildResult<WebhookAttributes>(\n \"webhook\",\n mode,\n [\n issue(\n ISSUE_CODES.WEBHOOK_NOT_FOUND,\n \"error\",\n `No webhook registered for URL ${options.url} on store ${options.storeId}.`,\n {\n suggestedFix:\n \"Register the webhook in Lemon Squeezy (Settings → Webhooks) and subscribe to the recommended events.\",\n context: { storeId: String(options.storeId), url: options.url },\n },\n ),\n ],\n undefined,\n target,\n );\n }\n\n const issues: ValidationIssue[] = [];\n const subscribed = new Set(match.attributes.events);\n const missingRecommended = RECOMMENDED_WEBHOOK_EVENTS.filter((event) => !subscribed.has(event));\n const missingOptional = OPTIONAL_WEBHOOK_EVENTS.filter((event) => !subscribed.has(event));\n\n if (missingRecommended.length > 0) {\n issues.push(\n issue(\n ISSUE_CODES.WEBHOOK_EVENTS_MISSING,\n \"error\",\n `Webhook is missing recommended events: ${missingRecommended.join(\", \")}.`,\n {\n suggestedFix:\n \"Subscribe to all recommended events so the integration survives plan changes and refunds.\",\n context: { missing: missingRecommended.join(\",\") },\n },\n ),\n );\n }\n\n if (missingOptional.length > 0) {\n issues.push(\n issue(\n ISSUE_CODES.WEBHOOK_OPTIONAL_EVENTS,\n \"info\",\n `Optional events not subscribed: ${missingOptional.join(\", \")}.`,\n { context: { missing: missingOptional.join(\",\") } },\n ),\n );\n }\n\n return buildResult(\"webhook\", mode, issues, match.attributes, {\n label: match.attributes.url,\n id: match.id,\n url: match.attributes.url,\n });\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { HttpClient } from \"../core/http.js\";\nimport type { DoctorReport, Mode, ValidationResult } from \"../core/types.js\";\nimport type { DiscountAttributes } from \"../resources/discounts.js\";\nimport type { LicenseKeyAttributes } from \"../resources/licenseKeys.js\";\nimport type { ProductAttributes } from \"../resources/products.js\";\nimport type { StoreAttributes } from \"../resources/stores.js\";\nimport type { WebhookAttributes } from \"../resources/webhooks.js\";\nimport { type ConnectionSummary, validateConnection } from \"./connection.js\";\nimport { type DiscountValidationOptions, validateDiscount } from \"./discount.js\";\nimport { type LicenseKeyValidationOptions, validateLicenseKey } from \"./licenseKey.js\";\nimport { type ProductValidationOptions, validateProduct } from \"./product.js\";\nimport { validateStore } from \"./store.js\";\nimport {\n type SubscriptionPlanValidationOptions,\n validateSubscriptionPlan,\n} from \"./subscriptionPlan.js\";\nimport { type WebhookValidationOptions, validateWebhook } from \"./webhook.js\";\n\n/**\n * Optional targets for the doctor run. If a target is omitted, its validator\n * is skipped — consumers only pay for what they configure.\n */\nexport interface DoctorOptions {\n storeId?: string | number;\n productId?: string | number;\n productIds?: Array<string | number>;\n webhookUrl?: string;\n webhookUrls?: string[];\n discountId?: string | number;\n discountIds?: Array<string | number>;\n licenseKeyId?: string | number;\n licenseKeyIds?: Array<string | number>;\n variantId?: string | number;\n variantIds?: Array<string | number>;\n}\n\n/**\n * The set of validator functions doctor composes.\n *\n * Exposed as an injectable seam so tests can exercise composition order,\n * short-circuiting on connection failure, and option propagation without\n * setting up an HTTP route table for every validator. Production callers\n * normally rely on `DEFAULT_VALIDATORS`, which wires in the real\n * implementations from each `validate/*` module.\n */\nexport interface DoctorValidators {\n connection: (http: HttpClient, mode: Mode) => Promise<ValidationResult<ConnectionSummary>>;\n store: (\n http: HttpClient,\n mode: Mode,\n storeId: string | number,\n ) => Promise<ValidationResult<StoreAttributes>>;\n product: (\n http: HttpClient,\n mode: Mode,\n options: ProductValidationOptions,\n ) => Promise<ValidationResult<ProductAttributes>>;\n webhook: (\n http: HttpClient,\n mode: Mode,\n options: WebhookValidationOptions,\n ) => Promise<ValidationResult<WebhookAttributes>>;\n discount: (\n http: HttpClient,\n mode: Mode,\n options: DiscountValidationOptions,\n ) => Promise<ValidationResult<DiscountAttributes>>;\n licenseKey: (\n http: HttpClient,\n mode: Mode,\n options: LicenseKeyValidationOptions,\n ) => Promise<ValidationResult<LicenseKeyAttributes>>;\n subscriptionPlan: (\n http: HttpClient,\n mode: Mode,\n options: SubscriptionPlanValidationOptions,\n ) => Promise<ValidationResult>;\n}\n\n/** Default wiring used by `doctor` when no overrides are provided. */\nexport const DEFAULT_VALIDATORS: DoctorValidators = {\n connection: validateConnection,\n store: validateStore,\n product: validateProduct,\n webhook: validateWebhook,\n discount: validateDiscount,\n licenseKey: validateLicenseKey,\n subscriptionPlan: validateSubscriptionPlan,\n};\n\n/**\n * Compose every configured validator into a single report. This is the\n * primary entry point for CI health checks: one call, one structured result,\n * one exit code decision.\n *\n * Order is meaningful. Connection runs first because downstream validators\n * have nothing useful to say if the API key is broken.\n *\n * The optional `validators` parameter lets tests inject fakes without a fetch\n * mock; production callers omit it and get `DEFAULT_VALIDATORS`.\n */\nexport const doctor = async (\n http: HttpClient,\n mode: Mode,\n options: DoctorOptions = {},\n validators: DoctorValidators = DEFAULT_VALIDATORS,\n): Promise<DoctorReport> => {\n assertOptionsCoherent(options);\n\n const results: ValidationResult[] = [];\n const productIds = collectValues(options.productId, options.productIds);\n const webhookUrls = collectValues(options.webhookUrl, options.webhookUrls);\n const discountIds = collectValues(options.discountId, options.discountIds);\n const licenseKeyIds = collectValues(options.licenseKeyId, options.licenseKeyIds);\n const variantIds = collectValues(options.variantId, options.variantIds);\n\n const connection = await validators.connection(http, mode);\n results.push(connection);\n\n if (!connection.ok) {\n return { ok: false, mode, results };\n }\n\n if (options.storeId !== undefined) {\n results.push(await validators.store(http, mode, options.storeId));\n }\n\n for (const productId of productIds) {\n results.push(\n await validators.product(http, mode, {\n productId,\n expectedStoreId: options.storeId,\n }),\n );\n }\n\n // webhook / discount / licenseKey / subscriptionPlan all require storeId\n // (assertOptionsCoherent rejects those options when storeId is absent).\n if (options.storeId !== undefined) {\n const storeId = options.storeId;\n for (const url of webhookUrls) {\n results.push(await validators.webhook(http, mode, { storeId, url }));\n }\n for (const discountId of discountIds) {\n results.push(await validators.discount(http, mode, { storeId, discountId }));\n }\n for (const licenseKeyId of licenseKeyIds) {\n results.push(await validators.licenseKey(http, mode, { storeId, licenseKeyId }));\n }\n for (const variantId of variantIds) {\n results.push(await validators.subscriptionPlan(http, mode, { storeId, variantId }));\n }\n }\n\n return { ok: results.every((entry) => entry.ok), mode, results };\n};\n\n/**\n * Fail fast when store-scoped targets are set without `storeId`. Without this,\n * doctor would silently skip those validators and report a false-positive ok.\n */\nconst assertOptionsCoherent = (options: DoctorOptions): void => {\n if (options.storeId !== undefined) return;\n\n const dependent: Array<keyof DoctorOptions> = [];\n if (hasAny(options.webhookUrl, options.webhookUrls)) dependent.push(\"webhookUrl\");\n if (hasAny(options.discountId, options.discountIds)) dependent.push(\"discountId\");\n if (hasAny(options.licenseKeyId, options.licenseKeyIds)) dependent.push(\"licenseKeyId\");\n if (hasAny(options.variantId, options.variantIds)) dependent.push(\"variantId\");\n\n if (dependent.length === 0) return;\n\n throw new FreshSqueezyError({\n code: \"DOCTOR_OPTIONS_INVALID\",\n message: `doctor() received ${dependent.join(\", \")} without storeId. These validators cannot run without a store; pass \\`storeId\\` or remove the dependent options.`,\n });\n};\n\nconst collectValues = <T>(single: T | undefined, many: T[] | undefined): T[] => {\n const values = new Set<T>();\n if (single !== undefined) values.add(single);\n for (const value of many ?? []) {\n if (value !== undefined) values.add(value);\n }\n return Array.from(values);\n};\n\nconst hasAny = <T>(single: T | undefined, many: T[] | undefined): boolean => {\n return single !== undefined || (many?.length ?? 0) > 0;\n};\n","import { resolveConfig } from \"./core/config.js\";\nimport { HttpClient, type RequestOptions } from \"./core/http.js\";\nimport type { DoctorReport, FreshSqueezyConfig, Mode, ValidationResult } from \"./core/types.js\";\nimport type { DiscountAttributes } from \"./resources/discounts.js\";\nimport { type InvokeOpArgs, invokeOp } from \"./resources/invokeOp.js\";\nimport type { LicenseKeyAttributes } from \"./resources/licenseKeys.js\";\nimport type { ProductAttributes } from \"./resources/products.js\";\nimport type { OpVerb } from \"./resources/registry.js\";\nimport type { StoreAttributes } from \"./resources/stores.js\";\nimport type { WebhookAttributes } from \"./resources/webhooks.js\";\nimport { type ConnectionSummary, validateConnection } from \"./validate/connection.js\";\nimport { type DiscountValidationOptions, validateDiscount } from \"./validate/discount.js\";\nimport { type DoctorOptions, doctor } from \"./validate/doctor.js\";\nimport { type LicenseKeyValidationOptions, validateLicenseKey } from \"./validate/licenseKey.js\";\nimport { type ProductValidationOptions, validateProduct } from \"./validate/product.js\";\nimport { validateStore } from \"./validate/store.js\";\nimport {\n type SubscriptionPlanSummary,\n type SubscriptionPlanValidationOptions,\n validateSubscriptionPlan,\n} from \"./validate/subscriptionPlan.js\";\nimport { type WebhookValidationOptions, validateWebhook } from \"./validate/webhook.js\";\n\n/**\n * Nested resource namespaces for docs-backed Lemon Squeezy ops.\n *\n * Every method routes through `invokeOp` + `resourceRegistry` (docsPath required).\n * Methods exist only when the official API documents them — no product/variant create.\n * Ops return JSON:API payloads as `unknown`; callers narrow or use resource helpers.\n * Failures throw `FreshSqueezyError` (branch on `.code`).\n */\nexport interface FreshSqueezyOps {\n users: {\n me: () => Promise<unknown>;\n };\n stores: {\n get: (id: string | number) => Promise<unknown>;\n list: () => Promise<unknown>;\n };\n products: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n };\n variants: {\n get: (id: string | number) => Promise<unknown>;\n list: (productId: string | number) => Promise<unknown>;\n };\n prices: {\n get: (id: string | number) => Promise<unknown>;\n list: (variantId: string | number) => Promise<unknown>;\n };\n files: {\n get: (id: string | number) => Promise<unknown>;\n list: (variantId: string | number) => Promise<unknown>;\n };\n customers: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n };\n orders: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n refund: (id: string | number, body?: unknown) => Promise<unknown>;\n generateInvoice: (id: string | number, body?: unknown) => Promise<unknown>;\n };\n orderItems: {\n get: (id: string | number) => Promise<unknown>;\n list: (orderId: string | number) => Promise<unknown>;\n };\n subscriptions: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n cancel: (id: string | number) => Promise<unknown>;\n };\n subscriptionItems: {\n get: (id: string | number) => Promise<unknown>;\n list: (subscriptionId: string | number) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n currentUsage: (id: string | number) => Promise<unknown>;\n };\n subscriptionInvoices: {\n get: (id: string | number) => Promise<unknown>;\n list: (subscriptionId: string | number) => Promise<unknown>;\n refund: (id: string | number, body?: unknown) => Promise<unknown>;\n generateInvoice: (id: string | number, body?: unknown) => Promise<unknown>;\n };\n usageRecords: {\n get: (id: string | number) => Promise<unknown>;\n list: (subscriptionItemId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n };\n discounts: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n delete: (id: string | number) => Promise<unknown>;\n };\n discountRedemptions: {\n get: (id: string | number) => Promise<unknown>;\n list: (discountId: string | number) => Promise<unknown>;\n };\n licenseKeys: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n };\n licenseKeyInstances: {\n get: (id: string | number) => Promise<unknown>;\n list: (licenseKeyId: string | number) => Promise<unknown>;\n };\n checkouts: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n };\n webhooks: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n delete: (id: string | number) => Promise<unknown>;\n };\n affiliates: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n };\n}\n\n/**\n * The public client. Validators stay flat; ops live under nested namespaces\n * that mirror docs-backed resources (see `resourceRegistry`).\n */\nexport interface FreshSqueezyClient extends FreshSqueezyOps {\n /** Resolved mode (test or live). Surfaced so consumers can log it. */\n readonly mode: Mode;\n\n /** Raw HTTP escape hatch for endpoints fresh-squeezy does not wrap. */\n request<T = unknown>(options: RequestOptions): Promise<T>;\n\n validateConnection(): Promise<ValidationResult<ConnectionSummary>>;\n validateStore(storeId: string | number): Promise<ValidationResult<StoreAttributes>>;\n validateProduct(options: ProductValidationOptions): Promise<ValidationResult<ProductAttributes>>;\n validateWebhook(options: WebhookValidationOptions): Promise<ValidationResult<WebhookAttributes>>;\n validateDiscount(\n options: DiscountValidationOptions,\n ): Promise<ValidationResult<DiscountAttributes>>;\n validateLicenseKey(\n options: LicenseKeyValidationOptions,\n ): Promise<ValidationResult<LicenseKeyAttributes>>;\n validateSubscriptionPlan(\n options: SubscriptionPlanValidationOptions,\n ): Promise<ValidationResult<SubscriptionPlanSummary>>;\n /**\n * Compose configured validators into one report.\n * Defaults `storeId` from client config when the call omits it.\n */\n doctor(options?: DoctorOptions): Promise<DoctorReport>;\n}\n\n/**\n * Create a fresh-squeezy client. Zero-config usage reads\n * `LEMON_SQUEEZY_API_KEY`, `LEMON_SQUEEZY_STORE_ID`, and `LEMON_SQUEEZY_MODE`\n * from `process.env`.\n *\n * @param config - Optional overrides for key, mode, store, fetch.\n * @returns Client with validators + nested docs-backed ops.\n * @throws {FreshSqueezyError} When config is invalid (missing key, bad mode).\n *\n * @example\n * ```ts\n * const lemon = createFreshSqueezy();\n * const report = await lemon.doctor();\n * if (!report.ok) process.exit(1);\n * const product = await lemon.products.get(42);\n * const webhook = await lemon.webhooks.create({ data: { type: \"webhooks\", … } });\n * ```\n */\nexport const createFreshSqueezy = (config: FreshSqueezyConfig = {}): FreshSqueezyClient => {\n const resolved = resolveConfig(config);\n const http = new HttpClient(resolved);\n\n /** Dispatch a registry-backed op; never invents endpoints outside `resourceRegistry`. */\n const op = (resource: string, verb: OpVerb, args: InvokeOpArgs = {}) =>\n invokeOp(http, resource, verb, args);\n\n return {\n mode: resolved.mode,\n request: (options) => http.request(options),\n validateConnection: () => validateConnection(http, resolved.mode),\n validateStore: (storeId) => validateStore(http, resolved.mode, storeId),\n validateProduct: (options) => validateProduct(http, resolved.mode, options),\n validateWebhook: (options) => validateWebhook(http, resolved.mode, options),\n validateDiscount: (options) => validateDiscount(http, resolved.mode, options),\n validateLicenseKey: (options) => validateLicenseKey(http, resolved.mode, options),\n validateSubscriptionPlan: (options) => validateSubscriptionPlan(http, resolved.mode, options),\n doctor: (options) =>\n doctor(http, resolved.mode, {\n ...options,\n storeId: options?.storeId ?? resolved.storeId,\n }),\n\n users: {\n me: () => op(\"user\", \"get\"),\n },\n stores: {\n get: (id) => op(\"store\", \"get\", { id }),\n list: () => op(\"store\", \"list\"),\n },\n products: {\n get: (id) => op(\"product\", \"get\", { id }),\n list: (storeId) => op(\"product\", \"list\", { storeId }),\n },\n variants: {\n get: (id) => op(\"variant\", \"get\", { id }),\n list: (productId) => op(\"variant\", \"list\", { parentId: productId }),\n },\n prices: {\n get: (id) => op(\"price\", \"get\", { id }),\n list: (variantId) => op(\"price\", \"list\", { parentId: variantId }),\n },\n files: {\n get: (id) => op(\"file\", \"get\", { id }),\n list: (variantId) => op(\"file\", \"list\", { parentId: variantId }),\n },\n customers: {\n get: (id) => op(\"customer\", \"get\", { id }),\n list: (storeId) => op(\"customer\", \"list\", { storeId }),\n create: (body) => op(\"customer\", \"create\", { body }),\n update: (id, body) => op(\"customer\", \"update\", { id, body }),\n },\n orders: {\n get: (id) => op(\"order\", \"get\", { id }),\n list: (storeId) => op(\"order\", \"list\", { storeId }),\n refund: (id, body) => op(\"order\", \"refund\", { id, body }),\n generateInvoice: (id, body) => op(\"order\", \"generate-invoice\", { id, body }),\n },\n orderItems: {\n get: (id) => op(\"order-item\", \"get\", { id }),\n list: (orderId) => op(\"order-item\", \"list\", { parentId: orderId }),\n },\n subscriptions: {\n get: (id) => op(\"subscription\", \"get\", { id }),\n list: (storeId) => op(\"subscription\", \"list\", { storeId }),\n update: (id, body) => op(\"subscription\", \"update\", { id, body }),\n cancel: (id) => op(\"subscription\", \"cancel\", { id }),\n },\n subscriptionItems: {\n get: (id) => op(\"subscription-item\", \"get\", { id }),\n list: (subscriptionId) => op(\"subscription-item\", \"list\", { parentId: subscriptionId }),\n update: (id, body) => op(\"subscription-item\", \"update\", { id, body }),\n currentUsage: (id) => op(\"subscription-item\", \"current-usage\", { id }),\n },\n subscriptionInvoices: {\n get: (id) => op(\"subscription-invoice\", \"get\", { id }),\n list: (subscriptionId) => op(\"subscription-invoice\", \"list\", { parentId: subscriptionId }),\n refund: (id, body) => op(\"subscription-invoice\", \"refund\", { id, body }),\n generateInvoice: (id, body) => op(\"subscription-invoice\", \"generate-invoice\", { id, body }),\n },\n usageRecords: {\n get: (id) => op(\"usage-record\", \"get\", { id }),\n list: (subscriptionItemId) => op(\"usage-record\", \"list\", { parentId: subscriptionItemId }),\n create: (body) => op(\"usage-record\", \"create\", { body }),\n },\n discounts: {\n get: (id) => op(\"discount\", \"get\", { id }),\n list: (storeId) => op(\"discount\", \"list\", { storeId }),\n create: (body) => op(\"discount\", \"create\", { body }),\n delete: (id) => op(\"discount\", \"delete\", { id }),\n },\n discountRedemptions: {\n get: (id) => op(\"discount-redemption\", \"get\", { id }),\n list: (discountId) => op(\"discount-redemption\", \"list\", { parentId: discountId }),\n },\n licenseKeys: {\n get: (id) => op(\"license-key\", \"get\", { id }),\n list: (storeId) => op(\"license-key\", \"list\", { storeId }),\n update: (id, body) => op(\"license-key\", \"update\", { id, body }),\n },\n licenseKeyInstances: {\n get: (id) => op(\"license-key-instance\", \"get\", { id }),\n list: (licenseKeyId) => op(\"license-key-instance\", \"list\", { parentId: licenseKeyId }),\n },\n checkouts: {\n get: (id) => op(\"checkout\", \"get\", { id }),\n list: (storeId) => op(\"checkout\", \"list\", { storeId }),\n create: (body) => op(\"checkout\", \"create\", { body }),\n },\n webhooks: {\n get: (id) => op(\"webhook\", \"get\", { id }),\n list: (storeId) => op(\"webhook\", \"list\", { storeId }),\n create: (body) => op(\"webhook\", \"create\", { body }),\n update: (id, body) => op(\"webhook\", \"update\", { id, body }),\n delete: (id) => op(\"webhook\", \"delete\", { id }),\n },\n affiliates: {\n get: (id) => op(\"affiliate\", \"get\", { id }),\n list: (storeId) => op(\"affiliate\", \"list\", { storeId }),\n },\n };\n};\n","import { ENV_KEYS } from \"../core/config.js\";\nimport { FreshSqueezyError } from \"../core/errors.js\";\nimport type { ValidateTarget } from \"./commands/validate.js\";\n\nexport const renderCliError = (message: string, hints: string[] = []): string => {\n const lines = [`fresh-squeezy: ${message}`];\n\n if (hints.length > 0) {\n lines.push(\"\", \"Try:\");\n for (const hint of hints) {\n lines.push(` ${hint}`);\n }\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n};\n\nexport const getDoctorHints = (err: unknown): string[] => {\n if (!isFreshSqueezyError(err)) return [];\n\n if (err.code === \"MISSING_API_KEY\") {\n return [\"fresh-squeezy init\", `export ${ENV_KEYS.apiKey}=ls_live_or_test_key`];\n }\n\n if (err.code === \"INVALID_MODE\") {\n return [\"fresh-squeezy doctor --mode test\", \"fresh-squeezy doctor --mode live\"];\n }\n\n if (err.code === \"NO_STORES\") {\n return [\"Check that the API key belongs to an account with a Lemon Squeezy store.\"];\n }\n\n return [];\n};\n\nexport const getValidateHints = (err: unknown, target: ValidateTarget): string[] => {\n if (!isFreshSqueezyError(err)) return [];\n\n if (err.code === \"MISSING_API_KEY\") {\n return [\"fresh-squeezy init\", `export ${ENV_KEYS.apiKey}=ls_live_or_test_key`];\n }\n\n if (err.code === \"INVALID_MODE\") {\n return [\n `fresh-squeezy validate ${target} --mode test`,\n `fresh-squeezy validate ${target} --mode live`,\n ];\n }\n\n if (err.code === \"MISSING_ARG\") {\n return getMissingArgHints(target);\n }\n\n return [];\n};\n\nconst getMissingArgHints = (target: ValidateTarget): string[] => {\n if (target === \"connection\") {\n return [\"fresh-squeezy validate connection\"];\n }\n\n if (target === \"store\") {\n return [\n \"fresh-squeezy validate store --store-ids 12\",\n \"fresh-squeezy validate store --all-stores\",\n ];\n }\n\n if (target === \"product\") {\n return [\"fresh-squeezy validate product --product-id 987\"];\n }\n\n if (target === \"webhook\") {\n return [\n \"fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n \"fresh-squeezy validate webhook --all-stores --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n ];\n }\n\n if (target === \"discount\") {\n return [\"fresh-squeezy validate discount --store-ids 12 --discount-id 123\"];\n }\n\n if (target === \"license-key\") {\n return [\"fresh-squeezy validate license-key --store-ids 12 --license-key-id 123\"];\n }\n\n return [\"fresh-squeezy validate subscription-plan --store-ids 12 --variant-id 123\"];\n};\n\nconst isFreshSqueezyError = (err: unknown): err is FreshSqueezyError => {\n return err instanceof FreshSqueezyError;\n};\n","import chalk from \"chalk\";\nimport type {\n DoctorReport,\n ValidationIssue,\n ValidationResult,\n ValidationTarget,\n} from \"../core/types.js\";\n\n/**\n * Human-readable pretty-printer for a validation result. Keeps color logic in\n * one place so doctor/validate commands share formatting and consumers can\n * redirect stdout without ANSI codes leaking through (chalk auto-detects TTY).\n */\nexport const renderResult = (result: ValidationResult): string => {\n const lines: string[] = [];\n const badge = result.ok ? chalk.green(\"PASS\") : chalk.red(\"FAIL\");\n const mode = chalk.dim(`[${result.mode}]`);\n const target = renderTarget(result.target);\n const suffix = target ? ` ${chalk.dim(target)}` : \"\";\n lines.push(`${badge} ${mode} ${chalk.bold(result.name)}${suffix}`);\n\n for (const issue of result.issues) {\n lines.push(` ${renderIssueLine(issue)}`);\n if (issue.suggestedFix) {\n lines.push(` ${chalk.dim(\"fix:\")} ${issue.suggestedFix}`);\n }\n }\n\n return lines.join(\"\\n\");\n};\n\nconst renderTarget = (target: ValidationTarget | undefined): string => {\n if (!target) return \"\";\n const parts = [target.label];\n if (target.id) parts.push(`id ${target.id}`);\n if (target.url && target.url !== target.label) parts.push(target.url);\n return parts.join(\" - \");\n};\n\nexport const renderReport = (report: DoctorReport): string => {\n const header = report.ok\n ? chalk.green.bold(\"fresh-squeezy doctor: OK\")\n : chalk.red.bold(\"fresh-squeezy doctor: FAILED\");\n const failed = report.results.filter((result) => !result.ok).length;\n const summary =\n failed === 0\n ? chalk.dim(`${report.results.length} checks passed`)\n : chalk.dim(`${failed}/${report.results.length} checks failed`);\n const body = report.results.map(renderResult).join(\"\\n\\n\");\n return `${header} ${chalk.dim(`(mode: ${report.mode})`)}\\n${summary}\\n\\n${body}`;\n};\n\nconst renderIssueLine = (issue: ValidationIssue): string => {\n const label =\n issue.severity === \"error\"\n ? chalk.red(\"✗ error\")\n : issue.severity === \"warning\"\n ? chalk.yellow(\"! warn \")\n : chalk.blue(\"i info \");\n return `${label} ${chalk.gray(`[${issue.code}]`)} ${issue.message}`;\n};\n","import path from \"node:path\";\nimport { checkbox, confirm, input, password, select } from \"@inquirer/prompts\";\nimport {\n EMPTY_INIT_RESOURCE_CHOICES,\n type InitResourceChoices,\n type ResourceChoiceGroup,\n} from \"./resourceDiscovery.js\";\n\n/**\n * Interactive prompts used by `fresh-squeezy init`.\n *\n * Isolated from the command handler so the command stays focused on the flow\n * (ask → detect → confirm → write) and prompts can be unit-tested by mocking\n * `@inquirer/prompts` without pulling in the full commander program.\n */\n\nexport interface InitAnswers {\n apiKey: string;\n}\n\nexport interface InitDoctorTargets {\n productIds?: string[];\n webhookUrls?: string[];\n discountIds?: string[];\n licenseKeyIds?: string[];\n variantIds?: string[];\n}\n\nexport type InitDoctorTarget =\n | \"product\"\n | \"webhook\"\n | \"discount\"\n | \"license-key\"\n | \"subscription-plan\";\nexport type LauncherAction = \"init\" | \"doctor\" | \"examples\" | \"exit\";\n\ntype DoctorTargetField = keyof InitDoctorTargets;\ntype ManualQuestion = {\n field: DoctorTargetField;\n message: string;\n validate: (value: string) => true | string;\n};\ntype EmptyTargetAction = \"manual\" | \"skip\";\n\nconst PROMPT_THEME = {\n prefix: {\n idle: \"›\",\n done: \"✓\",\n },\n} as const;\n\nexport const pickLauncherAction = async (): Promise<LauncherAction> => {\n return select<LauncherAction>({\n message: \"What do you want to do?\",\n theme: PROMPT_THEME,\n choices: [\n {\n name: \"Start guided setup — key, store, checks, doctor\",\n value: \"init\",\n },\n {\n name: \"Run doctor now — pick stores interactively when needed\",\n value: \"doctor\",\n },\n {\n name: \"Show command examples — copy/paste friendly\",\n value: \"examples\",\n },\n {\n name: \"Exit\",\n value: \"exit\",\n },\n ],\n });\n};\n\nexport const askForApiKey = async (): Promise<InitAnswers> => {\n const apiKey = await password({\n message: \"Paste your Lemon Squeezy API key:\",\n mask: false,\n theme: PROMPT_THEME,\n validate: (value: string) => (value.trim().length > 0 ? true : \"API key is required.\"),\n });\n return { apiKey: apiKey.trim() };\n};\n\nexport const pickStore = async (\n choices: { id: string; name: string; slug: string }[],\n): Promise<string> => {\n return select<string>({\n message: \"Pick a store to validate against:\",\n theme: PROMPT_THEME,\n choices: choices.map((entry) => ({\n name: `${entry.name} (${entry.slug}) — id ${entry.id}`,\n value: entry.id,\n })),\n });\n};\n\n/**\n * Multi-select store picker used by `doctor` and `validate` when no\n * `--store-ids` / `--all-stores` flag is supplied and stdin is a TTY.\n * The first store is pre-checked so hitting Enter without toggling still\n * picks something — callers enforce the \"at least one\" rule.\n */\nexport const pickStores = async (\n choices: { id: string; name: string; slug: string }[],\n): Promise<string[]> => {\n return checkbox<string>({\n message: \"Pick one or more stores (space to toggle, enter to confirm):\",\n theme: PROMPT_THEME,\n choices: choices.map((entry, index) => ({\n name: `${entry.name} (${entry.slug}) — id ${entry.id}`,\n value: entry.id,\n checked: index === 0,\n })),\n validate: (selected) => (selected.length > 0 ? true : \"Pick at least one store.\"),\n });\n};\n\nexport const selectDoctorTargets = async (): Promise<InitDoctorTarget[]> => {\n return checkbox<InitDoctorTarget>({\n message: \"Add resource checks to this doctor run?\",\n theme: PROMPT_THEME,\n choices: [\n { name: \"Product checkout\", value: \"product\" },\n { name: \"Webhook registration\", value: \"webhook\" },\n { name: \"Discount code\", value: \"discount\" },\n { name: \"License key\", value: \"license-key\" },\n { name: \"Subscription plan\", value: \"subscription-plan\" },\n ],\n });\n};\n\nconst splitManualValues = (value: string | undefined): string[] =>\n (value ?? \"\")\n .split(\",\")\n .map((entry) => entry.trim())\n .filter(Boolean);\n\nconst required = (label: string): ((value: string) => true | string) => {\n return (value: string) => (value.trim().length > 0 ? true : `${label} is required.`);\n};\n\nconst optional = (label: string): ((value: string) => true | string) => {\n return (value: string) => {\n const trimmed = value.trim();\n if (trimmed.length === 0) return true;\n return required(label)(trimmed);\n };\n};\n\nconst validateWebhookUrl = (value: string): true | string => {\n const trimmed = value.trim();\n if (trimmed.length === 0) return \"Webhook URL is required.\";\n\n try {\n const url = new URL(trimmed);\n return url.protocol === \"http:\" || url.protocol === \"https:\"\n ? true\n : \"Webhook URL must start with http:// or https://.\";\n } catch {\n return \"Enter a valid webhook URL.\";\n }\n};\n\nconst optionalWebhookUrls = (value: string): true | string => {\n const values = splitManualValues(value);\n if (values.length === 0) return true;\n return values.every((entry) => validateWebhookUrl(entry) === true)\n ? true\n : \"Enter valid webhook URLs.\";\n};\n\nconst cleanList = (value: string[] | string | undefined): string[] | undefined => {\n const values = Array.isArray(value) ? value : splitManualValues(value);\n const cleaned = Array.from(new Set(values.map((entry) => entry.trim()).filter(Boolean)));\n return cleaned.length > 0 ? cleaned : undefined;\n};\n\nconst DOCTOR_TARGET_SPECS: Array<{\n target: InitDoctorTarget;\n field: DoctorTargetField;\n group: keyof InitResourceChoices;\n pickMessage: string;\n emptyMessage: string;\n manualMessage: string;\n validate: (value: string) => true | string;\n}> = [\n {\n target: \"product\",\n field: \"productIds\",\n group: \"products\",\n pickMessage: \"Pick products to validate:\",\n emptyMessage: \"No products selected. What now?\",\n manualMessage: \"Product IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"Product ID\"),\n },\n {\n target: \"webhook\",\n field: \"webhookUrls\",\n group: \"webhooks\",\n pickMessage: \"Pick webhook URLs to validate:\",\n emptyMessage: \"No webhook URLs selected. What now?\",\n manualMessage: \"Webhook URLs to validate (comma-separated, leave empty to skip):\",\n validate: optionalWebhookUrls,\n },\n {\n target: \"discount\",\n field: \"discountIds\",\n group: \"discounts\",\n pickMessage: \"Pick discounts to validate:\",\n emptyMessage: \"No discounts selected. What now?\",\n manualMessage: \"Discount IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"Discount ID\"),\n },\n {\n target: \"license-key\",\n field: \"licenseKeyIds\",\n group: \"licenseKeys\",\n pickMessage: \"Pick license keys to validate:\",\n emptyMessage: \"No license keys selected. What now?\",\n manualMessage: \"License key IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"License key ID\"),\n },\n {\n target: \"subscription-plan\",\n field: \"variantIds\",\n group: \"subscriptionPlans\",\n pickMessage: \"Pick subscription plans to validate:\",\n emptyMessage: \"No subscription plans selected. What now?\",\n manualMessage:\n \"Subscription plan variant IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"Variant ID\"),\n },\n];\n\nexport const askForDoctorTargetValues = async (\n targets: InitDoctorTarget[],\n choices: InitResourceChoices = EMPTY_INIT_RESOURCE_CHOICES,\n): Promise<InitDoctorTargets> => {\n if (targets.length === 0) return {};\n\n const answers: Partial<Record<DoctorTargetField, string[] | string>> = {};\n const manualQuestions: ManualQuestion[] = [];\n\n for (const spec of DOCTOR_TARGET_SPECS) {\n if (!targets.includes(spec.target)) continue;\n await resolveTargetValue({\n answers,\n manualQuestions,\n group: choices[spec.group],\n field: spec.field,\n pickMessage: spec.pickMessage,\n emptyMessage: spec.emptyMessage,\n manualMessage: spec.manualMessage,\n validate: spec.validate,\n });\n }\n\n for (const question of manualQuestions) {\n answers[question.field] = await input({\n message: question.message,\n theme: PROMPT_THEME,\n validate: question.validate,\n });\n }\n\n return {\n productIds: cleanList(answers.productIds),\n webhookUrls: cleanList(answers.webhookUrls),\n discountIds: cleanList(answers.discountIds),\n licenseKeyIds: cleanList(answers.licenseKeyIds),\n variantIds: cleanList(answers.variantIds),\n };\n};\n\nexport const confirmLiveModeRun = async (): Promise<boolean> => {\n return confirm({\n message: \"This is a live-mode key. Continue with live checks?\",\n default: false,\n theme: PROMPT_THEME,\n });\n};\n\nexport const confirmWriteEnvFile = async (filePath: string): Promise<boolean> => {\n return confirm({\n message: `Write these values to ${formatPromptPath(filePath)}?`,\n default: true,\n theme: PROMPT_THEME,\n });\n};\n\n/**\n * Confirm a destructive or live-mode resource op before mutating.\n *\n * @param message - Prompt shown to the operator.\n * @returns Whether the user confirmed.\n *\n * @example\n * ```ts\n * const ok = await confirmResourceOp(\"Delete webhook 12?\");\n * ```\n */\nexport const confirmResourceOp = async (message: string): Promise<boolean> => {\n return confirm({\n message,\n default: false,\n theme: PROMPT_THEME,\n });\n};\n\nconst resolveTargetValue = async (input: {\n answers: Partial<Record<DoctorTargetField, string[] | string>>;\n manualQuestions: ManualQuestion[];\n group: ResourceChoiceGroup;\n field: DoctorTargetField;\n pickMessage: string;\n emptyMessage: string;\n manualMessage: string;\n validate: (value: string) => true | string;\n}): Promise<void> => {\n if (input.group.choices.length === 0) {\n input.manualQuestions.push({\n field: input.field,\n message: input.manualMessage,\n validate: input.validate,\n });\n return;\n }\n\n const values = await checkbox<string>({\n message: input.pickMessage,\n theme: PROMPT_THEME,\n choices: input.group.choices.map((choice) => ({\n name: choice.label,\n value: choice.value,\n })),\n });\n\n if (values.length > 0) {\n input.answers[input.field] = values;\n return;\n }\n\n const action = await askEmptyTargetAction(input.emptyMessage);\n if (action === \"manual\") {\n input.manualQuestions.push({\n field: input.field,\n message: input.manualMessage,\n validate: input.validate,\n });\n }\n};\n\nconst askEmptyTargetAction = async (message: string): Promise<EmptyTargetAction> => {\n return select<EmptyTargetAction>({\n message,\n theme: PROMPT_THEME,\n choices: [\n { name: \"Enter manually\", value: \"manual\" },\n { name: \"Skip this check\", value: \"skip\" },\n ],\n });\n};\n\nconst formatPromptPath = (filePath: string): string => {\n const relative = path.relative(process.cwd(), filePath);\n if (relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative)) return relative;\n return path.basename(filePath);\n};\n\nexport const isPromptCancel = (error: unknown): boolean => {\n if (!(error instanceof Error)) return false;\n return error.name === \"ExitPromptError\" || error.message.includes(\"User force closed\");\n};\n","import type { RequestOptions } from \"../core/http.js\";\nimport type { JsonApiCollection, JsonApiResource } from \"../core/types.js\";\nimport type { FreshSqueezyClient } from \"../createFreshSqueezy.js\";\nimport type { DiscountAttributes } from \"../resources/discounts.js\";\nimport type { LicenseKeyAttributes } from \"../resources/licenseKeys.js\";\nimport type { ProductAttributes } from \"../resources/products.js\";\nimport type { SubscriptionVariantAttributes } from \"../resources/variants.js\";\nimport type { WebhookAttributes } from \"../resources/webhooks.js\";\nimport type { InitDoctorTarget } from \"./prompts.js\";\n\nexport interface ResourceChoice {\n label: string;\n value: string;\n}\n\nexport interface ResourceChoiceGroup {\n choices: ResourceChoice[];\n error?: string;\n}\n\nexport interface InitResourceChoices {\n products: ResourceChoiceGroup;\n webhooks: ResourceChoiceGroup;\n discounts: ResourceChoiceGroup;\n licenseKeys: ResourceChoiceGroup;\n subscriptionPlans: ResourceChoiceGroup;\n}\n\nexport const EMPTY_INIT_RESOURCE_CHOICES: InitResourceChoices = {\n products: { choices: [] },\n webhooks: { choices: [] },\n discounts: { choices: [] },\n licenseKeys: { choices: [] },\n subscriptionPlans: { choices: [] },\n};\n\nexport const discoverInitResourceChoices = async (\n client: FreshSqueezyClient,\n storeId: string,\n targets: InitDoctorTarget[],\n): Promise<InitResourceChoices> => {\n const choices: InitResourceChoices = {\n products: { choices: [] },\n webhooks: { choices: [] },\n discounts: { choices: [] },\n licenseKeys: { choices: [] },\n subscriptionPlans: { choices: [] },\n };\n let products: JsonApiResource<ProductAttributes>[] | undefined;\n\n if (targets.includes(\"product\") || targets.includes(\"subscription-plan\")) {\n const result = await discover(() =>\n paginate<ProductAttributes>(client, \"/v1/products\", { \"filter[store_id]\": storeId }),\n );\n if (result.ok) {\n products = result.value;\n choices.products = { choices: result.value.map(toProductChoice) };\n } else {\n choices.products = { choices: [], error: result.error };\n }\n }\n\n if (targets.includes(\"webhook\")) {\n const result = await discover(() =>\n paginate<WebhookAttributes>(client, \"/v1/webhooks\", { \"filter[store_id]\": storeId }),\n );\n choices.webhooks = result.ok\n ? { choices: result.value.map(toWebhookChoice) }\n : { choices: [], error: result.error };\n }\n\n if (targets.includes(\"discount\")) {\n const result = await discover(() =>\n paginate<DiscountAttributes>(client, \"/v1/discounts\", { \"filter[store_id]\": storeId }),\n );\n choices.discounts = result.ok\n ? { choices: result.value.map(toDiscountChoice) }\n : { choices: [], error: result.error };\n }\n\n if (targets.includes(\"license-key\")) {\n const result = await discover(() =>\n paginate<LicenseKeyAttributes>(client, \"/v1/license-keys\", { \"filter[store_id]\": storeId }),\n );\n choices.licenseKeys = result.ok\n ? { choices: result.value.map(toLicenseKeyChoice) }\n : { choices: [], error: result.error };\n }\n\n if (targets.includes(\"subscription-plan\")) {\n const listedProducts = products ?? [];\n if (choices.products.error) {\n choices.subscriptionPlans = { choices: [], error: choices.products.error };\n } else {\n choices.subscriptionPlans = await discoverSubscriptionPlans(client, listedProducts);\n }\n }\n\n return choices;\n};\n\nconst discoverSubscriptionPlans = async (\n client: FreshSqueezyClient,\n products: JsonApiResource<ProductAttributes>[],\n): Promise<ResourceChoiceGroup> => {\n const discovered: ResourceChoice[] = [];\n\n for (const product of products) {\n const result = await discover(() =>\n paginate<SubscriptionVariantAttributes>(client, \"/v1/variants\", {\n \"filter[product_id]\": product.id,\n }),\n );\n if (!result.ok) {\n return { choices: discovered, error: result.error };\n }\n\n for (const variant of result.value) {\n if (variant.attributes.is_subscription) {\n discovered.push(toSubscriptionPlanChoice(variant, product.attributes.name));\n }\n }\n }\n\n return { choices: discovered };\n};\n\nconst paginate = async <TAttributes>(\n client: FreshSqueezyClient,\n path: string,\n query: RequestOptions[\"query\"],\n): Promise<JsonApiResource<TAttributes>[]> => {\n const all: JsonApiResource<TAttributes>[] = [];\n let pageNumber = Number(query?.[\"page[number]\"] ?? 1);\n\n while (true) {\n const doc = await client.request<JsonApiCollection<TAttributes>>({\n path,\n query: { ...(query ?? {}), \"page[number]\": pageNumber },\n });\n all.push(...doc.data);\n\n const lastPage = doc.meta?.page?.lastPage;\n if (lastPage === undefined || pageNumber >= lastPage) return all;\n pageNumber += 1;\n }\n};\n\nconst discover = async <T>(\n load: () => Promise<T>,\n): Promise<{ ok: true; value: T } | { ok: false; error: string }> => {\n try {\n return { ok: true, value: await load() };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n};\n\nconst toProductChoice = (product: JsonApiResource<ProductAttributes>): ResourceChoice => {\n return {\n value: product.id,\n label: `${product.attributes.name} (${product.attributes.status}) - id ${product.id}`,\n };\n};\n\nconst toWebhookChoice = (webhook: JsonApiResource<WebhookAttributes>): ResourceChoice => {\n return {\n value: webhook.attributes.url,\n label: `${webhook.attributes.url} - id ${webhook.id}`,\n };\n};\n\nconst toDiscountChoice = (discount: JsonApiResource<DiscountAttributes>): ResourceChoice => {\n return {\n value: discount.id,\n label: `${discount.attributes.name} (${discount.attributes.code}) - id ${discount.id}`,\n };\n};\n\nconst toLicenseKeyChoice = (licenseKey: JsonApiResource<LicenseKeyAttributes>): ResourceChoice => {\n return {\n value: licenseKey.id,\n label: `${licenseKey.attributes.key_short} (${licenseKey.attributes.status}) - id ${licenseKey.id}`,\n };\n};\n\nconst toSubscriptionPlanChoice = (\n variant: JsonApiResource<SubscriptionVariantAttributes>,\n productName: string,\n): ResourceChoice => {\n const interval = variant.attributes.interval\n ? `${variant.attributes.interval_count ?? 1}/${variant.attributes.interval}`\n : \"no interval\";\n return {\n value: variant.id,\n label: `${productName} / ${variant.attributes.name} (${interval}) - id ${variant.id}`,\n };\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { FreshSqueezyClient } from \"../createFreshSqueezy.js\";\nimport { pickStores } from \"./prompts.js\";\n\n/**\n * Inputs the CLI has when it needs to figure out which stores to validate.\n * Kept flag-only + TTY — the CLI deliberately does not read\n * `LEMON_SQUEEZY_STORE_ID`. Library consumers still can (via `createFreshSqueezy`).\n */\nexport interface ResolveStoresInput {\n storeIds?: string[];\n allStores?: boolean;\n /** Whether stdin is attached to a TTY so we can prompt. */\n isInteractive: boolean;\n}\n\nexport interface ResolveStoresOutput {\n storeIds: string[];\n /**\n * True when the resolver could not pick any store AND was not asked to.\n * The caller should fall back to a connection-only run in that case.\n */\n skipped: boolean;\n}\n\n/**\n * Decide which store IDs a doctor/validate run should cover.\n *\n * Resolution order (highest → lowest):\n * 1. `--store-ids 1,2,3` flag\n * 2. `--all-stores` flag (fetch every reachable store)\n * 3. TTY + inquirer multi-select\n * 4. Non-TTY, no flag → `skipped: true`\n *\n * `skipped` lets the caller decide whether to run only connection-level checks\n * or fail loudly — different subcommands want different behavior.\n */\nexport const resolveStores = async (\n client: FreshSqueezyClient,\n input: ResolveStoresInput,\n): Promise<ResolveStoresOutput> => {\n if (input.storeIds && input.storeIds.length > 0) {\n return { storeIds: dedupe(input.storeIds), skipped: false };\n }\n\n if (input.allStores) {\n const ids = await fetchReachableStoreIds(client);\n if (ids.length === 0) {\n throw new FreshSqueezyError({\n code: \"NO_STORES\",\n message: \"No stores reachable with this API key.\",\n });\n }\n return { storeIds: ids, skipped: false };\n }\n\n if (!input.isInteractive) {\n return { storeIds: [], skipped: true };\n }\n\n const ids = await fetchReachableStoreIds(client);\n if (ids.length === 0) {\n throw new FreshSqueezyError({\n code: \"NO_STORES\",\n message: \"No stores reachable with this API key.\",\n });\n }\n if (ids.length === 1) {\n return { storeIds: ids, skipped: false };\n }\n\n const detailed = await Promise.all(\n ids.map(async (id) => {\n const result = await client.validateStore(id);\n return {\n id,\n name: result.resource?.name ?? \"(unnamed)\",\n slug: result.resource?.slug ?? \"\",\n };\n }),\n );\n\n const picked = await pickStores(detailed);\n if (picked.length === 0) {\n throw new FreshSqueezyError({\n code: \"NO_SELECTION\",\n message: \"No store selected. Pick at least one to continue.\",\n });\n }\n return { storeIds: picked, skipped: false };\n};\n\n/**\n * Fetch every store reachable with the current key. Errors from the underlying\n * request propagate — callers handle them at the command boundary.\n */\nconst fetchReachableStoreIds = async (client: FreshSqueezyClient): Promise<string[]> => {\n const connection = await client.validateConnection();\n if (!connection.ok) {\n const authIssue = connection.issues.find((entry) => entry.code === \"AUTH_FAILED\");\n if (authIssue) {\n throw new FreshSqueezyError({\n code: \"AUTH_FAILED\",\n message: authIssue.message,\n });\n }\n }\n return connection.resource?.storeIds ?? [];\n};\n\nconst dedupe = (values: string[]): string[] => {\n return Array.from(new Set(values.map((value) => value.trim()).filter(Boolean)));\n};\n","import { FreshSqueezyError } from \"../../core/errors.js\";\nimport type { DoctorReport, Mode } from \"../../core/types.js\";\nimport { type FreshSqueezyClient, createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport { getDoctorHints, renderCliError } from \"../errors.js\";\nimport type { InitDoctorTarget } from \"../prompts.js\";\nimport { renderReport } from \"../render.js\";\nimport { resolveStores } from \"../resolveStores.js\";\nimport { type InitResourceChoices, discoverInitResourceChoices } from \"../resourceDiscovery.js\";\n\nexport interface DoctorCommandOptions {\n mode?: Mode;\n storeIds?: string[];\n allStores?: boolean;\n allResources?: boolean;\n productId?: string;\n webhookUrl?: string;\n discountId?: string;\n licenseKeyId?: string;\n variantId?: string;\n json?: boolean;\n isInteractive?: boolean;\n}\n\n/**\n * Aggregate payload emitted when `--json` is set. When a single store is\n * resolved, `reports` still contains one entry — consumers always see an\n * array so JSON parsers don't need two code paths.\n */\nexport interface DoctorJsonOutput {\n ok: boolean;\n mode: Mode;\n reports: DoctorReport[];\n}\n\nconst ALL_RESOURCE_TARGETS: InitDoctorTarget[] = [\n \"product\",\n \"webhook\",\n \"discount\",\n \"license-key\",\n \"subscription-plan\",\n];\n\n/**\n * `fresh-squeezy doctor` — run every validator across each resolved store and\n * emit one combined exit code. Store resolution (flag → --all-stores → TTY\n * prompt → connection-only) lives in resolveStores so validate commands can\n * reuse it.\n */\nexport const runDoctorCommand = async (options: DoctorCommandOptions): Promise<number> => {\n try {\n const client = createFreshSqueezy({ mode: options.mode });\n const resolved = await resolveStores(client, {\n storeIds: options.storeIds,\n allStores: options.allStores,\n isInteractive: options.isInteractive ?? false,\n });\n\n if (resolved.skipped) {\n return await runConnectionOnly(client, options);\n }\n\n const reports = await Promise.all(\n resolved.storeIds.map(async (storeId) => {\n const targets = await resolveDoctorTargets(client, storeId, options);\n return client.doctor({ storeId, ...targets });\n }),\n );\n\n const ok = reports.every((report) => report.ok);\n const payload: DoctorJsonOutput = { ok, mode: client.mode, reports };\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n } else {\n for (const report of reports) {\n process.stdout.write(`${renderReport(report)}\\n\\n`);\n }\n if (!options.allResources && !hasExplicitResourceSelection(options)) {\n process.stderr.write(\n \"fresh-squeezy: resource checks were skipped; pass --all-resources or explicit resource flags to validate products, webhooks, discounts, license keys, and subscription plans.\\n\",\n );\n }\n }\n\n return ok ? 0 : 1;\n } catch (err) {\n writeFatal(err, options.json ?? false);\n return 2;\n }\n};\n\nconst resolveDoctorTargets = async (\n client: FreshSqueezyClient,\n storeId: string,\n options: DoctorCommandOptions,\n): Promise<{\n productIds?: string[];\n webhookUrls?: string[];\n discountIds?: string[];\n licenseKeyIds?: string[];\n variantIds?: string[];\n}> => {\n const explicit = {\n productIds: one(options.productId),\n webhookUrls: one(options.webhookUrl),\n discountIds: one(options.discountId),\n licenseKeyIds: one(options.licenseKeyId),\n variantIds: one(options.variantId),\n };\n\n if (!options.allResources) return explicit;\n\n const discovered = await discoverInitResourceChoices(client, storeId, ALL_RESOURCE_TARGETS);\n reportDiscoveryErrors(discovered);\n if (!options.json) {\n process.stderr.write(\n `fresh-squeezy: discovered store ${storeId} resources: ${formatDiscoveryCounts(discovered)}.\\n`,\n );\n }\n\n return {\n productIds: mergeValues(explicit.productIds, values(discovered.products)),\n webhookUrls: mergeValues(explicit.webhookUrls, values(discovered.webhooks)),\n discountIds: mergeValues(explicit.discountIds, values(discovered.discounts)),\n licenseKeyIds: mergeValues(explicit.licenseKeyIds, values(discovered.licenseKeys)),\n variantIds: mergeValues(explicit.variantIds, values(discovered.subscriptionPlans)),\n };\n};\n\nconst DISCOVERY_LABELS = [\n [\"products\", \"products\"],\n [\"webhooks\", \"webhooks\"],\n [\"discounts\", \"discounts\"],\n [\"licenseKeys\", \"license keys\"],\n [\"subscriptionPlans\", \"subscription plans\"],\n] as const;\n\nconst formatDiscoveryCounts = (choices: InitResourceChoices): string =>\n DISCOVERY_LABELS.map(([key, label]) => `${label} ${choices[key].choices.length}`).join(\", \");\n\nconst reportDiscoveryErrors = (choices: InitResourceChoices): void => {\n for (const [key, label] of DISCOVERY_LABELS) {\n const error = choices[key].error;\n if (error) process.stderr.write(`fresh-squeezy: discovery skipped ${label}: ${error}\\n`);\n }\n};\n\nconst values = (group: { choices: Array<{ value: string }> }): string[] | undefined =>\n group.choices.length > 0 ? group.choices.map((choice) => choice.value) : undefined;\n\nconst one = (value: string | undefined): string[] | undefined => (value ? [value] : undefined);\n\nconst mergeValues = (\n explicit: string[] | undefined,\n discovered: string[] | undefined,\n): string[] | undefined => {\n const merged = Array.from(new Set([...(explicit ?? []), ...(discovered ?? [])]));\n return merged.length > 0 ? merged : undefined;\n};\n\nconst hasExplicitResourceSelection = (options: DoctorCommandOptions): boolean =>\n Boolean(\n options.productId ||\n options.webhookUrl ||\n options.discountId ||\n options.licenseKeyId ||\n options.variantId,\n );\n\n/**\n * Fallback when no store could be resolved and we are not interactive.\n * Running connection-only gives CI a useful signal (\"key works\") without\n * silently pretending everything is fine.\n */\nconst runConnectionOnly = async (\n client: FreshSqueezyClient,\n options: DoctorCommandOptions,\n): Promise<number> => {\n const connection = await client.validateConnection();\n const report: DoctorReport = {\n ok: connection.ok,\n mode: client.mode,\n results: [connection],\n };\n const payload: DoctorJsonOutput = { ok: connection.ok, mode: client.mode, reports: [report] };\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n } else {\n process.stderr.write(\n \"fresh-squeezy: no --store-ids or --all-stores and stdin is not a TTY; running connection-only.\\n\",\n );\n process.stdout.write(`${renderReport(report)}\\n`);\n }\n return connection.ok ? 0 : 1;\n};\n\nconst writeFatal = (err: unknown, asJson: boolean): void => {\n if (asJson) {\n const code = err instanceof FreshSqueezyError ? err.code : \"UNKNOWN\";\n const message = err instanceof Error ? err.message : String(err);\n const status = err instanceof FreshSqueezyError ? (err.status ?? null) : null;\n process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message, status } })}\\n`);\n return;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(renderCliError(message, getDoctorHints(err)));\n};\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { ENV_KEYS } from \"../../core/config.js\";\nimport type { Mode, ValidationResult } from \"../../core/types.js\";\nimport { type FreshSqueezyClient, createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport type { ConnectionSummary } from \"../../validate/connection.js\";\nimport { renderBrandHeader, renderCancelMessage, renderDetected, renderStep } from \"../brand.js\";\nimport { renderCliError } from \"../errors.js\";\nimport {\n type InitDoctorTarget,\n type InitDoctorTargets,\n askForApiKey,\n askForDoctorTargetValues,\n confirmLiveModeRun,\n confirmWriteEnvFile,\n isPromptCancel,\n pickStore,\n selectDoctorTargets,\n} from \"../prompts.js\";\nimport { renderReport } from \"../render.js\";\nimport {\n EMPTY_INIT_RESOURCE_CHOICES,\n type InitResourceChoices,\n type ResourceChoiceGroup,\n discoverInitResourceChoices,\n} from \"../resourceDiscovery.js\";\n\nexport interface InitCommandOptions {\n envFile?: string;\n isInteractive?: boolean;\n}\n\n/**\n * `fresh-squeezy init` — interactive onboarding. Walks the user through the\n * fastest path from \"I have an API key\" to \"my integration is verified\":\n *\n * 1. Read API key from env or ask for it if missing.\n * 2. List reachable stores via `/v1/stores`, let the user pick one.\n * 3. Ask which resource-specific validators should run now.\n * 4. Optionally persist credentials to `.env`.\n * 5. Run `doctor()` against the chosen config and print the report.\n *\n * Returns an exit code so the CLI wrapper can forward it to `process.exit`.\n */\nexport const runInitCommand = async (options: InitCommandOptions = {}): Promise<number> => {\n try {\n return await runInitFlow(options);\n } catch (err) {\n if (isPromptCancel(err)) {\n process.stderr.write(renderCancelMessage());\n return 130;\n }\n throw err;\n }\n};\n\nconst runInitFlow = async (options: InitCommandOptions): Promise<number> => {\n if (options.isInteractive === false) {\n process.stderr.write(\n renderCliError(\"`fresh-squeezy init` requires an interactive terminal.\", [\n \"fresh-squeezy doctor --all-stores\",\n \"fresh-squeezy validate connection\",\n ]),\n );\n return 2;\n }\n\n process.stdout.write(\n renderBrandHeader(\n \"Guided setup\",\n \"Connect a key, pick the right store, and run a focused billing doctor.\",\n ),\n );\n\n process.stdout.write(renderStep(1, 5, \"Credentials\", \"reuse env when available\"));\n const apiKey = await resolveApiKey();\n\n process.stdout.write(renderStep(2, 5, \"Account probe\", \"detect mode and reachable stores\"));\n const { client, mode, connection } = await createDetectedClient(apiKey);\n\n if (!connection.ok) {\n process.stdout.write(`${renderReport({ ok: false, mode, results: [connection] })}\\n`);\n return 1;\n }\n\n if (mode === \"live\" && !(await confirmLiveModeRun())) {\n process.stderr.write(renderCancelMessage());\n return 130;\n }\n\n const storeIds = connection.resource?.storeIds ?? [];\n if (storeIds.length === 0) {\n process.stdout.write(\n chalk.yellow(\n \"No stores reachable with this key. Create a store in Lemon Squeezy and retry.\\n\",\n ),\n );\n return 1;\n }\n\n process.stdout.write(renderDetected(\"Stores\", String(storeIds.length), \"Lemon Squeezy API\"));\n const stores = await Promise.all(storeIds.map((id) => client.validateStore(id)));\n const pickable = stores\n .filter((entry) => entry.ok && entry.resource)\n .map((entry, index) => ({\n id: storeIds[index] ?? \"\",\n name: entry.resource?.name ?? \"(unnamed)\",\n slug: entry.resource?.slug ?? \"\",\n }))\n .filter((entry) => entry.id !== \"\");\n\n if (pickable.length === 0) {\n process.stdout.write(\n chalk.yellow(\n \"Stores were discovered, but none could be validated. Check account access and retry.\\n\",\n ),\n );\n return 1;\n }\n\n process.stdout.write(renderStep(3, 5, \"Store selection\", \"auto-select when unambiguous\"));\n const storeId = await resolveStoreSelection(pickable);\n\n process.stdout.write(renderStep(4, 5, \"Optional checks\", \"pick resources before manual IDs\"));\n const selectedTargets = await selectDoctorTargets();\n const resourceChoices = await discoverChoices(client, storeId, selectedTargets);\n process.stdout.write(renderDiscoverySummary(resourceChoices, selectedTargets));\n const doctorTargets = await askForDoctorTargetValues(selectedTargets, resourceChoices);\n\n const envPath = path.resolve(process.cwd(), options.envFile ?? \".env\");\n const checkNames = getDoctorCheckNames(doctorTargets);\n process.stdout.write(renderSetupSummary({ envPath, mode, storeId, checkNames }));\n const shouldWrite = await confirmWriteEnvFile(envPath);\n if (shouldWrite) {\n await writeEnvFile(envPath, { apiKey, mode, storeId });\n process.stdout.write(chalk.green(`Wrote ${envPath}\\n`));\n }\n\n process.stdout.write(chalk.dim(`\\nRunning doctor (${checkNames.join(\", \")})...\\n\\n`));\n const report = await client.doctor({ storeId, ...doctorTargets });\n process.stdout.write(`${renderReport(report)}\\n`);\n\n return report.ok ? 0 : 1;\n};\n\nconst resolveStoreSelection = async (\n pickable: Array<{ id: string; name: string; slug: string }>,\n): Promise<string> => {\n if (pickable.length === 1) {\n const store = pickable[0];\n if (!store) throw new Error(\"Expected one reachable store.\");\n process.stdout.write(\n renderDetected(\"Store\", `${store.name} (${store.slug})`, `id ${store.id}`),\n );\n return store.id;\n }\n\n return pickStore(pickable);\n};\n\nconst discoverChoices = async (\n client: FreshSqueezyClient,\n storeId: string,\n selectedTargets: InitDoctorTarget[],\n): Promise<InitResourceChoices> => {\n if (selectedTargets.length === 0) return EMPTY_INIT_RESOURCE_CHOICES;\n return discoverInitResourceChoices(client, storeId, selectedTargets);\n};\n\nconst resolveApiKey = async (): Promise<string> => {\n const envApiKey = process.env[ENV_KEYS.apiKey]?.trim();\n if (envApiKey) {\n process.stdout.write(chalk.dim(`Using ${ENV_KEYS.apiKey} from environment.\\n`));\n return envApiKey;\n }\n\n const answers = await askForApiKey();\n return answers.apiKey;\n};\n\nconst createDetectedClient = async (\n apiKey: string,\n): Promise<{\n client: FreshSqueezyClient;\n mode: Mode;\n connection: ValidationResult<ConnectionSummary>;\n}> => {\n const envMode = parseEnvMode();\n const initialMode = envMode ?? \"test\";\n let client = createFreshSqueezy({ apiKey, mode: initialMode });\n let connection = await client.validateConnection();\n const actualMode = connection.resource?.actualMode;\n\n if (actualMode && actualMode !== initialMode) {\n const message = envMode\n ? `Detected ${actualMode}-mode API key; ignoring ${ENV_KEYS.mode}=${initialMode} for this run.`\n : `Detected ${actualMode}-mode API key.`;\n process.stdout.write(chalk.yellow(`${message}\\n`));\n client = createFreshSqueezy({ apiKey, mode: actualMode });\n connection = await client.validateConnection();\n return { client, mode: actualMode, connection };\n }\n\n if (actualMode) {\n process.stdout.write(chalk.dim(`Detected ${actualMode}-mode API key.\\n`));\n return { client, mode: actualMode, connection };\n }\n\n if (envMode) {\n process.stdout.write(\n chalk.dim(`Using ${ENV_KEYS.mode}=${envMode}; API mode was not exposed.\\n`),\n );\n return { client, mode: envMode, connection };\n }\n\n process.stdout.write(chalk.dim(\"Could not auto-detect key mode; using test mode.\\n\"));\n return { client, mode: initialMode, connection };\n};\n\nconst parseEnvMode = (): Mode | undefined => {\n const value = process.env[ENV_KEYS.mode]?.trim();\n if (value === \"test\" || value === \"live\") return value;\n if (value) {\n process.stdout.write(\n chalk.yellow(`Ignoring invalid ${ENV_KEYS.mode}=${value}; expected test or live.\\n`),\n );\n }\n return undefined;\n};\n\nconst getDoctorCheckNames = (targets: InitDoctorTargets): string[] => {\n const names = [\"connection\", \"store\"];\n pushCheckName(names, \"product\", targets.productIds);\n pushCheckName(names, \"webhook\", targets.webhookUrls);\n pushCheckName(names, \"discount\", targets.discountIds);\n pushCheckName(names, \"licenseKey\", targets.licenseKeyIds);\n pushCheckName(names, \"subscriptionPlan\", targets.variantIds);\n return names;\n};\n\nconst pushCheckName = (names: string[], name: string, values: string[] | undefined): void => {\n if (!values || values.length === 0) return;\n names.push(values.length === 1 ? name : `${name} x${values.length}`);\n};\n\nconst renderSetupSummary = (input: {\n envPath: string;\n mode: Mode;\n storeId: string;\n checkNames: string[];\n}): string => {\n return [\n renderStep(5, 5, \"Ready to verify\", \"review before writing env\"),\n ` ${chalk.dim(\"mode\")} ${input.mode}`,\n ` ${chalk.dim(\"store\")} ${input.storeId}`,\n ` ${chalk.dim(\"checks\")} ${input.checkNames.join(\", \")}`,\n ` ${chalk.dim(\"env\")} ${input.envPath}`,\n \"\",\n ].join(\"\\n\");\n};\n\nconst writeEnvFile = async (\n envPath: string,\n values: { apiKey: string; mode: string; storeId: string },\n): Promise<void> => {\n const updates = new Map<string, string>([\n [ENV_KEYS.apiKey, values.apiKey],\n [ENV_KEYS.storeId, values.storeId],\n [ENV_KEYS.mode, values.mode],\n ]);\n const existing = await readEnvFile(envPath);\n const lines = existing.length > 0 ? existing.split(/\\r?\\n/) : [];\n const seen = new Set<string>();\n const next = lines.map((line) => {\n const match = /^([A-Za-z_][A-Za-z0-9_]*)=/.exec(line);\n const key = match?.[1];\n if (!key || !updates.has(key)) return line;\n seen.add(key);\n return `${key}=${updates.get(key) ?? \"\"}`;\n });\n\n if (next.length > 0 && next.at(-1) !== \"\") {\n next.push(\"\");\n }\n\n for (const [key, value] of updates) {\n if (!seen.has(key)) {\n next.push(`${key}=${value}`);\n }\n }\n\n await fs.mkdir(path.dirname(envPath), { recursive: true });\n await fs.writeFile(envPath, `${next.join(\"\\n\").replace(/\\n*$/, \"\")}\\n`, { encoding: \"utf8\" });\n};\n\nconst readEnvFile = async (envPath: string): Promise<string> => {\n try {\n return await fs.readFile(envPath, \"utf8\");\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") {\n return \"\";\n }\n throw err;\n }\n};\n\nconst renderDiscoverySummary = (\n choices: InitResourceChoices,\n selectedTargets: InitDoctorTarget[],\n): string => {\n if (selectedTargets.length === 0) return chalk.dim(\" No optional resource checks selected.\\n\");\n\n const groups: Array<[InitDoctorTarget, string, ResourceChoiceGroup]> = [\n [\"product\", \"Products\", choices.products],\n [\"webhook\", \"Webhooks\", choices.webhooks],\n [\"discount\", \"Discounts\", choices.discounts],\n [\"license-key\", \"License keys\", choices.licenseKeys],\n [\"subscription-plan\", \"Subscription plans\", choices.subscriptionPlans],\n ];\n\n const lines: string[] = [];\n for (const [target, label, group] of groups) {\n if (!selectedTargets.includes(target)) continue;\n if (group.error) {\n lines.push(chalk.yellow(` ! ${label} discovery failed; manual entry is available.`));\n } else {\n lines.push(\n renderDetected(label, String(group.choices.length), \"Lemon Squeezy API\").trimEnd(),\n );\n }\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n};\n","import chalk from \"chalk\";\n\nconst brand = chalk.green.bold(\"fresh-squeezy\");\nconst divider = chalk.dim(\"•\");\n\nexport const renderBrandHeader = (title: string, subtitle?: string): string => {\n const lines = [`${brand} ${divider} ${chalk.bold(title)}`];\n if (subtitle) lines.push(chalk.dim(subtitle));\n lines.push(\"\");\n return lines.join(\"\\n\");\n};\n\nexport const renderStep = (\n index: number,\n total: number,\n title: string,\n detail?: string,\n): string => {\n const suffix = detail ? ` ${chalk.dim(detail)}` : \"\";\n const prefix = index > 1 ? \"\\n\" : \"\";\n return `${prefix}${chalk.yellow(\"●\")} ${chalk.dim(`${index}/${total}`)} ${chalk.bold(title)}${suffix}\\n`;\n};\n\nexport const renderDetected = (label: string, value: string, source?: string): string => {\n const suffix = source ? ` ${chalk.dim(`from ${source}`)}` : \"\";\n return ` ${chalk.green(\"✓\")} ${chalk.bold(label)} ${value}${suffix}\\n`;\n};\n\nexport const renderCommandExamples = (): string => {\n return [\n renderBrandHeader(\"Command examples\", \"Direct commands stay stable for scripts and CI.\"),\n `${chalk.bold(\"Guided setup\")}`,\n \" fresh-squeezy init\",\n \"\",\n `${chalk.bold(\"Full doctor\")}`,\n \" fresh-squeezy doctor --all-stores\",\n \" fresh-squeezy doctor --store-ids 12 --product-id 987 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n \"\",\n `${chalk.bold(\"Single checks\")}`,\n \" fresh-squeezy validate connection\",\n \" fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n \"\",\n `${chalk.bold(\"Bulk ops (delete / cancel / refund)\")}`,\n \" fresh-squeezy delete discount --all --store-ids 12 --dry-run\",\n \" fresh-squeezy delete discount --all --store-ids 12 --match TEST --yes\",\n \" fresh-squeezy delete webhook --ids 1,2,3 --yes\",\n \"\",\n `${chalk.bold(\"Automation\")}`,\n \" fresh-squeezy doctor --all-stores --json\",\n \"\",\n ].join(\"\\n\");\n};\n\nexport const renderCancelMessage = (): string => {\n return `${chalk.dim(\"fresh-squeezy cancelled.\")}\\n`;\n};\n","import chalk from \"chalk\";\nimport { ENV_KEYS } from \"../../core/config.js\";\nimport {\n renderBrandHeader,\n renderCancelMessage,\n renderCommandExamples,\n renderDetected,\n renderStep,\n} from \"../brand.js\";\nimport { type ProjectInstallResult, ensureFreshSqueezyDevDependency } from \"../projectInstall.js\";\nimport { type LauncherAction, isPromptCancel, pickLauncherAction } from \"../prompts.js\";\nimport { runDoctorCommand } from \"./doctor.js\";\nimport { runInitCommand } from \"./init.js\";\n\nexport interface LauncherCommandOptions {\n isInteractive: boolean;\n install?: boolean;\n packageVersion?: string;\n}\n\nexport const runLauncherCommand = async (options: LauncherCommandOptions): Promise<number> => {\n if (!options.isInteractive) return 2;\n\n try {\n process.stdout.write(\n renderBrandHeader(\n \"Project bootstrap\",\n \"Install the billing doctor locally, then verify Lemon Squeezy in one guided run.\",\n ),\n );\n\n process.stdout.write(renderStep(1, 2, \"Project dependency\", \"add fresh-squeezy when missing\"));\n const installResult = await ensureFreshSqueezyDevDependency({\n skipInstall: options.install === false,\n packageVersion: options.packageVersion,\n });\n process.stdout.write(renderProjectInstallResult(installResult));\n\n // No key yet → the only useful next step is guided setup, so skip the menu.\n // With a key configured, open the interactive front door and route the choice.\n if (!process.env[ENV_KEYS.apiKey]?.trim()) {\n return startGuidedSetup();\n }\n return routeLauncherAction(await pickLauncherAction());\n } catch (err) {\n if (isPromptCancel(err)) {\n process.stderr.write(renderCancelMessage());\n return 130;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`${chalk.red(\"fresh-squeezy bootstrap failed:\")} ${message}\\n\\n`);\n process.stderr.write(renderCommandExamples());\n return 1;\n }\n};\n\n/**\n * Route a front-door menu choice to the same command handlers the flag-driven\n * CLI uses. `doctor` runs interactively so store selection falls through to the\n * TTY multi-select; `examples` prints the copy/paste cheatsheet; `exit` is a\n * clean no-op.\n */\nconst routeLauncherAction = async (action: LauncherAction): Promise<number> => {\n switch (action) {\n case \"init\":\n return startGuidedSetup();\n case \"doctor\":\n return runDoctorCommand({ isInteractive: true });\n case \"examples\":\n process.stdout.write(renderCommandExamples());\n return 0;\n case \"exit\":\n return 0;\n }\n};\n\nconst startGuidedSetup = (): Promise<number> => {\n process.stdout.write(\n renderStep(2, 2, \"Guided setup\", \"detect credentials, stores, and resources\"),\n );\n return runInitCommand({ isInteractive: true });\n};\n\nconst renderProjectInstallResult = (result: ProjectInstallResult): string => {\n if (result.status === \"installed\") {\n return renderDetected(\n \"Dev dependency\",\n \"fresh-squeezy\",\n `${result.packageManager ?? \"npm\"} install`,\n );\n }\n\n if (result.status === \"already-present\") {\n return renderDetected(\"Dev dependency\", \"fresh-squeezy\", \"package.json\");\n }\n\n if (result.status === \"self-package\") {\n return renderDetected(\"Project\", \"fresh-squeezy source repo\", \"package.json\");\n }\n\n if (result.status === \"skipped\") {\n return chalk.dim(\" Skipped dev dependency install (--no-install).\\n\");\n }\n\n return chalk.yellow(\" No package.json found; running without installing a dev dependency.\\n\");\n};\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nconst PACKAGE_NAME = \"fresh-squeezy\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport type ProjectInstallStatus =\n | \"already-present\"\n | \"installed\"\n | \"no-package-json\"\n | \"self-package\"\n | \"skipped\";\n\nexport interface ProjectInstallResult {\n status: ProjectInstallStatus;\n projectDir?: string;\n packageJsonPath?: string;\n packageManager?: PackageManager;\n command?: string[];\n}\n\nexport interface EnsureProjectInstallOptions {\n cwd?: string;\n packageVersion?: string;\n skipInstall?: boolean;\n runCommand?: RunPackageCommand;\n}\n\nexport type RunPackageCommand = (\n command: string,\n args: string[],\n options: { cwd: string },\n) => Promise<number>;\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nexport const ensureFreshSqueezyDevDependency = async (\n options: EnsureProjectInstallOptions = {},\n): Promise<ProjectInstallResult> => {\n if (options.skipInstall) {\n return { status: \"skipped\" };\n }\n\n const cwd = options.cwd ?? process.cwd();\n const packageJsonPath = await findPackageJson(cwd);\n if (!packageJsonPath) {\n return { status: \"no-package-json\" };\n }\n\n const projectDir = path.dirname(packageJsonPath);\n const manifest = await readPackageJson(packageJsonPath);\n if (manifest.name === PACKAGE_NAME) {\n return { status: \"self-package\", projectDir, packageJsonPath };\n }\n\n const packageManager = await detectPackageManager(projectDir);\n if (hasFreshSqueezy(manifest)) {\n return { status: \"already-present\", projectDir, packageJsonPath, packageManager };\n }\n\n const packageSpec = options.packageVersion\n ? `${PACKAGE_NAME}@${options.packageVersion}`\n : PACKAGE_NAME;\n const command = buildInstallCommand(packageManager, packageSpec);\n const executable = command[0];\n if (!executable) throw new Error(\"No package manager command resolved.\");\n\n const runCommand = options.runCommand ?? runPackageCommand;\n const code = await runCommand(executable, command.slice(1), { cwd: projectDir });\n if (code !== 0) {\n throw new Error(`${command.join(\" \")} failed with exit code ${code}`);\n }\n\n return { status: \"installed\", projectDir, packageJsonPath, packageManager, command };\n};\n\nexport const findPackageJson = async (cwd: string): Promise<string | undefined> => {\n let current = path.resolve(cwd);\n\n while (true) {\n const candidate = path.join(current, \"package.json\");\n if (await pathExists(candidate)) return candidate;\n\n const parent = path.dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n};\n\nconst readPackageJson = async (packageJsonPath: string): Promise<PackageJson> => {\n const raw = await fs.readFile(packageJsonPath, \"utf8\");\n return JSON.parse(raw) as PackageJson;\n};\n\nconst detectPackageManager = async (projectDir: string): Promise<PackageManager> => {\n if (await pathExists(path.join(projectDir, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (await pathExists(path.join(projectDir, \"yarn.lock\"))) return \"yarn\";\n if (\n (await pathExists(path.join(projectDir, \"bun.lock\"))) ||\n (await pathExists(path.join(projectDir, \"bun.lockb\")))\n ) {\n return \"bun\";\n }\n return \"npm\";\n};\n\nconst hasFreshSqueezy = (manifest: PackageJson): boolean => {\n return [\n manifest.dependencies,\n manifest.devDependencies,\n manifest.optionalDependencies,\n manifest.peerDependencies,\n ].some((section) => section?.[PACKAGE_NAME] !== undefined);\n};\n\nconst buildInstallCommand = (packageManager: PackageManager, packageSpec: string): string[] => {\n if (packageManager === \"pnpm\") return [\"pnpm\", \"add\", \"-D\", packageSpec];\n if (packageManager === \"yarn\") return [\"yarn\", \"add\", \"-D\", packageSpec];\n if (packageManager === \"bun\") return [\"bun\", \"add\", \"-d\", packageSpec];\n return [\"npm\", \"install\", \"--save-dev\", packageSpec];\n};\n\nconst runPackageCommand = (\n command: string,\n args: string[],\n options: { cwd: string },\n): Promise<number> => {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: false,\n });\n\n child.on(\"error\", reject);\n child.on(\"close\", (code) => resolve(code ?? 1));\n });\n};\n\nconst pathExists = async (filePath: string): Promise<boolean> => {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n};\n","import { readFileSync } from \"node:fs\";\nimport { resolveConfig } from \"../../core/config.js\";\nimport { FreshSqueezyError } from \"../../core/errors.js\";\nimport { HttpClient } from \"../../core/http.js\";\nimport type { Mode } from \"../../core/types.js\";\nimport { createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport { invokeOp } from \"../../resources/invokeOp.js\";\nimport {\n type OpVerb,\n findResourceVerb,\n listRegisteredResources,\n resourceRegistry,\n} from \"../../resources/registry.js\";\nimport { renderCliError } from \"../errors.js\";\nimport { confirmResourceOp } from \"../prompts.js\";\nimport {\n type BulkSelector,\n collectBulkTargets,\n executeBulk,\n previewTargets,\n renderBulkSummary,\n supportsBulk,\n} from \"./bulkOps.js\";\n\n/**\n * Options for hybrid resource ops (get/list/create/…/refund).\n */\nexport interface ResourceOpCommandOptions {\n resource: string;\n verb: OpVerb | string;\n mode?: Mode;\n id?: string;\n storeIds?: string[];\n parentId?: string;\n body?: string;\n bodyFile?: string;\n yes?: boolean;\n json?: boolean;\n isInteractive?: boolean;\n listCatalog?: boolean;\n /** Bulk: apply the verb to every listed item. */\n all?: boolean;\n /** Bulk: apply the verb to these ids. */\n ids?: string[];\n /** Bulk: with `all`, keep only items whose text attributes contain this. */\n match?: string;\n /** Bulk: show targets, send nothing. */\n dryRun?: boolean;\n}\n\n/**\n * Run a docs-backed resource op from the CLI.\n *\n * Dual-mode: non-TTY never prompts; live writes and destructive verbs need\n * `--yes` or TTY confirm.\n *\n * @param options - Verb, resource, flags, body sources.\n * @returns Process exit code (0 success, 1 bulk partial failure, 2 fatal/usage).\n *\n * @example\n * ```ts\n * await runResourceOpCommand({\n * verb: \"get\",\n * resource: \"product\",\n * id: \"42\",\n * json: true,\n * });\n * ```\n */\nexport const runResourceOpCommand = async (options: ResourceOpCommandOptions): Promise<number> => {\n if (options.listCatalog) {\n writeCatalog(options.json ?? false);\n return 0;\n }\n\n const spec = findResourceVerb(options.resource, options.verb);\n if (!spec) {\n process.stderr.write(\n renderCliError(`Unknown or unsupported op: ${options.verb} ${options.resource}`, [\n \"fresh-squeezy ops --list\",\n \"fresh-squeezy get product --id 1\",\n \"fresh-squeezy list webhook --store-ids 1\",\n ]),\n );\n return 2;\n }\n\n const bulkError = validateBulkFlags(spec, options);\n if (bulkError) {\n writeFatal(\n new FreshSqueezyError({ code: \"INVALID_ARGS\", message: bulkError }),\n options.json ?? false,\n );\n return 2;\n }\n\n try {\n const body = readBody(options);\n if (spec.body === \"required\" && body === undefined) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"This op requires a JSON body (--body, --body-file, or stdin).\",\n });\n }\n\n const client = createFreshSqueezy({ mode: options.mode });\n const config = resolveConfig({ mode: options.mode });\n const http = new HttpClient(config);\n // CLI flag wins; LEMON_SQUEEZY_STORE_ID (already in config) is the fallback.\n const storeId = options.storeIds?.[0] ?? config.storeId;\n\n if (options.all || options.ids) {\n return await runBulk(http, spec, client.mode, options, { storeId, body });\n }\n\n const allowed = await assertWriteSafety(spec, client.mode, options);\n if (!allowed) return 2;\n\n const opBody = await invokeOp(http, options.resource, options.verb, {\n id: options.id,\n storeId,\n parentId: options.parentId,\n body,\n });\n\n const envelope = {\n ok: true as const,\n mode: client.mode,\n resource: spec.resource,\n verb: spec.verb,\n docs: `https://docs.lemonsqueezy.com/api/${spec.docsPath}`,\n data: opBody ?? null,\n };\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(envelope, null, 2)}\\n`);\n } else {\n process.stdout.write(\n `${spec.verb} ${spec.resource} — ok (mode=${client.mode})\\n` +\n `${JSON.stringify(opBody ?? null, null, 2)}\\n`,\n );\n }\n return 0;\n } catch (err) {\n writeFatal(err, options.json ?? false);\n return 2;\n }\n};\n\n/**\n * Print the implemented ops matrix (docs-backed).\n *\n * @param asJson - Machine-readable when true.\n */\nconst writeCatalog = (asJson: boolean): void => {\n if (asJson) {\n process.stdout.write(\n `${JSON.stringify(\n {\n resources: listRegisteredResources(),\n ops: resourceRegistry,\n },\n null,\n 2,\n )}\\n`,\n );\n return;\n }\n process.stdout.write(\"Docs-backed ops (Lemon Squeezy official API only):\\n\\n\");\n for (const entry of resourceRegistry) {\n const flags = [\n entry.destructive ? \"destructive\" : undefined,\n entry.body && entry.body !== \"none\" ? `body=${entry.body}` : undefined,\n ]\n .filter(Boolean)\n .join(\", \");\n process.stdout.write(\n ` ${entry.verb.padEnd(18)} ${entry.resource.padEnd(22)} ${entry.docsPath}${flags ? ` (${flags})` : \"\"}\\n`,\n );\n }\n process.stdout.write(\n \"\\nCatalog resources (product, variant, price, file, store, …) are read-only in the API.\\n\",\n );\n};\n\ntype VerbSpec = NonNullable<ReturnType<typeof findResourceVerb>>;\n\n/**\n * Reject flag combinations that make no sense before any network call.\n *\n * @returns An error message, or undefined when the flags are consistent.\n */\nconst validateBulkFlags = (\n spec: VerbSpec,\n options: ResourceOpCommandOptions,\n): string | undefined => {\n const bulk = Boolean(options.all || options.ids);\n if (!bulk) {\n if (options.match) return \"--match needs --all.\";\n if (options.dryRun) return \"--dry-run needs --all or --ids.\";\n return undefined;\n }\n if (!supportsBulk(spec)) {\n return `--all/--ids only apply to delete, cancel, and refund ops (not ${spec.verb} ${spec.resource}).`;\n }\n if (options.all && options.ids) return \"Use either --all or --ids, not both.\";\n if (options.id) return \"--id targets one resource; drop it when using --all or --ids.\";\n if (options.match && !options.all) return \"--match needs --all.\";\n return undefined;\n};\n\n/**\n * Bulk path: resolve targets, confirm once, apply, report.\n *\n * @returns 0 when every item succeeded (or dry run), 1 on partial failure, 2 when declined.\n */\nconst runBulk = async (\n http: HttpClient,\n spec: VerbSpec,\n mode: Mode,\n options: ResourceOpCommandOptions,\n scope: { storeId?: string; body?: unknown },\n): Promise<number> => {\n const selector: BulkSelector = {\n all: options.all,\n ids: options.ids,\n match: options.match,\n storeId: scope.storeId,\n parentId: options.parentId,\n };\n const targets = await collectBulkTargets(http, spec, selector);\n\n if (!options.dryRun && targets.length > 0) {\n const allowed = await assertWriteSafety(spec, mode, options, {\n count: targets.length,\n preview: previewTargets(targets),\n });\n if (!allowed) return 2;\n }\n\n const summary = await executeBulk(http, spec, targets, {\n dryRun: options.dryRun,\n body: scope.body,\n });\n\n if (options.json) {\n const envelope = {\n ok: summary.failed === 0,\n mode,\n resource: spec.resource,\n verb: spec.verb,\n docs: `https://docs.lemonsqueezy.com/api/${spec.docsPath}`,\n ...summary,\n };\n process.stdout.write(`${JSON.stringify(envelope, null, 2)}\\n`);\n } else {\n process.stdout.write(`${spec.verb} ${spec.resource} (mode=${mode})\\n`);\n process.stdout.write(renderBulkSummary(spec, summary));\n }\n return summary.failed > 0 ? 1 : 0;\n};\n\nconst assertWriteSafety = async (\n spec: VerbSpec,\n mode: Mode,\n options: ResourceOpCommandOptions,\n bulk?: { count: number; preview: string },\n): Promise<boolean> => {\n const isWrite = spec.verb !== \"get\" && spec.verb !== \"list\" && spec.verb !== \"current-usage\";\n if (!isWrite) return true;\n\n const needsGate = Boolean(spec.destructive) || mode === \"live\";\n if (!needsGate) return true;\n\n if (options.yes) return true;\n\n if (options.isInteractive) {\n const what = bulk\n ? `${spec.verb} ${bulk.count} ${spec.resource} item(s) (${bulk.preview})`\n : `${spec.verb} ${spec.resource}`;\n return confirmResourceOp(mode === \"live\" ? `LIVE mode: allow ${what}?` : `Confirm ${what}?`);\n }\n\n process.stderr.write(\n renderCliError(\n `${spec.verb} ${spec.resource} requires --yes in non-interactive ${mode} mode${spec.destructive ? \" (destructive op)\" : \"\"}`,\n [\n `fresh-squeezy ${spec.verb} ${spec.resource}${bulk ? \" --all\" : \"\"} --yes …`,\n \"Use test mode for safer experimentation: --mode test\",\n ],\n ),\n );\n return false;\n};\n\nconst readBody = (options: ResourceOpCommandOptions): unknown | undefined => {\n // Bodies come from flags only — never auto-read stdin (would hang non-TTY pipes).\n if (options.bodyFile) {\n return JSON.parse(readFileSync(options.bodyFile, \"utf8\")) as unknown;\n }\n if (options.body !== undefined) {\n return JSON.parse(options.body) as unknown;\n }\n return undefined;\n};\n\nconst writeFatal = (err: unknown, json: boolean): void => {\n if (json) {\n const code = err instanceof FreshSqueezyError ? err.code : \"FATAL\";\n const message = err instanceof Error ? err.message : String(err);\n const status = err instanceof FreshSqueezyError ? err.status : undefined;\n process.stderr.write(\n `${JSON.stringify({ ok: false, error: { code, message, status } }, null, 2)}\\n`,\n );\n return;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(renderCliError(message, [\"fresh-squeezy ops --list\"]));\n};\n","import { FreshSqueezyError } from \"../../core/errors.js\";\nimport type { HttpClient } from \"../../core/http.js\";\nimport { invokeOp } from \"../../resources/invokeOp.js\";\nimport { type ResourceVerbSpec, findResourceVerb } from \"../../resources/registry.js\";\n\n/** One resource the bulk run will act on. */\nexport interface BulkTarget {\n id: string;\n /** Human label (code, name, url) shown in confirms and results. */\n label: string;\n}\n\n/** Per-item outcome of a bulk run. */\nexport interface BulkResult extends BulkTarget {\n ok: boolean;\n error?: string;\n}\n\n/** Aggregate outcome of a bulk run. */\nexport interface BulkSummary {\n dryRun: boolean;\n total: number;\n succeeded: number;\n failed: number;\n results: BulkResult[];\n}\n\n/** Selector flags that choose which resources a bulk run touches. */\nexport interface BulkSelector {\n all?: boolean;\n ids?: string[];\n match?: string;\n storeId?: string;\n parentId?: string;\n}\n\n/**\n * Whether a registry spec can run in bulk: write verbs that act on one id\n * (delete / cancel / refund) and have a matching `list` to enumerate from.\n *\n * @param spec - Registry entry for the verb.\n * @returns True when `--all` / `--ids` make sense for this op.\n */\nexport const supportsBulk = (spec: ResourceVerbSpec): boolean =>\n Boolean(spec.destructive) && spec.idRole === \"id\";\n\n/**\n * Pick a readable label from a JSON:API resource (code, name, url, …).\n *\n * @param item - Resource returned by `list`.\n * @returns The best label, falling back to the id.\n */\nexport const describeBulkTarget = (item: {\n id: string | number;\n attributes?: Record<string, unknown>;\n}): BulkTarget => {\n const attrs = item.attributes ?? {};\n const id = String(item.id);\n for (const key of [\"code\", \"name\", \"url\", \"identifier\", \"user_email\", \"status\"]) {\n const value = attrs[key];\n if (typeof value === \"string\" && value.length > 0) return { id, label: value };\n }\n return { id, label: id };\n};\n\n/**\n * Case-insensitive substring match against every string attribute.\n */\nconst matchesText = (item: { attributes?: Record<string, unknown> }, text: string): boolean => {\n const needle = text.toLowerCase();\n return Object.values(item.attributes ?? {}).some(\n (value) => typeof value === \"string\" && value.toLowerCase().includes(needle),\n );\n};\n\n/**\n * Resolve the targets of a bulk run: explicit `--ids`, or every item from the\n * resource's `list` (all pages), optionally narrowed by `--match`.\n *\n * @param http - Shared API client.\n * @param spec - Registry entry for the write verb.\n * @param selector - Which resources to touch, plus the list scope.\n * @returns Targets in API order.\n * @throws {FreshSqueezyError} `MISSING_ARG` when list scope is missing, `UNKNOWN_OP` without a list op.\n *\n * @example\n * ```ts\n * const targets = await collectBulkTargets(http, spec, { all: true, storeId: \"1\" });\n * ```\n */\nexport const collectBulkTargets = async (\n http: HttpClient,\n spec: ResourceVerbSpec,\n selector: BulkSelector,\n): Promise<BulkTarget[]> => {\n if (selector.ids?.length) {\n return selector.ids.map((id) => ({ id, label: id }));\n }\n\n const listSpec = findResourceVerb(spec.resource, \"list\");\n if (!listSpec) {\n throw new FreshSqueezyError({\n code: \"UNKNOWN_OP\",\n message: `Cannot use --all: ${spec.resource} has no list op. Pass --ids instead.`,\n });\n }\n if (listSpec.idRole === \"store\" && !selector.storeId) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"--all needs a store: pass --store-ids or set LEMON_SQUEEZY_STORE_ID.\",\n });\n }\n if (listSpec.idRole === \"parent\" && !selector.parentId) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--all needs --parent-id to list ${spec.resource} items.`,\n });\n }\n\n const items = (await invokeOp(http, spec.resource, \"list\", {\n storeId: selector.storeId,\n parentId: selector.parentId,\n })) as Array<{ id: string | number; attributes?: Record<string, unknown> }>;\n\n return items\n .filter((item) => (selector.match ? matchesText(item, selector.match) : true))\n .map(describeBulkTarget);\n};\n\n/**\n * Apply the write verb to each target. Keeps going after a failure so one bad\n * id never blocks the rest; with `dryRun` nothing is sent.\n *\n * @param http - Shared API client.\n * @param spec - Registry entry for the write verb.\n * @param targets - Resources to act on.\n * @param opts - `dryRun` skips writes; `body` is forwarded to every call.\n * @returns Per-item results and totals.\n *\n * @example\n * ```ts\n * const summary = await executeBulk(http, spec, targets, { dryRun: false });\n * if (summary.failed > 0) process.exitCode = 1;\n * ```\n */\nexport const executeBulk = async (\n http: HttpClient,\n spec: ResourceVerbSpec,\n targets: BulkTarget[],\n opts: { dryRun?: boolean; body?: unknown } = {},\n): Promise<BulkSummary> => {\n const dryRun = Boolean(opts.dryRun);\n const results: BulkResult[] = [];\n for (const target of targets) {\n if (dryRun) {\n results.push({ ...target, ok: true });\n continue;\n }\n try {\n await invokeOp(http, spec.resource, spec.verb, { id: target.id, body: opts.body });\n results.push({ ...target, ok: true });\n } catch (err) {\n results.push({\n ...target,\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n return { dryRun, total: results.length, succeeded: results.length - failed, failed, results };\n};\n\n/**\n * Short preview of target labels for confirm prompts.\n *\n * @param targets - Resources about to be touched.\n * @param max - Labels to show before eliding.\n */\nexport const previewTargets = (targets: BulkTarget[], max = 5): string => {\n const shown = targets.slice(0, max).map((t) => t.label);\n const more = targets.length - shown.length;\n return more > 0 ? `${shown.join(\", \")}, … +${more} more` : shown.join(\", \");\n};\n\n/**\n * Render a bulk summary for terminal output.\n *\n * @param spec - Registry entry for the write verb.\n * @param summary - Result of `executeBulk`.\n */\nexport const renderBulkSummary = (spec: ResourceVerbSpec, summary: BulkSummary): string => {\n if (summary.total === 0) return `No ${spec.resource} items matched — nothing to ${spec.verb}.\\n`;\n const verb = summary.dryRun ? `would ${spec.verb}` : spec.verb;\n const lines = summary.results.map((r) =>\n r.ok\n ? ` ✓ ${verb} ${spec.resource} ${r.id} (${r.label})`\n : ` ✗ ${spec.verb} ${spec.resource} ${r.id} (${r.label}): ${r.error}`,\n );\n const tail = summary.dryRun\n ? `dry run — ${summary.total} ${spec.resource} item(s) would be affected, nothing sent`\n : `${summary.succeeded}/${summary.total} succeeded${summary.failed ? `, ${summary.failed} failed` : \"\"}`;\n return `${lines.join(\"\\n\")}\\n${tail}\\n`;\n};\n","import { FreshSqueezyError } from \"../../core/errors.js\";\nimport type { Mode, ValidationResult } from \"../../core/types.js\";\nimport { type FreshSqueezyClient, createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport { getValidateHints, renderCliError } from \"../errors.js\";\nimport { renderResult } from \"../render.js\";\nimport { resolveStores } from \"../resolveStores.js\";\n\nexport interface ValidateCommandOptions {\n mode?: Mode;\n storeIds?: string[];\n allStores?: boolean;\n productId?: string;\n webhookUrl?: string;\n discountId?: string;\n licenseKeyId?: string;\n variantId?: string;\n json?: boolean;\n isInteractive?: boolean;\n}\n\nexport type ValidateTarget =\n | \"connection\"\n | \"store\"\n | \"product\"\n | \"webhook\"\n | \"discount\"\n | \"license-key\"\n | \"subscription-plan\";\n\n/**\n * `fresh-squeezy validate <target>` — run one validator. Store-scoped targets\n * reuse the same store resolution the `doctor` command uses, so a single\n * `--store-ids` flag or interactive pick works across every subcommand.\n *\n * Connection runs once (no stores needed). Store/webhook loop per resolved\n * store. Product runs once because a product ID identifies a single resource;\n * the `--store-ids` value (if any) is used for the cross-store ownership check.\n */\nexport const runValidateCommand = async (\n target: ValidateTarget,\n options: ValidateCommandOptions,\n): Promise<number> => {\n try {\n const client = createFreshSqueezy({ mode: options.mode });\n\n if (target === \"connection\") {\n return emit(await client.validateConnection(), options);\n }\n\n if (target === \"product\") {\n return emit(await runProduct(client, options), options);\n }\n\n if (target === \"discount\") {\n return emit(await runDiscount(client, options), options);\n }\n\n if (target === \"license-key\") {\n return emit(await runLicenseKey(client, options), options);\n }\n\n if (target === \"subscription-plan\") {\n return emit(await runSubscriptionPlan(client, options), options);\n }\n\n const storeIds = await resolveStoresForTarget(client, target, options);\n const results = await runPerStore(client, target, storeIds, options);\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(results, null, 2)}\\n`);\n } else {\n for (const result of results) {\n process.stdout.write(`${renderResult(result)}\\n\\n`);\n }\n }\n\n return results.every((result) => result.ok) ? 0 : 1;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(renderCliError(message, getValidateHints(err, target)));\n return 2;\n }\n};\n\nconst resolveStoresForTarget = async (\n client: FreshSqueezyClient,\n target: ValidateTarget,\n options: ValidateCommandOptions,\n): Promise<string[]> => {\n const resolved = await resolveStores(client, {\n storeIds: options.storeIds,\n allStores: options.allStores,\n isInteractive: options.isInteractive ?? false,\n });\n if (resolved.skipped) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--store-ids or --all-stores is required for \\`validate ${target}\\` in non-interactive mode.`,\n });\n }\n return resolved.storeIds;\n};\n\nconst runPerStore = async (\n client: FreshSqueezyClient,\n target: ValidateTarget,\n storeIds: string[],\n options: ValidateCommandOptions,\n): Promise<ValidationResult[]> => {\n if (target === \"store\") {\n return Promise.all(storeIds.map((id) => client.validateStore(id)));\n }\n if (target === \"webhook\") {\n const url = required(options.webhookUrl, \"--webhook-url is required for `validate webhook`.\");\n return Promise.all(storeIds.map((storeId) => client.validateWebhook({ storeId, url })));\n }\n return [];\n};\n\nconst runProduct = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const productId = required(options.productId, \"--product-id is required for `validate product`.\");\n const expected = options.storeIds?.[0];\n return client.validateProduct({\n productId,\n expectedStoreId: expected,\n });\n};\n\nconst runDiscount = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const discountId = required(\n options.discountId,\n \"--discount-id is required for `validate discount`.\",\n );\n const storeId = required(\n options.storeIds?.[0],\n \"--store-ids is required for `validate discount`.\",\n );\n return client.validateDiscount({ storeId, discountId });\n};\n\nconst runLicenseKey = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const licenseKeyId = required(\n options.licenseKeyId,\n \"--license-key-id is required for `validate license-key`.\",\n );\n const storeId = required(\n options.storeIds?.[0],\n \"--store-ids is required for `validate license-key`.\",\n );\n return client.validateLicenseKey({ storeId, licenseKeyId });\n};\n\nconst runSubscriptionPlan = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const variantId = required(\n options.variantId,\n \"--variant-id is required for `validate subscription-plan`.\",\n );\n const storeId = required(\n options.storeIds?.[0],\n \"--store-ids is required for `validate subscription-plan`.\",\n );\n return client.validateSubscriptionPlan({ storeId, variantId });\n};\n\nconst emit = (result: ValidationResult, options: ValidateCommandOptions): number => {\n if (options.json) {\n process.stdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n } else {\n process.stdout.write(`${renderResult(result)}\\n`);\n }\n return result.ok ? 0 : 1;\n};\n\nconst required = <T>(value: T | undefined, message: string): T => {\n if (value === undefined || value === null || value === \"\") {\n throw new FreshSqueezyError({ code: \"MISSING_ARG\", message });\n }\n return value;\n};\n"],"mappings":"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","names":["readFileSync","input","path","userDoc","stores","values","issue","path","values","input","input","ids","values","message","path","chalk","chalk","chalk","path","values","input","chalk","fs","path","resolve","chalk","writeFatal","message","required","readFileSync","doctor"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/main.ts","../src/cli/commands/augment.ts","../src/core/errors.ts","../src/core/config.ts","../src/core/http.ts","../src/resources/affiliates.ts","../src/resources/checkouts.ts","../src/resources/customers.ts","../src/resources/discountRedemptions.ts","../src/resources/discounts.ts","../src/resources/files.ts","../src/resources/licenseKeyInstances.ts","../src/resources/licenseKeys.ts","../src/resources/orderItems.ts","../src/resources/orders.ts","../src/resources/prices.ts","../src/resources/products.ts","../src/resources/registry.ts","../src/resources/stores.ts","../src/resources/subscriptionInvoices.ts","../src/resources/subscriptionItems.ts","../src/resources/subscriptions.ts","../src/resources/usageRecords.ts","../src/resources/users.ts","../src/resources/variants.ts","../src/resources/webhooks.ts","../src/resources/invokeOp.ts","../src/core/mode.ts","../src/validate/rules.ts","../src/validate/probe.ts","../src/validate/connection.ts","../src/validate/discount.ts","../src/validate/licenseKey.ts","../src/validate/product.ts","../src/validate/store.ts","../src/validate/subscriptionPlan.ts","../src/core/equality.ts","../src/support/manifest.ts","../src/validate/webhook.ts","../src/validate/doctor.ts","../src/createFreshSqueezy.ts","../src/cli/errors.ts","../src/cli/render.ts","../src/cli/prompts.ts","../src/cli/resourceDiscovery.ts","../src/cli/resolveStores.ts","../src/cli/commands/doctor.ts","../src/cli/commands/init.ts","../src/cli/brand.ts","../src/cli/commands/launcher.ts","../src/cli/projectInstall.ts","../src/cli/commands/bulkOps.ts","../src/cli/commands/manage.ts","../src/cli/commands/resourceOps.ts","../src/cli/commands/validate.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { Command } from \"commander\";\nimport dotenv from \"dotenv\";\nimport type { Mode } from \"../core/types.js\";\nimport type { OpVerb } from \"../resources/registry.js\";\nimport { runAugmentCommand } from \"./commands/augment.js\";\nimport { runDoctorCommand } from \"./commands/doctor.js\";\nimport { runInitCommand } from \"./commands/init.js\";\nimport { runLauncherCommand } from \"./commands/launcher.js\";\nimport { runResourceOpCommand } from \"./commands/resourceOps.js\";\nimport { type ValidateTarget, runValidateCommand } from \"./commands/validate.js\";\nimport { renderCliError } from \"./errors.js\";\n\n/**\n * CLI entry. Wires commander subcommands to their handlers. Each handler\n * returns an exit code; the wrapper below forwards it to `process.exit`.\n *\n * Store resolution is a CLI concern: `--store-ids 1,2,3` (CSV) for scripts,\n * `--all-stores` for \"run against every reachable store\", or interactive\n * multi-select when stdin is a TTY and neither flag is supplied. The library\n * API deliberately stays single-store-per-call.\n */\n\ndotenv.config();\n\nconst OP_VERBS: OpVerb[] = [\n \"get\",\n \"list\",\n \"create\",\n \"update\",\n \"delete\",\n \"cancel\",\n \"refund\",\n \"generate-invoice\",\n \"current-usage\",\n];\n\nconst parseMode = (value: string): Mode => {\n if (value === \"test\" || value === \"live\") return value;\n throw new Error(`Mode must be \"test\" or \"live\", got \"${value}\"`);\n};\n\nconst parseCsv = (value: string): string[] =>\n value\n .split(\",\")\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0);\n\nconst readPackageVersion = (): string => {\n const candidates = [\n new URL(\"../package.json\", import.meta.url),\n new URL(\"../../package.json\", import.meta.url),\n ];\n\n for (const candidate of candidates) {\n try {\n const pkg = JSON.parse(readFileSync(candidate, \"utf8\")) as { version?: unknown };\n if (typeof pkg.version === \"string\") return pkg.version;\n } catch {\n // Source runs from src/cli; the built binary runs from dist.\n }\n }\n\n return \"0.0.0\";\n};\n\nconst isInteractive = Boolean(process.stdin.isTTY);\nconst packageVersion = readPackageVersion();\n\ninterface SharedCliOpts {\n mode?: Mode;\n storeIds?: string[];\n allStores?: boolean;\n productId?: string;\n webhookUrl?: string;\n discountId?: string;\n licenseKeyId?: string;\n variantId?: string;\n json?: boolean;\n}\n\ninterface DoctorCliOpts extends SharedCliOpts {\n allResources?: boolean;\n}\n\ninterface ResourceOpCliOpts {\n mode?: Mode;\n id?: string;\n storeIds?: string[];\n parentId?: string;\n body?: string;\n bodyFile?: string;\n yes?: boolean;\n json?: boolean;\n all?: boolean;\n ids?: string[];\n match?: string;\n dryRun?: boolean;\n}\n\n/** Store-flag shapes reused by validate targets. */\ntype StoreFlagKind = \"none\" | \"multi\" | \"ownership\";\n\ninterface ValidateCommandSpec {\n name: ValidateTarget;\n description: string;\n stores: StoreFlagKind;\n required?: [flag: string, description: string];\n /** Extra store-ids help text when `stores` is multi/ownership. */\n storeIdsHelp?: string;\n}\n\nconst VALIDATE_COMMANDS: ValidateCommandSpec[] = [\n {\n name: \"connection\",\n description: \"Check that the API key authenticates\",\n stores: \"none\",\n },\n {\n name: \"store\",\n description: \"Check one or more stores are reachable\",\n stores: \"multi\",\n storeIdsHelp: \"Comma-separated store IDs\",\n },\n {\n name: \"product\",\n description: \"Check a product is published with at least one variant\",\n stores: \"ownership\",\n required: [\"--product-id <id>\", \"Product ID to validate\"],\n storeIdsHelp: \"Expected owning store IDs (first is used for cross-check)\",\n },\n {\n name: \"webhook\",\n description: \"Check a webhook is registered with the recommended events\",\n stores: \"multi\",\n required: [\"--webhook-url <url>\", \"Public webhook URL\"],\n storeIdsHelp: \"Comma-separated store IDs\",\n },\n {\n name: \"discount\",\n description: \"Check a discount code is valid and redeemable\",\n stores: \"ownership\",\n required: [\"--discount-id <id>\", \"Discount ID to validate\"],\n storeIdsHelp: \"Store ID for ownership check (first ID used)\",\n },\n {\n name: \"license-key\",\n description: \"Check a license key is active and not at its activation limit\",\n stores: \"ownership\",\n required: [\"--license-key-id <id>\", \"License key ID to validate\"],\n storeIdsHelp: \"Store ID for ownership check (first ID used)\",\n },\n {\n name: \"subscription-plan\",\n description: \"Check a subscription plan variant has valid billing interval and trial config\",\n stores: \"ownership\",\n required: [\"--variant-id <id>\", \"Variant ID of the subscription plan\"],\n storeIdsHelp: \"Store ID for ownership check (first ID used)\",\n },\n];\n\nconst exitWith = async (code: Promise<number> | number): Promise<void> => {\n process.exit(await code);\n};\n\nconst toValidateOptions = (opts: SharedCliOpts) => ({\n mode: opts.mode,\n storeIds: opts.storeIds,\n allStores: Boolean(opts.allStores),\n productId: opts.productId,\n webhookUrl: opts.webhookUrl,\n discountId: opts.discountId,\n licenseKeyId: opts.licenseKeyId,\n variantId: opts.variantId,\n json: Boolean(opts.json),\n isInteractive,\n});\n\nconst attachModeJson = (cmd: Command): Command =>\n cmd\n .option(\"-m, --mode <mode>\", \"test or live\", parseMode)\n .option(\"--json\", \"Emit machine-readable JSON\");\n\nconst attachValidateFlags = (cmd: Command, spec: ValidateCommandSpec): Command => {\n if (spec.required) cmd.requiredOption(spec.required[0], spec.required[1]);\n\n if (spec.stores === \"multi\") {\n cmd\n .option(\"--store-ids <ids>\", spec.storeIdsHelp ?? \"Comma-separated store IDs\", parseCsv)\n .option(\"--all-stores\", \"Run against every reachable store\");\n } else if (spec.stores === \"ownership\") {\n cmd.option(\n \"--store-ids <ids>\",\n spec.storeIdsHelp ?? \"Store ID for ownership check (first ID used)\",\n parseCsv,\n );\n }\n\n return attachModeJson(cmd);\n};\n\nconst program = new Command();\n\nprogram\n .name(\"fresh-squeezy\")\n .description(\n \"Dual-mode Lemon Squeezy CLI: doctor/validate pre-flight + docs-backed resource ops (get/list/create/…)\",\n )\n .version(packageVersion)\n .option(\"--no-install\", \"Skip adding fresh-squeezy to devDependencies before guided setup\")\n .showSuggestionAfterError()\n .showHelpAfterError(\"\\nRun `fresh-squeezy --help` for examples.\");\n\nprogram.addHelpText(\n \"after\",\n `\nStart (doctor setup):\n fresh-squeezy add as a dev dependency, then run guided setup\n fresh-squeezy --no-install run guided setup without editing package.json\n fresh-squeezy doctor --all-stores --all-resources\n fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\n\nOps (docs-backed Lemon Squeezy API only — products/variants are read-only):\n fresh-squeezy ops --list\n fresh-squeezy get product --id 42 --json\n fresh-squeezy list webhook --store-ids 12\n fresh-squeezy create webhook --body-file webhook.json --yes\n fresh-squeezy cancel subscription --id 9 --yes\n fresh-squeezy refund order --id 100 --yes\n fresh-squeezy generate-invoice order --id 100 --yes\n\nSafety: delete/cancel/refund always need --yes (or TTY confirm); live-mode writes need --yes too.\nBodies are JSON:API documents via --body or --body-file (not flat flags).\n\nStore selection:\n Use --store-ids 12,34 for explicit stores, --all-stores for automation, or run in a TTY to pick stores interactively.\n`,\n);\n\nprogram.action(async (opts: { install?: boolean }) => {\n if (!isInteractive) {\n process.stderr.write(\n renderCliError(\"`fresh-squeezy` guided setup requires an interactive terminal.\", [\n \"fresh-squeezy doctor --all-stores\",\n \"fresh-squeezy validate connection\",\n ]),\n );\n process.exit(2);\n }\n\n await exitWith(\n runLauncherCommand({\n isInteractive,\n install: opts.install,\n packageVersion,\n }),\n );\n});\n\nconst doctor = program\n .command(\"doctor\")\n .description(\"Run the full integration doctor\")\n .option(\"-m, --mode <mode>\", \"test or live\", parseMode)\n .option(\"--store-ids <ids>\", \"Comma-separated store IDs (e.g. 1,2,3)\", parseCsv)\n .option(\"--all-stores\", \"Run against every reachable store, no prompt\")\n .option(\n \"--all-resources\",\n \"Discover and validate every supported resource in each selected store\",\n )\n .option(\"--product-id <id>\", \"Product to validate\")\n .option(\"--webhook-url <url>\", \"Webhook URL to validate\")\n .option(\"--discount-id <id>\", \"Discount to validate\")\n .option(\"--license-key-id <id>\", \"License key to validate\")\n .option(\"--variant-id <id>\", \"Subscription plan variant to validate\")\n .option(\"--json\", \"Emit machine-readable JSON\")\n .action(async (opts: DoctorCliOpts) => {\n await exitWith(\n runDoctorCommand({\n ...toValidateOptions(opts),\n allResources: Boolean(opts.allResources),\n }),\n );\n });\n\ndoctor.addHelpText(\n \"after\",\n `\nExamples:\n fresh-squeezy doctor\n fresh-squeezy doctor --all-stores\n fresh-squeezy doctor --all-stores --all-resources\n fresh-squeezy doctor --store-ids 12 --product-id 987 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\n fresh-squeezy doctor --all-stores --all-resources --json\n`,\n);\n\nconst validate = program.command(\"validate\").description(\"Run a single validator\");\n\nvalidate.addHelpText(\n \"after\",\n `\nExamples:\n fresh-squeezy validate connection\n fresh-squeezy validate store --all-stores\n fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\n\nTargets:\n connection, store, product, webhook, discount, license-key, subscription-plan\n`,\n);\n\nfor (const spec of VALIDATE_COMMANDS) {\n attachValidateFlags(validate.command(spec.name).description(spec.description), spec).action(\n async (opts: SharedCliOpts) => {\n await exitWith(runValidateCommand(spec.name, toValidateOptions(opts)));\n },\n );\n}\n\nprogram\n .command(\"init\")\n .description(\"Interactive setup: ask for credentials, pick a store, run doctor\")\n .option(\"--env-file <path>\", \"Where to write credentials (default: .env)\")\n .action(async (opts: { envFile?: string }) => {\n await exitWith(runInitCommand({ envFile: opts.envFile, isInteractive }));\n });\n\nconst types = program\n .command(\"types\")\n .description(\n \"Type-augmentation utilities for the official Lemon Squeezy SDK and hand-rolled types\",\n );\n\ntypes\n .command(\"augment\")\n .description(\n \"Generate a .d.ts that intersects your Lemon Squeezy resource types with changelog fields fresh-squeezy tracks.\",\n )\n .option(\"--out <path>\", \"Output path (default: lemonsqueezy.augment.d.ts in CWD)\")\n .option(\"--force\", \"Emit the generic file even when @lemonsqueezy/lemonsqueezy.js is detected\")\n .action(async (opts: { out?: string; force?: boolean }) => {\n await exitWith(runAugmentCommand({ out: opts.out, force: Boolean(opts.force) }));\n });\n\nprogram\n .command(\"ops\")\n .description(\"List docs-backed resource ops (Lemon Squeezy official API matrix)\")\n .option(\"--list\", \"Print the full verb matrix\", true)\n .option(\"--json\", \"Emit machine-readable JSON\")\n .action(async (opts: { json?: boolean }) => {\n await exitWith(\n runResourceOpCommand({\n resource: \"\",\n verb: \"get\",\n listCatalog: true,\n json: Boolean(opts.json),\n }),\n );\n });\n\nconst BULK_VERBS: readonly OpVerb[] = [\"delete\", \"cancel\", \"refund\"];\n\n/** Per-verb `--help` footer; bulk verbs get --all/--ids/--dry-run examples. */\nconst opHelpText = (verb: OpVerb): string => {\n if (!BULK_VERBS.includes(verb)) {\n return `\\nExample:\\n fresh-squeezy ${verb} <resource> --id 42 --json\\n`;\n }\n const r = verb === \"delete\" ? \"discount\" : verb === \"cancel\" ? \"subscription\" : \"order\";\n return `\nExamples:\n fresh-squeezy ${verb} ${r} --id 42 --yes\n fresh-squeezy ${verb} ${r} --ids 1,2,3 --yes\n fresh-squeezy ${verb} ${r} --all --store-ids 12 --dry-run\n fresh-squeezy ${verb} ${r} --all --store-ids 12 --match TEST --yes --json\n\nBulk notes:\n --all lists every page first, then asks once (TTY) or needs --yes (non-TTY).\n Store falls back to LEMON_SQUEEZY_STORE_ID when --store-ids is omitted.\n Exit codes: 0 ok, 1 some items failed, 2 usage error / declined.\n`;\n};\n\nfor (const verb of OP_VERBS) {\n program\n .command(`${verb} <resource>`)\n .description(`Docs-backed ${verb} for a Lemon Squeezy resource`)\n .option(\"-m, --mode <mode>\", \"test or live\", parseMode)\n .option(\"--id <id>\", \"Resource id\")\n .option(\n \"--store-ids <ids>\",\n \"Comma-separated store IDs (first used for list filters)\",\n parseCsv,\n )\n .option(\n \"--parent-id <id>\",\n \"Parent resource id for nested lists (product, order, subscription, …)\",\n )\n .option(\"--body <json>\", \"JSON:API body string\")\n .option(\"--body-file <path>\", \"Path to JSON:API body file\")\n .option(\"--yes\", \"Skip confirm; required for live writes and destructive ops when non-TTY\")\n .option(\"--json\", \"Emit machine-readable JSON\")\n .option(\"--all\", \"Bulk: apply to every item from `list` (delete, cancel, refund)\")\n .option(\"--ids <ids>\", \"Bulk: comma-separated ids (delete, cancel, refund)\", parseCsv)\n .option(\"--match <text>\", \"Bulk: with --all, only items whose name/code/url contain <text>\")\n .option(\"--dry-run\", \"Bulk: show what would be affected; send nothing\")\n .addHelpText(\"after\", opHelpText(verb))\n .action(async (resource: string, opts: ResourceOpCliOpts) => {\n await exitWith(\n runResourceOpCommand({\n verb,\n resource,\n mode: opts.mode,\n id: opts.id,\n storeIds: opts.storeIds,\n parentId: opts.parentId,\n body: opts.body,\n bodyFile: opts.bodyFile,\n yes: Boolean(opts.yes),\n json: Boolean(opts.json),\n isInteractive,\n all: Boolean(opts.all),\n ids: opts.ids,\n match: opts.match,\n dryRun: Boolean(opts.dryRun),\n }),\n );\n });\n}\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n const hints = message.includes(\"Mode must be\")\n ? [\"fresh-squeezy doctor --mode test\", \"fresh-squeezy doctor --mode live\"]\n : [\"fresh-squeezy --help\"];\n process.stderr.write(renderCliError(message, hints));\n process.exit(2);\n});\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\n\n/**\n * Options for `fresh-squeezy types:augment`.\n *\n * All paths are CLI-friendly defaults: the command runs in the consumer's\n * CWD, reads their `package.json`, and writes the augmentation `.d.ts`\n * next to it (or wherever they redirect with `--out`).\n */\nexport interface AugmentCommandOptions {\n /** Project root. Defaults to `process.cwd()`. */\n cwd?: string;\n /** Output path for the augmentation file. Defaults to `lemonsqueezy.augment.d.ts`. */\n out?: string;\n /** Suppress \"no SDK detected\" message and emit the generic file anyway. */\n force?: boolean;\n}\n\n/**\n * Two flavours of file we emit.\n *\n * - `with-sdk` — the consumer has `@lemonsqueezy/lemonsqueezy.js` installed.\n * The file imports types from the SDK and intersects them with our\n * `Latest*Fields`. Consumers reach the augmented type via\n * `LemonSqueezyAugmented[\"subscription\"]`.\n *\n * - `generic` — the consumer's resource types are home-rolled or come from\n * another SDK. The file re-exports `WithLatestLemonSqueezyFields<T, R>`\n * so consumers can wire their own base type.\n */\ntype Flavour = \"with-sdk\" | \"generic\";\n\n/**\n * Generate a `.d.ts` file in the consumer's project so their existing\n * Lemon Squeezy resource types pick up fields fresh-squeezy already knows\n * about (per the changelog audit in `src/support/manifest.ts`).\n *\n * Writes a single file. Idempotent: re-running overwrites with the\n * current version, so a CI step can safely regenerate after each\n * fresh-squeezy upgrade. Returns 0 on success, 2 on I/O failure.\n */\nexport const runAugmentCommand = async (options: AugmentCommandOptions = {}): Promise<number> => {\n const cwd = options.cwd ?? process.cwd();\n const outPath = resolve(cwd, options.out ?? \"lemonsqueezy.augment.d.ts\");\n\n try {\n const flavour = await detectFlavour(cwd, options.force ?? false);\n const contents = renderAugmentationFile(flavour);\n await mkdir(dirname(outPath), { recursive: true });\n await writeFile(outPath, contents, \"utf8\");\n\n process.stdout.write(`fresh-squeezy: wrote ${outPath} (${flavour}).\\n`);\n if (flavour === \"with-sdk\") {\n process.stdout.write(\n `Use it via: import type { LemonSqueezyAugmented } from \"./lemonsqueezy.augment\";\\n`,\n );\n } else {\n process.stdout.write(\n `Use it via: import type { WithLatestLemonSqueezyFields } from \"./lemonsqueezy.augment\";\\n`,\n );\n }\n return 0;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`fresh-squeezy: ${message}\\n`);\n return 2;\n }\n};\n\nconst detectFlavour = async (cwd: string, force: boolean): Promise<Flavour> => {\n if (force) return \"generic\";\n const pkgPath = resolve(cwd, \"package.json\");\n if (!existsSync(pkgPath)) return \"generic\";\n\n const raw = await readFile(pkgPath, \"utf8\");\n const pkg = JSON.parse(raw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n };\n\n const deps = {\n ...(pkg.dependencies ?? {}),\n ...(pkg.devDependencies ?? {}),\n ...(pkg.peerDependencies ?? {}),\n };\n\n return \"@lemonsqueezy/lemonsqueezy.js\" in deps ? \"with-sdk\" : \"generic\";\n};\n\nconst renderAugmentationFile = (flavour: Flavour): string => {\n const header = `/**\n * Generated by \\`fresh-squeezy types:augment\\` — re-run after upgrading\n * fresh-squeezy to refresh the field set.\n *\n * Why this file exists: the live Lemon Squeezy API has acquired fields\n * since the SDK / hand-rolled types in this repo were last updated\n * (e.g. \\`payment_processor\\`, \\`tax_inclusive\\`, \\`refunded_amount*\\`,\n * \\`setup_fee*\\`, \\`unit_price_decimal\\`, checkout color options,\n * \\`skip_trial\\`, \\`variant_quantities\\`, subscription item proration\n * flags, and order item \\`quantity\\`). fresh-squeezy also generates a\n * broad resource map from Lemon Squeezy's object docs, so newly documented\n * attributes can flow in after \\`npm run generate:api-types\\`.\n *\n * To wire it in:\n * 1. Make sure your tsconfig.json's \"include\" covers this file (most\n * do by default if it's in the project root or under \"src\").\n * 2. Import the augmented type from this file instead of the raw SDK\n * type — see the example at the bottom of this file.\n */\n\n`;\n\n if (flavour === \"with-sdk\") {\n return `${header}import type {\n Subscription,\n SubscriptionInvoice,\n Order,\n OrderItem,\n Variant,\n Price,\n Checkout,\n} from \"@lemonsqueezy/lemonsqueezy.js\";\nimport type {\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n WithLatestLemonSqueezyFields,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n} from \"fresh-squeezy\";\n\n/**\n * One-stop reference for resources fresh-squeezy has wider knowledge of\n * than the official SDK. The shape mirrors the SDK's response envelope\n * (\\`{ data: { attributes: ... } }\\`) — only the inner attributes are\n * widened. Request-only field sets (e.g. subscription-item update params)\n * are not response documents, so they ship as standalone \\`Latest*Fields\\`\n * exports below rather than as entries here.\n */\nexport interface LemonSqueezyAugmented {\n subscription: AugmentResponse<Subscription, LatestSubscriptionFields>;\n subscriptionInvoice: AugmentResponse<SubscriptionInvoice, LatestSubscriptionInvoiceFields>;\n order: AugmentResponse<Order, LatestOrderFields>;\n orderItem: AugmentResponse<OrderItem, LatestOrderItemFields>;\n variant: AugmentResponse<Variant, LatestVariantFields>;\n price: AugmentResponse<Price, LatestPriceFields>;\n checkout: AugmentResponse<Checkout, LatestCheckoutFields>;\n}\n\nexport type {\n WithLatestLemonSqueezyFields,\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n};\n\n/**\n * Helper that walks the official SDK's response envelope and intersects\n * the inner \\`attributes\\` record with the supplied field set.\n */\ntype AugmentResponse<T, Fields> = T extends {\n data: infer Data;\n}\n ? Data extends { attributes: infer Attrs }\n ? Omit<T, \"data\"> & {\n data: Omit<Data, \"attributes\"> & { attributes: Attrs & Fields };\n }\n : T\n : T;\n\n/* Example:\n *\n * import type { LemonSqueezyAugmented } from \"./lemonsqueezy.augment\";\n *\n * function describe(sub: LemonSqueezyAugmented[\"subscription\"]) {\n * const attrs = sub.data.attributes;\n * console.log(attrs.payment_processor); // ← typed, no manual extension\n * console.log(attrs.urls?.update_customer_portal);\n * }\n */\n`;\n }\n\n return `${header}import type {\n WithLatestLemonSqueezyFields,\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n} from \"fresh-squeezy\";\n\nexport type {\n WithLatestLemonSqueezyFields,\n LatestSubscriptionFields,\n LatestSubscriptionInvoiceFields,\n LatestSubscriptionItemUpdateFields,\n LatestOrderFields,\n LatestOrderItemFields,\n LatestVariantFields,\n LatestPriceFields,\n LatestCheckoutFields,\n LatestCheckoutOptionsFields,\n LatestCheckoutDataFields,\n LatestLemonSqueezyResourceName,\n LatestFieldsFor,\n GeneratedLemonSqueezyFieldMap,\n GeneratedLemonSqueezyResourceName,\n GeneratedLemonSqueezyResourceType,\n};\n\n/* Example with a hand-rolled or third-party type:\n *\n * import type { WithLatestLemonSqueezyFields } from \"./lemonsqueezy.augment\";\n *\n * type MySubscription = WithLatestLemonSqueezyFields<MyExistingSubscription, \"subscription\">;\n *\n * function describe(sub: MySubscription) {\n * console.log(sub.payment_processor); // typed\n * type MyCheckout = WithLatestLemonSqueezyFields<MyExistingCheckout, \"checkout\">;\n * }\n */\n`;\n};\n","/**\n * Unified error type for fresh-squeezy. All HTTP and validation failures that\n * bubble up to consumers pass through this class so caller code can branch on\n * a single `instanceof` check.\n *\n * Why a class over a discriminated union: Node's `fetch` rejections interleave\n * with library errors in user stack traces. A class keeps the stack readable\n * and gives one stable prototype chain for consumer `catch` blocks.\n */\nexport class FreshSqueezyError extends Error {\n public readonly code: string;\n public readonly status?: number;\n public readonly detail?: unknown;\n\n constructor(opts: { code: string; message: string; status?: number; detail?: unknown }) {\n super(opts.message);\n this.name = \"FreshSqueezyError\";\n this.code = opts.code;\n this.status = opts.status;\n this.detail = opts.detail;\n Object.setPrototypeOf(this, FreshSqueezyError.prototype);\n }\n}\n","import { FreshSqueezyError } from \"./errors.js\";\nimport type { FreshSqueezyConfig, Mode, ResolvedConfig } from \"./types.js\";\n\n/**\n * Lemon Squeezy API root. Test and live share the same host — mode is determined\n * by which API key is used. Documented at https://docs.lemonsqueezy.com/api.\n */\nconst DEFAULT_BASE_URL = \"https://api.lemonsqueezy.com\";\n\n/**\n * Env variable names read when a field is not passed explicitly. Consuming\n * products rely on these names being stable — treat them as public API.\n */\nexport const ENV_KEYS = {\n apiKey: \"LEMON_SQUEEZY_API_KEY\",\n storeId: \"LEMON_SQUEEZY_STORE_ID\",\n mode: \"LEMON_SQUEEZY_MODE\",\n} as const;\n\n/**\n * Resolve the user-supplied config against environment variables and defaults.\n *\n * Precedence (highest → lowest): explicit argument → env var → built-in default.\n * Throws `FreshSqueezyError` only for fields that cannot be defaulted (currently\n * just `apiKey`), so callers can surface a clear setup error at construction\n * time rather than at first request.\n */\nexport const resolveConfig = (input: FreshSqueezyConfig = {}): ResolvedConfig => {\n const apiKey = input.apiKey ?? process.env[ENV_KEYS.apiKey];\n if (!apiKey) {\n throw new FreshSqueezyError({\n code: \"MISSING_API_KEY\",\n message: `No API key provided. Pass \\`apiKey\\` or set ${ENV_KEYS.apiKey}.`,\n });\n }\n\n const mode = normalizeMode(input.mode ?? process.env[ENV_KEYS.mode] ?? \"test\");\n const storeIdRaw = input.storeId ?? process.env[ENV_KEYS.storeId];\n\n return {\n apiKey,\n storeId: storeIdRaw == null ? undefined : String(storeIdRaw),\n mode,\n baseUrl: input.baseUrl ?? DEFAULT_BASE_URL,\n fetch: input.fetch ?? globalThis.fetch,\n };\n};\n\nconst normalizeMode = (value: string): Mode => {\n if (value === \"test\" || value === \"live\") return value;\n throw new FreshSqueezyError({\n code: \"INVALID_MODE\",\n message: `Mode must be \"test\" or \"live\", got \"${value}\".`,\n });\n};\n","import { FreshSqueezyError } from \"./errors.js\";\nimport type {\n JsonApiCollection,\n JsonApiDocument,\n JsonApiResource,\n ResolvedConfig,\n} from \"./types.js\";\n\n/**\n * Stable FreshSqueezyError.code values for common HTTP status codes.\n * Unlisted statuses fall through to the JSON:API error `code` or `HTTP_<status>`.\n */\nconst HTTP_STATUS_CODES = {\n 401: \"UNAUTHORIZED\",\n 404: \"NOT_FOUND\",\n 429: \"RATE_LIMITED\",\n} as const;\n\n/**\n * Options for a single HTTP request.\n *\n * `path` is a Lemon Squeezy API path starting with `/v1/...`. The `query`\n * record is serialized via `URLSearchParams` (JSON:API bracket keys such as\n * `filter[store_id]` are accepted as-is and percent-encoded in the final URL).\n */\nexport interface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n path: string;\n query?: Record<string, string | number | undefined>;\n /** JSON:API document or other request body; stringified when present. */\n body?: unknown;\n signal?: AbortSignal;\n}\n\n/**\n * Lemon Squeezy JSON:API error object. Kept loose because the API occasionally\n * includes extra keys; the fields we surface are the stable ones.\n */\ninterface JsonApiError {\n status?: string;\n code?: string;\n title?: string;\n detail?: string;\n}\n\n/**\n * Low-level HTTP client. Callers usually go through resource/validator helpers,\n * but this is also exposed as the public escape hatch so consumers can reach\n * endpoints fresh-squeezy does not wrap yet.\n *\n * Responsibilities kept in this one place (per plan.md \"one source of truth\n * for transport\"):\n * - auth header injection\n * - query string serialization (JSON:API bracket keys via URLSearchParams)\n * - response parsing + error normalization\n * - surfacing HTTP status in `FreshSqueezyError`\n *\n * Retries, pagination helpers, and rate-limit handling live in separate files\n * so this layer stays small and obvious.\n */\nexport class HttpClient {\n constructor(private readonly config: ResolvedConfig) {}\n\n async request<T>(options: RequestOptions): Promise<T> {\n const url = this.requestUrl(options.path, options.query);\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.config.apiKey}`,\n Accept: \"application/vnd.api+json\",\n };\n if (options.body !== undefined) {\n headers[\"Content-Type\"] = \"application/vnd.api+json\";\n }\n\n let httpResponse: Response;\n try {\n httpResponse = await this.config.fetch(url, {\n method: options.method ?? \"GET\",\n headers,\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n signal: options.signal,\n });\n } catch (cause) {\n throw new FreshSqueezyError({\n code: \"NETWORK_ERROR\",\n message: cause instanceof Error ? cause.message : \"Network request failed\",\n detail: cause,\n });\n }\n\n const text = await httpResponse.text();\n const parsed = text.length > 0 ? parseJsonBody(text) : undefined;\n\n if (!httpResponse.ok) {\n throw apiError(httpResponse.status, parsed);\n }\n\n return parsed as T;\n }\n\n /**\n * Fetch a single JSON:API resource and return its `data` object.\n */\n async getResource<TAttr>(path: string): Promise<JsonApiResource<TAttr>> {\n const doc = await this.request<JsonApiDocument<TAttr>>({ path });\n return doc.data;\n }\n\n /**\n * POST a JSON:API document and return the created `data` resource.\n *\n * @param path - API path starting with `/v1/...`.\n * @param body - JSON:API create document.\n * @returns The created resource.\n */\n async postResource<TAttr>(path: string, body: unknown): Promise<JsonApiResource<TAttr>> {\n const doc = await this.request<JsonApiDocument<TAttr>>({ method: \"POST\", path, body });\n return doc.data;\n }\n\n /**\n * PATCH a JSON:API document and return the updated `data` resource.\n *\n * @param path - API path starting with `/v1/...`.\n * @param body - JSON:API update document.\n * @returns The updated resource.\n */\n async patchResource<TAttr>(path: string, body: unknown): Promise<JsonApiResource<TAttr>> {\n const doc = await this.request<JsonApiDocument<TAttr>>({ method: \"PATCH\", path, body });\n return doc.data;\n }\n\n /**\n * DELETE a resource. Lemon Squeezy often returns an empty body on success.\n *\n * @param path - API path starting with `/v1/...`.\n * @returns Nothing — single void return, not a multi-field bag.\n */\n async deleteResource(path: string): Promise<void> {\n await this.request({ method: \"DELETE\", path });\n }\n\n /**\n * Fetch a single page of a JSON:API collection. Most callers want\n * `paginate()` instead — this method is kept for one-shot lookups where\n * the caller knows the result fits in a single page.\n */\n async getCollection<TAttr>(\n path: string,\n query?: RequestOptions[\"query\"],\n ): Promise<JsonApiResource<TAttr>[]> {\n const doc = await this.request<JsonApiCollection<TAttr>>({ path, query });\n return doc.data;\n }\n\n /**\n * Walk a JSON:API collection across every page and concatenate the\n * results. Lemon Squeezy returns 25 items per page by default; without\n * pagination, validators silently miss anything past the first page (e.g.\n * `validateWebhook` on a store with 26+ webhooks would falsely report\n * `WEBHOOK_NOT_FOUND` for any webhook on page 2).\n *\n * Stops as soon as `meta.page.lastPage` is reached. Falls back to a\n * single-page fetch if the API does not surface page metadata.\n *\n * Caller-supplied `page[number]` is honored as the starting page; we\n * advance from there. `page[size]` is left untouched so callers can tune\n * batch size (max 100 per Lemon Squeezy docs).\n */\n async paginate<TAttr>(\n path: string,\n query?: RequestOptions[\"query\"],\n ): Promise<JsonApiResource<TAttr>[]> {\n const startPage = Number(query?.[\"page[number]\"] ?? 1);\n const all: JsonApiResource<TAttr>[] = [];\n\n let pageNumber = startPage;\n while (true) {\n const pagedQuery = { ...(query ?? {}), \"page[number]\": pageNumber };\n const doc = await this.request<JsonApiCollection<TAttr>>({ path, query: pagedQuery });\n all.push(...doc.data);\n\n const lastPage = doc.meta?.page?.lastPage;\n if (lastPage === undefined || pageNumber >= lastPage) return all;\n pageNumber += 1;\n }\n }\n\n private requestUrl(path: string, query?: RequestOptions[\"query\"]): string {\n const url = new URL(path, this.config.baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined) continue;\n url.searchParams.append(key, String(value));\n }\n }\n return url.toString();\n }\n}\n\nconst parseJsonBody = (text: string): unknown => {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n};\n\nconst apiError = (status: number, responseBody: unknown): FreshSqueezyError => {\n const errors = extractJsonApiErrors(responseBody);\n const first = errors[0];\n const mapped = HTTP_STATUS_CODES[status as keyof typeof HTTP_STATUS_CODES];\n const code = mapped ?? first?.code ?? `HTTP_${status}`;\n const message =\n first?.detail ?? first?.title ?? `Lemon Squeezy request failed with status ${status}`;\n return new FreshSqueezyError({ code, status, message, detail: responseBody });\n};\n\nconst extractJsonApiErrors = (responseBody: unknown): JsonApiError[] => {\n if (!responseBody || typeof responseBody !== \"object\") return [];\n const errors = (responseBody as { errors?: unknown }).errors;\n if (!Array.isArray(errors)) return [];\n return errors.filter(\n (entry): entry is JsonApiError => typeof entry === \"object\" && entry !== null,\n );\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedAffiliateAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type AffiliateStatus = \"active\" | \"pending\" | \"disabled\";\n\n/**\n * Affiliate attributes added with the 2025-01-21 Affiliates API surface.\n * No validator consumes these yet; the helpers give typed access while\n * preserving the raw request escape hatch for mutations and includes.\n */\nexport interface AffiliateAttributes extends GeneratedAffiliateAttributes {\n store_id: number;\n user_id: number;\n user_name: string;\n user_email: string;\n share_domain: string;\n status: AffiliateStatus;\n application_note?: string | null;\n products?: unknown;\n total_earnings: number;\n unpaid_earnings: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getAffiliate = async (\n http: HttpClient,\n affiliateId: string | number,\n): Promise<JsonApiResource<AffiliateAttributes>> => {\n return http.getResource<AffiliateAttributes>(`/v1/affiliates/${affiliateId}`);\n};\n\nexport const listAffiliatesForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<AffiliateAttributes>[]> => {\n return http.paginate<AffiliateAttributes>(\"/v1/affiliates\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedCheckoutAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type CheckoutLocale =\n | \"bg\"\n | \"hr\"\n | \"cs\"\n | \"da\"\n | \"nl\"\n | \"en\"\n | \"et\"\n | \"fil\"\n | \"fi\"\n | \"fr\"\n | \"de\"\n | \"el\"\n | \"hu\"\n | \"id\"\n | \"it\"\n | \"ja\"\n | \"ko\"\n | \"lv\"\n | \"lt\"\n | \"ms\"\n | \"mt\"\n | \"pl\"\n | \"pt\"\n | \"ro\"\n | \"ru\"\n | \"zh-CN\"\n | \"sk\"\n | \"sl\"\n | \"es\"\n | \"sv\"\n | \"th\"\n | \"tr\"\n | \"vi\";\n\nexport interface CheckoutProductOptions {\n name?: string;\n description?: string;\n media?: string[];\n redirect_url?: string;\n receipt_button_text?: string;\n receipt_link_url?: string;\n receipt_thank_you_note?: string;\n enabled_variants?: number[];\n}\n\nexport interface CheckoutOptions {\n embed?: boolean;\n media?: boolean;\n logo?: boolean;\n desc?: boolean;\n discount?: boolean;\n subscription_preview?: boolean;\n /** Added 2024-03-28. */\n skip_trial?: boolean;\n /** Deprecated 2024-09-04; keep typed so old payloads still compile. */\n dark?: boolean;\n background_color?: string;\n headings_color?: string;\n primary_text_color?: string;\n secondary_text_color?: string;\n links_color?: string;\n borders_color?: string;\n checkbox_color?: string;\n active_state_color?: string;\n button_color?: string;\n button_text_color?: string;\n terms_privacy_color?: string;\n locale?: CheckoutLocale | string | null;\n}\n\nexport interface CheckoutVariantQuantity {\n variant_id: number;\n quantity: number;\n}\n\nexport interface CheckoutData {\n email?: string;\n name?: string;\n billing_address?: {\n country?: string;\n zip?: string;\n };\n tax_number?: string;\n discount_code?: string;\n custom?: Record<string, unknown>;\n /** Added 2023-08-23 for multi-variant checkout quantities. */\n variant_quantities?: CheckoutVariantQuantity[];\n}\n\nexport interface CheckoutPreview {\n currency: string;\n currency_rate: number | string;\n subtotal: number;\n discount_total: number;\n tax: number;\n total: number;\n subtotal_usd: number;\n discount_total_usd: number;\n tax_usd: number;\n total_usd: number;\n subtotal_formatted: string;\n discount_total_formatted: string;\n tax_formatted: string;\n total_formatted: string;\n}\n\nexport interface CheckoutAttributes extends GeneratedCheckoutAttributes {\n store_id: number;\n variant_id: number;\n custom_price?: number | null;\n product_options?: CheckoutProductOptions;\n checkout_options?: CheckoutOptions;\n checkout_data?: CheckoutData;\n preview?: CheckoutPreview;\n expires_at?: string | null;\n url?: string;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve a checkout (GET /v1/checkouts/:id).\n *\n * @param http - Shared API client.\n * @param checkoutId - Checkout id.\n * @returns The checkout resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const checkout = await getCheckout(http, 1);\n * ```\n */\nexport const getCheckout = async (\n http: HttpClient,\n checkoutId: string | number,\n): Promise<JsonApiResource<CheckoutAttributes>> => {\n return http.getResource<CheckoutAttributes>(`/v1/checkouts/${checkoutId}`);\n};\n\n/**\n * List checkouts for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Checkout resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const checkouts = await listCheckoutsForStore(http, 1);\n * ```\n */\nexport const listCheckoutsForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<CheckoutAttributes>[]> => {\n return http.paginate<CheckoutAttributes>(\"/v1/checkouts\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a checkout (POST /v1/checkouts).\n * Docs: https://docs.lemonsqueezy.com/api/checkouts/create-checkout\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document (store + variant relationships).\n * @returns The created checkout (includes `url` for the hosted checkout).\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const checkout = await createCheckout(http, {\n * data: {\n * type: \"checkouts\",\n * attributes: { checkout_data: { email: \"buyer@example.com\" } },\n * relationships: {\n * store: { data: { type: \"stores\", id: \"1\" } },\n * variant: { data: { type: \"variants\", id: \"1\" } },\n * },\n * },\n * });\n * ```\n */\nexport const createCheckout = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<CheckoutAttributes>> => {\n return http.postResource<CheckoutAttributes>(\"/v1/checkouts\", body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedCustomerAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type CustomerStatus =\n | \"subscribed\"\n | \"unsubscribed\"\n | \"archived\"\n | \"requires_verification\"\n | \"invalid_email\"\n | \"bounced\";\n\nexport interface CustomerUrls {\n customer_portal?: string | null;\n}\n\n/**\n * Lemon Squeezy customer attributes. The customer portal URL was called out\n * in the 2023-09-19 changelog and is useful for apps linking users back to\n * billing without another API shape.\n */\nexport interface CustomerAttributes extends GeneratedCustomerAttributes {\n store_id: number;\n name: string;\n email: string;\n status: CustomerStatus;\n city?: string | null;\n region?: string | null;\n country?: string | null;\n total_revenue_currency: number;\n mrr: number;\n status_formatted: string;\n country_formatted?: string | null;\n total_revenue_currency_formatted: string;\n mrr_formatted: string;\n urls?: CustomerUrls;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve a customer (GET /v1/customers/:id).\n *\n * @param http - Shared API client.\n * @param customerId - Customer id.\n * @returns The customer resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customer = await getCustomer(http, 1);\n * ```\n */\nexport const getCustomer = async (\n http: HttpClient,\n customerId: string | number,\n): Promise<JsonApiResource<CustomerAttributes>> => {\n return http.getResource<CustomerAttributes>(`/v1/customers/${customerId}`);\n};\n\n/**\n * List customers for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Customer resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customers = await listCustomersForStore(http, 1);\n * ```\n */\nexport const listCustomersForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<CustomerAttributes>[]> => {\n return http.paginate<CustomerAttributes>(\"/v1/customers\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a customer (POST /v1/customers).\n * Docs: https://docs.lemonsqueezy.com/api/customers/create-customer\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created customer.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customer = await createCustomer(http, {\n * data: {\n * type: \"customers\",\n * attributes: { name: \"Ada\", email: \"ada@example.com\" },\n * relationships: { store: { data: { type: \"stores\", id: \"1\" } } },\n * },\n * });\n * ```\n */\nexport const createCustomer = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<CustomerAttributes>> => {\n return http.postResource<CustomerAttributes>(\"/v1/customers\", body);\n};\n\n/**\n * Update a customer (PATCH /v1/customers/:id).\n * Docs: https://docs.lemonsqueezy.com/api/customers/update-customer\n *\n * @param http - Shared API client.\n * @param customerId - Customer id.\n * @param body - JSON:API update document.\n * @returns The updated customer.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const customer = await updateCustomer(http, 1, {\n * data: { type: \"customers\", id: \"1\", attributes: { name: \"Ada Lovelace\" } },\n * });\n * ```\n */\nexport const updateCustomer = async (\n http: HttpClient,\n customerId: string | number,\n body: unknown,\n): Promise<JsonApiResource<CustomerAttributes>> => {\n return http.patchResource<CustomerAttributes>(`/v1/customers/${customerId}`, body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedDiscountRedemptionAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface DiscountRedemptionAttributes extends GeneratedDiscountRedemptionAttributes {\n discount_id: number;\n order_id: number;\n discount_name: string;\n discount_code: string;\n discount_amount: number;\n discount_amount_type: \"percent\" | \"fixed\";\n amount: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getDiscountRedemption = async (\n http: HttpClient,\n discountRedemptionId: string | number,\n): Promise<JsonApiResource<DiscountRedemptionAttributes>> => {\n return http.getResource<DiscountRedemptionAttributes>(\n `/v1/discount-redemptions/${discountRedemptionId}`,\n );\n};\n\nexport const listDiscountRedemptionsForDiscount = async (\n http: HttpClient,\n discountId: string | number,\n): Promise<JsonApiResource<DiscountRedemptionAttributes>[]> => {\n return http.paginate<DiscountRedemptionAttributes>(\"/v1/discount-redemptions\", {\n \"filter[discount_id]\": String(discountId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedDiscountAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of Lemon Squeezy discount attributes used by the discount validator.\n * Full schema at https://docs.lemonsqueezy.com/api/discounts.\n */\nexport interface DiscountAttributes extends GeneratedDiscountAttributes {\n name: string;\n code: string;\n amount: number;\n amount_type: \"percent\" | \"fixed\";\n is_limited_to_products: boolean;\n is_limited_redemptions: boolean;\n max_redemptions: number;\n starts_at: string | null;\n expires_at: string | null;\n status: \"draft\" | \"published\";\n duration: \"once\" | \"repeating\" | \"forever\";\n store_id: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Fetch a single discount by ID. The validator uses the discount's\n * `relationships.store` to confirm ownership against the caller's storeId.\n *\n * @param http - Shared API client.\n * @param discountId - Discount id.\n * @returns The discount resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const discount = await getDiscount(http, 1);\n * ```\n */\nexport const getDiscount = async (\n http: HttpClient,\n discountId: string | number,\n): Promise<JsonApiResource<DiscountAttributes>> => {\n return http.getResource<DiscountAttributes>(`/v1/discounts/${discountId}`);\n};\n\n/**\n * List discounts for a store (GET /v1/discounts?filter[store_id]=…).\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Discount resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const discounts = await listDiscountsForStore(http, 1);\n * ```\n */\nexport const listDiscountsForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<DiscountAttributes>[]> => {\n return http.paginate<DiscountAttributes>(\"/v1/discounts\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a discount (POST /v1/discounts). No update endpoint exists in the API.\n * Docs: https://docs.lemonsqueezy.com/api/discounts/create-discount\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created discount.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const discount = await createDiscount(http, {\n * data: {\n * type: \"discounts\",\n * attributes: { name: \"Launch\", code: \"LAUNCH10\", amount: 10, amount_type: \"percent\" },\n * relationships: { store: { data: { type: \"stores\", id: \"1\" } } },\n * },\n * });\n * ```\n */\nexport const createDiscount = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<DiscountAttributes>> => {\n return http.postResource<DiscountAttributes>(\"/v1/discounts\", body);\n};\n\n/**\n * Delete a discount (DELETE /v1/discounts/:id).\n * Docs: https://docs.lemonsqueezy.com/api/discounts/delete-discount\n *\n * @param http - Shared API client.\n * @param discountId - Discount id.\n * @returns Nothing on success.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * await deleteDiscount(http, 1);\n * ```\n */\nexport const deleteDiscount = async (\n http: HttpClient,\n discountId: string | number,\n): Promise<void> => {\n await http.deleteResource(`/v1/discounts/${discountId}`);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedFileAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Lemon Squeezy file attributes, generated from the public object docs.\n * Exposed so consumers can type file-resource escape-hatch calls without\n * waiting for a hand-written validator.\n */\nexport interface FileAttributes extends GeneratedFileAttributes {}\n\nexport const getFile = async (\n http: HttpClient,\n fileId: string | number,\n): Promise<JsonApiResource<FileAttributes>> => {\n return http.getResource<FileAttributes>(`/v1/files/${fileId}`);\n};\n\nexport const listFilesForVariant = async (\n http: HttpClient,\n variantId: string | number,\n): Promise<JsonApiResource<FileAttributes>[]> => {\n return http.paginate<FileAttributes>(\"/v1/files\", {\n \"filter[variant_id]\": String(variantId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedLicenseKeyInstanceAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface LicenseKeyInstanceAttributes extends GeneratedLicenseKeyInstanceAttributes {\n license_key_id: number;\n identifier: string;\n name: string;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getLicenseKeyInstance = async (\n http: HttpClient,\n licenseKeyInstanceId: string | number,\n): Promise<JsonApiResource<LicenseKeyInstanceAttributes>> => {\n return http.getResource<LicenseKeyInstanceAttributes>(\n `/v1/license-key-instances/${licenseKeyInstanceId}`,\n );\n};\n\nexport const listLicenseKeyInstancesForLicenseKey = async (\n http: HttpClient,\n licenseKeyId: string | number,\n): Promise<JsonApiResource<LicenseKeyInstanceAttributes>[]> => {\n return http.paginate<LicenseKeyInstanceAttributes>(\"/v1/license-key-instances\", {\n \"filter[license_key_id]\": String(licenseKeyId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedLicenseKeyAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of Lemon Squeezy license-key attributes used by the license key\n * validator. Full schema at https://docs.lemonsqueezy.com/api/license-keys.\n */\nexport interface LicenseKeyAttributes extends GeneratedLicenseKeyAttributes {\n key_short: string;\n status: \"active\" | \"inactive\" | \"expired\" | \"disabled\";\n expires_at: string | null;\n activation_limit: number | null;\n instances_count: number;\n disabled: boolean;\n store_id: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Fetch a single license key by ID. Used by the license key validator to\n * check activation limits, expiration, and store ownership.\n *\n * @param http - Shared API client.\n * @param licenseKeyId - License key id.\n * @returns The license key resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const key = await getLicenseKey(http, 1);\n * ```\n */\nexport const getLicenseKey = async (\n http: HttpClient,\n licenseKeyId: string | number,\n): Promise<JsonApiResource<LicenseKeyAttributes>> => {\n return http.getResource<LicenseKeyAttributes>(`/v1/license-keys/${licenseKeyId}`);\n};\n\n/**\n * List license keys for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns License key resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const keys = await listLicenseKeysForStore(http, 1);\n * ```\n */\nexport const listLicenseKeysForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<LicenseKeyAttributes>[]> => {\n return http.paginate<LicenseKeyAttributes>(\"/v1/license-keys\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Update a license key (PATCH /v1/license-keys/:id) — e.g. `expires_at`, disabled.\n * Docs: https://docs.lemonsqueezy.com/api/license-keys/update-license-key\n *\n * @param http - Shared API client.\n * @param licenseKeyId - License key id.\n * @param body - JSON:API update document.\n * @returns The updated license key.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const key = await updateLicenseKey(http, 1, {\n * data: { type: \"license-keys\", id: \"1\", attributes: { disabled: true } },\n * });\n * ```\n */\nexport const updateLicenseKey = async (\n http: HttpClient,\n licenseKeyId: string | number,\n body: unknown,\n): Promise<JsonApiResource<LicenseKeyAttributes>> => {\n return http.patchResource<LicenseKeyAttributes>(`/v1/license-keys/${licenseKeyId}`, body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedOrderItemAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Order item attributes. `quantity` was added to the documented object in\n * the 2024-12-06 changelog and is needed for multi-quantity reconciliation.\n */\nexport interface OrderItemAttributes extends GeneratedOrderItemAttributes {\n order_id: number;\n product_id: number;\n variant_id: number;\n product_name: string;\n variant_name: string;\n price: number;\n quantity: number;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getOrderItem = async (\n http: HttpClient,\n orderItemId: string | number,\n): Promise<JsonApiResource<OrderItemAttributes>> => {\n return http.getResource<OrderItemAttributes>(`/v1/order-items/${orderItemId}`);\n};\n\nexport const listOrderItemsForOrder = async (\n http: HttpClient,\n orderId: string | number,\n): Promise<JsonApiResource<OrderItemAttributes>[]> => {\n return http.paginate<OrderItemAttributes>(\"/v1/order-items\", {\n \"filter[order_id]\": String(orderId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedOrderAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface OrderUrls {\n receipt?: string;\n}\n\nexport interface OrderFirstItem {\n id: number;\n order_id?: number;\n product_id: number;\n variant_id: number;\n product_name: string;\n variant_name: string;\n price: number;\n quantity?: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Subset of Lemon Squeezy order attributes fresh-squeezy understands.\n *\n * fresh-squeezy does not (yet) validate orders — the type is exported so\n * consumers using the raw `client.request<OrderAttributes>()` escape hatch\n * get a typed response that includes platform additions the official SDK\n * has not yet picked up.\n *\n * Field provenance against the changelog\n * (https://docs.lemonsqueezy.com/api/getting-started/changelog):\n *\n * - `status: \"fraudulent\"` — added 2024-09-10. Indicates a manual fraud\n * flag; treat as terminal and refund or chargeback as appropriate.\n * - `refunded_amount`, `refunded_amount_usd`, `refunded_amount_formatted`\n * — added 2024-08-07. Useful for consumers reconciling partial refunds.\n * - `tax_inclusive` — added 2024-02-05.\n */\nexport interface OrderAttributes extends GeneratedOrderAttributes {\n store_id: number;\n customer_id?: number;\n identifier: string;\n order_number: number;\n user_name: string;\n user_email: string;\n currency: string;\n currency_rate: string;\n subtotal: number;\n setup_fee?: number;\n discount_total: number;\n tax: number;\n tax_inclusive?: boolean;\n total: number;\n refunded_amount?: number;\n subtotal_usd?: number;\n setup_fee_usd?: number;\n discount_total_usd?: number;\n tax_usd?: number;\n total_usd?: number;\n refunded_amount_usd?: number | null;\n tax_name?: string | null;\n tax_rate?: number | string | null;\n refunded_amount_formatted?: string | null;\n refunded?: boolean;\n refunded_at?: string | null;\n status: \"pending\" | \"failed\" | \"paid\" | \"refunded\" | \"fraudulent\" | \"partial_refund\";\n status_formatted: string;\n subtotal_formatted?: string;\n setup_fee_formatted?: string;\n discount_total_formatted?: string;\n tax_formatted?: string;\n total_formatted?: string;\n first_order_item?: OrderFirstItem | null;\n urls?: OrderUrls;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Fetch a single order by ID.\n *\n * @param http - Shared API client.\n * @param orderId - Order id.\n * @returns The order resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const order = await getOrder(http, 1);\n * ```\n */\nexport const getOrder = async (\n http: HttpClient,\n orderId: string | number,\n): Promise<JsonApiResource<OrderAttributes>> => {\n return http.getResource<OrderAttributes>(`/v1/orders/${orderId}`);\n};\n\n/**\n * List orders for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Order resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const orders = await listOrdersForStore(http, 1);\n * ```\n */\nexport const listOrdersForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<OrderAttributes>[]> => {\n return http.paginate<OrderAttributes>(\"/v1/orders\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Issue a full or partial order refund (POST /v1/orders/:id/refund).\n * Docs: https://docs.lemonsqueezy.com/api/orders/issue-refund\n *\n * @param http - Shared API client.\n * @param orderId - Order to refund.\n * @param body - Optional JSON:API body (`attributes.amount` for partial).\n * @returns The updated order after refund.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const order = await refundOrder(http, 1);\n * ```\n */\nexport const refundOrder = async (\n http: HttpClient,\n orderId: string | number,\n body?: unknown,\n): Promise<JsonApiResource<OrderAttributes>> => {\n return http.postResource<OrderAttributes>(`/v1/orders/${orderId}/refund`, body ?? {});\n};\n\n/**\n * Generate an order invoice (POST /v1/orders/:id/generate-invoice).\n * Docs: https://docs.lemonsqueezy.com/api/orders/generate-order-invoice\n *\n * @param http - Shared API client.\n * @param orderId - Order id.\n * @param body - Optional locale/name attributes document.\n * @returns API response document (invoice URL payload).\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoice = await generateOrderInvoice(http, 1);\n * ```\n */\nexport const generateOrderInvoice = async (\n http: HttpClient,\n orderId: string | number,\n body?: unknown,\n): Promise<unknown> => {\n return http.request({\n method: \"POST\",\n path: `/v1/orders/${orderId}/generate-invoice`,\n body: body ?? {},\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedPriceAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of Lemon Squeezy price attributes. Prices are nested under\n * variants in the API surface; consumers that read them directly via\n * `client.request<PriceAttributes>()` get a typed response that includes\n * the setup-fee fields the official SDK does not yet surface.\n *\n * Field provenance:\n * - `setup_fee_enabled`, `setup_fee` — added 2024-01-21.\n * - `unit_price_decimal` — added 2024-01-15.\n */\nexport interface PriceAttributes extends GeneratedPriceAttributes {\n variant_id: number;\n category: \"one_time\" | \"subscription\" | \"lead_magnet\" | \"pwyw\";\n scheme: \"standard\" | \"package\" | \"graduated\" | \"volume\";\n usage_aggregation?: string | null;\n unit_price?: number;\n /** Added 2024-01-15. Decimal string for sub-cent accuracy. */\n unit_price_decimal?: string | null;\n package_size?: number;\n tiers?: unknown;\n renewal_interval_unit?: \"day\" | \"week\" | \"month\" | \"year\" | null;\n renewal_interval_quantity?: number | null;\n trial_interval_unit?: \"day\" | \"week\" | \"month\" | \"year\" | null;\n trial_interval_quantity?: number | null;\n min_price?: number | null;\n suggested_price?: number | null;\n tax_code?: string;\n /** Added 2024-01-21. */\n setup_fee_enabled?: boolean | null;\n /** Added 2024-01-21. Setup fee in cents, paired with `setup_fee_enabled`. */\n setup_fee?: number | null;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Fetch a single price by ID (read-only — no create/update/delete in LS API).\n *\n * @param http - Shared API client.\n * @param priceId - Price id.\n * @returns The price resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const price = await getPrice(http, 1);\n * ```\n */\nexport const getPrice = async (\n http: HttpClient,\n priceId: string | number,\n): Promise<JsonApiResource<PriceAttributes>> => {\n return http.getResource<PriceAttributes>(`/v1/prices/${priceId}`);\n};\n\n/**\n * List prices for a variant.\n *\n * @param http - Shared API client.\n * @param variantId - Variant filter.\n * @returns Price resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const prices = await listPricesForVariant(http, 1);\n * ```\n */\nexport const listPricesForVariant = async (\n http: HttpClient,\n variantId: string | number,\n): Promise<JsonApiResource<PriceAttributes>[]> => {\n return http.paginate<PriceAttributes>(\"/v1/prices\", {\n \"filter[variant_id]\": String(variantId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedProductAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of product attributes we need for validation. `status` drives the\n * \"unpublished product\" check; `store_id` drives ownership checks.\n */\nexport interface ProductAttributes extends GeneratedProductAttributes {\n name: string;\n slug: string;\n description?: string | null;\n status: \"draft\" | \"published\";\n status_formatted?: string;\n store_id: number;\n buy_now_url?: string | null;\n from_price?: number | null;\n to_price?: number | null;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getProduct = async (\n http: HttpClient,\n productId: string | number,\n): Promise<JsonApiResource<ProductAttributes>> => {\n return http.getResource<ProductAttributes>(`/v1/products/${productId}`);\n};\n\n/**\n * List every product in the store, paginated. Used by the CLI's\n * interactive product picker; without pagination only the first 25\n * products are offered.\n */\nexport const listProducts = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<ProductAttributes>[]> => {\n return http.paginate<ProductAttributes>(\"/v1/products\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n","/**\n * Docs-backed ops matrix for Lemon Squeezy.\n *\n * Only verbs that exist at https://docs.lemonsqueezy.com/api are listed.\n * Catalog resources (products, variants, prices, files, stores, …) are\n * read-only. CI changelog scrape may propose gaps; this registry is what ships.\n */\n\n/** CLI / client verb tokens, including non-CRUD LS actions. */\nexport type OpVerb =\n | \"get\"\n | \"list\"\n | \"create\"\n | \"update\"\n | \"delete\"\n | \"cancel\"\n | \"refund\"\n | \"generate-invoice\"\n | \"current-usage\";\n\n/**\n * One implemented, documented operation.\n *\n * @remarks `docsPath` is the path under `/api/` on the LS docs site.\n */\nexport interface ResourceVerbSpec {\n /** CLI resource token (singular), e.g. `webhook`. */\n resource: string;\n verb: OpVerb;\n /** Docs path fragment, e.g. `webhooks/create-webhook`. */\n docsPath: string;\n /** Requires --yes or TTY confirm always (delete/cancel/refund). */\n destructive?: boolean;\n body?: \"required\" | \"optional\" | \"none\";\n /**\n * How list/get resolve the primary id filter.\n * - `id` — --id\n * - `store` — --store-ids (first) or store filter\n * - `parent` — --parent-id (subscription, order, product, …)\n */\n idRole?: \"id\" | \"store\" | \"parent\" | \"none\";\n}\n\n/**\n * Implemented ops. Keep in sync with exports in `src/resources/*` and the\n * CLI dispatcher. Do not register fantasy endpoints (e.g. product create).\n */\nexport const resourceRegistry: readonly ResourceVerbSpec[] = [\n // users\n { resource: \"user\", verb: \"get\", docsPath: \"users/retrieve-user\", body: \"none\", idRole: \"none\" },\n\n // stores (read-only)\n { resource: \"store\", verb: \"get\", docsPath: \"stores/retrieve-store\", body: \"none\", idRole: \"id\" },\n {\n resource: \"store\",\n verb: \"list\",\n docsPath: \"stores/list-all-stores\",\n body: \"none\",\n idRole: \"none\",\n },\n\n // products (read-only)\n {\n resource: \"product\",\n verb: \"get\",\n docsPath: \"products/retrieve-product\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"product\",\n verb: \"list\",\n docsPath: \"products/list-all-products\",\n body: \"none\",\n idRole: \"store\",\n },\n\n // variants (read-only)\n {\n resource: \"variant\",\n verb: \"get\",\n docsPath: \"variants/retrieve-variant\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"variant\",\n verb: \"list\",\n docsPath: \"variants/list-all-variants\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // prices (read-only)\n { resource: \"price\", verb: \"get\", docsPath: \"prices/retrieve-price\", body: \"none\", idRole: \"id\" },\n {\n resource: \"price\",\n verb: \"list\",\n docsPath: \"prices/list-all-prices\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // files (read-only)\n { resource: \"file\", verb: \"get\", docsPath: \"files/retrieve-file\", body: \"none\", idRole: \"id\" },\n {\n resource: \"file\",\n verb: \"list\",\n docsPath: \"files/list-all-files\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // customers\n {\n resource: \"customer\",\n verb: \"get\",\n docsPath: \"customers/retrieve-customer\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"customer\",\n verb: \"list\",\n docsPath: \"customers/list-all-customers\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"customer\",\n verb: \"create\",\n docsPath: \"customers/create-customer\",\n body: \"required\",\n idRole: \"none\",\n },\n {\n resource: \"customer\",\n verb: \"update\",\n docsPath: \"customers/update-customer\",\n body: \"required\",\n idRole: \"id\",\n },\n\n // orders\n { resource: \"order\", verb: \"get\", docsPath: \"orders/retrieve-order\", body: \"none\", idRole: \"id\" },\n {\n resource: \"order\",\n verb: \"list\",\n docsPath: \"orders/list-all-orders\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"order\",\n verb: \"refund\",\n docsPath: \"orders/issue-refund\",\n body: \"optional\",\n destructive: true,\n idRole: \"id\",\n },\n {\n resource: \"order\",\n verb: \"generate-invoice\",\n docsPath: \"orders/generate-order-invoice\",\n body: \"optional\",\n idRole: \"id\",\n },\n\n // order-items (read-only)\n {\n resource: \"order-item\",\n verb: \"get\",\n docsPath: \"order-items/retrieve-order-item\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"order-item\",\n verb: \"list\",\n docsPath: \"order-items/list-all-order-items\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // subscriptions\n {\n resource: \"subscription\",\n verb: \"get\",\n docsPath: \"subscriptions/retrieve-subscription\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"subscription\",\n verb: \"list\",\n docsPath: \"subscriptions/list-all-subscriptions\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"subscription\",\n verb: \"update\",\n docsPath: \"subscriptions/update-subscription\",\n body: \"required\",\n idRole: \"id\",\n },\n {\n resource: \"subscription\",\n verb: \"cancel\",\n docsPath: \"subscriptions/cancel-subscription\",\n body: \"none\",\n destructive: true,\n idRole: \"id\",\n },\n\n // subscription-items\n {\n resource: \"subscription-item\",\n verb: \"get\",\n docsPath: \"subscription-items/retrieve-subscription-item\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"subscription-item\",\n verb: \"list\",\n docsPath: \"subscription-items/list-all-subscription-items\",\n body: \"none\",\n idRole: \"parent\",\n },\n {\n resource: \"subscription-item\",\n verb: \"update\",\n docsPath: \"subscription-items/update-subscription-item\",\n body: \"required\",\n idRole: \"id\",\n },\n {\n resource: \"subscription-item\",\n verb: \"current-usage\",\n docsPath: \"subscription-items/retrieve-subscription-item-current-usage\",\n body: \"none\",\n idRole: \"id\",\n },\n\n // subscription-invoices\n {\n resource: \"subscription-invoice\",\n verb: \"get\",\n docsPath: \"subscription-invoices/retrieve-subscription-invoice\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"subscription-invoice\",\n verb: \"list\",\n docsPath: \"subscription-invoices/list-all-subscription-invoices\",\n body: \"none\",\n idRole: \"parent\",\n },\n {\n resource: \"subscription-invoice\",\n verb: \"refund\",\n docsPath: \"subscription-invoices/issue-refund\",\n body: \"optional\",\n destructive: true,\n idRole: \"id\",\n },\n {\n resource: \"subscription-invoice\",\n verb: \"generate-invoice\",\n docsPath: \"subscription-invoices/generate-subscription-invoice\",\n body: \"optional\",\n idRole: \"id\",\n },\n\n // usage-records\n {\n resource: \"usage-record\",\n verb: \"get\",\n docsPath: \"usage-records/retrieve-usage-record\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"usage-record\",\n verb: \"list\",\n docsPath: \"usage-records/list-all-usage-records\",\n body: \"none\",\n idRole: \"parent\",\n },\n {\n resource: \"usage-record\",\n verb: \"create\",\n docsPath: \"usage-records/create-usage-record\",\n body: \"required\",\n idRole: \"none\",\n },\n\n // discounts\n {\n resource: \"discount\",\n verb: \"get\",\n docsPath: \"discounts/retrieve-discount\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"discount\",\n verb: \"list\",\n docsPath: \"discounts/list-all-discounts\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"discount\",\n verb: \"create\",\n docsPath: \"discounts/create-discount\",\n body: \"required\",\n idRole: \"none\",\n },\n {\n resource: \"discount\",\n verb: \"delete\",\n docsPath: \"discounts/delete-discount\",\n body: \"none\",\n destructive: true,\n idRole: \"id\",\n },\n\n // discount-redemptions (read-only)\n {\n resource: \"discount-redemption\",\n verb: \"get\",\n docsPath: \"discount-redemptions/retrieve-discount-redemption\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"discount-redemption\",\n verb: \"list\",\n docsPath: \"discount-redemptions/list-all-discount-redemptions\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // license-keys\n {\n resource: \"license-key\",\n verb: \"get\",\n docsPath: \"license-keys/retrieve-license-key\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"license-key\",\n verb: \"list\",\n docsPath: \"license-keys/list-all-license-keys\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"license-key\",\n verb: \"update\",\n docsPath: \"license-keys/update-license-key\",\n body: \"required\",\n idRole: \"id\",\n },\n\n // license-key-instances (read-only)\n {\n resource: \"license-key-instance\",\n verb: \"get\",\n docsPath: \"license-key-instances/retrieve-license-key-instance\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"license-key-instance\",\n verb: \"list\",\n docsPath: \"license-key-instances/list-all-license-key-instances\",\n body: \"none\",\n idRole: \"parent\",\n },\n\n // checkouts\n {\n resource: \"checkout\",\n verb: \"get\",\n docsPath: \"checkouts/retrieve-checkout\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"checkout\",\n verb: \"list\",\n docsPath: \"checkouts/list-all-checkouts\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"checkout\",\n verb: \"create\",\n docsPath: \"checkouts/create-checkout\",\n body: \"required\",\n idRole: \"none\",\n },\n\n // webhooks\n {\n resource: \"webhook\",\n verb: \"get\",\n docsPath: \"webhooks/retrieve-webhook\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"webhook\",\n verb: \"list\",\n docsPath: \"webhooks/list-all-webhooks\",\n body: \"none\",\n idRole: \"store\",\n },\n {\n resource: \"webhook\",\n verb: \"create\",\n docsPath: \"webhooks/create-webhook\",\n body: \"required\",\n idRole: \"none\",\n },\n {\n resource: \"webhook\",\n verb: \"update\",\n docsPath: \"webhooks/update-webhook\",\n body: \"required\",\n idRole: \"id\",\n },\n {\n resource: \"webhook\",\n verb: \"delete\",\n docsPath: \"webhooks/delete-webhook\",\n body: \"none\",\n destructive: true,\n idRole: \"id\",\n },\n\n // affiliates (read-only)\n {\n resource: \"affiliate\",\n verb: \"get\",\n docsPath: \"affiliates/retrieve-affiliate\",\n body: \"none\",\n idRole: \"id\",\n },\n {\n resource: \"affiliate\",\n verb: \"list\",\n docsPath: \"affiliates/list-all-affiliates\",\n body: \"none\",\n idRole: \"store\",\n },\n] as const;\n\n/**\n * Plural CLI tokens → singular registry keys.\n * Lookups run after `_` → `-` normalization, so only kebab forms live here.\n */\nconst RESOURCE_ALIASES: Record<string, string> = {\n products: \"product\",\n stores: \"store\",\n customers: \"customer\",\n orders: \"order\",\n \"order-items\": \"order-item\",\n subscriptions: \"subscription\",\n \"subscription-items\": \"subscription-item\",\n \"subscription-invoices\": \"subscription-invoice\",\n \"usage-records\": \"usage-record\",\n discounts: \"discount\",\n \"discount-redemptions\": \"discount-redemption\",\n \"license-keys\": \"license-key\",\n \"license-key-instances\": \"license-key-instance\",\n checkouts: \"checkout\",\n webhooks: \"webhook\",\n affiliates: \"affiliate\",\n variants: \"variant\",\n prices: \"price\",\n files: \"file\",\n users: \"user\",\n};\n\n/**\n * Normalize a CLI resource token to the singular registry key.\n *\n * @param resource - Raw token (`products`, `order_items`, `webhook`).\n * @returns Canonical singular resource name used in `resourceRegistry`.\n */\nexport const normalizeResourceName = (resource: string): string => {\n const normalized = resource.replace(/_/g, \"-\").toLowerCase();\n if (RESOURCE_ALIASES[normalized]) {\n return RESOURCE_ALIASES[normalized];\n }\n // naive singular for simple plurals; leave tokens like \"status\" alone\n if (normalized.endsWith(\"s\") && normalized !== \"status\") {\n return normalized.slice(0, -1);\n }\n return normalized;\n};\n\n/**\n * Look up a registry entry.\n *\n * @param resource - CLI resource token.\n * @param verb - Op verb.\n * @returns The spec, or undefined when not implemented / not in LS API.\n */\nexport const findResourceVerb = (resource: string, verb: string): ResourceVerbSpec | undefined => {\n const key = normalizeResourceName(resource);\n return resourceRegistry.find((entry) => entry.resource === key && entry.verb === verb);\n};\n\n/**\n * Unique resource names that have at least one verb.\n *\n * @returns Sorted resource tokens for help text / menus.\n */\nexport const listRegisteredResources = (): string[] => {\n return [...new Set(resourceRegistry.map((entry) => entry.resource))].sort();\n};\n\n/**\n * All verbs registered for a resource (empty when unknown).\n *\n * @param resource - CLI resource token (plural or singular).\n * @returns Sorted verb list for help / menus.\n */\nexport const listRegisteredVerbs = (resource: string): OpVerb[] => {\n const key = normalizeResourceName(resource);\n return resourceRegistry\n .filter((entry) => entry.resource === key)\n .map((entry) => entry.verb)\n .sort();\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedStoreAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of store attributes fresh-squeezy reads.\n * Full schema at https://docs.lemonsqueezy.com/api/stores.\n */\nexport interface StoreAttributes extends GeneratedStoreAttributes {\n name: string;\n slug: string;\n domain?: string | null;\n url?: string | null;\n country?: string;\n currency?: string;\n plan?: string;\n created_at?: string;\n updated_at?: string;\n}\n\nexport const getStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<StoreAttributes>> => {\n return http.getResource<StoreAttributes>(`/v1/stores/${storeId}`);\n};\n\n/**\n * List every store reachable with the configured API key, paginated.\n * Used by `validateConnection` to populate the connection summary, and by\n * the CLI's `--all-stores` flag. Pagination matters here for accounts that\n * own a large catalogue of stores.\n */\nexport const listStores = async (http: HttpClient): Promise<JsonApiResource<StoreAttributes>[]> => {\n return http.paginate<StoreAttributes>(\"/v1/stores\");\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedSubscriptionInvoiceAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type SubscriptionInvoiceStatus = \"pending\" | \"paid\" | \"void\" | \"refunded\" | \"partial_refund\";\n\nexport type SubscriptionInvoiceBillingReason = \"initial\" | \"renewal\" | \"updated\";\n\nexport interface SubscriptionInvoiceUrls {\n invoice_url?: string;\n}\n\n/**\n * Subscription invoice attributes, including fields added across the\n * changelog: customer identity, tax inclusion, and partial refund amounts.\n */\nexport interface SubscriptionInvoiceAttributes extends GeneratedSubscriptionInvoiceAttributes {\n store_id: number;\n subscription_id: number;\n customer_id: number;\n user_name: string;\n user_email: string;\n billing_reason: SubscriptionInvoiceBillingReason | string;\n card_brand?: string | null;\n card_last_four?: string | null;\n currency: string;\n currency_rate: string;\n status: SubscriptionInvoiceStatus;\n status_formatted: string;\n refunded: boolean;\n refunded_at: string | null;\n subtotal: number;\n discount_total: number;\n tax: number;\n tax_inclusive: boolean;\n total: number;\n refunded_amount: number;\n subtotal_usd: number;\n discount_total_usd: number;\n tax_usd: number;\n total_usd: number;\n refunded_amount_usd: number;\n subtotal_formatted: string;\n discount_total_formatted: string;\n tax_formatted: string;\n total_formatted: string;\n refunded_amount_formatted: string;\n urls?: SubscriptionInvoiceUrls;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve a subscription invoice.\n *\n * @param http - Shared API client.\n * @param subscriptionInvoiceId - Invoice id.\n * @returns The invoice resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoice = await getSubscriptionInvoice(http, 1);\n * ```\n */\nexport const getSubscriptionInvoice = async (\n http: HttpClient,\n subscriptionInvoiceId: string | number,\n): Promise<JsonApiResource<SubscriptionInvoiceAttributes>> => {\n return http.getResource<SubscriptionInvoiceAttributes>(\n `/v1/subscription-invoices/${subscriptionInvoiceId}`,\n );\n};\n\n/**\n * List invoices for a subscription.\n *\n * @param http - Shared API client.\n * @param subscriptionId - Parent subscription id.\n * @returns Invoice resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoices = await listSubscriptionInvoicesForSubscription(http, 1);\n * ```\n */\nexport const listSubscriptionInvoicesForSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionInvoiceAttributes>[]> => {\n return http.paginate<SubscriptionInvoiceAttributes>(\"/v1/subscription-invoices\", {\n \"filter[subscription_id]\": String(subscriptionId),\n });\n};\n\n/**\n * Refund a subscription invoice (POST /v1/subscription-invoices/:id/refund).\n * Docs: https://docs.lemonsqueezy.com/api/subscription-invoices/issue-refund\n *\n * @param http - Shared API client.\n * @param subscriptionInvoiceId - Invoice id.\n * @param body - Optional partial-refund document.\n * @returns The updated invoice.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const invoice = await refundSubscriptionInvoice(http, 1);\n * ```\n */\nexport const refundSubscriptionInvoice = async (\n http: HttpClient,\n subscriptionInvoiceId: string | number,\n body?: unknown,\n): Promise<JsonApiResource<SubscriptionInvoiceAttributes>> => {\n return http.postResource<SubscriptionInvoiceAttributes>(\n `/v1/subscription-invoices/${subscriptionInvoiceId}/refund`,\n body ?? {},\n );\n};\n\n/**\n * Generate a subscription invoice PDF/URL.\n * Docs: https://docs.lemonsqueezy.com/api/subscription-invoices/generate-subscription-invoice\n *\n * @param http - Shared API client.\n * @param subscriptionInvoiceId - Invoice id.\n * @param body - Optional generation attributes.\n * @returns API response document.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const doc = await generateSubscriptionInvoice(http, 1);\n * ```\n */\nexport const generateSubscriptionInvoice = async (\n http: HttpClient,\n subscriptionInvoiceId: string | number,\n body?: unknown,\n): Promise<unknown> => {\n return http.request({\n method: \"POST\",\n path: `/v1/subscription-invoices/${subscriptionInvoiceId}/generate-invoice`,\n body: body ?? {},\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedSubscriptionItemAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface SubscriptionItemAttributes extends GeneratedSubscriptionItemAttributes {\n subscription_id: number;\n price_id: number;\n quantity: number;\n is_usage_based: boolean;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Attributes accepted by the update subscription item endpoint. The proration\n * controls were added in the 2024-02-12 changelog.\n */\nexport interface SubscriptionItemUpdateAttributes {\n quantity?: number;\n invoice_immediately?: boolean;\n disable_prorations?: boolean;\n}\n\n/**\n * Retrieve a subscription item.\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Item id.\n * @returns The subscription item resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const item = await getSubscriptionItem(http, 1);\n * ```\n */\nexport const getSubscriptionItem = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n): Promise<JsonApiResource<SubscriptionItemAttributes>> => {\n return http.getResource<SubscriptionItemAttributes>(\n `/v1/subscription-items/${subscriptionItemId}`,\n );\n};\n\n/**\n * List subscription items for a subscription.\n *\n * @param http - Shared API client.\n * @param subscriptionId - Parent subscription id.\n * @returns Subscription item resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const items = await listSubscriptionItemsForSubscription(http, 1);\n * ```\n */\nexport const listSubscriptionItemsForSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionItemAttributes>[]> => {\n return http.paginate<SubscriptionItemAttributes>(\"/v1/subscription-items\", {\n \"filter[subscription_id]\": String(subscriptionId),\n });\n};\n\n/**\n * Build a JSON:API update body for a subscription item (quantity / proration).\n *\n * @param subscriptionItemId - Item id embedded in the document.\n * @param attributes - Fields accepted by the update endpoint.\n * @returns A single JSON:API document (not multiple loose objects).\n *\n * @example\n * ```ts\n * const body = buildSubscriptionItemUpdateBody(1, { quantity: 3 });\n * await updateSubscriptionItem(http, 1, body);\n * ```\n */\nexport const buildSubscriptionItemUpdateBody = (\n subscriptionItemId: string | number,\n attributes: SubscriptionItemUpdateAttributes,\n): unknown => {\n return {\n data: {\n type: \"subscription-items\",\n id: String(subscriptionItemId),\n attributes,\n },\n };\n};\n\n/**\n * Update a subscription item (PATCH /v1/subscription-items/:id).\n * Docs: https://docs.lemonsqueezy.com/api/subscription-items/update-subscription-item\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Item id.\n * @param body - JSON:API update document.\n * @returns The updated subscription item.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const item = await updateSubscriptionItem(\n * http,\n * 1,\n * buildSubscriptionItemUpdateBody(1, { quantity: 2 }),\n * );\n * ```\n */\nexport const updateSubscriptionItem = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n body: unknown,\n): Promise<JsonApiResource<SubscriptionItemAttributes>> => {\n return http.patchResource<SubscriptionItemAttributes>(\n `/v1/subscription-items/${subscriptionItemId}`,\n body,\n );\n};\n\n/**\n * Current-period usage for a usage-based subscription item.\n * Docs: https://docs.lemonsqueezy.com/api/subscription-items/retrieve-subscription-item-current-usage\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Item id.\n * @returns Usage payload for the current billing period.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const usage = await getSubscriptionItemCurrentUsage(http, 1);\n * ```\n */\nexport const getSubscriptionItemCurrentUsage = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n): Promise<unknown> => {\n return http.request({\n path: `/v1/subscription-items/${subscriptionItemId}/current-usage`,\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedSubscriptionAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * URLs Lemon Squeezy attaches to a subscription so consumers can deep-link\n * users to billing pages. The set has grown over time; we keep optional\n * fields for forward-compatibility.\n */\nexport interface SubscriptionUrls {\n update_payment_method?: string;\n customer_portal?: string;\n /** Added 2024-02-20: lets consumers offer \"manage subscription\" without an extra round-trip. */\n update_customer_portal?: string | null;\n /** Current API examples also surface this key name for PayPal update flows. */\n customer_portal_update_subscription?: string | null;\n}\n\nexport interface SubscriptionPause {\n mode: \"void\" | \"free\" | string;\n resumes_at?: string | null;\n}\n\nexport interface SubscriptionItemSummary {\n id: number;\n subscription_id: number;\n price_id: number;\n quantity: number;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Subset of subscription attributes. fresh-squeezy does not (yet) validate\n * subscriptions — this type is exported so consumers using the raw\n * `client.request<SubscriptionAttributes>()` escape hatch get a typed\n * response that includes platform additions the official SDK has not yet\n * picked up.\n *\n * Field provenance against the changelog:\n * - `payment_processor` — added 2025-06-11.\n * - `urls.update_customer_portal` — added 2024-02-20.\n * - `tax_inclusive` — invoice-only in current API docs; retained here as\n * a compatibility field for consumers that previously normalised\n * subscription and subscription invoice payloads together.\n */\nexport interface SubscriptionAttributes extends GeneratedSubscriptionAttributes {\n store_id: number;\n customer_id: number;\n order_id?: number;\n order_item_id?: number;\n product_id: number;\n variant_id: number;\n product_name: string;\n variant_name: string;\n user_name: string;\n user_email: string;\n status: \"on_trial\" | \"active\" | \"paused\" | \"past_due\" | \"unpaid\" | \"cancelled\" | \"expired\";\n status_formatted: string;\n card_brand?: string | null;\n card_last_four?: string | null;\n /** Added 2025-06-11. Identifies which payment provider processed the transaction. */\n payment_processor?: \"stripe\" | \"lemonsqueezy\" | \"paypal\" | string;\n pause?: SubscriptionPause | null;\n cancelled?: boolean;\n trial_ends_at?: string | null;\n billing_anchor?: number;\n first_subscription_item?: SubscriptionItemSummary | null;\n urls?: SubscriptionUrls;\n renews_at?: string | null;\n ends_at?: string | null;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n /** Compatibility field for older fresh-squeezy consumers; prefer SubscriptionInvoiceAttributes.tax_inclusive. */\n tax_inclusive?: boolean;\n}\n\n/**\n * Fetch a single subscription by ID.\n *\n * @param http - Shared API client.\n * @param subscriptionId - Subscription id.\n * @returns The subscription resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const sub = await getSubscription(http, 1);\n * ```\n */\nexport const getSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionAttributes>> => {\n return http.getResource<SubscriptionAttributes>(`/v1/subscriptions/${subscriptionId}`);\n};\n\n/**\n * List subscriptions for a store.\n *\n * @param http - Shared API client.\n * @param storeId - Store filter.\n * @returns Subscription resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const subs = await listSubscriptionsForStore(http, 1);\n * ```\n */\nexport const listSubscriptionsForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<SubscriptionAttributes>[]> => {\n return http.paginate<SubscriptionAttributes>(\"/v1/subscriptions\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Update a subscription (PATCH /v1/subscriptions/:id) — plan change, pause, etc.\n * Docs: https://docs.lemonsqueezy.com/api/subscriptions/update-subscription\n *\n * @param http - Shared API client.\n * @param subscriptionId - Subscription id.\n * @param body - JSON:API update document.\n * @returns The updated subscription.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const sub = await updateSubscription(http, 1, {\n * data: { type: \"subscriptions\", id: \"1\", attributes: { variant_id: 2 } },\n * });\n * ```\n */\nexport const updateSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n body: unknown,\n): Promise<JsonApiResource<SubscriptionAttributes>> => {\n return http.patchResource<SubscriptionAttributes>(`/v1/subscriptions/${subscriptionId}`, body);\n};\n\n/**\n * Cancel a subscription (DELETE /v1/subscriptions/:id).\n * Docs: https://docs.lemonsqueezy.com/api/subscriptions/cancel-subscription\n *\n * @param http - Shared API client.\n * @param subscriptionId - Subscription id.\n * @returns The cancelled subscription resource when the API returns one.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const sub = await cancelSubscription(http, 1);\n * ```\n */\nexport const cancelSubscription = async (\n http: HttpClient,\n subscriptionId: string | number,\n): Promise<JsonApiResource<SubscriptionAttributes> | undefined> => {\n const doc = await http.request<{ data?: JsonApiResource<SubscriptionAttributes> }>({\n method: \"DELETE\",\n path: `/v1/subscriptions/${subscriptionId}`,\n });\n return doc?.data;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedUsageRecordAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport type UsageRecordAction = \"increment\" | \"set\";\n\nexport interface UsageRecordAttributes extends GeneratedUsageRecordAttributes {\n subscription_item_id: number;\n quantity: number;\n action: UsageRecordAction;\n created_at?: string;\n updated_at?: string;\n}\n\n/**\n * Retrieve a usage record.\n *\n * @param http - Shared API client.\n * @param usageRecordId - Usage record id.\n * @returns The usage record resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const record = await getUsageRecord(http, 1);\n * ```\n */\nexport const getUsageRecord = async (\n http: HttpClient,\n usageRecordId: string | number,\n): Promise<JsonApiResource<UsageRecordAttributes>> => {\n return http.getResource<UsageRecordAttributes>(`/v1/usage-records/${usageRecordId}`);\n};\n\n/**\n * List usage records for a subscription item.\n *\n * @param http - Shared API client.\n * @param subscriptionItemId - Parent subscription item id.\n * @returns Usage record resources.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const records = await listUsageRecordsForSubscriptionItem(http, 1);\n * ```\n */\nexport const listUsageRecordsForSubscriptionItem = async (\n http: HttpClient,\n subscriptionItemId: string | number,\n): Promise<JsonApiResource<UsageRecordAttributes>[]> => {\n return http.paginate<UsageRecordAttributes>(\"/v1/usage-records\", {\n \"filter[subscription_item_id]\": String(subscriptionItemId),\n });\n};\n\n/**\n * Create a usage record (POST /v1/usage-records).\n * Docs: https://docs.lemonsqueezy.com/api/usage-records/create-usage-record\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created usage record.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const record = await createUsageRecord(http, {\n * data: {\n * type: \"usage-records\",\n * attributes: { quantity: 5, action: \"increment\" },\n * relationships: {\n * \"subscription-item\": { data: { type: \"subscription-items\", id: \"1\" } },\n * },\n * },\n * });\n * ```\n */\nexport const createUsageRecord = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<UsageRecordAttributes>> => {\n return http.postResource<UsageRecordAttributes>(\"/v1/usage-records\", body);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiDocument } from \"../core/types.js\";\nimport type { GeneratedUserAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of the Lemon Squeezy `users` resource attributes we rely on.\n * Full schema at https://docs.lemonsqueezy.com/api/users.\n */\nexport interface UserAttributes extends GeneratedUserAttributes {\n name: string;\n email: string;\n color?: string;\n avatar_url?: string | null;\n has_custom_avatar?: boolean;\n createdAt?: string;\n updatedAt?: string;\n}\n\n/**\n * Document-level metadata on `/v1/users/me`.\n *\n * `test_mode` was added to the endpoint on 2024-01-05 (per the Lemon Squeezy\n * API changelog: https://docs.lemonsqueezy.com/api/getting-started/changelog).\n * It reports whether the *key* being used is a test-mode key, independent of\n * what the caller declared. The connection validator compares this against\n * the caller's declared mode to catch the common \"prod key in staging\"\n * (or vice versa) misconfiguration.\n */\nexport interface UserMeta {\n test_mode?: boolean;\n}\n\n/**\n * Authenticated-user document with the `data` + `meta` block preserved.\n * The connection validator needs the meta flag, so we return the full\n * document here rather than just `data` as the collection helpers do.\n */\nexport type AuthenticatedUserDocument = JsonApiDocument<UserAttributes> & { meta?: UserMeta };\n\n/**\n * Fetch the user associated with the API key. Primary use is the connection\n * validator: a successful call confirms the key is valid, surfaces the\n * account identity for logs, and exposes `meta.test_mode` for mode\n * mismatch detection.\n *\n * @param http - Shared API client.\n * @returns Full `/v1/users/me` document including `meta.test_mode`.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const doc = await getAuthenticatedUser(http);\n * const mode = doc.meta?.test_mode ? \"test\" : \"live\";\n * ```\n */\nexport const getAuthenticatedUser = async (\n http: HttpClient,\n): Promise<AuthenticatedUserDocument> => {\n return http.request<AuthenticatedUserDocument>({ path: \"/v1/users/me\" });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedVariantAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\nexport interface VariantLink {\n title: string;\n url: string;\n}\n\n/**\n * Variant attributes used by the product validator to detect\n * variant/price drift from the product they belong to.\n */\nexport interface VariantAttributes extends GeneratedVariantAttributes {\n product_id: number;\n name: string;\n slug: string;\n description?: string | null;\n has_license_keys?: boolean;\n license_activation_limit?: number | null;\n is_license_limit_unlimited?: boolean;\n license_length_value?: number | null;\n license_length_unit?: \"day\" | \"week\" | \"month\" | \"year\" | null;\n is_license_length_unlimited?: boolean;\n status: \"pending\" | \"draft\" | \"published\";\n status_formatted?: string;\n is_subscription?: boolean;\n interval?: string | null;\n interval_count?: number | null;\n sort?: number;\n /**\n * Hosted-checkout-style links keyed by purpose. Added 2024-06-09 — older\n * SDK and validator versions don't surface this field, so consumers had\n * to read `meta.product_links` manually before. Optional because the\n * field is absent on older variants.\n */\n links?: VariantLink[] | Record<string, string>;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Extended variant attributes for subscription plan validation. In Lemon\n * Squeezy, \"subscription plans\" live as variants with `is_subscription: true`.\n * These fields are only present on subscription variants and are checked by\n * the subscription plan validator to catch misconfigured trial periods,\n * zero-price plans, and invalid billing intervals.\n */\nexport interface SubscriptionVariantAttributes extends VariantAttributes {\n is_subscription: boolean;\n interval: string | null;\n interval_count: number | null;\n has_free_trial: boolean;\n trial_interval: string | null;\n trial_interval_count: number | null;\n price: number;\n}\n\n/**\n * Fetch a single variant by ID. Used by the subscription plan validator to\n * inspect subscription-specific fields (interval, trial, price).\n */\nexport const getVariant = async <TAttr = VariantAttributes>(\n http: HttpClient,\n variantId: string | number,\n): Promise<JsonApiResource<TAttr>> => {\n return http.getResource<TAttr>(`/v1/variants/${variantId}`);\n};\n\n/**\n * List every variant of the product, paginated so products with more than\n * one page of variants don't trip the `VARIANT_UNPUBLISHED` heuristic when\n * the only published variants happen to live past page 1.\n */\nexport const listVariantsForProduct = async (\n http: HttpClient,\n productId: string | number,\n): Promise<JsonApiResource<VariantAttributes>[]> => {\n return http.paginate<VariantAttributes>(\"/v1/variants\", {\n \"filter[product_id]\": String(productId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { JsonApiResource } from \"../core/types.js\";\nimport type { GeneratedWebhookAttributes } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Subset of webhook attributes we read. `events` is an ordered list of\n * subscribed event names; the validator cross-references these against the\n * support manifest to catch missing subscriptions.\n */\nexport interface WebhookAttributes extends GeneratedWebhookAttributes {\n store_id: number;\n url: string;\n events: string[];\n last_sent_at?: string | null;\n created_at?: string;\n updated_at?: string;\n test_mode?: boolean;\n}\n\n/**\n * Retrieve one webhook by id.\n *\n * @param http - Shared API client.\n * @param webhookId - Webhook id.\n * @returns The webhook resource.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhook = await getWebhook(http, 1);\n * ```\n */\nexport const getWebhook = async (\n http: HttpClient,\n webhookId: string | number,\n): Promise<JsonApiResource<WebhookAttributes>> => {\n return http.getResource<WebhookAttributes>(`/v1/webhooks/${webhookId}`);\n};\n\n/**\n * List every webhook registered on the store, walking pagination so a store\n * with more than one page of webhooks doesn't produce a false\n * `WEBHOOK_NOT_FOUND` from `validateWebhook`.\n *\n * @param http - Shared API client.\n * @param storeId - Store to filter.\n * @returns All webhook resources for the store.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhooks = await listWebhooksForStore(http, 1);\n * ```\n */\nexport const listWebhooksForStore = async (\n http: HttpClient,\n storeId: string | number,\n): Promise<JsonApiResource<WebhookAttributes>[]> => {\n return http.paginate<WebhookAttributes>(\"/v1/webhooks\", {\n \"filter[store_id]\": String(storeId),\n });\n};\n\n/**\n * Create a webhook (POST /v1/webhooks).\n * Docs: https://docs.lemonsqueezy.com/api/webhooks/create-webhook\n *\n * @param http - Shared API client.\n * @param body - JSON:API create document.\n * @returns The created webhook.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhook = await createWebhook(http, {\n * data: {\n * type: \"webhooks\",\n * attributes: { url: \"https://app.example.com/hook\", events: [\"order_created\"] },\n * relationships: { store: { data: { type: \"stores\", id: \"1\" } } },\n * },\n * });\n * ```\n */\nexport const createWebhook = async (\n http: HttpClient,\n body: unknown,\n): Promise<JsonApiResource<WebhookAttributes>> => {\n return http.postResource<WebhookAttributes>(\"/v1/webhooks\", body);\n};\n\n/**\n * Update a webhook (PATCH /v1/webhooks/:id).\n * Docs: https://docs.lemonsqueezy.com/api/webhooks/update-webhook\n *\n * @param http - Shared API client.\n * @param webhookId - Webhook id.\n * @param body - JSON:API update document.\n * @returns The updated webhook.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * const webhook = await updateWebhook(http, 1, {\n * data: { type: \"webhooks\", id: \"1\", attributes: { events: [\"order_created\"] } },\n * });\n * ```\n */\nexport const updateWebhook = async (\n http: HttpClient,\n webhookId: string | number,\n body: unknown,\n): Promise<JsonApiResource<WebhookAttributes>> => {\n return http.patchResource<WebhookAttributes>(`/v1/webhooks/${webhookId}`, body);\n};\n\n/**\n * Delete a webhook (DELETE /v1/webhooks/:id).\n * Docs: https://docs.lemonsqueezy.com/api/webhooks/delete-webhook\n *\n * @param http - Shared API client.\n * @param webhookId - Webhook id.\n * @returns Nothing on success.\n * @throws {FreshSqueezyError} On HTTP/network failure.\n *\n * @example\n * ```ts\n * await deleteWebhook(http, 1);\n * ```\n */\nexport const deleteWebhook = async (\n http: HttpClient,\n webhookId: string | number,\n): Promise<void> => {\n await http.deleteResource(`/v1/webhooks/${webhookId}`);\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { HttpClient } from \"../core/http.js\";\nimport { getAffiliate, listAffiliatesForStore } from \"./affiliates.js\";\nimport { createCheckout, getCheckout, listCheckoutsForStore } from \"./checkouts.js\";\nimport { createCustomer, getCustomer, listCustomersForStore, updateCustomer } from \"./customers.js\";\nimport {\n getDiscountRedemption,\n listDiscountRedemptionsForDiscount,\n} from \"./discountRedemptions.js\";\nimport { createDiscount, deleteDiscount, getDiscount, listDiscountsForStore } from \"./discounts.js\";\nimport { getFile, listFilesForVariant } from \"./files.js\";\nimport {\n getLicenseKeyInstance,\n listLicenseKeyInstancesForLicenseKey,\n} from \"./licenseKeyInstances.js\";\nimport { getLicenseKey, listLicenseKeysForStore, updateLicenseKey } from \"./licenseKeys.js\";\nimport { getOrderItem, listOrderItemsForOrder } from \"./orderItems.js\";\nimport { generateOrderInvoice, getOrder, listOrdersForStore, refundOrder } from \"./orders.js\";\nimport { getPrice, listPricesForVariant } from \"./prices.js\";\nimport { getProduct, listProducts } from \"./products.js\";\nimport { type OpVerb, findResourceVerb } from \"./registry.js\";\nimport { getStore, listStores } from \"./stores.js\";\nimport {\n generateSubscriptionInvoice,\n getSubscriptionInvoice,\n listSubscriptionInvoicesForSubscription,\n refundSubscriptionInvoice,\n} from \"./subscriptionInvoices.js\";\nimport {\n getSubscriptionItem,\n getSubscriptionItemCurrentUsage,\n listSubscriptionItemsForSubscription,\n updateSubscriptionItem,\n} from \"./subscriptionItems.js\";\nimport {\n cancelSubscription,\n getSubscription,\n listSubscriptionsForStore,\n updateSubscription,\n} from \"./subscriptions.js\";\nimport {\n createUsageRecord,\n getUsageRecord,\n listUsageRecordsForSubscriptionItem,\n} from \"./usageRecords.js\";\nimport { getAuthenticatedUser } from \"./users.js\";\nimport { getVariant, listVariantsForProduct } from \"./variants.js\";\nimport {\n createWebhook,\n deleteWebhook,\n getWebhook,\n listWebhooksForStore,\n updateWebhook,\n} from \"./webhooks.js\";\n\n/**\n * Arguments for a single resource op invocation.\n *\n * One named input type — not a bag of unrelated returns.\n */\nexport interface InvokeOpArgs {\n id?: string | number;\n storeId?: string | number;\n parentId?: string | number;\n body?: unknown;\n}\n\n/**\n * Dispatch a docs-backed resource verb through the thin resource helpers.\n *\n * @param http - Shared API client.\n * @param resource - CLI resource token (`webhook`, `product`, …).\n * @param verb - Op verb (`get`, `create`, `refund`, …).\n * @param args - Ids / body for the call.\n * @returns A single JSON:API resource, list, void, or action payload.\n * @throws {FreshSqueezyError} When the verb is unknown or HTTP fails.\n *\n * @example\n * ```ts\n * const product = await invokeOp(http, \"product\", \"get\", { id: 42 });\n * ```\n */\nexport const invokeOp = async (\n http: HttpClient,\n resource: string,\n verb: OpVerb | string,\n args: InvokeOpArgs = {},\n): Promise<unknown> => {\n const spec = findResourceVerb(resource, verb);\n if (!spec) {\n throw new FreshSqueezyError({\n code: \"UNKNOWN_OP\",\n message: `Unknown or unsupported op: ${verb} ${resource}. Run \\`fresh-squeezy ops --list\\`.`,\n });\n }\n\n const key = `${spec.resource}:${spec.verb}` as const;\n switch (key) {\n case \"user:get\": {\n const doc = await getAuthenticatedUser(http);\n return doc.data;\n }\n\n case \"store:get\":\n return getStore(http, requireId(args, \"store\"));\n case \"store:list\":\n return listStores(http);\n\n case \"product:get\":\n return getProduct(http, requireId(args, \"product\"));\n case \"product:list\":\n return listProducts(http, requireStore(args));\n\n case \"variant:get\":\n return getVariant(http, requireId(args, \"variant\"));\n case \"variant:list\":\n return listVariantsForProduct(http, requireParent(args, \"product\"));\n\n case \"price:get\":\n return getPrice(http, requireId(args, \"price\"));\n case \"price:list\":\n return listPricesForVariant(http, requireParent(args, \"variant\"));\n\n case \"file:get\":\n return getFile(http, requireId(args, \"file\"));\n case \"file:list\":\n return listFilesForVariant(http, requireParent(args, \"variant\"));\n\n case \"customer:get\":\n return getCustomer(http, requireId(args, \"customer\"));\n case \"customer:list\":\n return listCustomersForStore(http, requireStore(args));\n case \"customer:create\":\n return createCustomer(http, requireBody(args));\n case \"customer:update\":\n return updateCustomer(http, requireId(args, \"customer\"), requireBody(args));\n\n case \"order:get\":\n return getOrder(http, requireId(args, \"order\"));\n case \"order:list\":\n return listOrdersForStore(http, requireStore(args));\n case \"order:refund\":\n return refundOrder(http, requireId(args, \"order\"), args.body);\n case \"order:generate-invoice\":\n return generateOrderInvoice(http, requireId(args, \"order\"), args.body);\n\n case \"order-item:get\":\n return getOrderItem(http, requireId(args, \"order-item\"));\n case \"order-item:list\":\n return listOrderItemsForOrder(http, requireParent(args, \"order\"));\n\n case \"subscription:get\":\n return getSubscription(http, requireId(args, \"subscription\"));\n case \"subscription:list\":\n return listSubscriptionsForStore(http, requireStore(args));\n case \"subscription:update\":\n return updateSubscription(http, requireId(args, \"subscription\"), requireBody(args));\n case \"subscription:cancel\":\n return cancelSubscription(http, requireId(args, \"subscription\"));\n\n case \"subscription-item:get\":\n return getSubscriptionItem(http, requireId(args, \"subscription-item\"));\n case \"subscription-item:list\":\n return listSubscriptionItemsForSubscription(http, requireParent(args, \"subscription\"));\n case \"subscription-item:update\":\n return updateSubscriptionItem(http, requireId(args, \"subscription-item\"), requireBody(args));\n case \"subscription-item:current-usage\":\n return getSubscriptionItemCurrentUsage(http, requireId(args, \"subscription-item\"));\n\n case \"subscription-invoice:get\":\n return getSubscriptionInvoice(http, requireId(args, \"subscription-invoice\"));\n case \"subscription-invoice:list\":\n return listSubscriptionInvoicesForSubscription(http, requireParent(args, \"subscription\"));\n case \"subscription-invoice:refund\":\n return refundSubscriptionInvoice(http, requireId(args, \"subscription-invoice\"), args.body);\n case \"subscription-invoice:generate-invoice\":\n return generateSubscriptionInvoice(http, requireId(args, \"subscription-invoice\"), args.body);\n\n case \"usage-record:get\":\n return getUsageRecord(http, requireId(args, \"usage-record\"));\n case \"usage-record:list\":\n return listUsageRecordsForSubscriptionItem(http, requireParent(args, \"subscription-item\"));\n case \"usage-record:create\":\n return createUsageRecord(http, requireBody(args));\n\n case \"discount:get\":\n return getDiscount(http, requireId(args, \"discount\"));\n case \"discount:list\":\n return listDiscountsForStore(http, requireStore(args));\n case \"discount:create\":\n return createDiscount(http, requireBody(args));\n case \"discount:delete\":\n await deleteDiscount(http, requireId(args, \"discount\"));\n return undefined;\n\n case \"discount-redemption:get\":\n return getDiscountRedemption(http, requireId(args, \"discount-redemption\"));\n case \"discount-redemption:list\":\n return listDiscountRedemptionsForDiscount(http, requireParent(args, \"discount\"));\n\n case \"license-key:get\":\n return getLicenseKey(http, requireId(args, \"license-key\"));\n case \"license-key:list\":\n return listLicenseKeysForStore(http, requireStore(args));\n case \"license-key:update\":\n return updateLicenseKey(http, requireId(args, \"license-key\"), requireBody(args));\n\n case \"license-key-instance:get\":\n return getLicenseKeyInstance(http, requireId(args, \"license-key-instance\"));\n case \"license-key-instance:list\":\n return listLicenseKeyInstancesForLicenseKey(http, requireParent(args, \"license-key\"));\n\n case \"checkout:get\":\n return getCheckout(http, requireId(args, \"checkout\"));\n case \"checkout:list\":\n return listCheckoutsForStore(http, requireStore(args));\n case \"checkout:create\":\n return createCheckout(http, requireBody(args));\n\n case \"webhook:get\":\n return getWebhook(http, requireId(args, \"webhook\"));\n case \"webhook:list\":\n return listWebhooksForStore(http, requireStore(args));\n case \"webhook:create\":\n return createWebhook(http, requireBody(args));\n case \"webhook:update\":\n return updateWebhook(http, requireId(args, \"webhook\"), requireBody(args));\n case \"webhook:delete\":\n await deleteWebhook(http, requireId(args, \"webhook\"));\n return undefined;\n\n case \"affiliate:get\":\n return getAffiliate(http, requireId(args, \"affiliate\"));\n case \"affiliate:list\":\n return listAffiliatesForStore(http, requireStore(args));\n\n default:\n throw new FreshSqueezyError({\n code: \"UNKNOWN_OP\",\n message: `Op registered but not wired: ${key}`,\n });\n }\n};\n\nconst requireId = (args: InvokeOpArgs, label: string): string | number => {\n if (args.id === undefined || args.id === \"\") {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--id is required for this ${label} operation.`,\n });\n }\n return args.id;\n};\n\nconst requireStore = (args: InvokeOpArgs): string | number => {\n if (args.storeId === undefined || args.storeId === \"\") {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"--store-ids (or store id) is required for this list operation.\",\n });\n }\n return args.storeId;\n};\n\nconst requireParent = (args: InvokeOpArgs, label: string): string | number => {\n if (args.parentId === undefined || args.parentId === \"\") {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--parent-id (${label} id) is required for this list operation.`,\n });\n }\n return args.parentId;\n};\n\nconst requireBody = (args: InvokeOpArgs): unknown => {\n if (args.body === undefined) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"A JSON body is required (--body, --body-file, or stdin).\",\n });\n }\n return args.body;\n};\n","import type { Mode } from \"./types.js\";\n\n/**\n * Map the boolean `meta.test_mode` flag from `/v1/users/me` to our `Mode` type.\n *\n * Returns `undefined` when the field is absent so older accounts and proxies\n * that don't surface the flag don't produce spurious mode mismatches. Lemon\n * Squeezy added `meta.test_mode` to the endpoint on 2024-01-05 (see API\n * changelog: https://docs.lemonsqueezy.com/api/getting-started/changelog).\n *\n * Pure function — exposed publicly so consumers can resolve a key's true mode\n * from a `/v1/users/me` document they already have, without re-running the\n * full connection validator. Keeping it free of any resource import is what\n * lets `core/` stay foundational (it never reaches up into `resources/`); the\n * I/O counterpart `fetchActualMode` lives in `validate/connection.ts`.\n */\nexport const resolveActualMode = (testMode: boolean | undefined): Mode | undefined => {\n if (testMode === true) return \"test\";\n if (testMode === false) return \"live\";\n return undefined;\n};\n","import type {\n ValidationIssue,\n ValidationResult,\n ValidationSeverity,\n ValidationTarget,\n} from \"../core/types.js\";\n\n/**\n * Stable issue codes. Consumers may switch on these in CI — do not rename\n * without a major version bump.\n */\nexport const ISSUE_CODES = {\n AUTH_FAILED: \"AUTH_FAILED\",\n MODE_MISMATCH: \"MODE_MISMATCH\",\n STORE_NOT_FOUND: \"STORE_NOT_FOUND\",\n STORE_NOT_OWNED: \"STORE_NOT_OWNED\",\n PRODUCT_NOT_FOUND: \"PRODUCT_NOT_FOUND\",\n PRODUCT_WRONG_STORE: \"PRODUCT_WRONG_STORE\",\n PRODUCT_UNPUBLISHED: \"PRODUCT_UNPUBLISHED\",\n PRODUCT_NO_BUY_URL: \"PRODUCT_NO_BUY_URL\",\n VARIANT_UNPUBLISHED: \"VARIANT_UNPUBLISHED\",\n VARIANT_MISSING: \"VARIANT_MISSING\",\n WEBHOOK_NOT_FOUND: \"WEBHOOK_NOT_FOUND\",\n WEBHOOK_EVENTS_MISSING: \"WEBHOOK_EVENTS_MISSING\",\n WEBHOOK_OPTIONAL_EVENTS: \"WEBHOOK_OPTIONAL_EVENTS\",\n DISCOUNT_NOT_FOUND: \"DISCOUNT_NOT_FOUND\",\n DISCOUNT_DRAFT: \"DISCOUNT_DRAFT\",\n DISCOUNT_EXPIRED: \"DISCOUNT_EXPIRED\",\n DISCOUNT_NOT_STARTED: \"DISCOUNT_NOT_STARTED\",\n DISCOUNT_REDEMPTIONS_EXHAUSTED: \"DISCOUNT_REDEMPTIONS_EXHAUSTED\",\n DISCOUNT_INVALID_AMOUNT: \"DISCOUNT_INVALID_AMOUNT\",\n DISCOUNT_STORE_MISMATCH: \"DISCOUNT_STORE_MISMATCH\",\n LICENSE_KEY_NOT_FOUND: \"LICENSE_KEY_NOT_FOUND\",\n LICENSE_KEY_DISABLED: \"LICENSE_KEY_DISABLED\",\n LICENSE_KEY_EXPIRED: \"LICENSE_KEY_EXPIRED\",\n LICENSE_KEY_AT_ACTIVATION_LIMIT: \"LICENSE_KEY_AT_ACTIVATION_LIMIT\",\n LICENSE_KEY_STORE_MISMATCH: \"LICENSE_KEY_STORE_MISMATCH\",\n PLAN_VARIANT_NOT_FOUND: \"PLAN_VARIANT_NOT_FOUND\",\n PLAN_NOT_SUBSCRIPTION: \"PLAN_NOT_SUBSCRIPTION\",\n PLAN_INVALID_INTERVAL: \"PLAN_INVALID_INTERVAL\",\n PLAN_FREE_PRICE: \"PLAN_FREE_PRICE\",\n PLAN_TRIAL_INCONSISTENT: \"PLAN_TRIAL_INCONSISTENT\",\n PLAN_DRAFT: \"PLAN_DRAFT\",\n PLAN_STORE_MISMATCH: \"PLAN_STORE_MISMATCH\",\n NETWORK_ERROR: \"NETWORK_ERROR\",\n UNKNOWN: \"UNKNOWN\",\n} as const;\n\n/**\n * Build a `ValidationIssue` with defaults for the common case.\n * Extracted so every validator produces consistently shaped issues.\n */\nexport const issue = (\n code: string,\n severity: ValidationSeverity,\n message: string,\n extras: { suggestedFix?: string; context?: ValidationIssue[\"context\"] } = {},\n): ValidationIssue => {\n const base: ValidationIssue = { code, severity, message };\n if (extras.suggestedFix !== undefined) base.suggestedFix = extras.suggestedFix;\n if (extras.context !== undefined) base.context = extras.context;\n return base;\n};\n\n/**\n * Fold an issue list into a boolean. Used by every validator so `ok` is\n * computed the same way everywhere.\n */\nexport const isOk = (issues: ValidationIssue[]): boolean => {\n return !issues.some((entry) => entry.severity === \"error\");\n};\n\n/**\n * Compose a `ValidationResult` with the `ok` flag derived from issues.\n */\nexport const buildResult = <T>(\n name: string,\n mode: ValidationResult[\"mode\"],\n issues: ValidationIssue[],\n resource?: T,\n target?: ValidationTarget,\n): ValidationResult<T> => {\n const result: ValidationResult<T> = {\n name,\n ok: isOk(issues),\n mode,\n issues,\n };\n if (resource !== undefined) result.resource = resource;\n if (target !== undefined) result.target = target;\n return result;\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { ValidationIssue } from \"../core/types.js\";\nimport { ISSUE_CODES, issue } from \"./rules.js\";\n\n/**\n * How a caller wants the error mapper to translate specific failure modes.\n * Every field is optional — omit a slot and that mode falls through to the\n * generic mappings (`NETWORK_ERROR`, `UNKNOWN`).\n */\nexport interface IssueMapping {\n /** Translate 401 / `UNAUTHORIZED` to a specific issue code (e.g. `AUTH_FAILED`). */\n unauthorized?: { code: string; message: string; suggestedFix?: string };\n /** Translate 404 to a resource-specific not-found issue. */\n notFound?: {\n code: string;\n message: string;\n suggestedFix?: string;\n context?: ValidationIssue[\"context\"];\n };\n}\n\n/**\n * Map any thrown error from a resource fetch to a `ValidationIssue`. The\n * single source of truth for \"how does this validator surface failures?\":\n *\n * - 401 → `mapping.unauthorized.code` if provided, else fall through\n * - 404 → `mapping.notFound.code` if provided, else fall through\n * - network failure → `NETWORK_ERROR`\n * - any other `FreshSqueezyError` → `UNKNOWN` (with status + code context)\n * - any other `Error` → `UNKNOWN`\n *\n * Public so validators that own a non-trivial composite call (e.g.\n * `validateConnection`, which fetches users + stores in one try-block) can\n * reuse the same mapper as `probeFetch` does for single-resource fetches.\n */\nexport const mapErrorToIssue = (err: unknown, mapping: IssueMapping = {}): ValidationIssue => {\n if (err instanceof FreshSqueezyError) {\n if (mapping.unauthorized && (err.status === 401 || err.code === \"UNAUTHORIZED\")) {\n return issue(mapping.unauthorized.code, \"error\", mapping.unauthorized.message, {\n suggestedFix: mapping.unauthorized.suggestedFix,\n context: { status: err.status ?? null },\n });\n }\n if (mapping.notFound && err.status === 404) {\n return issue(mapping.notFound.code, \"error\", mapping.notFound.message, {\n suggestedFix: mapping.notFound.suggestedFix,\n context: mapping.notFound.context,\n });\n }\n if (err.code === \"NETWORK_ERROR\") {\n return issue(\n ISSUE_CODES.NETWORK_ERROR,\n \"error\",\n `Could not reach Lemon Squeezy: ${err.message}`,\n );\n }\n return issue(ISSUE_CODES.UNKNOWN, \"error\", err.message, {\n context: { status: err.status ?? null, code: err.code },\n });\n }\n const message = err instanceof Error ? err.message : \"Unknown error\";\n return issue(ISSUE_CODES.UNKNOWN, \"error\", message);\n};\n\n/**\n * Per-validator metadata for the resource-fetch probe.\n *\n * `notFoundCode` and `notFoundMessage` are resource-specific so each validator\n * keeps its stable `ISSUE_CODES.*_NOT_FOUND` identifier in callsite-visible\n * code. Everything else (mapping `FreshSqueezyError` shapes, falling back to\n * `UNKNOWN`, attaching status/code context) is handled here so validators\n * stop re-implementing the same try/catch skeleton.\n */\nexport interface FetchProbeOptions {\n notFoundCode: string;\n notFoundMessage: string;\n notFoundFix?: string;\n notFoundContext?: ValidationIssue[\"context\"];\n}\n\n/**\n * Outcome of a probed resource fetch. Either the resource (caller continues\n * with assertions) or one normalized issue (caller bails with `buildResult`).\n */\nexport type FetchProbeOutcome<T> =\n | { ok: true; resource: T }\n | { ok: false; issue: ValidationIssue };\n\n/**\n * Run a resource fetch with the same error mapping every single-resource\n * validator needs. Delegates to `mapErrorToIssue` so the rules live in\n * exactly one place.\n *\n * Validators keep their resource-specific assertion logic; only the I/O\n * scaffolding lives here. The deletion test: if this module disappeared every\n * validator would grow back the same try/catch skeleton.\n */\nexport const probeFetch = async <T>(\n fetcher: () => Promise<T>,\n options: FetchProbeOptions,\n): Promise<FetchProbeOutcome<T>> => {\n return probeCollection(fetcher, {\n notFound: {\n code: options.notFoundCode,\n message: options.notFoundMessage,\n suggestedFix: options.notFoundFix,\n context: options.notFoundContext,\n },\n });\n};\n\n/**\n * Run a fetch — typically a list/collection endpoint — through the shared\n * error mapper without `probeFetch`'s single-resource `notFound` slot. Pass an\n * `IssueMapping` to translate specific statuses (e.g. 401 → `AUTH_FAILED` for\n * the connection validator); omit it and every failure normalizes to\n * `NETWORK_ERROR` / `UNKNOWN`.\n *\n * The deletion test: without this, `validateWebhook` and `validateConnection`\n * would each hand-roll the same try/catch → `mapErrorToIssue` skeleton that\n * `probeFetch` already centralizes for single-resource fetches.\n */\nexport const probeCollection = async <T>(\n fetcher: () => Promise<T>,\n mapping: IssueMapping = {},\n): Promise<FetchProbeOutcome<T>> => {\n try {\n return { ok: true, resource: await fetcher() };\n } catch (err) {\n return { ok: false, issue: mapErrorToIssue(err, mapping) };\n }\n};\n\n/**\n * Inputs for a store-ownership cross-check.\n *\n * `code` and `label` are resource-specific so the issue stays informative\n * (\"Discount belongs to store …\" vs \"Product belongs to store …\"). `id` and\n * `extraContext` let validators describe which resource was inspected so\n * downstream tooling can correlate the mismatch with the request that\n * produced it.\n */\nexport interface OwnershipCheck {\n expectedStoreId: string | number;\n actualStoreId: string | number;\n /** Stable issue code (e.g. `ISSUE_CODES.DISCOUNT_STORE_MISMATCH`). */\n code: string;\n /** Resource label used in the issue message (e.g. `\"Discount\"`). */\n label: string;\n suggestedFix?: string;\n /** Extra context fields merged in alongside `expectedStoreId` / `actualStoreId`. */\n extraContext?: ValidationIssue[\"context\"];\n}\n\n/**\n * Compare an expected store ID against the value Lemon Squeezy returned on\n * the resource. Returns a `ValidationIssue` if they don't match, or `null` if\n * ownership is fine. Validators add the issue to their issue list — this\n * helper does not push for them.\n *\n * Both inputs are coerced via `String(...)` so a numeric `store_id` from JSON\n * compares correctly against a string-typed `storeId` from the CLI / env.\n */\nexport const checkStoreOwnership = (check: OwnershipCheck): ValidationIssue | null => {\n const expected = String(check.expectedStoreId);\n const actual = String(check.actualStoreId);\n if (expected === actual) return null;\n\n return issue(\n check.code,\n \"error\",\n `${check.label} belongs to store ${actual}, expected ${expected}.`,\n {\n suggestedFix: check.suggestedFix,\n context: {\n expectedStoreId: expected,\n actualStoreId: actual,\n ...(check.extraContext ?? {}),\n },\n },\n );\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport { resolveActualMode } from \"../core/mode.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { listStores } from \"../resources/stores.js\";\nimport { type UserAttributes, getAuthenticatedUser } from \"../resources/users.js\";\nimport { probeCollection } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\n/**\n * Connection validator summary attached to the `resource` field. Keeps the\n * validator self-contained — consumers need not call `users/me` again.\n *\n * `actualMode` is derived from the `meta.test_mode` field Lemon Squeezy added\n * to `/v1/users/me` on 2024-01-05 (API changelog). When the caller declared\n * one mode but the key actually belongs to the other, the validator fires a\n * `MODE_MISMATCH` error — the single misconfiguration most likely to cause a\n * prod-in-staging (or vice versa) incident.\n */\nexport interface ConnectionSummary {\n user: UserAttributes;\n storeCount: number;\n storeIds: string[];\n /** The mode the API key actually belongs to (per `/v1/users/me` meta). */\n actualMode?: Mode;\n /** The mode the caller asked for at construction time. */\n declaredMode: Mode;\n}\n\n/**\n * Verify that the API key works, surface the account identity + reachable\n * stores, and cross-check declared mode vs the key's true mode.\n *\n * This is the first check every `doctor()` run performs; if it fails,\n * no downstream validator has anything useful to report.\n */\nexport const validateConnection = async (\n http: HttpClient,\n mode: Mode,\n): Promise<ValidationResult<ConnectionSummary>> => {\n const fetched = await probeCollection(\n async () => {\n const userDoc = await getAuthenticatedUser(http);\n const stores = await listStores(http);\n return { userDoc, stores };\n },\n {\n unauthorized: {\n code: ISSUE_CODES.AUTH_FAILED,\n message: \"API key rejected by Lemon Squeezy.\",\n suggestedFix: \"Regenerate the key at https://app.lemonsqueezy.com/settings/api.\",\n },\n },\n );\n\n if (!fetched.ok) {\n return buildResult(\"connection\", mode, [fetched.issue]);\n }\n\n const { userDoc, stores } = fetched.resource;\n const actualMode = resolveActualMode(userDoc.meta?.test_mode);\n const summary: ConnectionSummary = {\n user: userDoc.data.attributes,\n storeCount: stores.length,\n storeIds: stores.map((store) => store.id),\n declaredMode: mode,\n ...(actualMode ? { actualMode } : {}),\n };\n\n const issues: ValidationIssue[] = [];\n\n if (actualMode && actualMode !== mode) {\n issues.push(\n issue(\n ISSUE_CODES.MODE_MISMATCH,\n \"error\",\n `API key is a ${actualMode}-mode key but was run with --mode ${mode}.`,\n {\n suggestedFix: `Either pass --mode ${actualMode} or use a ${mode}-mode key from https://app.lemonsqueezy.com/settings/api.`,\n context: { declared: mode, actual: actualMode },\n },\n ),\n );\n }\n\n if (stores.length === 0) {\n issues.push(\n issue(\n ISSUE_CODES.STORE_NOT_FOUND,\n \"warning\",\n \"API key authenticated but no stores are reachable.\",\n { suggestedFix: \"Confirm the API key belongs to an account that owns at least one store.\" },\n ),\n );\n }\n\n return buildResult(\"connection\", mode, issues, summary);\n};\n\n/**\n * Ask the Lemon Squeezy API which mode the configured key actually belongs to.\n *\n * Useful as a fail-fast check at app boot — e.g. refuse to start if a prod key\n * is loaded into a staging deployment — without paying for a full doctor run.\n * Returns `undefined` if the API doesn't surface `meta.test_mode` (older\n * proxies, partial responses).\n *\n * Lives here rather than in `core/mode.ts` so the foundational `core/` layer\n * never imports from `resources/`; the pure `resolveActualMode` it delegates to\n * still lives in `core/`. Throws `FreshSqueezyError` on auth or network\n * failure; callers that want a structured non-throwing result should use\n * `validateConnection` instead.\n */\nexport const fetchActualMode = async (http: HttpClient): Promise<Mode | undefined> => {\n const doc = await getAuthenticatedUser(http);\n return resolveActualMode(doc.meta?.test_mode);\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type DiscountAttributes, getDiscount } from \"../resources/discounts.js\";\nimport { checkStoreOwnership, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface DiscountValidationOptions {\n storeId: string | number;\n discountId: string | number;\n}\n\n/**\n * Validate a Lemon Squeezy discount code. Catches the most common\n * misconfigurations: draft discounts that can't be redeemed, expired or\n * not-yet-active windows, invalid amounts (negative or >100% for percent\n * type), and store ownership mismatches.\n *\n * The redemption exhaustion check is deliberately conservative (v1): it only\n * flags when `is_limited_redemptions` is true and `max_redemptions` is zero,\n * because a full redemption count fetch against\n * `/v1/discount-redemptions?filter[discount_id]=` is YAGNI until a consumer\n * asks for it.\n */\nexport const validateDiscount = async (\n http: HttpClient,\n mode: Mode,\n options: DiscountValidationOptions,\n): Promise<ValidationResult<DiscountAttributes>> => {\n const target = {\n label: `discount ${options.discountId}`,\n id: String(options.discountId),\n };\n\n const fetched = await probeFetch(() => getDiscount(http, options.discountId), {\n notFoundCode: ISSUE_CODES.DISCOUNT_NOT_FOUND,\n notFoundMessage: `Discount ${options.discountId} not found.`,\n notFoundFix: \"Verify the discount ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { discountId: String(options.discountId) },\n });\n\n if (!fetched.ok) {\n return buildResult<DiscountAttributes>(\"discount\", mode, [fetched.issue], undefined, target);\n }\n\n const attrs = fetched.resource.attributes;\n return buildResult(\"discount\", mode, checkDiscount(attrs, { storeId: options.storeId }), attrs, {\n label: `${attrs.name} (${attrs.code})`,\n id: String(options.discountId),\n });\n};\n\n/**\n * Pure attribute assertions for a discount: store ownership, draft/expiry/\n * activation windows, redemption exhaustion, and amount validity. No I/O, so\n * the rules are unit-testable with plain data.\n */\nexport const checkDiscount = (\n attrs: DiscountAttributes,\n options: { storeId: string | number },\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.storeId,\n actualStoreId: attrs.store_id,\n code: ISSUE_CODES.DISCOUNT_STORE_MISMATCH,\n label: \"Discount\",\n suggestedFix: \"Use the correct store ID or discount ID — discounts should not cross stores.\",\n });\n if (mismatch) issues.push(mismatch);\n\n if (attrs.status === \"draft\") {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_DRAFT,\n \"warning\",\n `Discount \"${attrs.name}\" is in draft status — customers cannot redeem it.`,\n {\n suggestedFix:\n \"Publish the discount in the Lemon Squeezy dashboard before sharing the code.\",\n context: { name: attrs.name, code: attrs.code },\n },\n ),\n );\n }\n\n const now = new Date();\n if (attrs.expires_at && new Date(attrs.expires_at) < now) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_EXPIRED,\n \"error\",\n `Discount \"${attrs.name}\" expired at ${attrs.expires_at}.`,\n {\n suggestedFix: \"Extend the expiration date or create a new discount.\",\n context: { name: attrs.name, expiresAt: attrs.expires_at },\n },\n ),\n );\n }\n\n if (attrs.starts_at && new Date(attrs.starts_at) > now) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_NOT_STARTED,\n \"warning\",\n `Discount \"${attrs.name}\" starts at ${attrs.starts_at} — not yet active.`,\n {\n suggestedFix: \"Wait for the start date or adjust it in the dashboard.\",\n context: { name: attrs.name, startsAt: attrs.starts_at },\n },\n ),\n );\n }\n\n if (attrs.is_limited_redemptions && attrs.max_redemptions <= 0) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_REDEMPTIONS_EXHAUSTED,\n \"warning\",\n `Discount \"${attrs.name}\" has limited redemptions with max_redemptions ≤ 0.`,\n {\n suggestedFix: \"Increase max_redemptions or disable the redemption limit.\",\n context: { name: attrs.name, maxRedemptions: attrs.max_redemptions },\n },\n ),\n );\n }\n\n if (attrs.amount <= 0) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_INVALID_AMOUNT,\n \"error\",\n `Discount \"${attrs.name}\" has amount ${attrs.amount} — must be positive.`,\n {\n suggestedFix: \"Set a positive discount amount in the dashboard.\",\n context: { name: attrs.name, amount: attrs.amount },\n },\n ),\n );\n } else if (attrs.amount_type === \"percent\" && attrs.amount > 100) {\n issues.push(\n issue(\n ISSUE_CODES.DISCOUNT_INVALID_AMOUNT,\n \"error\",\n `Discount \"${attrs.name}\" is ${attrs.amount}% — percent discounts cannot exceed 100%.`,\n {\n suggestedFix: \"Set the discount to 100% or less.\",\n context: { name: attrs.name, amount: attrs.amount, amountType: attrs.amount_type },\n },\n ),\n );\n }\n\n return issues;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type LicenseKeyAttributes, getLicenseKey } from \"../resources/licenseKeys.js\";\nimport { checkStoreOwnership, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface LicenseKeyValidationOptions {\n storeId: string | number;\n licenseKeyId: string | number;\n}\n\n/**\n * Validate a Lemon Squeezy license key. Surfaces disabled keys, expired\n * keys, keys at their activation limit, and store ownership mismatches — the\n * four states most likely to cause \"why can't my customer activate?\"\n * support tickets.\n */\nexport const validateLicenseKey = async (\n http: HttpClient,\n mode: Mode,\n options: LicenseKeyValidationOptions,\n): Promise<ValidationResult<LicenseKeyAttributes>> => {\n const target = {\n label: `license key ${options.licenseKeyId}`,\n id: String(options.licenseKeyId),\n };\n\n const fetched = await probeFetch(() => getLicenseKey(http, options.licenseKeyId), {\n notFoundCode: ISSUE_CODES.LICENSE_KEY_NOT_FOUND,\n notFoundMessage: `License key ${options.licenseKeyId} not found.`,\n notFoundFix: \"Verify the license key ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { licenseKeyId: String(options.licenseKeyId) },\n });\n\n if (!fetched.ok) {\n return buildResult<LicenseKeyAttributes>(\n \"licenseKey\",\n mode,\n [fetched.issue],\n undefined,\n target,\n );\n }\n\n const attrs = fetched.resource.attributes;\n return buildResult(\n \"licenseKey\",\n mode,\n checkLicenseKey(attrs, { storeId: options.storeId }),\n attrs,\n { label: attrs.key_short, id: String(options.licenseKeyId) },\n );\n};\n\n/**\n * Pure attribute assertions for a license key: store ownership, disabled/\n * expired state, and activation-limit exhaustion. No I/O, so the rules are\n * unit-testable with plain data.\n */\nexport const checkLicenseKey = (\n attrs: LicenseKeyAttributes,\n options: { storeId: string | number },\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.storeId,\n actualStoreId: attrs.store_id,\n code: ISSUE_CODES.LICENSE_KEY_STORE_MISMATCH,\n label: \"License key\",\n suggestedFix: \"Use the correct store ID or license key ID — keys should not cross stores.\",\n });\n if (mismatch) issues.push(mismatch);\n\n if (attrs.disabled) {\n issues.push(\n issue(\n ISSUE_CODES.LICENSE_KEY_DISABLED,\n \"error\",\n `License key ${attrs.key_short} is disabled.`,\n {\n suggestedFix: \"Re-enable the license key in the Lemon Squeezy dashboard.\",\n context: { keyShort: attrs.key_short },\n },\n ),\n );\n }\n\n if (attrs.expires_at && new Date(attrs.expires_at) < new Date()) {\n issues.push(\n issue(\n ISSUE_CODES.LICENSE_KEY_EXPIRED,\n \"error\",\n `License key ${attrs.key_short} expired at ${attrs.expires_at}.`,\n {\n suggestedFix: \"Extend the expiration date or issue a new license key.\",\n context: { keyShort: attrs.key_short, expiresAt: attrs.expires_at },\n },\n ),\n );\n }\n\n if (attrs.activation_limit !== null && attrs.instances_count >= attrs.activation_limit) {\n issues.push(\n issue(\n ISSUE_CODES.LICENSE_KEY_AT_ACTIVATION_LIMIT,\n \"warning\",\n `License key ${attrs.key_short} has reached its activation limit (${attrs.instances_count}/${attrs.activation_limit}).`,\n {\n suggestedFix: \"Increase the activation limit or deactivate unused instances.\",\n context: {\n keyShort: attrs.key_short,\n instancesCount: attrs.instances_count,\n activationLimit: attrs.activation_limit,\n },\n },\n ),\n );\n }\n\n return issues;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type ProductAttributes, getProduct } from \"../resources/products.js\";\nimport { listVariantsForProduct } from \"../resources/variants.js\";\nimport { checkStoreOwnership, probeCollection, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface ProductValidationOptions {\n productId: string | number;\n /** Optional: confirm the product belongs to this store. */\n expectedStoreId?: string | number;\n}\n\n/**\n * Validate a product's publish state, store ownership, and that it has at\n * least one published variant. Surfaces the most common misconfigurations\n * caught in the wild (unpublished product, wrong store, missing variants).\n */\nexport const validateProduct = async (\n http: HttpClient,\n mode: Mode,\n options: ProductValidationOptions,\n): Promise<ValidationResult<ProductAttributes>> => {\n const issues: ValidationIssue[] = [];\n const target = {\n label: `product ${options.productId}`,\n id: String(options.productId),\n };\n\n const fetched = await probeFetch(() => getProduct(http, options.productId), {\n notFoundCode: ISSUE_CODES.PRODUCT_NOT_FOUND,\n notFoundMessage: `Product ${options.productId} not found.`,\n notFoundFix: \"Verify the product ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { productId: String(options.productId) },\n });\n\n if (!fetched.ok) {\n return buildResult<ProductAttributes>(\"product\", mode, [fetched.issue], undefined, target);\n }\n\n const attrs = fetched.resource.attributes;\n issues.push(...checkProduct(attrs, { expectedStoreId: options.expectedStoreId }));\n\n // Variant population needs a second fetch, so it stays out of the pure check.\n // Listing is best-effort: map via probeCollection, then soft-fail as warning.\n const variantsProbed = await probeCollection(() =>\n listVariantsForProduct(http, options.productId),\n );\n if (!variantsProbed.ok) {\n issues.push({ ...variantsProbed.issue, severity: \"warning\" });\n } else if (variantsProbed.resource.length === 0) {\n issues.push(\n issue(\n ISSUE_CODES.VARIANT_MISSING,\n \"error\",\n \"Product has no variants. Customers cannot purchase it.\",\n { suggestedFix: \"Add at least one variant in the product configuration.\" },\n ),\n );\n } else if (\n !variantsProbed.resource.some((variant) => variant.attributes.status === \"published\")\n ) {\n issues.push(\n issue(\n ISSUE_CODES.VARIANT_UNPUBLISHED,\n \"error\",\n \"Product has variants but none are published.\",\n { suggestedFix: \"Publish at least one variant.\" },\n ),\n );\n }\n\n return buildResult(\"product\", mode, issues, attrs, {\n label: attrs.name,\n id: String(options.productId),\n });\n};\n\n/**\n * Pure attribute assertions for a product: store ownership, publish state, and\n * hosted-checkout availability. The variant-population rule needs a second\n * fetch and stays in `validateProduct`; everything here runs on plain data, so\n * the rules are unit-testable without a mock fetch.\n */\nexport const checkProduct = (\n attrs: ProductAttributes,\n options: { expectedStoreId?: string | number } = {},\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n if (options.expectedStoreId !== undefined) {\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.expectedStoreId,\n actualStoreId: attrs.store_id,\n code: ISSUE_CODES.PRODUCT_WRONG_STORE,\n label: \"Product\",\n suggestedFix:\n \"Either use the correct store ID or the correct product ID — IDs should not cross stores.\",\n });\n if (mismatch) issues.push(mismatch);\n }\n\n if (attrs.status !== \"published\") {\n issues.push(\n issue(\n ISSUE_CODES.PRODUCT_UNPUBLISHED,\n \"error\",\n `Product is in \"${attrs.status}\" state, not \"published\".`,\n {\n suggestedFix: \"Publish the product in the Lemon Squeezy dashboard before selling.\",\n context: { status: attrs.status },\n },\n ),\n );\n }\n\n if (!attrs.buy_now_url) {\n issues.push(\n issue(\n ISSUE_CODES.PRODUCT_NO_BUY_URL,\n \"warning\",\n \"Product has no buy-now URL. Hosted checkout may be disabled.\",\n { suggestedFix: \"Enable buy-now in product settings, or use a custom checkout flow.\" },\n ),\n );\n }\n\n return issues;\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationResult } from \"../core/types.js\";\nimport { type StoreAttributes, getStore } from \"../resources/stores.js\";\nimport { probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult } from \"./rules.js\";\n\n/**\n * Verify a store exists and is reachable with the current API key. A 404\n * typically means the key belongs to a different account, not that the store\n * is gone — the suggested fix reflects that.\n */\nexport const validateStore = async (\n http: HttpClient,\n mode: Mode,\n storeId: string | number,\n): Promise<ValidationResult<StoreAttributes>> => {\n const target = { label: `store ${storeId}`, id: String(storeId) };\n\n const fetched = await probeFetch(() => getStore(http, storeId), {\n notFoundCode: ISSUE_CODES.STORE_NOT_FOUND,\n notFoundMessage: `Store ${storeId} not found with the current API key.`,\n notFoundFix: \"Check the store ID and confirm the API key belongs to the account that owns it.\",\n notFoundContext: { storeId: String(storeId) },\n });\n\n if (!fetched.ok) {\n return buildResult<StoreAttributes>(\"store\", mode, [fetched.issue], undefined, target);\n }\n\n return buildResult(\"store\", mode, [], fetched.resource.attributes, {\n label: fetched.resource.attributes.name,\n id: String(storeId),\n });\n};\n","import type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { getProduct } from \"../resources/products.js\";\nimport { type SubscriptionVariantAttributes, getVariant } from \"../resources/variants.js\";\nimport { checkStoreOwnership, probeFetch } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface SubscriptionPlanValidationOptions {\n storeId: string | number;\n variantId: string | number;\n}\n\n/** Summary of a subscription plan variant's validated state. */\nexport interface SubscriptionPlanSummary {\n variantId: string;\n interval: string | null;\n intervalCount: number | null;\n price: number;\n hasFreeTrial: boolean;\n status: string;\n}\n\nconst VALID_INTERVALS = new Set([\"day\", \"week\", \"month\", \"year\"]);\n\n/**\n * Validate a Lemon Squeezy \"subscription plan\", which is a variant with\n * `is_subscription: true`. Checks that the variant is actually a subscription,\n * has a valid billing interval, and that trial settings are consistent.\n *\n * Store cross-check requires fetching the parent product to read its\n * `store_id`. This is an extra network hop but catches the common mistake of\n * passing a variant ID from one store while targeting another. Accept the\n * `storeId` as advisory — if the product fetch fails the cross-check is\n * silently skipped rather than blocking the entire validation.\n */\nexport const validateSubscriptionPlan = async (\n http: HttpClient,\n mode: Mode,\n options: SubscriptionPlanValidationOptions,\n): Promise<ValidationResult<SubscriptionPlanSummary>> => {\n const target = {\n label: `variant ${options.variantId}`,\n id: String(options.variantId),\n };\n\n const fetched = await probeFetch(\n () => getVariant<SubscriptionVariantAttributes>(http, options.variantId),\n {\n notFoundCode: ISSUE_CODES.PLAN_VARIANT_NOT_FOUND,\n notFoundMessage: `Variant ${options.variantId} not found.`,\n notFoundFix: \"Verify the variant ID in the Lemon Squeezy dashboard.\",\n notFoundContext: { variantId: String(options.variantId) },\n },\n );\n\n if (!fetched.ok) {\n return buildResult<SubscriptionPlanSummary>(\n \"subscriptionPlan\",\n mode,\n [fetched.issue],\n undefined,\n target,\n );\n }\n\n const variant = fetched.resource;\n const attrs = variant.attributes;\n const issues = checkSubscriptionPlan(attrs, { variantId: options.variantId });\n\n // Store cross-check needs a second fetch (parent product). Advisory only —\n // skip on failure rather than blocking the pure attribute checks above.\n const productProbed = await probeFetch(() => getProduct(http, attrs.product_id), {\n notFoundCode: ISSUE_CODES.PRODUCT_NOT_FOUND,\n notFoundMessage: `Product ${attrs.product_id} not found.`,\n });\n if (productProbed.ok) {\n const mismatch = checkStoreOwnership({\n expectedStoreId: options.storeId,\n actualStoreId: productProbed.resource.attributes.store_id,\n code: ISSUE_CODES.PLAN_STORE_MISMATCH,\n label: `Subscription variant (via product ${attrs.product_id})`,\n suggestedFix: \"Use the correct store ID or variant ID — plans should not cross stores.\",\n extraContext: { productId: String(attrs.product_id) },\n });\n if (mismatch) issues.push(mismatch);\n }\n // product fetch failed: keep silent skip (advisory ownership only)\n\n const summary: SubscriptionPlanSummary = {\n variantId: variant.id,\n interval: attrs.interval,\n intervalCount: attrs.interval_count,\n price: attrs.price,\n hasFreeTrial: attrs.has_free_trial,\n status: attrs.status,\n };\n\n return buildResult(\"subscriptionPlan\", mode, issues, summary, {\n label: attrs.name,\n id: String(options.variantId),\n });\n};\n\n/**\n * Pure attribute assertions for a subscription variant: that it is actually a\n * subscription, has a valid interval / interval_count, is not free-priced, has\n * consistent trial settings, and is not a draft. The store cross-check needs a\n * second fetch and stays in `validateSubscriptionPlan`; everything here runs on\n * plain data, so the rules are unit-testable without a mock fetch.\n */\nexport const checkSubscriptionPlan = (\n attrs: SubscriptionVariantAttributes,\n options: { variantId: string | number },\n): ValidationIssue[] => {\n const issues: ValidationIssue[] = [];\n\n if (!attrs.is_subscription) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_NOT_SUBSCRIPTION,\n \"error\",\n `Variant ${options.variantId} is not a subscription variant (is_subscription is false).`,\n {\n suggestedFix:\n \"Use a variant that has subscription billing enabled, or use the regular variant validator.\",\n context: { variantId: String(options.variantId) },\n },\n ),\n );\n }\n\n if (!attrs.interval || !VALID_INTERVALS.has(attrs.interval)) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_INVALID_INTERVAL,\n \"error\",\n `Subscription variant has invalid interval: \"${attrs.interval ?? \"missing\"}\". Expected one of: day, week, month, year.`,\n {\n suggestedFix: \"Set a valid billing interval in the variant configuration.\",\n context: { interval: attrs.interval ?? null },\n },\n ),\n );\n }\n\n if (attrs.interval_count === null || attrs.interval_count <= 0) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_INVALID_INTERVAL,\n \"error\",\n `Subscription variant has invalid interval_count: ${attrs.interval_count}. Must be a positive integer.`,\n {\n suggestedFix:\n \"Set interval_count to a positive value (e.g. 1 for monthly, 2 for biweekly).\",\n context: { intervalCount: attrs.interval_count },\n },\n ),\n );\n }\n\n if (attrs.price === 0 && attrs.is_subscription) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_FREE_PRICE,\n \"warning\",\n \"Subscription variant has a price of 0 — this is almost always a misconfiguration for paid plans.\",\n {\n suggestedFix:\n \"Set the variant price to the intended amount in cents, or confirm this is intentionally free.\",\n context: { price: attrs.price },\n },\n ),\n );\n }\n\n if (attrs.has_free_trial && (!attrs.trial_interval || (attrs.trial_interval_count ?? 0) <= 0)) {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_TRIAL_INCONSISTENT,\n \"warning\",\n `Subscription variant has free trial enabled but trial interval is misconfigured (interval: \"${attrs.trial_interval ?? \"missing\"}\", count: ${attrs.trial_interval_count ?? 0}).`,\n {\n suggestedFix: \"Set a valid trial interval and count, or disable the free trial.\",\n context: {\n trialInterval: attrs.trial_interval ?? null,\n trialIntervalCount: attrs.trial_interval_count ?? null,\n },\n },\n ),\n );\n }\n\n if (attrs.status === \"draft\") {\n issues.push(\n issue(\n ISSUE_CODES.PLAN_DRAFT,\n \"warning\",\n \"Subscription variant is in draft status — customers cannot subscribe.\",\n {\n suggestedFix: \"Publish the variant in the Lemon Squeezy dashboard.\",\n context: { status: attrs.status },\n },\n ),\n );\n }\n\n return issues;\n};\n","/**\n * Domain-equality primitives for fresh-squeezy.\n *\n * These helpers encode \"when are two values the same in our domain?\" — separate\n * from the validators that consume them so the rules are testable on their own\n * and reusable from any future surface (init, dedupe, repair, etc.).\n */\n\n/**\n * Compare two webhook URLs ignoring trailing slashes and casing.\n *\n * Lemon Squeezy strips trailing slashes when persisting a webhook, but users\n * often paste the trailing-slash form into their config. The webhook validator\n * relies on this rule to match a configured URL against the registered list.\n */\nexport const sameWebhookUrl = (a: string, b: string): boolean => {\n return normalizeWebhookUrl(a) === normalizeWebhookUrl(b);\n};\n\nconst normalizeWebhookUrl = (raw: string): string => {\n return raw.replace(/\\/+$/, \"\").toLowerCase();\n};\n","import { GENERATED_LEMON_SQUEEZY_RESOURCES } from \"../generated/lemonSqueezyApiTypes.js\";\n\n/**\n * Support manifest: the locally reviewed source of truth for what\n * fresh-squeezy explicitly understands on the Lemon Squeezy platform.\n *\n * Resource/type coverage is generated from Lemon Squeezy object docs with\n * `pnpm generate:api-types`. Validator policy remains reviewed here:\n * when the platform adds new webhook events or behavior, bump the entries\n * below and re-snapshot the changelog page with\n * `pnpm check:changelog -- --update`.\n *\n * Changelog source: https://docs.lemonsqueezy.com/api/getting-started/changelog\n * Last reviewed: 2026-05-07\n */\n\n/** Resources fresh-squeezy understands today, generated from object docs. */\nexport const SUPPORTED_RESOURCES = GENERATED_LEMON_SQUEEZY_RESOURCES;\n\n/**\n * Webhook events fresh-squeezy expects a production integration to subscribe to\n * at minimum. Consumers can still subscribe to more; the validator only flags\n * missing ones from this list.\n *\n * Rationale:\n * - `order_*` covers one-off purchases and refunds.\n * - `subscription_*` covers the recurring-billing lifecycle.\n * - `subscription_payment_*` covers dunning / retry loops.\n *\n * Confirmed present in the Lemon Squeezy webhook topic list as of 2026-04-24.\n */\nexport const RECOMMENDED_WEBHOOK_EVENTS = [\n \"order_created\",\n \"order_refunded\",\n \"subscription_created\",\n \"subscription_updated\",\n \"subscription_cancelled\",\n \"subscription_resumed\",\n \"subscription_expired\",\n \"subscription_payment_success\",\n \"subscription_payment_failed\",\n] as const;\n\n/**\n * Newer or integration-specific events surfaced as info-level suggestions\n * rather than errors. Missing these is common and not necessarily a\n * misconfiguration.\n *\n * Per-entry changelog provenance (source:\n * https://docs.lemonsqueezy.com/api/getting-started/changelog):\n *\n * - `customer_updated` — added 2026-02-25. Fires when a customer record\n * changes (e.g. email, marketing consent). Needed if the app mirrors\n * customer data locally.\n * - `affiliate_activated` — added 2025-01-21 alongside the affiliates\n * endpoints. Only relevant if the store has an affiliate program.\n * - `license_key_created` / `license_key_updated` — License API events.\n * Only relevant when variants have `has_license_keys: true`.\n */\nexport const OPTIONAL_WEBHOOK_EVENTS = [\n \"customer_updated\",\n \"affiliate_activated\",\n \"license_key_created\",\n \"license_key_updated\",\n] as const;\n\n/**\n * Platform additions we have read and decided *not* to validate against yet,\n * documented here so maintainers see the deliberate gap during review.\n *\n * Tracked so the drift workflow has an \"expected state\" to compare against:\n * if the changelog page changes and none of these items explain it, the diff\n * is probably something new that needs a manifest update.\n */\nexport const ACKNOWLEDGED_CHANGELOG_ENTRIES = [\n {\n date: \"2026-02-25\",\n summary: \"Added customer_updated webhook event.\",\n handledBy: \"OPTIONAL_WEBHOOK_EVENTS\",\n },\n {\n date: \"2025-06-11\",\n summary: \"Added payment_processor attribute to Subscription objects.\",\n handledBy:\n \"Surfaced as SubscriptionAttributes.payment_processor in src/resources/subscriptions.ts.\",\n },\n {\n date: \"2025-01-21\",\n summary: \"Added Affiliates endpoints and affiliate_activated webhook.\",\n handledBy: \"OPTIONAL_WEBHOOK_EVENTS (event only; resource stays v2 scope)\",\n },\n {\n date: \"2024-12-06\",\n summary: \"Added quantity parameter to OrderItem objects.\",\n handledBy: \"OrderItemAttributes.quantity (src/resources/orderItems.ts).\",\n },\n {\n date: \"2024-09-10\",\n summary: \"Added fraudulent Order status.\",\n handledBy: \"OrderAttributes.status union includes 'fraudulent' (src/resources/orders.ts).\",\n },\n {\n date: \"2024-09-04\",\n summary: \"Added Issue an Order refund and Issue a Subscription Invoice refund endpoints.\",\n handledBy:\n \"Not wrapped — reachable via client.request('/v1/orders/:id/refund'). Refund-amount fields surfaced on OrderAttributes.\",\n },\n {\n date: \"2024-08-07\",\n summary:\n \"Added refunded_amount, refunded_amount_usd, refunded_amount_formatted to Order and Subscription invoice objects.\",\n handledBy: \"OrderAttributes.refunded_amount*, SubscriptionInvoiceAttributes.refunded_amount*.\",\n },\n {\n date: \"2024-06-09\",\n summary: \"Added links property to Variant objects.\",\n handledBy: \"VariantAttributes.links (src/resources/variants.ts).\",\n },\n {\n date: \"2024-05-20\",\n summary: \"Added Generate order invoice endpoint.\",\n handledBy: \"Not wrapped — reachable via client.request('/v1/orders/:id/generate-invoice').\",\n },\n {\n date: \"2024-04-09\",\n summary: \"License Key expires_at is now mutable via the update endpoint.\",\n handledBy:\n \"Type unchanged (LicenseKeyAttributes.expires_at already nullable string). Mutation reachable via client.request('PATCH /v1/license-keys/:id').\",\n },\n {\n date: \"2024-03-28\",\n summary: \"Subscription trial_ends_at is now mutable via the update endpoint.\",\n handledBy:\n \"SubscriptionAttributes.trial_ends_at plus CheckoutOptions.skip_trial. Mutations remain reachable via client.request().\",\n },\n {\n date: \"2024-02-20\",\n summary: \"Added urls.update_customer_portal to Subscription objects.\",\n handledBy: \"SubscriptionUrls.update_customer_portal (src/resources/subscriptions.ts).\",\n },\n {\n date: \"2024-02-12\",\n summary:\n \"Added Generate subscription invoice endpoint and invoice_immediately / disable_prorations parameters.\",\n handledBy:\n \"SubscriptionItemUpdateAttributes.invoice_immediately / disable_prorations; invoice endpoint reachable via client.request().\",\n },\n {\n date: \"2024-02-05\",\n summary: \"Added tax_inclusive parameter to Order objects and Subscription invoice objects.\",\n handledBy: \"OrderAttributes.tax_inclusive, SubscriptionInvoiceAttributes.tax_inclusive.\",\n },\n {\n date: \"2024-01-21\",\n summary:\n \"Added setup_fee_enabled / setup_fee to Price objects; setup_fee* to Subscription invoice.\",\n handledBy: \"PriceAttributes.setup_fee*, OrderAttributes.setup_fee*.\",\n },\n {\n date: \"2024-01-15\",\n summary: \"Added unit_price_decimal to Price objects.\",\n handledBy: \"PriceAttributes.unit_price_decimal.\",\n },\n {\n date: \"2024-01-05\",\n summary: \"Added test_mode flag to /v1/users/me meta.\",\n handledBy:\n \"Read in validateConnection to emit MODE_MISMATCH when the key's true mode differs from the caller's declared mode.\",\n },\n {\n date: \"2023-09-19\",\n summary: \"Added customer_portal URLs to Subscription and Customer objects.\",\n handledBy: \"SubscriptionUrls.customer_portal and CustomerUrls.customer_portal.\",\n },\n {\n date: \"2023-08-23\",\n summary:\n \"Added checkout_data.variant_quantities, subscription items, prices, and usage-based billing.\",\n handledBy:\n \"CheckoutData.variant_quantities, SubscriptionItemAttributes, UsageRecordAttributes, PriceAttributes.\",\n },\n {\n date: \"2023-08-14\",\n summary: \"Added customer_id, user_name, user_email to Subscription invoice objects.\",\n handledBy: \"SubscriptionInvoiceAttributes customer fields.\",\n },\n {\n date: \"2023-03-30\",\n summary: \"Added receipt URL to Order objects.\",\n handledBy: \"OrderUrls.receipt.\",\n },\n] as const;\n\nexport type RecommendedEvent = (typeof RECOMMENDED_WEBHOOK_EVENTS)[number];\nexport type OptionalEvent = (typeof OPTIONAL_WEBHOOK_EVENTS)[number];\n","import { sameWebhookUrl } from \"../core/equality.js\";\nimport type { HttpClient } from \"../core/http.js\";\nimport type { Mode, ValidationIssue, ValidationResult } from \"../core/types.js\";\nimport { type WebhookAttributes, listWebhooksForStore } from \"../resources/webhooks.js\";\nimport { OPTIONAL_WEBHOOK_EVENTS, RECOMMENDED_WEBHOOK_EVENTS } from \"../support/manifest.js\";\nimport { probeCollection } from \"./probe.js\";\nimport { ISSUE_CODES, buildResult, issue } from \"./rules.js\";\n\nexport interface WebhookValidationOptions {\n storeId: string | number;\n /** The public URL your app exposes for Lemon Squeezy to POST to. */\n url: string;\n}\n\n/**\n * Confirm a webhook matching `options.url` is registered against the given\n * store, and cross-reference its subscribed events against the support\n * manifest's recommended + optional lists.\n *\n * Missing recommended events = error. Missing optional events = info, because\n * not every integration needs them.\n */\nexport const validateWebhook = async (\n http: HttpClient,\n mode: Mode,\n options: WebhookValidationOptions,\n): Promise<ValidationResult<WebhookAttributes>> => {\n const target = { label: options.url, url: options.url };\n\n const fetched = await probeCollection(() => listWebhooksForStore(http, options.storeId));\n if (!fetched.ok) {\n return buildResult<WebhookAttributes>(\"webhook\", mode, [fetched.issue], undefined, target);\n }\n\n const match = fetched.resource.find((webhook) =>\n sameWebhookUrl(webhook.attributes.url, options.url),\n );\n if (!match) {\n return buildResult<WebhookAttributes>(\n \"webhook\",\n mode,\n [\n issue(\n ISSUE_CODES.WEBHOOK_NOT_FOUND,\n \"error\",\n `No webhook registered for URL ${options.url} on store ${options.storeId}.`,\n {\n suggestedFix:\n \"Register the webhook in Lemon Squeezy (Settings → Webhooks) and subscribe to the recommended events.\",\n context: { storeId: String(options.storeId), url: options.url },\n },\n ),\n ],\n undefined,\n target,\n );\n }\n\n const issues: ValidationIssue[] = [];\n const subscribed = new Set(match.attributes.events);\n const missingRecommended = RECOMMENDED_WEBHOOK_EVENTS.filter((event) => !subscribed.has(event));\n const missingOptional = OPTIONAL_WEBHOOK_EVENTS.filter((event) => !subscribed.has(event));\n\n if (missingRecommended.length > 0) {\n issues.push(\n issue(\n ISSUE_CODES.WEBHOOK_EVENTS_MISSING,\n \"error\",\n `Webhook is missing recommended events: ${missingRecommended.join(\", \")}.`,\n {\n suggestedFix:\n \"Subscribe to all recommended events so the integration survives plan changes and refunds.\",\n context: { missing: missingRecommended.join(\",\") },\n },\n ),\n );\n }\n\n if (missingOptional.length > 0) {\n issues.push(\n issue(\n ISSUE_CODES.WEBHOOK_OPTIONAL_EVENTS,\n \"info\",\n `Optional events not subscribed: ${missingOptional.join(\", \")}.`,\n { context: { missing: missingOptional.join(\",\") } },\n ),\n );\n }\n\n return buildResult(\"webhook\", mode, issues, match.attributes, {\n label: match.attributes.url,\n id: match.id,\n url: match.attributes.url,\n });\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { HttpClient } from \"../core/http.js\";\nimport type { DoctorReport, Mode, ValidationResult } from \"../core/types.js\";\nimport type { DiscountAttributes } from \"../resources/discounts.js\";\nimport type { LicenseKeyAttributes } from \"../resources/licenseKeys.js\";\nimport type { ProductAttributes } from \"../resources/products.js\";\nimport type { StoreAttributes } from \"../resources/stores.js\";\nimport type { WebhookAttributes } from \"../resources/webhooks.js\";\nimport { type ConnectionSummary, validateConnection } from \"./connection.js\";\nimport { type DiscountValidationOptions, validateDiscount } from \"./discount.js\";\nimport { type LicenseKeyValidationOptions, validateLicenseKey } from \"./licenseKey.js\";\nimport { type ProductValidationOptions, validateProduct } from \"./product.js\";\nimport { validateStore } from \"./store.js\";\nimport {\n type SubscriptionPlanValidationOptions,\n validateSubscriptionPlan,\n} from \"./subscriptionPlan.js\";\nimport { type WebhookValidationOptions, validateWebhook } from \"./webhook.js\";\n\n/**\n * Optional targets for the doctor run. If a target is omitted, its validator\n * is skipped — consumers only pay for what they configure.\n */\nexport interface DoctorOptions {\n storeId?: string | number;\n productId?: string | number;\n productIds?: Array<string | number>;\n webhookUrl?: string;\n webhookUrls?: string[];\n discountId?: string | number;\n discountIds?: Array<string | number>;\n licenseKeyId?: string | number;\n licenseKeyIds?: Array<string | number>;\n variantId?: string | number;\n variantIds?: Array<string | number>;\n}\n\n/**\n * The set of validator functions doctor composes.\n *\n * Exposed as an injectable seam so tests can exercise composition order,\n * short-circuiting on connection failure, and option propagation without\n * setting up an HTTP route table for every validator. Production callers\n * normally rely on `DEFAULT_VALIDATORS`, which wires in the real\n * implementations from each `validate/*` module.\n */\nexport interface DoctorValidators {\n connection: (http: HttpClient, mode: Mode) => Promise<ValidationResult<ConnectionSummary>>;\n store: (\n http: HttpClient,\n mode: Mode,\n storeId: string | number,\n ) => Promise<ValidationResult<StoreAttributes>>;\n product: (\n http: HttpClient,\n mode: Mode,\n options: ProductValidationOptions,\n ) => Promise<ValidationResult<ProductAttributes>>;\n webhook: (\n http: HttpClient,\n mode: Mode,\n options: WebhookValidationOptions,\n ) => Promise<ValidationResult<WebhookAttributes>>;\n discount: (\n http: HttpClient,\n mode: Mode,\n options: DiscountValidationOptions,\n ) => Promise<ValidationResult<DiscountAttributes>>;\n licenseKey: (\n http: HttpClient,\n mode: Mode,\n options: LicenseKeyValidationOptions,\n ) => Promise<ValidationResult<LicenseKeyAttributes>>;\n subscriptionPlan: (\n http: HttpClient,\n mode: Mode,\n options: SubscriptionPlanValidationOptions,\n ) => Promise<ValidationResult>;\n}\n\n/** Default wiring used by `doctor` when no overrides are provided. */\nexport const DEFAULT_VALIDATORS: DoctorValidators = {\n connection: validateConnection,\n store: validateStore,\n product: validateProduct,\n webhook: validateWebhook,\n discount: validateDiscount,\n licenseKey: validateLicenseKey,\n subscriptionPlan: validateSubscriptionPlan,\n};\n\n/**\n * Compose every configured validator into a single report. This is the\n * primary entry point for CI health checks: one call, one structured result,\n * one exit code decision.\n *\n * Order is meaningful. Connection runs first because downstream validators\n * have nothing useful to say if the API key is broken.\n *\n * The optional `validators` parameter lets tests inject fakes without a fetch\n * mock; production callers omit it and get `DEFAULT_VALIDATORS`.\n */\nexport const doctor = async (\n http: HttpClient,\n mode: Mode,\n options: DoctorOptions = {},\n validators: DoctorValidators = DEFAULT_VALIDATORS,\n): Promise<DoctorReport> => {\n assertOptionsCoherent(options);\n\n const results: ValidationResult[] = [];\n const productIds = collectValues(options.productId, options.productIds);\n const webhookUrls = collectValues(options.webhookUrl, options.webhookUrls);\n const discountIds = collectValues(options.discountId, options.discountIds);\n const licenseKeyIds = collectValues(options.licenseKeyId, options.licenseKeyIds);\n const variantIds = collectValues(options.variantId, options.variantIds);\n\n const connection = await validators.connection(http, mode);\n results.push(connection);\n\n if (!connection.ok) {\n return { ok: false, mode, results };\n }\n\n if (options.storeId !== undefined) {\n results.push(await validators.store(http, mode, options.storeId));\n }\n\n for (const productId of productIds) {\n results.push(\n await validators.product(http, mode, {\n productId,\n expectedStoreId: options.storeId,\n }),\n );\n }\n\n // webhook / discount / licenseKey / subscriptionPlan all require storeId\n // (assertOptionsCoherent rejects those options when storeId is absent).\n if (options.storeId !== undefined) {\n const storeId = options.storeId;\n for (const url of webhookUrls) {\n results.push(await validators.webhook(http, mode, { storeId, url }));\n }\n for (const discountId of discountIds) {\n results.push(await validators.discount(http, mode, { storeId, discountId }));\n }\n for (const licenseKeyId of licenseKeyIds) {\n results.push(await validators.licenseKey(http, mode, { storeId, licenseKeyId }));\n }\n for (const variantId of variantIds) {\n results.push(await validators.subscriptionPlan(http, mode, { storeId, variantId }));\n }\n }\n\n return { ok: results.every((entry) => entry.ok), mode, results };\n};\n\n/**\n * Fail fast when store-scoped targets are set without `storeId`. Without this,\n * doctor would silently skip those validators and report a false-positive ok.\n */\nconst assertOptionsCoherent = (options: DoctorOptions): void => {\n if (options.storeId !== undefined) return;\n\n const dependent: Array<keyof DoctorOptions> = [];\n if (hasAny(options.webhookUrl, options.webhookUrls)) dependent.push(\"webhookUrl\");\n if (hasAny(options.discountId, options.discountIds)) dependent.push(\"discountId\");\n if (hasAny(options.licenseKeyId, options.licenseKeyIds)) dependent.push(\"licenseKeyId\");\n if (hasAny(options.variantId, options.variantIds)) dependent.push(\"variantId\");\n\n if (dependent.length === 0) return;\n\n throw new FreshSqueezyError({\n code: \"DOCTOR_OPTIONS_INVALID\",\n message: `doctor() received ${dependent.join(\", \")} without storeId. These validators cannot run without a store; pass \\`storeId\\` or remove the dependent options.`,\n });\n};\n\nconst collectValues = <T>(single: T | undefined, many: T[] | undefined): T[] => {\n const values = new Set<T>();\n if (single !== undefined) values.add(single);\n for (const value of many ?? []) {\n if (value !== undefined) values.add(value);\n }\n return Array.from(values);\n};\n\nconst hasAny = <T>(single: T | undefined, many: T[] | undefined): boolean => {\n return single !== undefined || (many?.length ?? 0) > 0;\n};\n","import { resolveConfig } from \"./core/config.js\";\nimport { HttpClient, type RequestOptions } from \"./core/http.js\";\nimport type { DoctorReport, FreshSqueezyConfig, Mode, ValidationResult } from \"./core/types.js\";\nimport type { DiscountAttributes } from \"./resources/discounts.js\";\nimport { type InvokeOpArgs, invokeOp } from \"./resources/invokeOp.js\";\nimport type { LicenseKeyAttributes } from \"./resources/licenseKeys.js\";\nimport type { ProductAttributes } from \"./resources/products.js\";\nimport type { OpVerb } from \"./resources/registry.js\";\nimport type { StoreAttributes } from \"./resources/stores.js\";\nimport type { WebhookAttributes } from \"./resources/webhooks.js\";\nimport { type ConnectionSummary, validateConnection } from \"./validate/connection.js\";\nimport { type DiscountValidationOptions, validateDiscount } from \"./validate/discount.js\";\nimport { type DoctorOptions, doctor } from \"./validate/doctor.js\";\nimport { type LicenseKeyValidationOptions, validateLicenseKey } from \"./validate/licenseKey.js\";\nimport { type ProductValidationOptions, validateProduct } from \"./validate/product.js\";\nimport { validateStore } from \"./validate/store.js\";\nimport {\n type SubscriptionPlanSummary,\n type SubscriptionPlanValidationOptions,\n validateSubscriptionPlan,\n} from \"./validate/subscriptionPlan.js\";\nimport { type WebhookValidationOptions, validateWebhook } from \"./validate/webhook.js\";\n\n/**\n * Nested resource namespaces for docs-backed Lemon Squeezy ops.\n *\n * Every method routes through `invokeOp` + `resourceRegistry` (docsPath required).\n * Methods exist only when the official API documents them — no product/variant create.\n * Ops return JSON:API payloads as `unknown`; callers narrow or use resource helpers.\n * Failures throw `FreshSqueezyError` (branch on `.code`).\n */\nexport interface FreshSqueezyOps {\n users: {\n me: () => Promise<unknown>;\n };\n stores: {\n get: (id: string | number) => Promise<unknown>;\n list: () => Promise<unknown>;\n };\n products: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n };\n variants: {\n get: (id: string | number) => Promise<unknown>;\n list: (productId: string | number) => Promise<unknown>;\n };\n prices: {\n get: (id: string | number) => Promise<unknown>;\n list: (variantId: string | number) => Promise<unknown>;\n };\n files: {\n get: (id: string | number) => Promise<unknown>;\n list: (variantId: string | number) => Promise<unknown>;\n };\n customers: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n };\n orders: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n refund: (id: string | number, body?: unknown) => Promise<unknown>;\n generateInvoice: (id: string | number, body?: unknown) => Promise<unknown>;\n };\n orderItems: {\n get: (id: string | number) => Promise<unknown>;\n list: (orderId: string | number) => Promise<unknown>;\n };\n subscriptions: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n cancel: (id: string | number) => Promise<unknown>;\n };\n subscriptionItems: {\n get: (id: string | number) => Promise<unknown>;\n list: (subscriptionId: string | number) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n currentUsage: (id: string | number) => Promise<unknown>;\n };\n subscriptionInvoices: {\n get: (id: string | number) => Promise<unknown>;\n list: (subscriptionId: string | number) => Promise<unknown>;\n refund: (id: string | number, body?: unknown) => Promise<unknown>;\n generateInvoice: (id: string | number, body?: unknown) => Promise<unknown>;\n };\n usageRecords: {\n get: (id: string | number) => Promise<unknown>;\n list: (subscriptionItemId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n };\n discounts: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n delete: (id: string | number) => Promise<unknown>;\n };\n discountRedemptions: {\n get: (id: string | number) => Promise<unknown>;\n list: (discountId: string | number) => Promise<unknown>;\n };\n licenseKeys: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n };\n licenseKeyInstances: {\n get: (id: string | number) => Promise<unknown>;\n list: (licenseKeyId: string | number) => Promise<unknown>;\n };\n checkouts: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n };\n webhooks: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n create: (body: unknown) => Promise<unknown>;\n update: (id: string | number, body: unknown) => Promise<unknown>;\n delete: (id: string | number) => Promise<unknown>;\n };\n affiliates: {\n get: (id: string | number) => Promise<unknown>;\n list: (storeId: string | number) => Promise<unknown>;\n };\n}\n\n/**\n * The public client. Validators stay flat; ops live under nested namespaces\n * that mirror docs-backed resources (see `resourceRegistry`).\n */\nexport interface FreshSqueezyClient extends FreshSqueezyOps {\n /** Resolved mode (test or live). Surfaced so consumers can log it. */\n readonly mode: Mode;\n\n /** Raw HTTP escape hatch for endpoints fresh-squeezy does not wrap. */\n request<T = unknown>(options: RequestOptions): Promise<T>;\n\n validateConnection(): Promise<ValidationResult<ConnectionSummary>>;\n validateStore(storeId: string | number): Promise<ValidationResult<StoreAttributes>>;\n validateProduct(options: ProductValidationOptions): Promise<ValidationResult<ProductAttributes>>;\n validateWebhook(options: WebhookValidationOptions): Promise<ValidationResult<WebhookAttributes>>;\n validateDiscount(\n options: DiscountValidationOptions,\n ): Promise<ValidationResult<DiscountAttributes>>;\n validateLicenseKey(\n options: LicenseKeyValidationOptions,\n ): Promise<ValidationResult<LicenseKeyAttributes>>;\n validateSubscriptionPlan(\n options: SubscriptionPlanValidationOptions,\n ): Promise<ValidationResult<SubscriptionPlanSummary>>;\n /**\n * Compose configured validators into one report.\n * Defaults `storeId` from client config when the call omits it.\n */\n doctor(options?: DoctorOptions): Promise<DoctorReport>;\n}\n\n/**\n * Create a fresh-squeezy client. Zero-config usage reads\n * `LEMON_SQUEEZY_API_KEY`, `LEMON_SQUEEZY_STORE_ID`, and `LEMON_SQUEEZY_MODE`\n * from `process.env`.\n *\n * @param config - Optional overrides for key, mode, store, fetch.\n * @returns Client with validators + nested docs-backed ops.\n * @throws {FreshSqueezyError} When config is invalid (missing key, bad mode).\n *\n * @example\n * ```ts\n * const lemon = createFreshSqueezy();\n * const report = await lemon.doctor();\n * if (!report.ok) process.exit(1);\n * const product = await lemon.products.get(42);\n * const webhook = await lemon.webhooks.create({ data: { type: \"webhooks\", … } });\n * ```\n */\nexport const createFreshSqueezy = (config: FreshSqueezyConfig = {}): FreshSqueezyClient => {\n const resolved = resolveConfig(config);\n const http = new HttpClient(resolved);\n\n /** Dispatch a registry-backed op; never invents endpoints outside `resourceRegistry`. */\n const op = (resource: string, verb: OpVerb, args: InvokeOpArgs = {}) =>\n invokeOp(http, resource, verb, args);\n\n return {\n mode: resolved.mode,\n request: (options) => http.request(options),\n validateConnection: () => validateConnection(http, resolved.mode),\n validateStore: (storeId) => validateStore(http, resolved.mode, storeId),\n validateProduct: (options) => validateProduct(http, resolved.mode, options),\n validateWebhook: (options) => validateWebhook(http, resolved.mode, options),\n validateDiscount: (options) => validateDiscount(http, resolved.mode, options),\n validateLicenseKey: (options) => validateLicenseKey(http, resolved.mode, options),\n validateSubscriptionPlan: (options) => validateSubscriptionPlan(http, resolved.mode, options),\n doctor: (options) =>\n doctor(http, resolved.mode, {\n ...options,\n storeId: options?.storeId ?? resolved.storeId,\n }),\n\n users: {\n me: () => op(\"user\", \"get\"),\n },\n stores: {\n get: (id) => op(\"store\", \"get\", { id }),\n list: () => op(\"store\", \"list\"),\n },\n products: {\n get: (id) => op(\"product\", \"get\", { id }),\n list: (storeId) => op(\"product\", \"list\", { storeId }),\n },\n variants: {\n get: (id) => op(\"variant\", \"get\", { id }),\n list: (productId) => op(\"variant\", \"list\", { parentId: productId }),\n },\n prices: {\n get: (id) => op(\"price\", \"get\", { id }),\n list: (variantId) => op(\"price\", \"list\", { parentId: variantId }),\n },\n files: {\n get: (id) => op(\"file\", \"get\", { id }),\n list: (variantId) => op(\"file\", \"list\", { parentId: variantId }),\n },\n customers: {\n get: (id) => op(\"customer\", \"get\", { id }),\n list: (storeId) => op(\"customer\", \"list\", { storeId }),\n create: (body) => op(\"customer\", \"create\", { body }),\n update: (id, body) => op(\"customer\", \"update\", { id, body }),\n },\n orders: {\n get: (id) => op(\"order\", \"get\", { id }),\n list: (storeId) => op(\"order\", \"list\", { storeId }),\n refund: (id, body) => op(\"order\", \"refund\", { id, body }),\n generateInvoice: (id, body) => op(\"order\", \"generate-invoice\", { id, body }),\n },\n orderItems: {\n get: (id) => op(\"order-item\", \"get\", { id }),\n list: (orderId) => op(\"order-item\", \"list\", { parentId: orderId }),\n },\n subscriptions: {\n get: (id) => op(\"subscription\", \"get\", { id }),\n list: (storeId) => op(\"subscription\", \"list\", { storeId }),\n update: (id, body) => op(\"subscription\", \"update\", { id, body }),\n cancel: (id) => op(\"subscription\", \"cancel\", { id }),\n },\n subscriptionItems: {\n get: (id) => op(\"subscription-item\", \"get\", { id }),\n list: (subscriptionId) => op(\"subscription-item\", \"list\", { parentId: subscriptionId }),\n update: (id, body) => op(\"subscription-item\", \"update\", { id, body }),\n currentUsage: (id) => op(\"subscription-item\", \"current-usage\", { id }),\n },\n subscriptionInvoices: {\n get: (id) => op(\"subscription-invoice\", \"get\", { id }),\n list: (subscriptionId) => op(\"subscription-invoice\", \"list\", { parentId: subscriptionId }),\n refund: (id, body) => op(\"subscription-invoice\", \"refund\", { id, body }),\n generateInvoice: (id, body) => op(\"subscription-invoice\", \"generate-invoice\", { id, body }),\n },\n usageRecords: {\n get: (id) => op(\"usage-record\", \"get\", { id }),\n list: (subscriptionItemId) => op(\"usage-record\", \"list\", { parentId: subscriptionItemId }),\n create: (body) => op(\"usage-record\", \"create\", { body }),\n },\n discounts: {\n get: (id) => op(\"discount\", \"get\", { id }),\n list: (storeId) => op(\"discount\", \"list\", { storeId }),\n create: (body) => op(\"discount\", \"create\", { body }),\n delete: (id) => op(\"discount\", \"delete\", { id }),\n },\n discountRedemptions: {\n get: (id) => op(\"discount-redemption\", \"get\", { id }),\n list: (discountId) => op(\"discount-redemption\", \"list\", { parentId: discountId }),\n },\n licenseKeys: {\n get: (id) => op(\"license-key\", \"get\", { id }),\n list: (storeId) => op(\"license-key\", \"list\", { storeId }),\n update: (id, body) => op(\"license-key\", \"update\", { id, body }),\n },\n licenseKeyInstances: {\n get: (id) => op(\"license-key-instance\", \"get\", { id }),\n list: (licenseKeyId) => op(\"license-key-instance\", \"list\", { parentId: licenseKeyId }),\n },\n checkouts: {\n get: (id) => op(\"checkout\", \"get\", { id }),\n list: (storeId) => op(\"checkout\", \"list\", { storeId }),\n create: (body) => op(\"checkout\", \"create\", { body }),\n },\n webhooks: {\n get: (id) => op(\"webhook\", \"get\", { id }),\n list: (storeId) => op(\"webhook\", \"list\", { storeId }),\n create: (body) => op(\"webhook\", \"create\", { body }),\n update: (id, body) => op(\"webhook\", \"update\", { id, body }),\n delete: (id) => op(\"webhook\", \"delete\", { id }),\n },\n affiliates: {\n get: (id) => op(\"affiliate\", \"get\", { id }),\n list: (storeId) => op(\"affiliate\", \"list\", { storeId }),\n },\n };\n};\n","import { ENV_KEYS } from \"../core/config.js\";\nimport { FreshSqueezyError } from \"../core/errors.js\";\nimport type { ValidateTarget } from \"./commands/validate.js\";\n\nexport const renderCliError = (message: string, hints: string[] = []): string => {\n const lines = [`fresh-squeezy: ${message}`];\n\n if (hints.length > 0) {\n lines.push(\"\", \"Try:\");\n for (const hint of hints) {\n lines.push(` ${hint}`);\n }\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n};\n\nexport const getDoctorHints = (err: unknown): string[] => {\n if (!isFreshSqueezyError(err)) return [];\n\n if (err.code === \"MISSING_API_KEY\") {\n return [\"fresh-squeezy init\", `export ${ENV_KEYS.apiKey}=ls_live_or_test_key`];\n }\n\n if (err.code === \"INVALID_MODE\") {\n return [\"fresh-squeezy doctor --mode test\", \"fresh-squeezy doctor --mode live\"];\n }\n\n if (err.code === \"NO_STORES\") {\n return [\"Check that the API key belongs to an account with a Lemon Squeezy store.\"];\n }\n\n return [];\n};\n\nexport const getValidateHints = (err: unknown, target: ValidateTarget): string[] => {\n if (!isFreshSqueezyError(err)) return [];\n\n if (err.code === \"MISSING_API_KEY\") {\n return [\"fresh-squeezy init\", `export ${ENV_KEYS.apiKey}=ls_live_or_test_key`];\n }\n\n if (err.code === \"INVALID_MODE\") {\n return [\n `fresh-squeezy validate ${target} --mode test`,\n `fresh-squeezy validate ${target} --mode live`,\n ];\n }\n\n if (err.code === \"MISSING_ARG\") {\n return getMissingArgHints(target);\n }\n\n return [];\n};\n\nconst getMissingArgHints = (target: ValidateTarget): string[] => {\n if (target === \"connection\") {\n return [\"fresh-squeezy validate connection\"];\n }\n\n if (target === \"store\") {\n return [\n \"fresh-squeezy validate store --store-ids 12\",\n \"fresh-squeezy validate store --all-stores\",\n ];\n }\n\n if (target === \"product\") {\n return [\"fresh-squeezy validate product --product-id 987\"];\n }\n\n if (target === \"webhook\") {\n return [\n \"fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n \"fresh-squeezy validate webhook --all-stores --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n ];\n }\n\n if (target === \"discount\") {\n return [\"fresh-squeezy validate discount --store-ids 12 --discount-id 123\"];\n }\n\n if (target === \"license-key\") {\n return [\"fresh-squeezy validate license-key --store-ids 12 --license-key-id 123\"];\n }\n\n return [\"fresh-squeezy validate subscription-plan --store-ids 12 --variant-id 123\"];\n};\n\nconst isFreshSqueezyError = (err: unknown): err is FreshSqueezyError => {\n return err instanceof FreshSqueezyError;\n};\n","import chalk from \"chalk\";\nimport type {\n DoctorReport,\n ValidationIssue,\n ValidationResult,\n ValidationTarget,\n} from \"../core/types.js\";\n\n/**\n * Human-readable pretty-printer for a validation result. Keeps color logic in\n * one place so doctor/validate commands share formatting and consumers can\n * redirect stdout without ANSI codes leaking through (chalk auto-detects TTY).\n */\nexport const renderResult = (result: ValidationResult): string => {\n const lines: string[] = [];\n const badge = result.ok ? chalk.green(\"PASS\") : chalk.red(\"FAIL\");\n const mode = chalk.dim(`[${result.mode}]`);\n const target = renderTarget(result.target);\n const suffix = target ? ` ${chalk.dim(target)}` : \"\";\n lines.push(`${badge} ${mode} ${chalk.bold(result.name)}${suffix}`);\n\n for (const issue of result.issues) {\n lines.push(` ${renderIssueLine(issue)}`);\n if (issue.suggestedFix) {\n lines.push(` ${chalk.dim(\"fix:\")} ${issue.suggestedFix}`);\n }\n }\n\n return lines.join(\"\\n\");\n};\n\nconst renderTarget = (target: ValidationTarget | undefined): string => {\n if (!target) return \"\";\n const parts = [target.label];\n if (target.id) parts.push(`id ${target.id}`);\n if (target.url && target.url !== target.label) parts.push(target.url);\n return parts.join(\" - \");\n};\n\nexport const renderReport = (report: DoctorReport): string => {\n const header = report.ok\n ? chalk.green.bold(\"fresh-squeezy doctor: OK\")\n : chalk.red.bold(\"fresh-squeezy doctor: FAILED\");\n const failed = report.results.filter((result) => !result.ok).length;\n const summary =\n failed === 0\n ? chalk.dim(`${report.results.length} checks passed`)\n : chalk.dim(`${failed}/${report.results.length} checks failed`);\n const body = report.results.map(renderResult).join(\"\\n\\n\");\n return `${header} ${chalk.dim(`(mode: ${report.mode})`)}\\n${summary}\\n\\n${body}`;\n};\n\nconst renderIssueLine = (issue: ValidationIssue): string => {\n const label =\n issue.severity === \"error\"\n ? chalk.red(\"✗ error\")\n : issue.severity === \"warning\"\n ? chalk.yellow(\"! warn \")\n : chalk.blue(\"i info \");\n return `${label} ${chalk.gray(`[${issue.code}]`)} ${issue.message}`;\n};\n","import path from \"node:path\";\nimport { checkbox, confirm, input, password, select } from \"@inquirer/prompts\";\nimport {\n EMPTY_INIT_RESOURCE_CHOICES,\n type InitResourceChoices,\n type ResourceChoiceGroup,\n} from \"./resourceDiscovery.js\";\n\n/**\n * Interactive prompts used by `fresh-squeezy init`.\n *\n * Isolated from the command handler so the command stays focused on the flow\n * (ask → detect → confirm → write) and prompts can be unit-tested by mocking\n * `@inquirer/prompts` without pulling in the full commander program.\n */\n\nexport interface InitAnswers {\n apiKey: string;\n}\n\nexport interface InitDoctorTargets {\n productIds?: string[];\n webhookUrls?: string[];\n discountIds?: string[];\n licenseKeyIds?: string[];\n variantIds?: string[];\n}\n\nexport type InitDoctorTarget =\n | \"product\"\n | \"webhook\"\n | \"discount\"\n | \"license-key\"\n | \"subscription-plan\";\nexport type LauncherAction = \"init\" | \"doctor\" | \"manage\" | \"examples\" | \"exit\";\n\ntype DoctorTargetField = keyof InitDoctorTargets;\ntype ManualQuestion = {\n field: DoctorTargetField;\n message: string;\n validate: (value: string) => true | string;\n};\ntype EmptyTargetAction = \"manual\" | \"skip\";\n\nconst PROMPT_THEME = {\n prefix: {\n idle: \"›\",\n done: \"✓\",\n },\n} as const;\n\nexport const pickLauncherAction = async (): Promise<LauncherAction> => {\n return select<LauncherAction>({\n message: \"What do you want to do?\",\n theme: PROMPT_THEME,\n choices: [\n {\n name: \"Start guided setup — key, store, checks, doctor\",\n value: \"init\",\n },\n {\n name: \"Run doctor now — pick stores interactively when needed\",\n value: \"doctor\",\n },\n {\n name: \"Manage resources — bulk delete / cancel / refund\",\n value: \"manage\",\n },\n {\n name: \"Show command examples — copy/paste friendly\",\n value: \"examples\",\n },\n {\n name: \"Exit\",\n value: \"exit\",\n },\n ],\n });\n};\n\nexport const askForApiKey = async (): Promise<InitAnswers> => {\n const apiKey = await password({\n message: \"Paste your Lemon Squeezy API key:\",\n mask: false,\n theme: PROMPT_THEME,\n validate: (value: string) => (value.trim().length > 0 ? true : \"API key is required.\"),\n });\n return { apiKey: apiKey.trim() };\n};\n\nexport const pickStore = async (\n choices: { id: string; name: string; slug: string }[],\n): Promise<string> => {\n return select<string>({\n message: \"Pick a store to validate against:\",\n theme: PROMPT_THEME,\n choices: choices.map((entry) => ({\n name: `${entry.name} (${entry.slug}) — id ${entry.id}`,\n value: entry.id,\n })),\n });\n};\n\n/**\n * Multi-select store picker used by `doctor` and `validate` when no\n * `--store-ids` / `--all-stores` flag is supplied and stdin is a TTY.\n * The first store is pre-checked so hitting Enter without toggling still\n * picks something — callers enforce the \"at least one\" rule.\n */\nexport const pickStores = async (\n choices: { id: string; name: string; slug: string }[],\n): Promise<string[]> => {\n return checkbox<string>({\n message: \"Pick one or more stores (space to toggle, enter to confirm):\",\n theme: PROMPT_THEME,\n choices: choices.map((entry, index) => ({\n name: `${entry.name} (${entry.slug}) — id ${entry.id}`,\n value: entry.id,\n checked: index === 0,\n })),\n validate: (selected) => (selected.length > 0 ? true : \"Pick at least one store.\"),\n });\n};\n\nexport const selectDoctorTargets = async (): Promise<InitDoctorTarget[]> => {\n return checkbox<InitDoctorTarget>({\n message: \"Add resource checks to this doctor run?\",\n theme: PROMPT_THEME,\n choices: [\n { name: \"Product checkout\", value: \"product\" },\n { name: \"Webhook registration\", value: \"webhook\" },\n { name: \"Discount code\", value: \"discount\" },\n { name: \"License key\", value: \"license-key\" },\n { name: \"Subscription plan\", value: \"subscription-plan\" },\n ],\n });\n};\n\nconst splitManualValues = (value: string | undefined): string[] =>\n (value ?? \"\")\n .split(\",\")\n .map((entry) => entry.trim())\n .filter(Boolean);\n\nconst required = (label: string): ((value: string) => true | string) => {\n return (value: string) => (value.trim().length > 0 ? true : `${label} is required.`);\n};\n\nconst optional = (label: string): ((value: string) => true | string) => {\n return (value: string) => {\n const trimmed = value.trim();\n if (trimmed.length === 0) return true;\n return required(label)(trimmed);\n };\n};\n\nconst validateWebhookUrl = (value: string): true | string => {\n const trimmed = value.trim();\n if (trimmed.length === 0) return \"Webhook URL is required.\";\n\n try {\n const url = new URL(trimmed);\n return url.protocol === \"http:\" || url.protocol === \"https:\"\n ? true\n : \"Webhook URL must start with http:// or https://.\";\n } catch {\n return \"Enter a valid webhook URL.\";\n }\n};\n\nconst optionalWebhookUrls = (value: string): true | string => {\n const values = splitManualValues(value);\n if (values.length === 0) return true;\n return values.every((entry) => validateWebhookUrl(entry) === true)\n ? true\n : \"Enter valid webhook URLs.\";\n};\n\nconst cleanList = (value: string[] | string | undefined): string[] | undefined => {\n const values = Array.isArray(value) ? value : splitManualValues(value);\n const cleaned = Array.from(new Set(values.map((entry) => entry.trim()).filter(Boolean)));\n return cleaned.length > 0 ? cleaned : undefined;\n};\n\nconst DOCTOR_TARGET_SPECS: Array<{\n target: InitDoctorTarget;\n field: DoctorTargetField;\n group: keyof InitResourceChoices;\n pickMessage: string;\n emptyMessage: string;\n manualMessage: string;\n validate: (value: string) => true | string;\n}> = [\n {\n target: \"product\",\n field: \"productIds\",\n group: \"products\",\n pickMessage: \"Pick products to validate:\",\n emptyMessage: \"No products selected. What now?\",\n manualMessage: \"Product IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"Product ID\"),\n },\n {\n target: \"webhook\",\n field: \"webhookUrls\",\n group: \"webhooks\",\n pickMessage: \"Pick webhook URLs to validate:\",\n emptyMessage: \"No webhook URLs selected. What now?\",\n manualMessage: \"Webhook URLs to validate (comma-separated, leave empty to skip):\",\n validate: optionalWebhookUrls,\n },\n {\n target: \"discount\",\n field: \"discountIds\",\n group: \"discounts\",\n pickMessage: \"Pick discounts to validate:\",\n emptyMessage: \"No discounts selected. What now?\",\n manualMessage: \"Discount IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"Discount ID\"),\n },\n {\n target: \"license-key\",\n field: \"licenseKeyIds\",\n group: \"licenseKeys\",\n pickMessage: \"Pick license keys to validate:\",\n emptyMessage: \"No license keys selected. What now?\",\n manualMessage: \"License key IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"License key ID\"),\n },\n {\n target: \"subscription-plan\",\n field: \"variantIds\",\n group: \"subscriptionPlans\",\n pickMessage: \"Pick subscription plans to validate:\",\n emptyMessage: \"No subscription plans selected. What now?\",\n manualMessage:\n \"Subscription plan variant IDs to validate (comma-separated, leave empty to skip):\",\n validate: optional(\"Variant ID\"),\n },\n];\n\nexport const askForDoctorTargetValues = async (\n targets: InitDoctorTarget[],\n choices: InitResourceChoices = EMPTY_INIT_RESOURCE_CHOICES,\n): Promise<InitDoctorTargets> => {\n if (targets.length === 0) return {};\n\n const answers: Partial<Record<DoctorTargetField, string[] | string>> = {};\n const manualQuestions: ManualQuestion[] = [];\n\n for (const spec of DOCTOR_TARGET_SPECS) {\n if (!targets.includes(spec.target)) continue;\n await resolveTargetValue({\n answers,\n manualQuestions,\n group: choices[spec.group],\n field: spec.field,\n pickMessage: spec.pickMessage,\n emptyMessage: spec.emptyMessage,\n manualMessage: spec.manualMessage,\n validate: spec.validate,\n });\n }\n\n for (const question of manualQuestions) {\n answers[question.field] = await input({\n message: question.message,\n theme: PROMPT_THEME,\n validate: question.validate,\n });\n }\n\n return {\n productIds: cleanList(answers.productIds),\n webhookUrls: cleanList(answers.webhookUrls),\n discountIds: cleanList(answers.discountIds),\n licenseKeyIds: cleanList(answers.licenseKeyIds),\n variantIds: cleanList(answers.variantIds),\n };\n};\n\nexport const confirmLiveModeRun = async (): Promise<boolean> => {\n return confirm({\n message: \"This is a live-mode key. Continue with live checks?\",\n default: false,\n theme: PROMPT_THEME,\n });\n};\n\nexport const confirmWriteEnvFile = async (filePath: string): Promise<boolean> => {\n return confirm({\n message: `Write these values to ${formatPromptPath(filePath)}?`,\n default: true,\n theme: PROMPT_THEME,\n });\n};\n\n/**\n * Confirm a destructive or live-mode resource op before mutating.\n *\n * @param message - Prompt shown to the operator.\n * @returns Whether the user confirmed.\n *\n * @example\n * ```ts\n * const ok = await confirmResourceOp(\"Delete webhook 12?\");\n * ```\n */\nexport const confirmResourceOp = async (message: string): Promise<boolean> => {\n return confirm({\n message,\n default: false,\n theme: PROMPT_THEME,\n });\n};\n\nconst resolveTargetValue = async (input: {\n answers: Partial<Record<DoctorTargetField, string[] | string>>;\n manualQuestions: ManualQuestion[];\n group: ResourceChoiceGroup;\n field: DoctorTargetField;\n pickMessage: string;\n emptyMessage: string;\n manualMessage: string;\n validate: (value: string) => true | string;\n}): Promise<void> => {\n if (input.group.choices.length === 0) {\n input.manualQuestions.push({\n field: input.field,\n message: input.manualMessage,\n validate: input.validate,\n });\n return;\n }\n\n const values = await checkbox<string>({\n message: input.pickMessage,\n theme: PROMPT_THEME,\n choices: input.group.choices.map((choice) => ({\n name: choice.label,\n value: choice.value,\n })),\n });\n\n if (values.length > 0) {\n input.answers[input.field] = values;\n return;\n }\n\n const action = await askEmptyTargetAction(input.emptyMessage);\n if (action === \"manual\") {\n input.manualQuestions.push({\n field: input.field,\n message: input.manualMessage,\n validate: input.validate,\n });\n }\n};\n\nconst askEmptyTargetAction = async (message: string): Promise<EmptyTargetAction> => {\n return select<EmptyTargetAction>({\n message,\n theme: PROMPT_THEME,\n choices: [\n { name: \"Enter manually\", value: \"manual\" },\n { name: \"Skip this check\", value: \"skip\" },\n ],\n });\n};\n\nconst formatPromptPath = (filePath: string): string => {\n const relative = path.relative(process.cwd(), filePath);\n if (relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative)) return relative;\n return path.basename(filePath);\n};\n\nexport const isPromptCancel = (error: unknown): boolean => {\n if (!(error instanceof Error)) return false;\n return error.name === \"ExitPromptError\" || error.message.includes(\"User force closed\");\n};\n\n/** One bulk-capable operation offered by the \"Manage resources\" menu. */\nexport interface ManageOperationChoice {\n resource: string;\n verb: string;\n}\n\n/**\n * Pick which destructive op to run (e.g. `delete discount`).\n *\n * @param ops - Registry-backed operations that can run in bulk.\n * @returns The chosen operation.\n */\nexport const pickManageOperation = async (\n ops: ManageOperationChoice[],\n): Promise<ManageOperationChoice> => {\n return select<ManageOperationChoice>({\n message: \"Which operation?\",\n theme: PROMPT_THEME,\n choices: ops.map((op) => ({ name: `${op.verb} ${op.resource}`, value: op })),\n });\n};\n\n/**\n * Ask for the parent resource id that scopes a nested list (order, subscription, …).\n *\n * @param resource - Resource being listed, used in the prompt text.\n */\nexport const askParentId = async (resource: string): Promise<string> => {\n const value = await input({\n message: `Parent id to list ${resource} items from:`,\n theme: PROMPT_THEME,\n validate: (entry: string) => (entry.trim().length > 0 ? true : \"A parent id is required.\"),\n });\n return value.trim();\n};\n\n/**\n * Multi-select the items to act on. Nothing is pre-checked so a stray Enter\n * cannot select everything; `a` toggles all.\n *\n * @param verb - Verb shown in the prompt.\n * @param items - Candidate items with a display label.\n * @returns Ids of the picked items.\n */\nexport const pickBulkTargets = async (\n verb: string,\n items: { id: string; label: string }[],\n): Promise<string[]> => {\n return checkbox<string>({\n message: `Pick items to ${verb} (space toggles, a selects all, enter confirms):`,\n theme: PROMPT_THEME,\n choices: items.map((item) => ({ name: `${item.label} — id ${item.id}`, value: item.id })),\n validate: (selected) => (selected.length > 0 ? true : \"Pick at least one item.\"),\n });\n};\n","import type { RequestOptions } from \"../core/http.js\";\nimport type { JsonApiCollection, JsonApiResource } from \"../core/types.js\";\nimport type { FreshSqueezyClient } from \"../createFreshSqueezy.js\";\nimport type { DiscountAttributes } from \"../resources/discounts.js\";\nimport type { LicenseKeyAttributes } from \"../resources/licenseKeys.js\";\nimport type { ProductAttributes } from \"../resources/products.js\";\nimport type { SubscriptionVariantAttributes } from \"../resources/variants.js\";\nimport type { WebhookAttributes } from \"../resources/webhooks.js\";\nimport type { InitDoctorTarget } from \"./prompts.js\";\n\nexport interface ResourceChoice {\n label: string;\n value: string;\n}\n\nexport interface ResourceChoiceGroup {\n choices: ResourceChoice[];\n error?: string;\n}\n\nexport interface InitResourceChoices {\n products: ResourceChoiceGroup;\n webhooks: ResourceChoiceGroup;\n discounts: ResourceChoiceGroup;\n licenseKeys: ResourceChoiceGroup;\n subscriptionPlans: ResourceChoiceGroup;\n}\n\nexport const EMPTY_INIT_RESOURCE_CHOICES: InitResourceChoices = {\n products: { choices: [] },\n webhooks: { choices: [] },\n discounts: { choices: [] },\n licenseKeys: { choices: [] },\n subscriptionPlans: { choices: [] },\n};\n\nexport const discoverInitResourceChoices = async (\n client: FreshSqueezyClient,\n storeId: string,\n targets: InitDoctorTarget[],\n): Promise<InitResourceChoices> => {\n const choices: InitResourceChoices = {\n products: { choices: [] },\n webhooks: { choices: [] },\n discounts: { choices: [] },\n licenseKeys: { choices: [] },\n subscriptionPlans: { choices: [] },\n };\n let products: JsonApiResource<ProductAttributes>[] | undefined;\n\n if (targets.includes(\"product\") || targets.includes(\"subscription-plan\")) {\n const result = await discover(() =>\n paginate<ProductAttributes>(client, \"/v1/products\", { \"filter[store_id]\": storeId }),\n );\n if (result.ok) {\n products = result.value;\n choices.products = { choices: result.value.map(toProductChoice) };\n } else {\n choices.products = { choices: [], error: result.error };\n }\n }\n\n if (targets.includes(\"webhook\")) {\n const result = await discover(() =>\n paginate<WebhookAttributes>(client, \"/v1/webhooks\", { \"filter[store_id]\": storeId }),\n );\n choices.webhooks = result.ok\n ? { choices: result.value.map(toWebhookChoice) }\n : { choices: [], error: result.error };\n }\n\n if (targets.includes(\"discount\")) {\n const result = await discover(() =>\n paginate<DiscountAttributes>(client, \"/v1/discounts\", { \"filter[store_id]\": storeId }),\n );\n choices.discounts = result.ok\n ? { choices: result.value.map(toDiscountChoice) }\n : { choices: [], error: result.error };\n }\n\n if (targets.includes(\"license-key\")) {\n const result = await discover(() =>\n paginate<LicenseKeyAttributes>(client, \"/v1/license-keys\", { \"filter[store_id]\": storeId }),\n );\n choices.licenseKeys = result.ok\n ? { choices: result.value.map(toLicenseKeyChoice) }\n : { choices: [], error: result.error };\n }\n\n if (targets.includes(\"subscription-plan\")) {\n const listedProducts = products ?? [];\n if (choices.products.error) {\n choices.subscriptionPlans = { choices: [], error: choices.products.error };\n } else {\n choices.subscriptionPlans = await discoverSubscriptionPlans(client, listedProducts);\n }\n }\n\n return choices;\n};\n\nconst discoverSubscriptionPlans = async (\n client: FreshSqueezyClient,\n products: JsonApiResource<ProductAttributes>[],\n): Promise<ResourceChoiceGroup> => {\n const discovered: ResourceChoice[] = [];\n\n for (const product of products) {\n const result = await discover(() =>\n paginate<SubscriptionVariantAttributes>(client, \"/v1/variants\", {\n \"filter[product_id]\": product.id,\n }),\n );\n if (!result.ok) {\n return { choices: discovered, error: result.error };\n }\n\n for (const variant of result.value) {\n if (variant.attributes.is_subscription) {\n discovered.push(toSubscriptionPlanChoice(variant, product.attributes.name));\n }\n }\n }\n\n return { choices: discovered };\n};\n\nconst paginate = async <TAttributes>(\n client: FreshSqueezyClient,\n path: string,\n query: RequestOptions[\"query\"],\n): Promise<JsonApiResource<TAttributes>[]> => {\n const all: JsonApiResource<TAttributes>[] = [];\n let pageNumber = Number(query?.[\"page[number]\"] ?? 1);\n\n while (true) {\n const doc = await client.request<JsonApiCollection<TAttributes>>({\n path,\n query: { ...(query ?? {}), \"page[number]\": pageNumber },\n });\n all.push(...doc.data);\n\n const lastPage = doc.meta?.page?.lastPage;\n if (lastPage === undefined || pageNumber >= lastPage) return all;\n pageNumber += 1;\n }\n};\n\nconst discover = async <T>(\n load: () => Promise<T>,\n): Promise<{ ok: true; value: T } | { ok: false; error: string }> => {\n try {\n return { ok: true, value: await load() };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n};\n\nconst toProductChoice = (product: JsonApiResource<ProductAttributes>): ResourceChoice => {\n return {\n value: product.id,\n label: `${product.attributes.name} (${product.attributes.status}) - id ${product.id}`,\n };\n};\n\nconst toWebhookChoice = (webhook: JsonApiResource<WebhookAttributes>): ResourceChoice => {\n return {\n value: webhook.attributes.url,\n label: `${webhook.attributes.url} - id ${webhook.id}`,\n };\n};\n\nconst toDiscountChoice = (discount: JsonApiResource<DiscountAttributes>): ResourceChoice => {\n return {\n value: discount.id,\n label: `${discount.attributes.name} (${discount.attributes.code}) - id ${discount.id}`,\n };\n};\n\nconst toLicenseKeyChoice = (licenseKey: JsonApiResource<LicenseKeyAttributes>): ResourceChoice => {\n return {\n value: licenseKey.id,\n label: `${licenseKey.attributes.key_short} (${licenseKey.attributes.status}) - id ${licenseKey.id}`,\n };\n};\n\nconst toSubscriptionPlanChoice = (\n variant: JsonApiResource<SubscriptionVariantAttributes>,\n productName: string,\n): ResourceChoice => {\n const interval = variant.attributes.interval\n ? `${variant.attributes.interval_count ?? 1}/${variant.attributes.interval}`\n : \"no interval\";\n return {\n value: variant.id,\n label: `${productName} / ${variant.attributes.name} (${interval}) - id ${variant.id}`,\n };\n};\n","import { FreshSqueezyError } from \"../core/errors.js\";\nimport type { FreshSqueezyClient } from \"../createFreshSqueezy.js\";\nimport { pickStores } from \"./prompts.js\";\n\n/**\n * Inputs the CLI has when it needs to figure out which stores to validate.\n * Kept flag-only + TTY — the CLI deliberately does not read\n * `LEMON_SQUEEZY_STORE_ID`. Library consumers still can (via `createFreshSqueezy`).\n */\nexport interface ResolveStoresInput {\n storeIds?: string[];\n allStores?: boolean;\n /** Whether stdin is attached to a TTY so we can prompt. */\n isInteractive: boolean;\n}\n\nexport interface ResolveStoresOutput {\n storeIds: string[];\n /**\n * True when the resolver could not pick any store AND was not asked to.\n * The caller should fall back to a connection-only run in that case.\n */\n skipped: boolean;\n}\n\n/**\n * Decide which store IDs a doctor/validate run should cover.\n *\n * Resolution order (highest → lowest):\n * 1. `--store-ids 1,2,3` flag\n * 2. `--all-stores` flag (fetch every reachable store)\n * 3. TTY + inquirer multi-select\n * 4. Non-TTY, no flag → `skipped: true`\n *\n * `skipped` lets the caller decide whether to run only connection-level checks\n * or fail loudly — different subcommands want different behavior.\n */\nexport const resolveStores = async (\n client: FreshSqueezyClient,\n input: ResolveStoresInput,\n): Promise<ResolveStoresOutput> => {\n if (input.storeIds && input.storeIds.length > 0) {\n return { storeIds: dedupe(input.storeIds), skipped: false };\n }\n\n if (input.allStores) {\n const ids = await fetchReachableStoreIds(client);\n if (ids.length === 0) {\n throw new FreshSqueezyError({\n code: \"NO_STORES\",\n message: \"No stores reachable with this API key.\",\n });\n }\n return { storeIds: ids, skipped: false };\n }\n\n if (!input.isInteractive) {\n return { storeIds: [], skipped: true };\n }\n\n const ids = await fetchReachableStoreIds(client);\n if (ids.length === 0) {\n throw new FreshSqueezyError({\n code: \"NO_STORES\",\n message: \"No stores reachable with this API key.\",\n });\n }\n if (ids.length === 1) {\n return { storeIds: ids, skipped: false };\n }\n\n const detailed = await Promise.all(\n ids.map(async (id) => {\n const result = await client.validateStore(id);\n return {\n id,\n name: result.resource?.name ?? \"(unnamed)\",\n slug: result.resource?.slug ?? \"\",\n };\n }),\n );\n\n const picked = await pickStores(detailed);\n if (picked.length === 0) {\n throw new FreshSqueezyError({\n code: \"NO_SELECTION\",\n message: \"No store selected. Pick at least one to continue.\",\n });\n }\n return { storeIds: picked, skipped: false };\n};\n\n/**\n * Fetch every store reachable with the current key. Errors from the underlying\n * request propagate — callers handle them at the command boundary.\n */\nconst fetchReachableStoreIds = async (client: FreshSqueezyClient): Promise<string[]> => {\n const connection = await client.validateConnection();\n if (!connection.ok) {\n const authIssue = connection.issues.find((entry) => entry.code === \"AUTH_FAILED\");\n if (authIssue) {\n throw new FreshSqueezyError({\n code: \"AUTH_FAILED\",\n message: authIssue.message,\n });\n }\n }\n return connection.resource?.storeIds ?? [];\n};\n\nconst dedupe = (values: string[]): string[] => {\n return Array.from(new Set(values.map((value) => value.trim()).filter(Boolean)));\n};\n","import { FreshSqueezyError } from \"../../core/errors.js\";\nimport type { DoctorReport, Mode } from \"../../core/types.js\";\nimport { type FreshSqueezyClient, createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport { getDoctorHints, renderCliError } from \"../errors.js\";\nimport type { InitDoctorTarget } from \"../prompts.js\";\nimport { renderReport } from \"../render.js\";\nimport { resolveStores } from \"../resolveStores.js\";\nimport { type InitResourceChoices, discoverInitResourceChoices } from \"../resourceDiscovery.js\";\n\nexport interface DoctorCommandOptions {\n mode?: Mode;\n storeIds?: string[];\n allStores?: boolean;\n allResources?: boolean;\n productId?: string;\n webhookUrl?: string;\n discountId?: string;\n licenseKeyId?: string;\n variantId?: string;\n json?: boolean;\n isInteractive?: boolean;\n}\n\n/**\n * Aggregate payload emitted when `--json` is set. When a single store is\n * resolved, `reports` still contains one entry — consumers always see an\n * array so JSON parsers don't need two code paths.\n */\nexport interface DoctorJsonOutput {\n ok: boolean;\n mode: Mode;\n reports: DoctorReport[];\n}\n\nconst ALL_RESOURCE_TARGETS: InitDoctorTarget[] = [\n \"product\",\n \"webhook\",\n \"discount\",\n \"license-key\",\n \"subscription-plan\",\n];\n\n/**\n * `fresh-squeezy doctor` — run every validator across each resolved store and\n * emit one combined exit code. Store resolution (flag → --all-stores → TTY\n * prompt → connection-only) lives in resolveStores so validate commands can\n * reuse it.\n */\nexport const runDoctorCommand = async (options: DoctorCommandOptions): Promise<number> => {\n try {\n const client = createFreshSqueezy({ mode: options.mode });\n const resolved = await resolveStores(client, {\n storeIds: options.storeIds,\n allStores: options.allStores,\n isInteractive: options.isInteractive ?? false,\n });\n\n if (resolved.skipped) {\n return await runConnectionOnly(client, options);\n }\n\n const reports = await Promise.all(\n resolved.storeIds.map(async (storeId) => {\n const targets = await resolveDoctorTargets(client, storeId, options);\n return client.doctor({ storeId, ...targets });\n }),\n );\n\n const ok = reports.every((report) => report.ok);\n const payload: DoctorJsonOutput = { ok, mode: client.mode, reports };\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n } else {\n for (const report of reports) {\n process.stdout.write(`${renderReport(report)}\\n\\n`);\n }\n if (!options.allResources && !hasExplicitResourceSelection(options)) {\n process.stderr.write(\n \"fresh-squeezy: resource checks were skipped; pass --all-resources or explicit resource flags to validate products, webhooks, discounts, license keys, and subscription plans.\\n\",\n );\n }\n }\n\n return ok ? 0 : 1;\n } catch (err) {\n writeFatal(err, options.json ?? false);\n return 2;\n }\n};\n\nconst resolveDoctorTargets = async (\n client: FreshSqueezyClient,\n storeId: string,\n options: DoctorCommandOptions,\n): Promise<{\n productIds?: string[];\n webhookUrls?: string[];\n discountIds?: string[];\n licenseKeyIds?: string[];\n variantIds?: string[];\n}> => {\n const explicit = {\n productIds: one(options.productId),\n webhookUrls: one(options.webhookUrl),\n discountIds: one(options.discountId),\n licenseKeyIds: one(options.licenseKeyId),\n variantIds: one(options.variantId),\n };\n\n if (!options.allResources) return explicit;\n\n const discovered = await discoverInitResourceChoices(client, storeId, ALL_RESOURCE_TARGETS);\n reportDiscoveryErrors(discovered);\n if (!options.json) {\n process.stderr.write(\n `fresh-squeezy: discovered store ${storeId} resources: ${formatDiscoveryCounts(discovered)}.\\n`,\n );\n }\n\n return {\n productIds: mergeValues(explicit.productIds, values(discovered.products)),\n webhookUrls: mergeValues(explicit.webhookUrls, values(discovered.webhooks)),\n discountIds: mergeValues(explicit.discountIds, values(discovered.discounts)),\n licenseKeyIds: mergeValues(explicit.licenseKeyIds, values(discovered.licenseKeys)),\n variantIds: mergeValues(explicit.variantIds, values(discovered.subscriptionPlans)),\n };\n};\n\nconst DISCOVERY_LABELS = [\n [\"products\", \"products\"],\n [\"webhooks\", \"webhooks\"],\n [\"discounts\", \"discounts\"],\n [\"licenseKeys\", \"license keys\"],\n [\"subscriptionPlans\", \"subscription plans\"],\n] as const;\n\nconst formatDiscoveryCounts = (choices: InitResourceChoices): string =>\n DISCOVERY_LABELS.map(([key, label]) => `${label} ${choices[key].choices.length}`).join(\", \");\n\nconst reportDiscoveryErrors = (choices: InitResourceChoices): void => {\n for (const [key, label] of DISCOVERY_LABELS) {\n const error = choices[key].error;\n if (error) process.stderr.write(`fresh-squeezy: discovery skipped ${label}: ${error}\\n`);\n }\n};\n\nconst values = (group: { choices: Array<{ value: string }> }): string[] | undefined =>\n group.choices.length > 0 ? group.choices.map((choice) => choice.value) : undefined;\n\nconst one = (value: string | undefined): string[] | undefined => (value ? [value] : undefined);\n\nconst mergeValues = (\n explicit: string[] | undefined,\n discovered: string[] | undefined,\n): string[] | undefined => {\n const merged = Array.from(new Set([...(explicit ?? []), ...(discovered ?? [])]));\n return merged.length > 0 ? merged : undefined;\n};\n\nconst hasExplicitResourceSelection = (options: DoctorCommandOptions): boolean =>\n Boolean(\n options.productId ||\n options.webhookUrl ||\n options.discountId ||\n options.licenseKeyId ||\n options.variantId,\n );\n\n/**\n * Fallback when no store could be resolved and we are not interactive.\n * Running connection-only gives CI a useful signal (\"key works\") without\n * silently pretending everything is fine.\n */\nconst runConnectionOnly = async (\n client: FreshSqueezyClient,\n options: DoctorCommandOptions,\n): Promise<number> => {\n const connection = await client.validateConnection();\n const report: DoctorReport = {\n ok: connection.ok,\n mode: client.mode,\n results: [connection],\n };\n const payload: DoctorJsonOutput = { ok: connection.ok, mode: client.mode, reports: [report] };\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n } else {\n process.stderr.write(\n \"fresh-squeezy: no --store-ids or --all-stores and stdin is not a TTY; running connection-only.\\n\",\n );\n process.stdout.write(`${renderReport(report)}\\n`);\n }\n return connection.ok ? 0 : 1;\n};\n\nconst writeFatal = (err: unknown, asJson: boolean): void => {\n if (asJson) {\n const code = err instanceof FreshSqueezyError ? err.code : \"UNKNOWN\";\n const message = err instanceof Error ? err.message : String(err);\n const status = err instanceof FreshSqueezyError ? (err.status ?? null) : null;\n process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message, status } })}\\n`);\n return;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(renderCliError(message, getDoctorHints(err)));\n};\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport { ENV_KEYS } from \"../../core/config.js\";\nimport type { Mode, ValidationResult } from \"../../core/types.js\";\nimport { type FreshSqueezyClient, createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport type { ConnectionSummary } from \"../../validate/connection.js\";\nimport { renderBrandHeader, renderCancelMessage, renderDetected, renderStep } from \"../brand.js\";\nimport { renderCliError } from \"../errors.js\";\nimport {\n type InitDoctorTarget,\n type InitDoctorTargets,\n askForApiKey,\n askForDoctorTargetValues,\n confirmLiveModeRun,\n confirmWriteEnvFile,\n isPromptCancel,\n pickStore,\n selectDoctorTargets,\n} from \"../prompts.js\";\nimport { renderReport } from \"../render.js\";\nimport {\n EMPTY_INIT_RESOURCE_CHOICES,\n type InitResourceChoices,\n type ResourceChoiceGroup,\n discoverInitResourceChoices,\n} from \"../resourceDiscovery.js\";\n\nexport interface InitCommandOptions {\n envFile?: string;\n isInteractive?: boolean;\n}\n\n/**\n * `fresh-squeezy init` — interactive onboarding. Walks the user through the\n * fastest path from \"I have an API key\" to \"my integration is verified\":\n *\n * 1. Read API key from env or ask for it if missing.\n * 2. List reachable stores via `/v1/stores`, let the user pick one.\n * 3. Ask which resource-specific validators should run now.\n * 4. Optionally persist credentials to `.env`.\n * 5. Run `doctor()` against the chosen config and print the report.\n *\n * Returns an exit code so the CLI wrapper can forward it to `process.exit`.\n */\nexport const runInitCommand = async (options: InitCommandOptions = {}): Promise<number> => {\n try {\n return await runInitFlow(options);\n } catch (err) {\n if (isPromptCancel(err)) {\n process.stderr.write(renderCancelMessage());\n return 130;\n }\n throw err;\n }\n};\n\nconst runInitFlow = async (options: InitCommandOptions): Promise<number> => {\n if (options.isInteractive === false) {\n process.stderr.write(\n renderCliError(\"`fresh-squeezy init` requires an interactive terminal.\", [\n \"fresh-squeezy doctor --all-stores\",\n \"fresh-squeezy validate connection\",\n ]),\n );\n return 2;\n }\n\n process.stdout.write(\n renderBrandHeader(\n \"Guided setup\",\n \"Connect a key, pick the right store, and run a focused billing doctor.\",\n ),\n );\n\n process.stdout.write(renderStep(1, 5, \"Credentials\", \"reuse env when available\"));\n const apiKey = await resolveApiKey();\n\n process.stdout.write(renderStep(2, 5, \"Account probe\", \"detect mode and reachable stores\"));\n const { client, mode, connection } = await createDetectedClient(apiKey);\n\n if (!connection.ok) {\n process.stdout.write(`${renderReport({ ok: false, mode, results: [connection] })}\\n`);\n return 1;\n }\n\n if (mode === \"live\" && !(await confirmLiveModeRun())) {\n process.stderr.write(renderCancelMessage());\n return 130;\n }\n\n const storeIds = connection.resource?.storeIds ?? [];\n if (storeIds.length === 0) {\n process.stdout.write(\n chalk.yellow(\n \"No stores reachable with this key. Create a store in Lemon Squeezy and retry.\\n\",\n ),\n );\n return 1;\n }\n\n process.stdout.write(renderDetected(\"Stores\", String(storeIds.length), \"Lemon Squeezy API\"));\n const stores = await Promise.all(storeIds.map((id) => client.validateStore(id)));\n const pickable = stores\n .filter((entry) => entry.ok && entry.resource)\n .map((entry, index) => ({\n id: storeIds[index] ?? \"\",\n name: entry.resource?.name ?? \"(unnamed)\",\n slug: entry.resource?.slug ?? \"\",\n }))\n .filter((entry) => entry.id !== \"\");\n\n if (pickable.length === 0) {\n process.stdout.write(\n chalk.yellow(\n \"Stores were discovered, but none could be validated. Check account access and retry.\\n\",\n ),\n );\n return 1;\n }\n\n process.stdout.write(renderStep(3, 5, \"Store selection\", \"auto-select when unambiguous\"));\n const storeId = await resolveStoreSelection(pickable);\n\n process.stdout.write(renderStep(4, 5, \"Optional checks\", \"pick resources before manual IDs\"));\n const selectedTargets = await selectDoctorTargets();\n const resourceChoices = await discoverChoices(client, storeId, selectedTargets);\n process.stdout.write(renderDiscoverySummary(resourceChoices, selectedTargets));\n const doctorTargets = await askForDoctorTargetValues(selectedTargets, resourceChoices);\n\n const envPath = path.resolve(process.cwd(), options.envFile ?? \".env\");\n const checkNames = getDoctorCheckNames(doctorTargets);\n process.stdout.write(renderSetupSummary({ envPath, mode, storeId, checkNames }));\n const shouldWrite = await confirmWriteEnvFile(envPath);\n if (shouldWrite) {\n await writeEnvFile(envPath, { apiKey, mode, storeId });\n process.stdout.write(chalk.green(`Wrote ${envPath}\\n`));\n }\n\n process.stdout.write(chalk.dim(`\\nRunning doctor (${checkNames.join(\", \")})...\\n\\n`));\n const report = await client.doctor({ storeId, ...doctorTargets });\n process.stdout.write(`${renderReport(report)}\\n`);\n\n return report.ok ? 0 : 1;\n};\n\nconst resolveStoreSelection = async (\n pickable: Array<{ id: string; name: string; slug: string }>,\n): Promise<string> => {\n if (pickable.length === 1) {\n const store = pickable[0];\n if (!store) throw new Error(\"Expected one reachable store.\");\n process.stdout.write(\n renderDetected(\"Store\", `${store.name} (${store.slug})`, `id ${store.id}`),\n );\n return store.id;\n }\n\n return pickStore(pickable);\n};\n\nconst discoverChoices = async (\n client: FreshSqueezyClient,\n storeId: string,\n selectedTargets: InitDoctorTarget[],\n): Promise<InitResourceChoices> => {\n if (selectedTargets.length === 0) return EMPTY_INIT_RESOURCE_CHOICES;\n return discoverInitResourceChoices(client, storeId, selectedTargets);\n};\n\nconst resolveApiKey = async (): Promise<string> => {\n const envApiKey = process.env[ENV_KEYS.apiKey]?.trim();\n if (envApiKey) {\n process.stdout.write(chalk.dim(`Using ${ENV_KEYS.apiKey} from environment.\\n`));\n return envApiKey;\n }\n\n const answers = await askForApiKey();\n return answers.apiKey;\n};\n\nconst createDetectedClient = async (\n apiKey: string,\n): Promise<{\n client: FreshSqueezyClient;\n mode: Mode;\n connection: ValidationResult<ConnectionSummary>;\n}> => {\n const envMode = parseEnvMode();\n const initialMode = envMode ?? \"test\";\n let client = createFreshSqueezy({ apiKey, mode: initialMode });\n let connection = await client.validateConnection();\n const actualMode = connection.resource?.actualMode;\n\n if (actualMode && actualMode !== initialMode) {\n const message = envMode\n ? `Detected ${actualMode}-mode API key; ignoring ${ENV_KEYS.mode}=${initialMode} for this run.`\n : `Detected ${actualMode}-mode API key.`;\n process.stdout.write(chalk.yellow(`${message}\\n`));\n client = createFreshSqueezy({ apiKey, mode: actualMode });\n connection = await client.validateConnection();\n return { client, mode: actualMode, connection };\n }\n\n if (actualMode) {\n process.stdout.write(chalk.dim(`Detected ${actualMode}-mode API key.\\n`));\n return { client, mode: actualMode, connection };\n }\n\n if (envMode) {\n process.stdout.write(\n chalk.dim(`Using ${ENV_KEYS.mode}=${envMode}; API mode was not exposed.\\n`),\n );\n return { client, mode: envMode, connection };\n }\n\n process.stdout.write(chalk.dim(\"Could not auto-detect key mode; using test mode.\\n\"));\n return { client, mode: initialMode, connection };\n};\n\nconst parseEnvMode = (): Mode | undefined => {\n const value = process.env[ENV_KEYS.mode]?.trim();\n if (value === \"test\" || value === \"live\") return value;\n if (value) {\n process.stdout.write(\n chalk.yellow(`Ignoring invalid ${ENV_KEYS.mode}=${value}; expected test or live.\\n`),\n );\n }\n return undefined;\n};\n\nconst getDoctorCheckNames = (targets: InitDoctorTargets): string[] => {\n const names = [\"connection\", \"store\"];\n pushCheckName(names, \"product\", targets.productIds);\n pushCheckName(names, \"webhook\", targets.webhookUrls);\n pushCheckName(names, \"discount\", targets.discountIds);\n pushCheckName(names, \"licenseKey\", targets.licenseKeyIds);\n pushCheckName(names, \"subscriptionPlan\", targets.variantIds);\n return names;\n};\n\nconst pushCheckName = (names: string[], name: string, values: string[] | undefined): void => {\n if (!values || values.length === 0) return;\n names.push(values.length === 1 ? name : `${name} x${values.length}`);\n};\n\nconst renderSetupSummary = (input: {\n envPath: string;\n mode: Mode;\n storeId: string;\n checkNames: string[];\n}): string => {\n return [\n renderStep(5, 5, \"Ready to verify\", \"review before writing env\"),\n ` ${chalk.dim(\"mode\")} ${input.mode}`,\n ` ${chalk.dim(\"store\")} ${input.storeId}`,\n ` ${chalk.dim(\"checks\")} ${input.checkNames.join(\", \")}`,\n ` ${chalk.dim(\"env\")} ${input.envPath}`,\n \"\",\n ].join(\"\\n\");\n};\n\nconst writeEnvFile = async (\n envPath: string,\n values: { apiKey: string; mode: string; storeId: string },\n): Promise<void> => {\n const updates = new Map<string, string>([\n [ENV_KEYS.apiKey, values.apiKey],\n [ENV_KEYS.storeId, values.storeId],\n [ENV_KEYS.mode, values.mode],\n ]);\n const existing = await readEnvFile(envPath);\n const lines = existing.length > 0 ? existing.split(/\\r?\\n/) : [];\n const seen = new Set<string>();\n const next = lines.map((line) => {\n const match = /^([A-Za-z_][A-Za-z0-9_]*)=/.exec(line);\n const key = match?.[1];\n if (!key || !updates.has(key)) return line;\n seen.add(key);\n return `${key}=${updates.get(key) ?? \"\"}`;\n });\n\n if (next.length > 0 && next.at(-1) !== \"\") {\n next.push(\"\");\n }\n\n for (const [key, value] of updates) {\n if (!seen.has(key)) {\n next.push(`${key}=${value}`);\n }\n }\n\n await fs.mkdir(path.dirname(envPath), { recursive: true });\n await fs.writeFile(envPath, `${next.join(\"\\n\").replace(/\\n*$/, \"\")}\\n`, { encoding: \"utf8\" });\n};\n\nconst readEnvFile = async (envPath: string): Promise<string> => {\n try {\n return await fs.readFile(envPath, \"utf8\");\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") {\n return \"\";\n }\n throw err;\n }\n};\n\nconst renderDiscoverySummary = (\n choices: InitResourceChoices,\n selectedTargets: InitDoctorTarget[],\n): string => {\n if (selectedTargets.length === 0) return chalk.dim(\" No optional resource checks selected.\\n\");\n\n const groups: Array<[InitDoctorTarget, string, ResourceChoiceGroup]> = [\n [\"product\", \"Products\", choices.products],\n [\"webhook\", \"Webhooks\", choices.webhooks],\n [\"discount\", \"Discounts\", choices.discounts],\n [\"license-key\", \"License keys\", choices.licenseKeys],\n [\"subscription-plan\", \"Subscription plans\", choices.subscriptionPlans],\n ];\n\n const lines: string[] = [];\n for (const [target, label, group] of groups) {\n if (!selectedTargets.includes(target)) continue;\n if (group.error) {\n lines.push(chalk.yellow(` ! ${label} discovery failed; manual entry is available.`));\n } else {\n lines.push(\n renderDetected(label, String(group.choices.length), \"Lemon Squeezy API\").trimEnd(),\n );\n }\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n};\n","import chalk from \"chalk\";\n\nconst brand = chalk.green.bold(\"fresh-squeezy\");\nconst divider = chalk.dim(\"•\");\n\nexport const renderBrandHeader = (title: string, subtitle?: string): string => {\n const lines = [`${brand} ${divider} ${chalk.bold(title)}`];\n if (subtitle) lines.push(chalk.dim(subtitle));\n lines.push(\"\");\n return lines.join(\"\\n\");\n};\n\nexport const renderStep = (\n index: number,\n total: number,\n title: string,\n detail?: string,\n): string => {\n const suffix = detail ? ` ${chalk.dim(detail)}` : \"\";\n const prefix = index > 1 ? \"\\n\" : \"\";\n return `${prefix}${chalk.yellow(\"●\")} ${chalk.dim(`${index}/${total}`)} ${chalk.bold(title)}${suffix}\\n`;\n};\n\nexport const renderDetected = (label: string, value: string, source?: string): string => {\n const suffix = source ? ` ${chalk.dim(`from ${source}`)}` : \"\";\n return ` ${chalk.green(\"✓\")} ${chalk.bold(label)} ${value}${suffix}\\n`;\n};\n\nexport const renderCommandExamples = (): string => {\n return [\n renderBrandHeader(\"Command examples\", \"Direct commands stay stable for scripts and CI.\"),\n `${chalk.bold(\"Guided setup\")}`,\n \" fresh-squeezy init\",\n \"\",\n `${chalk.bold(\"Full doctor\")}`,\n \" fresh-squeezy doctor --all-stores\",\n \" fresh-squeezy doctor --store-ids 12 --product-id 987 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n \"\",\n `${chalk.bold(\"Single checks\")}`,\n \" fresh-squeezy validate connection\",\n \" fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy\",\n \"\",\n `${chalk.bold(\"Bulk ops (delete / cancel / refund)\")}`,\n \" fresh-squeezy delete discount --all --store-ids 12 --dry-run\",\n \" fresh-squeezy delete discount --all --store-ids 12 --match TEST --yes\",\n \" fresh-squeezy delete webhook --ids 1,2,3 --yes\",\n \"\",\n `${chalk.bold(\"Automation\")}`,\n \" fresh-squeezy doctor --all-stores --json\",\n \"\",\n ].join(\"\\n\");\n};\n\nexport const renderCancelMessage = (): string => {\n return `${chalk.dim(\"fresh-squeezy cancelled.\")}\\n`;\n};\n","import chalk from \"chalk\";\nimport { ENV_KEYS } from \"../../core/config.js\";\nimport {\n renderBrandHeader,\n renderCancelMessage,\n renderCommandExamples,\n renderDetected,\n renderStep,\n} from \"../brand.js\";\nimport { type ProjectInstallResult, ensureFreshSqueezyDevDependency } from \"../projectInstall.js\";\nimport { type LauncherAction, isPromptCancel, pickLauncherAction } from \"../prompts.js\";\nimport { runDoctorCommand } from \"./doctor.js\";\nimport { runInitCommand } from \"./init.js\";\nimport { runManageCommand } from \"./manage.js\";\n\nexport interface LauncherCommandOptions {\n isInteractive: boolean;\n install?: boolean;\n packageVersion?: string;\n}\n\nexport const runLauncherCommand = async (options: LauncherCommandOptions): Promise<number> => {\n if (!options.isInteractive) return 2;\n\n try {\n process.stdout.write(\n renderBrandHeader(\n \"Project bootstrap\",\n \"Install the billing doctor locally, then verify Lemon Squeezy in one guided run.\",\n ),\n );\n\n process.stdout.write(renderStep(1, 2, \"Project dependency\", \"add fresh-squeezy when missing\"));\n const installResult = await ensureFreshSqueezyDevDependency({\n skipInstall: options.install === false,\n packageVersion: options.packageVersion,\n });\n process.stdout.write(renderProjectInstallResult(installResult));\n\n // No key yet → the only useful next step is guided setup, so skip the menu.\n // With a key configured, open the interactive front door and route the choice.\n if (!process.env[ENV_KEYS.apiKey]?.trim()) {\n return startGuidedSetup();\n }\n return routeLauncherAction(await pickLauncherAction());\n } catch (err) {\n if (isPromptCancel(err)) {\n process.stderr.write(renderCancelMessage());\n return 130;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`${chalk.red(\"fresh-squeezy bootstrap failed:\")} ${message}\\n\\n`);\n process.stderr.write(renderCommandExamples());\n return 1;\n }\n};\n\n/**\n * Route a front-door menu choice to the same command handlers the flag-driven\n * CLI uses. `doctor` runs interactively so store selection falls through to the\n * TTY multi-select; `manage` opens the bulk resource picker; `examples` prints the copy/paste cheatsheet; `exit` is a\n * clean no-op.\n */\nconst routeLauncherAction = async (action: LauncherAction): Promise<number> => {\n switch (action) {\n case \"init\":\n return startGuidedSetup();\n case \"doctor\":\n return runDoctorCommand({ isInteractive: true });\n case \"manage\":\n return runManageCommand();\n case \"examples\":\n process.stdout.write(renderCommandExamples());\n return 0;\n case \"exit\":\n return 0;\n }\n};\n\nconst startGuidedSetup = (): Promise<number> => {\n process.stdout.write(\n renderStep(2, 2, \"Guided setup\", \"detect credentials, stores, and resources\"),\n );\n return runInitCommand({ isInteractive: true });\n};\n\nconst renderProjectInstallResult = (result: ProjectInstallResult): string => {\n if (result.status === \"installed\") {\n return renderDetected(\n \"Dev dependency\",\n \"fresh-squeezy\",\n `${result.packageManager ?? \"npm\"} install`,\n );\n }\n\n if (result.status === \"already-present\") {\n return renderDetected(\"Dev dependency\", \"fresh-squeezy\", \"package.json\");\n }\n\n if (result.status === \"self-package\") {\n return renderDetected(\"Project\", \"fresh-squeezy source repo\", \"package.json\");\n }\n\n if (result.status === \"skipped\") {\n return chalk.dim(\" Skipped dev dependency install (--no-install).\\n\");\n }\n\n return chalk.yellow(\" No package.json found; running without installing a dev dependency.\\n\");\n};\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nconst PACKAGE_NAME = \"fresh-squeezy\";\n\nexport type PackageManager = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport type ProjectInstallStatus =\n | \"already-present\"\n | \"installed\"\n | \"no-package-json\"\n | \"self-package\"\n | \"skipped\";\n\nexport interface ProjectInstallResult {\n status: ProjectInstallStatus;\n projectDir?: string;\n packageJsonPath?: string;\n packageManager?: PackageManager;\n command?: string[];\n}\n\nexport interface EnsureProjectInstallOptions {\n cwd?: string;\n packageVersion?: string;\n skipInstall?: boolean;\n runCommand?: RunPackageCommand;\n}\n\nexport type RunPackageCommand = (\n command: string,\n args: string[],\n options: { cwd: string },\n) => Promise<number>;\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nexport const ensureFreshSqueezyDevDependency = async (\n options: EnsureProjectInstallOptions = {},\n): Promise<ProjectInstallResult> => {\n if (options.skipInstall) {\n return { status: \"skipped\" };\n }\n\n const cwd = options.cwd ?? process.cwd();\n const packageJsonPath = await findPackageJson(cwd);\n if (!packageJsonPath) {\n return { status: \"no-package-json\" };\n }\n\n const projectDir = path.dirname(packageJsonPath);\n const manifest = await readPackageJson(packageJsonPath);\n if (manifest.name === PACKAGE_NAME) {\n return { status: \"self-package\", projectDir, packageJsonPath };\n }\n\n const packageManager = await detectPackageManager(projectDir);\n if (hasFreshSqueezy(manifest)) {\n return { status: \"already-present\", projectDir, packageJsonPath, packageManager };\n }\n\n const packageSpec = options.packageVersion\n ? `${PACKAGE_NAME}@${options.packageVersion}`\n : PACKAGE_NAME;\n const command = buildInstallCommand(packageManager, packageSpec);\n const executable = command[0];\n if (!executable) throw new Error(\"No package manager command resolved.\");\n\n const runCommand = options.runCommand ?? runPackageCommand;\n const code = await runCommand(executable, command.slice(1), { cwd: projectDir });\n if (code !== 0) {\n throw new Error(`${command.join(\" \")} failed with exit code ${code}`);\n }\n\n return { status: \"installed\", projectDir, packageJsonPath, packageManager, command };\n};\n\nexport const findPackageJson = async (cwd: string): Promise<string | undefined> => {\n let current = path.resolve(cwd);\n\n while (true) {\n const candidate = path.join(current, \"package.json\");\n if (await pathExists(candidate)) return candidate;\n\n const parent = path.dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n};\n\nconst readPackageJson = async (packageJsonPath: string): Promise<PackageJson> => {\n const raw = await fs.readFile(packageJsonPath, \"utf8\");\n return JSON.parse(raw) as PackageJson;\n};\n\nconst detectPackageManager = async (projectDir: string): Promise<PackageManager> => {\n if (await pathExists(path.join(projectDir, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (await pathExists(path.join(projectDir, \"yarn.lock\"))) return \"yarn\";\n if (\n (await pathExists(path.join(projectDir, \"bun.lock\"))) ||\n (await pathExists(path.join(projectDir, \"bun.lockb\")))\n ) {\n return \"bun\";\n }\n return \"npm\";\n};\n\nconst hasFreshSqueezy = (manifest: PackageJson): boolean => {\n return [\n manifest.dependencies,\n manifest.devDependencies,\n manifest.optionalDependencies,\n manifest.peerDependencies,\n ].some((section) => section?.[PACKAGE_NAME] !== undefined);\n};\n\nconst buildInstallCommand = (packageManager: PackageManager, packageSpec: string): string[] => {\n if (packageManager === \"pnpm\") return [\"pnpm\", \"add\", \"-D\", packageSpec];\n if (packageManager === \"yarn\") return [\"yarn\", \"add\", \"-D\", packageSpec];\n if (packageManager === \"bun\") return [\"bun\", \"add\", \"-d\", packageSpec];\n return [\"npm\", \"install\", \"--save-dev\", packageSpec];\n};\n\nconst runPackageCommand = (\n command: string,\n args: string[],\n options: { cwd: string },\n): Promise<number> => {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd: options.cwd,\n stdio: \"inherit\",\n shell: false,\n });\n\n child.on(\"error\", reject);\n child.on(\"close\", (code) => resolve(code ?? 1));\n });\n};\n\nconst pathExists = async (filePath: string): Promise<boolean> => {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n};\n","import { FreshSqueezyError } from \"../../core/errors.js\";\nimport type { HttpClient } from \"../../core/http.js\";\nimport { invokeOp } from \"../../resources/invokeOp.js\";\nimport { type ResourceVerbSpec, findResourceVerb } from \"../../resources/registry.js\";\n\n/** One resource the bulk run will act on. */\nexport interface BulkTarget {\n id: string;\n /** Human label (code, name, url) shown in confirms and results. */\n label: string;\n}\n\n/** Per-item outcome of a bulk run. */\nexport interface BulkResult extends BulkTarget {\n ok: boolean;\n error?: string;\n}\n\n/** Aggregate outcome of a bulk run. */\nexport interface BulkSummary {\n dryRun: boolean;\n total: number;\n succeeded: number;\n failed: number;\n results: BulkResult[];\n}\n\n/** Selector flags that choose which resources a bulk run touches. */\nexport interface BulkSelector {\n all?: boolean;\n ids?: string[];\n match?: string;\n storeId?: string;\n parentId?: string;\n}\n\n/**\n * Whether a registry spec can run in bulk: write verbs that act on one id\n * (delete / cancel / refund) and have a matching `list` to enumerate from.\n *\n * @param spec - Registry entry for the verb.\n * @returns True when `--all` / `--ids` make sense for this op.\n */\nexport const supportsBulk = (spec: ResourceVerbSpec): boolean =>\n Boolean(spec.destructive) && spec.idRole === \"id\";\n\n/**\n * Pick a readable label from a JSON:API resource (code, name, url, …).\n *\n * @param item - Resource returned by `list`.\n * @returns The best label, falling back to the id.\n */\nexport const describeBulkTarget = (item: {\n id: string | number;\n attributes?: Record<string, unknown>;\n}): BulkTarget => {\n const attrs = item.attributes ?? {};\n const id = String(item.id);\n for (const key of [\"code\", \"name\", \"url\", \"identifier\", \"user_email\", \"status\"]) {\n const value = attrs[key];\n if (typeof value === \"string\" && value.length > 0) return { id, label: value };\n }\n return { id, label: id };\n};\n\n/**\n * Case-insensitive substring match against every string attribute.\n */\nconst matchesText = (item: { attributes?: Record<string, unknown> }, text: string): boolean => {\n const needle = text.toLowerCase();\n return Object.values(item.attributes ?? {}).some(\n (value) => typeof value === \"string\" && value.toLowerCase().includes(needle),\n );\n};\n\n/**\n * Resolve the targets of a bulk run: explicit `--ids`, or every item from the\n * resource's `list` (all pages), optionally narrowed by `--match`.\n *\n * @param http - Shared API client.\n * @param spec - Registry entry for the write verb.\n * @param selector - Which resources to touch, plus the list scope.\n * @returns Targets in API order.\n * @throws {FreshSqueezyError} `MISSING_ARG` when list scope is missing, `UNKNOWN_OP` without a list op.\n *\n * @example\n * ```ts\n * const targets = await collectBulkTargets(http, spec, { all: true, storeId: \"1\" });\n * ```\n */\nexport const collectBulkTargets = async (\n http: HttpClient,\n spec: ResourceVerbSpec,\n selector: BulkSelector,\n): Promise<BulkTarget[]> => {\n if (selector.ids?.length) {\n return selector.ids.map((id) => ({ id, label: id }));\n }\n\n const listSpec = findResourceVerb(spec.resource, \"list\");\n if (!listSpec) {\n throw new FreshSqueezyError({\n code: \"UNKNOWN_OP\",\n message: `Cannot use --all: ${spec.resource} has no list op. Pass --ids instead.`,\n });\n }\n if (listSpec.idRole === \"store\" && !selector.storeId) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"--all needs a store: pass --store-ids or set LEMON_SQUEEZY_STORE_ID.\",\n });\n }\n if (listSpec.idRole === \"parent\" && !selector.parentId) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--all needs --parent-id to list ${spec.resource} items.`,\n });\n }\n\n const items = (await invokeOp(http, spec.resource, \"list\", {\n storeId: selector.storeId,\n parentId: selector.parentId,\n })) as Array<{ id: string | number; attributes?: Record<string, unknown> }>;\n\n return items\n .filter((item) => (selector.match ? matchesText(item, selector.match) : true))\n .map(describeBulkTarget);\n};\n\n/**\n * Apply the write verb to each target. Keeps going after a failure so one bad\n * id never blocks the rest; with `dryRun` nothing is sent.\n *\n * @param http - Shared API client.\n * @param spec - Registry entry for the write verb.\n * @param targets - Resources to act on.\n * @param opts - `dryRun` skips writes; `body` is forwarded to every call.\n * @returns Per-item results and totals.\n *\n * @example\n * ```ts\n * const summary = await executeBulk(http, spec, targets, { dryRun: false });\n * if (summary.failed > 0) process.exitCode = 1;\n * ```\n */\nexport const executeBulk = async (\n http: HttpClient,\n spec: ResourceVerbSpec,\n targets: BulkTarget[],\n opts: { dryRun?: boolean; body?: unknown } = {},\n): Promise<BulkSummary> => {\n const dryRun = Boolean(opts.dryRun);\n const results: BulkResult[] = [];\n for (const target of targets) {\n if (dryRun) {\n results.push({ ...target, ok: true });\n continue;\n }\n try {\n await invokeOp(http, spec.resource, spec.verb, { id: target.id, body: opts.body });\n results.push({ ...target, ok: true });\n } catch (err) {\n results.push({\n ...target,\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n const failed = results.filter((r) => !r.ok).length;\n return { dryRun, total: results.length, succeeded: results.length - failed, failed, results };\n};\n\n/**\n * Short preview of target labels for confirm prompts.\n *\n * @param targets - Resources about to be touched.\n * @param max - Labels to show before eliding.\n */\nexport const previewTargets = (targets: BulkTarget[], max = 5): string => {\n const shown = targets.slice(0, max).map((t) => t.label);\n const more = targets.length - shown.length;\n return more > 0 ? `${shown.join(\", \")}, … +${more} more` : shown.join(\", \");\n};\n\n/**\n * Render a bulk summary for terminal output.\n *\n * @param spec - Registry entry for the write verb.\n * @param summary - Result of `executeBulk`.\n */\nexport const renderBulkSummary = (spec: ResourceVerbSpec, summary: BulkSummary): string => {\n if (summary.total === 0) return `No ${spec.resource} items matched — nothing to ${spec.verb}.\\n`;\n const verb = summary.dryRun ? `would ${spec.verb}` : spec.verb;\n const lines = summary.results.map((r) =>\n r.ok\n ? ` ✓ ${verb} ${spec.resource} ${r.id} (${r.label})`\n : ` ✗ ${spec.verb} ${spec.resource} ${r.id} (${r.label}): ${r.error}`,\n );\n const tail = summary.dryRun\n ? `dry run — ${summary.total} ${spec.resource} item(s) would be affected, nothing sent`\n : `${summary.succeeded}/${summary.total} succeeded${summary.failed ? `, ${summary.failed} failed` : \"\"}`;\n return `${lines.join(\"\\n\")}\\n${tail}\\n`;\n};\n","import { resolveConfig } from \"../../core/config.js\";\nimport { FreshSqueezyError } from \"../../core/errors.js\";\nimport { HttpClient } from \"../../core/http.js\";\nimport type { Mode } from \"../../core/types.js\";\nimport { createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport { findResourceVerb, resourceRegistry } from \"../../resources/registry.js\";\nimport { renderCliError } from \"../errors.js\";\nimport {\n type ManageOperationChoice,\n askParentId,\n confirmResourceOp,\n isPromptCancel,\n pickBulkTargets,\n pickManageOperation,\n} from \"../prompts.js\";\nimport { resolveStores } from \"../resolveStores.js\";\nimport {\n type BulkTarget,\n collectBulkTargets,\n executeBulk,\n previewTargets,\n renderBulkSummary,\n supportsBulk,\n} from \"./bulkOps.js\";\n\n/**\n * Operations the menu offers: every destructive, id-based registry op that also\n * has a `list` to enumerate from.\n *\n * @returns Resource/verb pairs in registry order.\n */\nexport const listManageOperations = (): ManageOperationChoice[] =>\n resourceRegistry\n .filter((spec) => supportsBulk(spec) && findResourceVerb(spec.resource, \"list\"))\n .map((spec) => ({ resource: spec.resource, verb: spec.verb }));\n\n/**\n * Build the flag-driven command that reproduces an interactive selection, so\n * the menu teaches the scriptable form.\n *\n * @param input - What was chosen and where.\n * @returns A copy/paste `fresh-squeezy …` command.\n *\n * @example\n * ```ts\n * renderEquivalentCommand({ verb: \"delete\", resource: \"discount\", mode: \"test\",\n * storeId: \"1\", picked: [\"7\"], total: 3 });\n * // fresh-squeezy delete discount --ids 7 --yes\n * ```\n */\nexport const renderEquivalentCommand = (input: {\n verb: string;\n resource: string;\n mode: Mode;\n storeId?: string;\n parentId?: string;\n picked: string[];\n total: number;\n}): string => {\n const parts = [\"fresh-squeezy\", input.verb, input.resource];\n if (input.picked.length === input.total) {\n parts.push(\"--all\");\n if (input.storeId) parts.push(\"--store-ids\", input.storeId);\n if (input.parentId) parts.push(\"--parent-id\", input.parentId);\n } else {\n parts.push(\"--ids\", input.picked.join(\",\"));\n }\n parts.push(\"--yes\");\n if (input.mode === \"live\") parts.push(\"--mode\", \"live\");\n return parts.join(\" \");\n};\n\n/**\n * Interactive \"Manage resources\": pick an op, a store, the items, confirm once,\n * run it through the same bulk executor the `--all` / `--ids` flags use.\n *\n * @returns 0 ok, 1 some items failed, 2 setup/API error. Prompt cancels propagate\n * to the launcher, which maps them to 130.\n *\n * @example\n * ```ts\n * const code = await runManageCommand();\n * ```\n */\nexport const runManageCommand = async (): Promise<number> => {\n try {\n const client = createFreshSqueezy();\n const http = new HttpClient(resolveConfig());\n const op = await pickManageOperation(listManageOperations());\n const spec = findResourceVerb(op.resource, op.verb);\n const listSpec = findResourceVerb(op.resource, \"list\");\n if (!spec || !listSpec) {\n throw new FreshSqueezyError({\n code: \"UNKNOWN_OP\",\n message: `${op.verb} ${op.resource} is not available.`,\n });\n }\n\n process.stdout.write(`\\n${op.verb} ${op.resource} — mode=${client.mode}\\n`);\n\n let scopes: Array<{ storeId?: string; parentId?: string }> = [{}];\n if (listSpec.idRole === \"store\") {\n const { storeIds } = await resolveStores(client, { isInteractive: true });\n scopes = storeIds.map((storeId) => ({ storeId }));\n } else if (listSpec.idRole === \"parent\") {\n scopes = [{ parentId: await askParentId(op.resource) }];\n }\n\n let exitCode = 0;\n for (const scope of scopes) {\n const targets = await collectBulkTargets(http, spec, { all: true, ...scope });\n if (targets.length === 0) {\n process.stdout.write(\n `No ${op.resource} items found${scope.storeId ? ` in store ${scope.storeId}` : \"\"}.\\n`,\n );\n continue;\n }\n\n const pickedIds = await pickBulkTargets(op.verb, targets);\n const picked: BulkTarget[] = targets.filter((t) => pickedIds.includes(t.id));\n const mark = client.mode === \"live\" ? \"LIVE mode: \" : \"\";\n const go = await confirmResourceOp(\n `${mark}${op.verb} ${picked.length} ${op.resource} item(s) (${previewTargets(picked)})?`,\n );\n if (!go) {\n process.stdout.write(\"Skipped — nothing changed.\\n\");\n continue;\n }\n\n const summary = await executeBulk(http, spec, picked);\n process.stdout.write(renderBulkSummary(spec, summary));\n process.stdout.write(\n `\\nNext time:\\n ${renderEquivalentCommand({\n verb: op.verb,\n resource: op.resource,\n mode: client.mode,\n ...scope,\n picked: pickedIds,\n total: targets.length,\n })}\\n`,\n );\n if (summary.failed > 0) exitCode = 1;\n }\n return exitCode;\n } catch (err) {\n if (isPromptCancel(err)) throw err;\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(renderCliError(message, [\"fresh-squeezy ops --list\"]));\n return 2;\n }\n};\n","import { readFileSync } from \"node:fs\";\nimport { resolveConfig } from \"../../core/config.js\";\nimport { FreshSqueezyError } from \"../../core/errors.js\";\nimport { HttpClient } from \"../../core/http.js\";\nimport type { Mode } from \"../../core/types.js\";\nimport { createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport { invokeOp } from \"../../resources/invokeOp.js\";\nimport {\n type OpVerb,\n findResourceVerb,\n listRegisteredResources,\n resourceRegistry,\n} from \"../../resources/registry.js\";\nimport { renderCliError } from \"../errors.js\";\nimport { confirmResourceOp } from \"../prompts.js\";\nimport {\n type BulkSelector,\n collectBulkTargets,\n executeBulk,\n previewTargets,\n renderBulkSummary,\n supportsBulk,\n} from \"./bulkOps.js\";\n\n/**\n * Options for hybrid resource ops (get/list/create/…/refund).\n */\nexport interface ResourceOpCommandOptions {\n resource: string;\n verb: OpVerb | string;\n mode?: Mode;\n id?: string;\n storeIds?: string[];\n parentId?: string;\n body?: string;\n bodyFile?: string;\n yes?: boolean;\n json?: boolean;\n isInteractive?: boolean;\n listCatalog?: boolean;\n /** Bulk: apply the verb to every listed item. */\n all?: boolean;\n /** Bulk: apply the verb to these ids. */\n ids?: string[];\n /** Bulk: with `all`, keep only items whose text attributes contain this. */\n match?: string;\n /** Bulk: show targets, send nothing. */\n dryRun?: boolean;\n}\n\n/**\n * Run a docs-backed resource op from the CLI.\n *\n * Dual-mode: non-TTY never prompts; live writes and destructive verbs need\n * `--yes` or TTY confirm.\n *\n * @param options - Verb, resource, flags, body sources.\n * @returns Process exit code (0 success, 1 bulk partial failure, 2 fatal/usage).\n *\n * @example\n * ```ts\n * await runResourceOpCommand({\n * verb: \"get\",\n * resource: \"product\",\n * id: \"42\",\n * json: true,\n * });\n * ```\n */\nexport const runResourceOpCommand = async (options: ResourceOpCommandOptions): Promise<number> => {\n if (options.listCatalog) {\n writeCatalog(options.json ?? false);\n return 0;\n }\n\n const spec = findResourceVerb(options.resource, options.verb);\n if (!spec) {\n process.stderr.write(\n renderCliError(`Unknown or unsupported op: ${options.verb} ${options.resource}`, [\n \"fresh-squeezy ops --list\",\n \"fresh-squeezy get product --id 1\",\n \"fresh-squeezy list webhook --store-ids 1\",\n ]),\n );\n return 2;\n }\n\n const bulkError = validateBulkFlags(spec, options);\n if (bulkError) {\n writeFatal(\n new FreshSqueezyError({ code: \"INVALID_ARGS\", message: bulkError }),\n options.json ?? false,\n );\n return 2;\n }\n\n try {\n const body = readBody(options);\n if (spec.body === \"required\" && body === undefined) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: \"This op requires a JSON body (--body, --body-file, or stdin).\",\n });\n }\n\n const client = createFreshSqueezy({ mode: options.mode });\n const config = resolveConfig({ mode: options.mode });\n const http = new HttpClient(config);\n // CLI flag wins; LEMON_SQUEEZY_STORE_ID (already in config) is the fallback.\n const storeId = options.storeIds?.[0] ?? config.storeId;\n\n if (options.all || options.ids) {\n return await runBulk(http, spec, client.mode, options, { storeId, body });\n }\n\n const allowed = await assertWriteSafety(spec, client.mode, options);\n if (!allowed) return 2;\n\n const opBody = await invokeOp(http, options.resource, options.verb, {\n id: options.id,\n storeId,\n parentId: options.parentId,\n body,\n });\n\n const envelope = {\n ok: true as const,\n mode: client.mode,\n resource: spec.resource,\n verb: spec.verb,\n docs: `https://docs.lemonsqueezy.com/api/${spec.docsPath}`,\n data: opBody ?? null,\n };\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(envelope, null, 2)}\\n`);\n } else {\n process.stdout.write(\n `${spec.verb} ${spec.resource} — ok (mode=${client.mode})\\n` +\n `${JSON.stringify(opBody ?? null, null, 2)}\\n`,\n );\n }\n return 0;\n } catch (err) {\n writeFatal(err, options.json ?? false);\n return 2;\n }\n};\n\n/**\n * Print the implemented ops matrix (docs-backed).\n *\n * @param asJson - Machine-readable when true.\n */\nconst writeCatalog = (asJson: boolean): void => {\n if (asJson) {\n process.stdout.write(\n `${JSON.stringify(\n {\n resources: listRegisteredResources(),\n ops: resourceRegistry,\n },\n null,\n 2,\n )}\\n`,\n );\n return;\n }\n process.stdout.write(\"Docs-backed ops (Lemon Squeezy official API only):\\n\\n\");\n for (const entry of resourceRegistry) {\n const flags = [\n entry.destructive ? \"destructive\" : undefined,\n entry.body && entry.body !== \"none\" ? `body=${entry.body}` : undefined,\n ]\n .filter(Boolean)\n .join(\", \");\n process.stdout.write(\n ` ${entry.verb.padEnd(18)} ${entry.resource.padEnd(22)} ${entry.docsPath}${flags ? ` (${flags})` : \"\"}\\n`,\n );\n }\n process.stdout.write(\n \"\\nCatalog resources (product, variant, price, file, store, …) are read-only in the API.\\n\",\n );\n};\n\ntype VerbSpec = NonNullable<ReturnType<typeof findResourceVerb>>;\n\n/**\n * Reject flag combinations that make no sense before any network call.\n *\n * @returns An error message, or undefined when the flags are consistent.\n */\nconst validateBulkFlags = (\n spec: VerbSpec,\n options: ResourceOpCommandOptions,\n): string | undefined => {\n const bulk = Boolean(options.all || options.ids);\n if (!bulk) {\n if (options.match) return \"--match needs --all.\";\n if (options.dryRun) return \"--dry-run needs --all or --ids.\";\n return undefined;\n }\n if (!supportsBulk(spec)) {\n return `--all/--ids only apply to delete, cancel, and refund ops (not ${spec.verb} ${spec.resource}).`;\n }\n if (options.all && options.ids) return \"Use either --all or --ids, not both.\";\n if (options.id) return \"--id targets one resource; drop it when using --all or --ids.\";\n if (options.match && !options.all) return \"--match needs --all.\";\n return undefined;\n};\n\n/**\n * Bulk path: resolve targets, confirm once, apply, report.\n *\n * @returns 0 when every item succeeded (or dry run), 1 on partial failure, 2 when declined.\n */\nconst runBulk = async (\n http: HttpClient,\n spec: VerbSpec,\n mode: Mode,\n options: ResourceOpCommandOptions,\n scope: { storeId?: string; body?: unknown },\n): Promise<number> => {\n const selector: BulkSelector = {\n all: options.all,\n ids: options.ids,\n match: options.match,\n storeId: scope.storeId,\n parentId: options.parentId,\n };\n const targets = await collectBulkTargets(http, spec, selector);\n\n if (!options.dryRun && targets.length > 0) {\n const allowed = await assertWriteSafety(spec, mode, options, {\n count: targets.length,\n preview: previewTargets(targets),\n });\n if (!allowed) return 2;\n }\n\n const summary = await executeBulk(http, spec, targets, {\n dryRun: options.dryRun,\n body: scope.body,\n });\n\n if (options.json) {\n const envelope = {\n ok: summary.failed === 0,\n mode,\n resource: spec.resource,\n verb: spec.verb,\n docs: `https://docs.lemonsqueezy.com/api/${spec.docsPath}`,\n ...summary,\n };\n process.stdout.write(`${JSON.stringify(envelope, null, 2)}\\n`);\n } else {\n process.stdout.write(`${spec.verb} ${spec.resource} (mode=${mode})\\n`);\n process.stdout.write(renderBulkSummary(spec, summary));\n }\n return summary.failed > 0 ? 1 : 0;\n};\n\nconst assertWriteSafety = async (\n spec: VerbSpec,\n mode: Mode,\n options: ResourceOpCommandOptions,\n bulk?: { count: number; preview: string },\n): Promise<boolean> => {\n const isWrite = spec.verb !== \"get\" && spec.verb !== \"list\" && spec.verb !== \"current-usage\";\n if (!isWrite) return true;\n\n const needsGate = Boolean(spec.destructive) || mode === \"live\";\n if (!needsGate) return true;\n\n if (options.yes) return true;\n\n if (options.isInteractive) {\n const what = bulk\n ? `${spec.verb} ${bulk.count} ${spec.resource} item(s) (${bulk.preview})`\n : `${spec.verb} ${spec.resource}`;\n return confirmResourceOp(mode === \"live\" ? `LIVE mode: allow ${what}?` : `Confirm ${what}?`);\n }\n\n process.stderr.write(\n renderCliError(\n `${spec.verb} ${spec.resource} requires --yes in non-interactive ${mode} mode${spec.destructive ? \" (destructive op)\" : \"\"}`,\n [\n `fresh-squeezy ${spec.verb} ${spec.resource}${bulk ? \" --all\" : \"\"} --yes …`,\n \"Use test mode for safer experimentation: --mode test\",\n ],\n ),\n );\n return false;\n};\n\nconst readBody = (options: ResourceOpCommandOptions): unknown | undefined => {\n // Bodies come from flags only — never auto-read stdin (would hang non-TTY pipes).\n if (options.bodyFile) {\n return JSON.parse(readFileSync(options.bodyFile, \"utf8\")) as unknown;\n }\n if (options.body !== undefined) {\n return JSON.parse(options.body) as unknown;\n }\n return undefined;\n};\n\nconst writeFatal = (err: unknown, json: boolean): void => {\n if (json) {\n const code = err instanceof FreshSqueezyError ? err.code : \"FATAL\";\n const message = err instanceof Error ? err.message : String(err);\n const status = err instanceof FreshSqueezyError ? err.status : undefined;\n process.stderr.write(\n `${JSON.stringify({ ok: false, error: { code, message, status } }, null, 2)}\\n`,\n );\n return;\n }\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(renderCliError(message, [\"fresh-squeezy ops --list\"]));\n};\n","import { FreshSqueezyError } from \"../../core/errors.js\";\nimport type { Mode, ValidationResult } from \"../../core/types.js\";\nimport { type FreshSqueezyClient, createFreshSqueezy } from \"../../createFreshSqueezy.js\";\nimport { getValidateHints, renderCliError } from \"../errors.js\";\nimport { renderResult } from \"../render.js\";\nimport { resolveStores } from \"../resolveStores.js\";\n\nexport interface ValidateCommandOptions {\n mode?: Mode;\n storeIds?: string[];\n allStores?: boolean;\n productId?: string;\n webhookUrl?: string;\n discountId?: string;\n licenseKeyId?: string;\n variantId?: string;\n json?: boolean;\n isInteractive?: boolean;\n}\n\nexport type ValidateTarget =\n | \"connection\"\n | \"store\"\n | \"product\"\n | \"webhook\"\n | \"discount\"\n | \"license-key\"\n | \"subscription-plan\";\n\n/**\n * `fresh-squeezy validate <target>` — run one validator. Store-scoped targets\n * reuse the same store resolution the `doctor` command uses, so a single\n * `--store-ids` flag or interactive pick works across every subcommand.\n *\n * Connection runs once (no stores needed). Store/webhook loop per resolved\n * store. Product runs once because a product ID identifies a single resource;\n * the `--store-ids` value (if any) is used for the cross-store ownership check.\n */\nexport const runValidateCommand = async (\n target: ValidateTarget,\n options: ValidateCommandOptions,\n): Promise<number> => {\n try {\n const client = createFreshSqueezy({ mode: options.mode });\n\n if (target === \"connection\") {\n return emit(await client.validateConnection(), options);\n }\n\n if (target === \"product\") {\n return emit(await runProduct(client, options), options);\n }\n\n if (target === \"discount\") {\n return emit(await runDiscount(client, options), options);\n }\n\n if (target === \"license-key\") {\n return emit(await runLicenseKey(client, options), options);\n }\n\n if (target === \"subscription-plan\") {\n return emit(await runSubscriptionPlan(client, options), options);\n }\n\n const storeIds = await resolveStoresForTarget(client, target, options);\n const results = await runPerStore(client, target, storeIds, options);\n\n if (options.json) {\n process.stdout.write(`${JSON.stringify(results, null, 2)}\\n`);\n } else {\n for (const result of results) {\n process.stdout.write(`${renderResult(result)}\\n\\n`);\n }\n }\n\n return results.every((result) => result.ok) ? 0 : 1;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(renderCliError(message, getValidateHints(err, target)));\n return 2;\n }\n};\n\nconst resolveStoresForTarget = async (\n client: FreshSqueezyClient,\n target: ValidateTarget,\n options: ValidateCommandOptions,\n): Promise<string[]> => {\n const resolved = await resolveStores(client, {\n storeIds: options.storeIds,\n allStores: options.allStores,\n isInteractive: options.isInteractive ?? false,\n });\n if (resolved.skipped) {\n throw new FreshSqueezyError({\n code: \"MISSING_ARG\",\n message: `--store-ids or --all-stores is required for \\`validate ${target}\\` in non-interactive mode.`,\n });\n }\n return resolved.storeIds;\n};\n\nconst runPerStore = async (\n client: FreshSqueezyClient,\n target: ValidateTarget,\n storeIds: string[],\n options: ValidateCommandOptions,\n): Promise<ValidationResult[]> => {\n if (target === \"store\") {\n return Promise.all(storeIds.map((id) => client.validateStore(id)));\n }\n if (target === \"webhook\") {\n const url = required(options.webhookUrl, \"--webhook-url is required for `validate webhook`.\");\n return Promise.all(storeIds.map((storeId) => client.validateWebhook({ storeId, url })));\n }\n return [];\n};\n\nconst runProduct = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const productId = required(options.productId, \"--product-id is required for `validate product`.\");\n const expected = options.storeIds?.[0];\n return client.validateProduct({\n productId,\n expectedStoreId: expected,\n });\n};\n\nconst runDiscount = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const discountId = required(\n options.discountId,\n \"--discount-id is required for `validate discount`.\",\n );\n const storeId = required(\n options.storeIds?.[0],\n \"--store-ids is required for `validate discount`.\",\n );\n return client.validateDiscount({ storeId, discountId });\n};\n\nconst runLicenseKey = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const licenseKeyId = required(\n options.licenseKeyId,\n \"--license-key-id is required for `validate license-key`.\",\n );\n const storeId = required(\n options.storeIds?.[0],\n \"--store-ids is required for `validate license-key`.\",\n );\n return client.validateLicenseKey({ storeId, licenseKeyId });\n};\n\nconst runSubscriptionPlan = async (\n client: FreshSqueezyClient,\n options: ValidateCommandOptions,\n): Promise<ValidationResult> => {\n const variantId = required(\n options.variantId,\n \"--variant-id is required for `validate subscription-plan`.\",\n );\n const storeId = required(\n options.storeIds?.[0],\n \"--store-ids is required for `validate subscription-plan`.\",\n );\n return client.validateSubscriptionPlan({ storeId, variantId });\n};\n\nconst emit = (result: ValidationResult, options: ValidateCommandOptions): number => {\n if (options.json) {\n process.stdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n } else {\n process.stdout.write(`${renderResult(result)}\\n`);\n }\n return result.ok ? 0 : 1;\n};\n\nconst required = <T>(value: T | undefined, message: string): T => {\n if (value === undefined || value === null || value === \"\") {\n throw new FreshSqueezyError({ code: \"MISSING_ARG\", message });\n }\n return value;\n};\n"],"mappings":"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","names":["readFileSync","input","path","userDoc","stores","values","issue","path","values","input","input","ids","values","message","path","chalk","chalk","chalk","path","values","input","chalk","fs","path","resolve","input","chalk","writeFatal","message","required","readFileSync","doctor"]}
|