diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e8c3db..3f13e42 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,6 +105,8 @@ jobs: - bun-darwin-x64 - bun-linux-arm64 - bun-linux-x64 + - bun-linux-arm64-musl + - bun-linux-x64-musl - bun-windows-x64 include: - target: bun-darwin-arm64 @@ -115,6 +117,10 @@ jobs: outfile: chargebee-cli-linux-arm64 - target: bun-linux-x64 outfile: chargebee-cli-linux-x64 + - target: bun-linux-arm64-musl + outfile: chargebee-cli-linux-arm64-musl + - target: bun-linux-x64-musl + outfile: chargebee-cli-linux-x64-musl - target: bun-windows-x64 outfile: chargebee-cli-windows-x64.exe diff --git a/.github/workflows/install-smoke.yml b/.github/workflows/install-smoke.yml index 8dee5e9..31a631c 100644 --- a/.github/workflows/install-smoke.yml +++ b/.github/workflows/install-smoke.yml @@ -24,6 +24,34 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: + alpine-install: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: "1.4.2" + + - run: bun install --frozen-lockfile + + - name: Build and install the musl binary on Alpine + run: | + bun run build --target=bun-linux-x64-musl + docker run --rm -v "$PWD:/work" -w /work alpine:3.20 sh -c ' + set -eu + apk add --no-cache bash libstdc++ libgcc + export CI=1 CHARGEBEE_CLI_NO_ONBOARDING=1 + export CHARGEBEE_CLI_INSTALL_FILE=/work/dist/chargebee-cli-linux-x64-musl + export CHARGEBEE_CLI_BIN_DIR=/tmp/cb-bin CHARGEBEE_CONFIG_DIR=/tmp/cb-config + bash install.sh + export PATH=/tmp/cb-bin:$PATH + bash scripts/install-smoke-assert.sh + test "$(cat /tmp/cb-config/install-method)" = github + ' + github-install: strategy: fail-fast: false @@ -32,6 +60,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: @@ -72,6 +102,8 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: @@ -114,6 +146,8 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: @@ -148,12 +182,13 @@ jobs: required-checks: name: Install required checks if: ${{ always() }} - needs: [github-install, npm-install, windows-install] + needs: [alpine-install, github-install, npm-install, windows-install] runs-on: ubuntu-latest steps: - name: Verify required job results env: GITHUB_INSTALL_RESULT: ${{ needs.github-install.result }} + ALPINE_INSTALL_RESULT: ${{ needs.alpine-install.result }} NPM_INSTALL_RESULT: ${{ needs.npm-install.result }} WINDOWS_INSTALL_RESULT: ${{ needs.windows-install.result }} run: | @@ -165,5 +200,6 @@ jobs: fi } require_result github-install "$GITHUB_INSTALL_RESULT" success + require_result alpine-install "$ALPINE_INSTALL_RESULT" success require_result npm-install "$NPM_INSTALL_RESULT" success require_result windows-install "$WINDOWS_INSTALL_RESULT" success diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 2f08549..58f8938 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -75,6 +75,8 @@ jobs: - bun-darwin-x64 - bun-linux-arm64 - bun-linux-x64 + - bun-linux-arm64-musl + - bun-linux-x64-musl - bun-windows-x64 include: - target: bun-darwin-arm64 @@ -85,6 +87,10 @@ jobs: outfile: chargebee-cli-linux-arm64 - target: bun-linux-x64 outfile: chargebee-cli-linux-x64 + - target: bun-linux-arm64-musl + outfile: chargebee-cli-linux-arm64-musl + - target: bun-linux-x64-musl + outfile: chargebee-cli-linux-x64-musl - target: bun-windows-x64 outfile: chargebee-cli-windows-x64.exe steps: diff --git a/README.md b/README.md index 9751817..5011c29 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ The Chargebee CLI is available for macOS, Linux, and Windows. curl -fsSL https://raw.githubusercontent.com/chargebee/cli/main/install.sh | bash ``` +On musl-based Linux distributions, install the `libstdc++` and `libgcc` runtime libraries with your package manager first. On Alpine, run `apk add --no-cache libstdc++ libgcc`. The installer selects the musl build automatically; glibc-based distributions use the standard Linux build. + The installer can also add the Chargebee skill for detected coding agents. To choose agents manually, decline the prompt and run: ```bash diff --git a/install.sh b/install.sh index b2fb96e..df8729a 100755 --- a/install.sh +++ b/install.sh @@ -186,7 +186,37 @@ main() { mkdir -p "$BIN_DIR" fi - local ASSET="chargebee-cli-${OS}-${ARCH}" + local LIBC_SUFFIX="" + if [[ "$OS" == "linux" ]]; then + local LIBC="${CHARGEBEE_CLI_LIBC:-}" + if [[ -z "$LIBC" ]]; then + local LDD_VERSION + LDD_VERSION=$(ldd --version 2>&1 || true) + if echo "$LDD_VERSION" | grep -qi musl; then + LIBC="musl" + elif echo "$LDD_VERSION" | grep -Eqi 'glibc|GNU C Library|GNU libc'; then + LIBC="glibc" + elif ls /lib/ld-musl-*.so.1 >/dev/null 2>&1; then + LIBC="musl" + else + LIBC="glibc" + fi + fi + case "$LIBC" in + musl) + LIBC_SUFFIX="-musl" + if [[ -z "$(find /lib /usr/lib -name 'libstdc++.so.6' -print -quit 2>/dev/null)" ]] || + [[ -z "$(find /lib /usr/lib -name 'libgcc_s.so.1' -print -quit 2>/dev/null)" ]]; then + echo "The Chargebee CLI needs libstdc++ and libgcc on musl Linux." >&2 + echo "On Alpine, run: apk add --no-cache libstdc++ libgcc" >&2 + exit 1 + fi + ;; + glibc) ;; + *) echo "Error: CHARGEBEE_CLI_LIBC must be musl or glibc" >&2; exit 1 ;; + esac + fi + local ASSET="chargebee-cli-${OS}-${ARCH}${LIBC_SUFFIX}" # Show current version if already installed local PREV_VERSION="" @@ -254,8 +284,20 @@ main() { verify_checksum "$TMP" "$ASSET" "$SUMS_URL" fi - chmod 0755 "$TMP" - mv "$TMP" "$BIN_DIR/$BIN_NAME" + # Probe the candidate from the destination filesystem before replacing an + # existing installation. A downloaded binary can have a valid checksum yet + # fail to start on this host (for example, a libc mismatch). + local STAGED NEW_VERSION + STAGED=$(mktemp "$BIN_DIR/.chargebee.XXXXXX") + trap 'rm -f "$TMP" "${STAGED:-}"' EXIT + cp "$TMP" "$STAGED" + chmod 0755 "$STAGED" + if ! NEW_VERSION=$("$STAGED" --version 2>/dev/null) || [[ -z "${NEW_VERSION//[[:space:]]/}" ]]; then + echo "Error: downloaded $ASSET cannot start on this system" >&2 + exit 1 + fi + NEW_VERSION=${NEW_VERSION%%$'\n'*} + mv -f "$STAGED" "$BIN_DIR/$BIN_NAME" local TARGET_HOME TARGET_HOME=$(target_home) @@ -273,13 +315,10 @@ main() { (mkdir -p -m 0700 "$MARKER_DIR" && printf 'github\n' > "$MARKER_DIR/install-method") || true own_as_target_user "$MARKER_ROOT" - local NEW_VERSION - NEW_VERSION=$("$BIN_DIR/$BIN_NAME" --version 2>/dev/null | head -1 || true) - if [[ -n "$PREV_VERSION" ]]; then - echo "Updated: ${PREV_VERSION} → ${NEW_VERSION:-done}" + echo "Updated: ${PREV_VERSION} → ${NEW_VERSION}" else - echo "Installed: ${NEW_VERSION:-chargebee} → $BIN_DIR/$BIN_NAME" + echo "Installed: ${NEW_VERSION} → $BIN_DIR/$BIN_NAME" fi # Warn if BIN_DIR isn't in PATH diff --git a/src/commands/docs.ts b/src/commands/docs.ts index 92a2bd5..f27e9b2 100644 --- a/src/commands/docs.ts +++ b/src/commands/docs.ts @@ -55,6 +55,10 @@ export function registerDocsCommand(program: Command): void { if (!op.ok) { if (op.reason === "offline") { diagnostic(OFFLINE_MSG); + } else if (op.reason === "ambiguous") { + diagnostic( + `Multiple documentation pages match "${resource} ${operation}": ${op.matches?.join(", ")}. Use an exact Docs slug.` + ); } else if (op.operations) { diagnostic( `Unknown operation "${operation}" for resource "${resource}". Available: ${formatOpHint(op.operations)}` diff --git a/src/commands/generated/alert.ts b/src/commands/generated/alert.ts index 07a6c2c..4816281 100644 --- a/src/commands/generated/alert.ts +++ b/src/commands/generated/alert.ts @@ -17,18 +17,19 @@ export function registerAlert(parent: Command): void { .description("API operations for alerts"); cmd - .command("application_alerts-for-subscription") + .command("application-alerts-for-subscription") + .alias("application_alerts-for-subscription") .argument("[subscription-id]", "The unique identifier of the subscription resource.") .argument("[json]", "'-' reads a JSON object from stdin.") .description("List applicable alerts for a subscription") .option("-d, --data ", "Request parameters in key=value format; repeat for multiple fields") .option("-s, --code-sample ", "Generate code sample (curl, python, nodejs, go, ruby, java, php, dotnet, list)") .addOption(new Option("--pc-version ", "Product catalog version for the code sample (v1 or v2)").hideHelp()) - .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs alert application_alerts-for-subscription\n") + .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs alert application-alerts-for-subscription\n") .action(async (id: string | undefined, json: string | undefined, opts: { data?: string[]; codeSample?: string; pcVersion?: string }, command: Command) => { const resource = takeResourceId(id, json, command); const params = await loadOperationParams(opts.data ?? [], resource.fromStdin, command, { method: "GET", jsonInput: false, opIdV2: "list_applicable_alerts_for_a_subscription", opIdV1: "", pcVersionFlag: opts.pcVersion }); - if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "alert application_alerts-for-subscription"); + if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "alert application-alerts-for-subscription"); if (opts.codeSample) return handleCodeSample({ lang: opts.codeSample, opIdV2: "list_applicable_alerts_for_a_subscription", opIdV1: "", method: "GET", uri: "/subscriptions/{id}/applicable_alerts", dataFlags: opts.data ?? [], params, resourceId: resource.id, pathParamName: "subscription-id", pcVersionFlag: opts.pcVersion }); if (!resource.id) command.error("error: missing required argument 'subscription-id'"); assertResourceId(resource.id, command); diff --git a/src/commands/generated/alert_status.ts b/src/commands/generated/alert_status.ts index 6b17d46..3235dd0 100644 --- a/src/commands/generated/alert_status.ts +++ b/src/commands/generated/alert_status.ts @@ -17,18 +17,19 @@ export function registerAlertStatus(parent: Command): void { .description("API operations for alert statuses"); cmd - .command("alert_statuses-for-alert") + .command("alert-statuses-for-alert") + .alias("alert_statuses-for-alert") .argument("[alert-id]", "Uniquely identifies the alert configuration.") .argument("[json]", "'-' reads a JSON object from stdin.") .description("List alert statuses for an alert") .option("-d, --data ", "Request parameters in key=value format; repeat for multiple fields") .option("-s, --code-sample ", "Generate code sample (curl, python, nodejs, go, ruby, java, php, dotnet, list)") .addOption(new Option("--pc-version ", "Product catalog version for the code sample (v1 or v2)").hideHelp()) - .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs alert-status alert_statuses-for-alert\n") + .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs alert-status alert-statuses-for-alert\n") .action(async (id: string | undefined, json: string | undefined, opts: { data?: string[]; codeSample?: string; pcVersion?: string }, command: Command) => { const resource = takeResourceId(id, json, command); const params = await loadOperationParams(opts.data ?? [], resource.fromStdin, command, { method: "GET", jsonInput: false, opIdV2: "list_alert_statuses_for_an_alert", opIdV1: "", pcVersionFlag: opts.pcVersion }); - if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "alert-status alert_statuses-for-alert"); + if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "alert-status alert-statuses-for-alert"); if (opts.codeSample) return handleCodeSample({ lang: opts.codeSample, opIdV2: "list_alert_statuses_for_an_alert", opIdV1: "", method: "GET", uri: "/alerts/{id}/alert_statuses", dataFlags: opts.data ?? [], params, resourceId: resource.id, pathParamName: "alert-id", pcVersionFlag: opts.pcVersion }); if (!resource.id) command.error("error: missing required argument 'alert-id'"); assertResourceId(resource.id, command); @@ -40,18 +41,19 @@ export function registerAlertStatus(parent: Command): void { }); cmd - .command("alert_statuses-for-subscription") + .command("alert-statuses-for-subscription") + .alias("alert_statuses-for-subscription") .argument("[subscription-id]", "The unique identifier of the subscription resource.") .argument("[json]", "'-' reads a JSON object from stdin.") .description("List alert statuses for a subscription") .option("-d, --data ", "Request parameters in key=value format; repeat for multiple fields") .option("-s, --code-sample ", "Generate code sample (curl, python, nodejs, go, ruby, java, php, dotnet, list)") .addOption(new Option("--pc-version ", "Product catalog version for the code sample (v1 or v2)").hideHelp()) - .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs alert-status alert_statuses-for-subscription\n") + .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs alert-status alert-statuses-for-subscription\n") .action(async (id: string | undefined, json: string | undefined, opts: { data?: string[]; codeSample?: string; pcVersion?: string }, command: Command) => { const resource = takeResourceId(id, json, command); const params = await loadOperationParams(opts.data ?? [], resource.fromStdin, command, { method: "GET", jsonInput: false, opIdV2: "list_alert_statuses_for_a_subscription", opIdV1: "", pcVersionFlag: opts.pcVersion }); - if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "alert-status alert_statuses-for-subscription"); + if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "alert-status alert-statuses-for-subscription"); if (opts.codeSample) return handleCodeSample({ lang: opts.codeSample, opIdV2: "list_alert_statuses_for_a_subscription", opIdV1: "", method: "GET", uri: "/subscriptions/{id}/alert_statuses", dataFlags: opts.data ?? [], params, resourceId: resource.id, pathParamName: "subscription-id", pcVersionFlag: opts.pcVersion }); if (!resource.id) command.error("error: missing required argument 'subscription-id'"); assertResourceId(resource.id, command); diff --git a/src/commands/generated/docs-operations.ts b/src/commands/generated/docs-operations.ts new file mode 100644 index 0000000..a2fec66 --- /dev/null +++ b/src/commands/generated/docs-operations.ts @@ -0,0 +1,2201 @@ +// Code generated by src/tools/generate.ts from Chargebee SDK endpoints and public OpenAPI specs. DO NOT EDIT. +// Regenerate with: bun run generate + +export const docsOperationIds: Record> = { + "addon": { + "copy": { + "v1": "copy_an_addon", + "v2": "" + }, + "create": { + "v1": "create_an_addon", + "v2": "" + }, + "delete": { + "v1": "delete_an_addon", + "v2": "" + }, + "list": { + "v1": "list_addons", + "v2": "" + }, + "retrieve": { + "v1": "retrieve_an_addon", + "v2": "" + }, + "unarchive": { + "v1": "unarchive_an_addon", + "v2": "" + }, + "update": { + "v1": "update_an_addon", + "v2": "" + } + }, + "address": { + "retrieve": { + "v1": "retrieve_an_address", + "v2": "retrieve_an_address" + }, + "update": { + "v1": "update_an_address", + "v2": "update_an_address" + } + }, + "alert": { + "application-alerts-for-subscription": { + "v1": "", + "v2": "list_applicable_alerts_for_a_subscription" + }, + "application_alerts-for-subscription": { + "v1": "", + "v2": "list_applicable_alerts_for_a_subscription" + }, + "create": { + "v1": "", + "v2": "create_an_alert" + }, + "delete": { + "v1": "", + "v2": "delete_an_alert" + }, + "list": { + "v1": "", + "v2": "list_alerts" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_an_alert" + }, + "update": { + "v1": "", + "v2": "update_an_alert" + } + }, + "alert-status": { + "alert-statuses-for-alert": { + "v1": "", + "v2": "list_alert_statuses_for_an_alert" + }, + "alert_statuses-for-alert": { + "v1": "", + "v2": "list_alert_statuses_for_an_alert" + }, + "alert-statuses-for-subscription": { + "v1": "", + "v2": "list_alert_statuses_for_a_subscription" + }, + "alert_statuses-for-subscription": { + "v1": "", + "v2": "list_alert_statuses_for_a_subscription" + } + }, + "attached-item": { + "create": { + "v1": "", + "v2": "create_an_attached_item" + }, + "delete": { + "v1": "", + "v2": "delete_an_attached_item" + }, + "list": { + "v1": "", + "v2": "list_attached_items" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_an_attached_item_" + }, + "update": { + "v1": "", + "v2": "update_an_attached_item" + } + }, + "business-entity": { + "create-transfers": { + "v1": "", + "v2": "transfer_resources_to_another_business_entity" + }, + "get-transfers": { + "v1": "", + "v2": "list_the_business_entity_transfers" + } + }, + "business-rule": { + "activate-rule": { + "v1": "", + "v2": "activate_a_business_rule" + }, + "apply-rules": { + "v1": "", + "v2": "apply_business_rules" + }, + "create": { + "v1": "", + "v2": "create_a_business_rule" + }, + "deactivate-rule": { + "v1": "", + "v2": "deactivate_a_business_rule" + }, + "delete": { + "v1": "", + "v2": "delete_a_business_rule" + }, + "delete-draft": { + "v1": "", + "v2": "delete_a_business_rule_draft" + }, + "list": { + "v1": "", + "v2": "list_business_rules" + }, + "release-rule": { + "v1": "", + "v2": "release_a_business_rule" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_business_rule" + }, + "retrieve-draft": { + "v1": "", + "v2": "retrieve_a_business_rule_draft" + }, + "update-draft": { + "v1": "", + "v2": "update_a_business_rule_draft" + } + }, + "business-ruleset": { + "activate": { + "v1": "", + "v2": "activate_a_business_ruleset" + }, + "add-rules": { + "v1": "", + "v2": "add_business_rules_to_a_ruleset" + }, + "create": { + "v1": "", + "v2": "create_a_business_ruleset" + }, + "deactivate": { + "v1": "", + "v2": "deactivate_a_business_ruleset" + }, + "delete": { + "v1": "", + "v2": "delete_a_business_ruleset" + }, + "list": { + "v1": "", + "v2": "list_business_rulesets" + }, + "list-rules": { + "v1": "", + "v2": "list_rules_in_a_business_ruleset" + }, + "remove-rules": { + "v1": "", + "v2": "remove_business_rules_from_a_ruleset" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_business_ruleset" + }, + "update": { + "v1": "", + "v2": "update_a_business_ruleset" + } + }, + "card": { + "copy-card-for-customer": { + "v1": "copy_card", + "v2": "copy_card" + }, + "delete-card-for-customer": { + "v1": "delete_card_for_a_customer", + "v2": "delete_card_for_a_customer" + }, + "retrieve": { + "v1": "retrieve_card_for_a_customer", + "v2": "retrieve_card_for_a_customer" + }, + "switch-gateway-for-customer": { + "v1": "switch_gateway", + "v2": "switch_gateway" + }, + "update-card-for-customer": { + "v1": "update_card_for_a_customer", + "v2": "update_card_for_a_customer" + } + }, + "comment": { + "create": { + "v1": "create_a_comment", + "v2": "create_a_comment" + }, + "delete": { + "v1": "delete_a_comment", + "v2": "delete_a_comment" + }, + "list": { + "v1": "list_comments", + "v2": "list_comments" + }, + "retrieve": { + "v1": "retrieve_a_comment", + "v2": "retrieve_a_comment" + } + }, + "configuration": { + "list": { + "v1": "list_site_configurations", + "v2": "list_site_configurations" + } + }, + "coupon": { + "copy": { + "v1": "copy_a_coupon", + "v2": "copy_a_coupon" + }, + "create": { + "v1": "create_a_coupon", + "v2": "" + }, + "create-for-items": { + "v1": "", + "v2": "create_a_coupon_for_items" + }, + "delete": { + "v1": "delete_a_coupon", + "v2": "delete_a_coupon" + }, + "list": { + "v1": "list_coupons", + "v2": "list_coupons" + }, + "retrieve": { + "v1": "retrieve_a_coupon", + "v2": "retrieve_a_coupon" + }, + "unarchive": { + "v1": "unarchive_a_coupon", + "v2": "unarchive_a_coupon" + }, + "update": { + "v1": "update_a_coupon", + "v2": "" + }, + "update-for-items": { + "v1": "", + "v2": "update_a_coupon_for_items" + } + }, + "coupon-code": { + "archive": { + "v1": "archive_a_coupon_code", + "v2": "archive_a_coupon_code" + }, + "create": { + "v1": "", + "v2": "" + }, + "list": { + "v1": "list_coupon_codes", + "v2": "list_coupon_codes" + }, + "retrieve": { + "v1": "retrieve_a_coupon_code", + "v2": "retrieve_a_coupon_code" + } + }, + "coupon-set": { + "add-coupon-codes": { + "v1": "add_coupon_codes_to_coupon_set", + "v2": "add_coupon_codes_to_coupon_set" + }, + "create": { + "v1": "create_a_coupon_set", + "v2": "create_a_coupon_set" + }, + "delete": { + "v1": "delete_a_coupon_set", + "v2": "delete_a_coupon_set" + }, + "delete-unused-coupon-codes": { + "v1": "delete_unused_coupon_codes", + "v2": "delete_unused_coupon_codes" + }, + "list": { + "v1": "list_coupon_sets", + "v2": "list_coupon_sets" + }, + "retrieve": { + "v1": "retrieve_a_coupon_set", + "v2": "retrieve_a_coupon_set" + }, + "update": { + "v1": "update_a_coupon_set", + "v2": "update_a_coupon_set" + } + }, + "credit-note": { + "create": { + "v1": "create_credit_note", + "v2": "create_credit_note" + }, + "credit-notes-for-customer": { + "v1": "", + "v2": "" + }, + "delete": { + "v1": "delete_a_credit_note", + "v2": "delete_a_credit_note" + }, + "download-einvoice": { + "v1": "download_e-invoice_for_credit_note", + "v2": "download_e-invoice_for_credit_note" + }, + "import-credit-note": { + "v1": "import_credit_note", + "v2": "import_credit_note" + }, + "list": { + "v1": "list_credit_notes", + "v2": "list_credit_notes" + }, + "pdf": { + "v1": "retrieve_credit_note_as_pdf", + "v2": "retrieve_credit_note_as_pdf" + }, + "record-refund": { + "v1": "record_refund_for_a_credit_note", + "v2": "record_refund_for_a_credit_note" + }, + "refund": { + "v1": "refund_a_credit_note", + "v2": "refund_a_credit_note" + }, + "remove-tax-withheld-refund": { + "v1": "remove_tax_withheld_refunds_from_a_credit_note", + "v2": "remove_tax_withheld_refunds_from_a_credit_note" + }, + "resend-einvoice": { + "v1": "resend_failed_einvoice_in_credit_notes", + "v2": "resend_failed_einvoice_in_credit_notes" + }, + "retrieve": { + "v1": "retrieve_a_credit_note", + "v2": "retrieve_a_credit_note" + }, + "send-einvoice": { + "v1": "send_an_einvoice_for_credit_notes", + "v2": "send_an_einvoice_for_credit_notes" + }, + "send-email": { + "v1": "send_credit_note_email", + "v2": "send_credit_note_email" + }, + "update": { + "v1": "update_credit_note_details", + "v2": "update_credit_note_details" + }, + "void-credit-note": { + "v1": "void_a_credit_note", + "v2": "void_a_credit_note" + } + }, + "credit-unit": { + "archive": { + "v1": "", + "v2": "archive_a_credit_unit" + }, + "create": { + "v1": "", + "v2": "create_a_credit_unit" + }, + "list": { + "v1": "", + "v2": "list_credit_units" + }, + "reactivate": { + "v1": "", + "v2": "reactivate_a_credit_unit" + }, + "update": { + "v1": "", + "v2": "update_a_credit_unit" + } + }, + "currency": { + "add-schedule": { + "v1": "add_schedule", + "v2": "add_schedule" + }, + "create": { + "v1": "add_a_new_currency", + "v2": "add_a_new_currency" + }, + "list": { + "v1": "list_currencies", + "v2": "list_currencies" + }, + "remove-schedule": { + "v1": "remove_schedule", + "v2": "remove_schedule" + }, + "retrieve": { + "v1": "retrieve_a_currency", + "v2": "retrieve_a_currency" + }, + "update": { + "v1": "update_a_currency", + "v2": "update_a_currency" + } + }, + "customer": { + "add-contact": { + "v1": "add_contacts_to_a_customer", + "v2": "add_contacts_to_a_customer" + }, + "add-promotional-credits": { + "v1": "", + "v2": "" + }, + "assign-payment-role": { + "v1": "assign_payment_role", + "v2": "assign_payment_role" + }, + "change-billing-date": { + "v1": "change_billing_date", + "v2": "change_billing_date" + }, + "clear-personal-data": { + "v1": "clear_personal_data_of_a_customer", + "v2": "clear_personal_data_of_a_customer" + }, + "collect-payment": { + "v1": "collect_payment_for_customer", + "v2": "collect_payment_for_customer" + }, + "contacts-for-customer": { + "v1": "list_of_contacts_for_a_customer", + "v2": "list_of_contacts_for_a_customer" + }, + "create": { + "v1": "create_a_customer", + "v2": "create_a_customer" + }, + "deduct-promotional-credits": { + "v1": "", + "v2": "" + }, + "delete": { + "v1": "delete_a_customer", + "v2": "delete_a_customer" + }, + "delete-contact": { + "v1": "delete_contacts_for_a_customer", + "v2": "delete_contacts_for_a_customer" + }, + "delete-relationship": { + "v1": "delink_a_customer", + "v2": "delink_a_customer" + }, + "hierarchy": { + "v1": "get_hierarchy", + "v2": "get_hierarchy" + }, + "list": { + "v1": "list_customers", + "v2": "list_customers" + }, + "list-hierarchy-detail": { + "v1": "list_hierarchy_details", + "v2": "list_hierarchy_details" + }, + "merge": { + "v1": "merge_customers", + "v2": "merge_customers" + }, + "move": { + "v1": "move_a_customer", + "v2": "move_a_customer" + }, + "record-excess-payment": { + "v1": "record_an_excess_payment_for_a_customer", + "v2": "record_an_excess_payment_for_a_customer" + }, + "relationships": { + "v1": "link_a_customer", + "v2": "link_a_customer" + }, + "retrieve": { + "v1": "retrieve_a_customer", + "v2": "retrieve_a_customer" + }, + "send-payment-request": { + "v1": "send_payment_request_email", + "v2": "send_payment_request_email" + }, + "set-promotional-credits": { + "v1": "", + "v2": "" + }, + "update": { + "v1": "update_a_customer", + "v2": "update_a_customer" + }, + "update-billing-info": { + "v1": "update_billing_info_for_a_customer", + "v2": "update_billing_info_for_a_customer" + }, + "update-contact": { + "v1": "update_contacts_for_a_customer", + "v2": "update_contacts_for_a_customer" + }, + "update-hierarchy-settings": { + "v1": "update_hierarchy_access_settings_for_a_customer", + "v2": "update_hierarchy_access_settings_for_a_customer" + }, + "update-payment-method": { + "v1": "update_payment_method_for_a_customer", + "v2": "update_payment_method_for_a_customer" + } + }, + "customer-entitlement": { + "entitlements-for-customer": { + "v1": "", + "v2": "list_customer_entitlements" + } + }, + "differential-price": { + "create": { + "v1": "", + "v2": "create_a_differential_price" + }, + "delete": { + "v1": "", + "v2": "delete_a_differential_price" + }, + "list": { + "v1": "", + "v2": "list_differential_prices" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_differential_price" + }, + "update": { + "v1": "", + "v2": "update_a_differential_price" + } + }, + "dispute": { + "list": { + "v1": "list_disputes", + "v2": "list_disputes" + }, + "retrieve": { + "v1": "retrieve_a_dispute", + "v2": "retrieve_a_dispute" + } + }, + "einvoice": { + "list-einvoices": { + "v1": "list_e-invoices", + "v2": "list_e-invoices" + }, + "retrieve": { + "v1": "retrieve_an_e-invoice", + "v2": "retrieve_an_e-invoice" + } + }, + "email-log": { + "email-logs-for-customer": { + "v1": "list_email_logs_for_a_customer", + "v2": "list_email_logs_for_a_customer" + } + }, + "entitlement": { + "create": { + "v1": "", + "v2": "upsert_or_remove_entitlements_for_a_feature" + }, + "list": { + "v1": "", + "v2": "list_all_entitlements" + } + }, + "entitlement-override": { + "add-entitlement-override-for-subscription": { + "v1": "", + "v2": "upsert_or_remove_entitlement_overrides_for_a_subscription" + }, + "list-entitlement-override-for-subscription": { + "v1": "", + "v2": "list_entitlement_overrides_for_a_subscription" + } + }, + "estimate": { + "advance-invoice-estimate": { + "v1": "advance_invoice_estimate", + "v2": "advance_invoice_estimate" + }, + "cancel-subscription": { + "v1": "cancel_subscription_estimate", + "v2": "" + }, + "cancel-subscription-for-items": { + "v1": "", + "v2": "cancel_subscription_for_items_estimate" + }, + "change-term-end": { + "v1": "subscription_change_term_end_estimate", + "v2": "subscription_change_term_end_estimate" + }, + "create-invoice": { + "v1": "create_invoice_estimate", + "v2": "" + }, + "create-invoice-for-items": { + "v1": "", + "v2": "create_invoice_for_items_estimate" + }, + "create-sub-for-customer-estimate": { + "v1": "create_subscription_for_a_customer_estimate", + "v2": "" + }, + "create-sub-item-estimate": { + "v1": "", + "v2": "estimate_for_creating_a_customer_and_subscription" + }, + "create-sub-item-for-customer-estimate": { + "v1": "", + "v2": "estimate_for_creating_a_subscription" + }, + "create-subscription": { + "v1": "create_subscription_estimate", + "v2": "" + }, + "gift-subscription": { + "v1": "gift_subscription_estimate", + "v2": "" + }, + "gift-subscription-for-items": { + "v1": "", + "v2": "gift_subscription_estimate_for_items" + }, + "pause-subscription": { + "v1": "pause_subscription_estimate", + "v2": "pause_subscription_estimate" + }, + "payment-schedules": { + "v1": "", + "v2": "estimates_for_payment_schedules" + }, + "regenerate-invoice-estimate": { + "v1": "regenerate_invoice_estimate", + "v2": "regenerate_invoice_estimate" + }, + "renewal-estimate": { + "v1": "subscription_renewal_estimate", + "v2": "subscription_renewal_estimate" + }, + "resume-subscription": { + "v1": "resume_subscription_estimate", + "v2": "resume_subscription_estimate" + }, + "upcoming-invoices-estimate": { + "v1": "upcoming_invoices_estimate", + "v2": "upcoming_invoices_estimate" + }, + "update-subscription": { + "v1": "update_subscription_estimate", + "v2": "" + }, + "update-subscription-for-items": { + "v1": "", + "v2": "estimate_for_updating_a_subscription" + } + }, + "event": { + "list": { + "v1": "list_events", + "v2": "list_events" + }, + "retrieve": { + "v1": "retrieve_an_event", + "v2": "retrieve_an_event" + } + }, + "export": { + "addons": { + "v1": "export_addons", + "v2": "" + }, + "attached-items": { + "v1": "", + "v2": "export_attached_items" + }, + "coupons": { + "v1": "export_coupons", + "v2": "export_coupons" + }, + "credit-notes": { + "v1": "export_credit_notes", + "v2": "export_credit_notes" + }, + "customers": { + "v1": "export_customers", + "v2": "export_customers" + }, + "deferred-revenue": { + "v1": "export_deferred_revenue_reports", + "v2": "export_deferred_revenue_reports" + }, + "differential-prices": { + "v1": "", + "v2": "export_differential_price" + }, + "invoices": { + "v1": "export_invoices", + "v2": "export_invoices" + }, + "item-families": { + "v1": "", + "v2": "export_item_families" + }, + "item-prices": { + "v1": "", + "v2": "export_item_prices" + }, + "items": { + "v1": "", + "v2": "export_items" + }, + "orders": { + "v1": "export_orders", + "v2": "export_orders" + }, + "plans": { + "v1": "export_plans", + "v2": "" + }, + "price-variants": { + "v1": "", + "v2": "export_price_variants" + }, + "ramps": { + "v1": "", + "v2": "export_subscription_ramps" + }, + "retrieve": { + "v1": "retrieve_an_export", + "v2": "retrieve_an_export" + }, + "revenue-recognition": { + "v1": "export_revenue_recognition_reports", + "v2": "export_revenue_recognition_reports" + }, + "subscriptions": { + "v1": "export_subscriptions", + "v2": "export_subscriptions" + }, + "transactions": { + "v1": "export_transactions", + "v2": "export_transactions" + } + }, + "feature": { + "activate": { + "v1": "", + "v2": "activate_a_feature" + }, + "archive": { + "v1": "", + "v2": "archive_a_feature" + }, + "create": { + "v1": "", + "v2": "create_a_feature" + }, + "delete": { + "v1": "", + "v2": "delete_a_feature" + }, + "list": { + "v1": "", + "v2": "list_features" + }, + "reactivate": { + "v1": "", + "v2": "reactivate_a_feature" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_feature" + }, + "update": { + "v1": "", + "v2": "update_a_feature" + } + }, + "gift": { + "cancel": { + "v1": "cancel_a_gift", + "v2": "cancel_a_gift" + }, + "claim": { + "v1": "claim_a_gift", + "v2": "claim_a_gift" + }, + "create": { + "v1": "create_a_gift", + "v2": "" + }, + "create-for-items": { + "v1": "", + "v2": "create_a_gift_subscription_for_items" + }, + "list": { + "v1": "list_gifts", + "v2": "list_gifts" + }, + "retrieve": { + "v1": "retrieve_a_gift", + "v2": "retrieve_a_gift" + }, + "update-gift": { + "v1": "update_a_gift", + "v2": "update_a_gift" + } + }, + "grant-block": { + "list-grant-blocks": { + "v1": "list_grant_blocks", + "v2": "list_grant_blocks" + } + }, + "hosted-page": { + "accept-quote": { + "v1": "accept_a_quote", + "v2": "accept_a_quote" + }, + "acknowledge": { + "v1": "acknowledge_a_hosted_page", + "v2": "acknowledge_a_hosted_page" + }, + "checkout-existing": { + "v1": "checkout_existing_subscription", + "v2": "" + }, + "checkout-existing-for-items": { + "v1": "", + "v2": "create_checkout_to_update_a_subscription" + }, + "checkout-gift": { + "v1": "checkout_gift_subscription", + "v2": "" + }, + "checkout-gift-for-items": { + "v1": "", + "v2": "checkout_gift_subscription_for_items" + }, + "checkout-new": { + "v1": "checkout_new_subscription", + "v2": "" + }, + "checkout-new-for-items": { + "v1": "", + "v2": "create_checkout_for_a_new_subscription" + }, + "checkout-one-time": { + "v1": "checkout_one-time_payments", + "v2": "" + }, + "checkout-one-time-for-items": { + "v1": "", + "v2": "checkout_charge-items_and_one-time_charges" + }, + "claim-gift": { + "v1": "claim_a_gift_subscription", + "v2": "claim_a_gift_subscription" + }, + "collect-now": { + "v1": "collect_now", + "v2": "collect_now" + }, + "events": { + "v1": "notify_an_event", + "v2": "notify_an_event" + }, + "extend-subscription": { + "v1": "extend_subscription", + "v2": "extend_subscription" + }, + "list": { + "v1": "list_hosted_pages", + "v2": "list_hosted_pages" + }, + "manage-payment-sources": { + "v1": "manage_payment_sources", + "v2": "manage_payment_sources" + }, + "pre-cancel": { + "v1": "create_a_pre-cancel_hosted_page", + "v2": "create_a_pre-cancel_hosted_page" + }, + "retrieve": { + "v1": "retrieve_a_hosted_page", + "v2": "retrieve_a_hosted_page" + }, + "retrieve-agreement-pdf": { + "v1": "retrieve_direct_debit_agreement_pdf", + "v2": "retrieve_direct_debit_agreement_pdf" + }, + "update-card": { + "v1": "", + "v2": "" + }, + "update-payment-method": { + "v1": "", + "v2": "" + }, + "view-voucher": { + "v1": "create_a_hosted_page_to_view_boleto_vouchers", + "v2": "create_a_hosted_page_to_view_boleto_vouchers" + } + }, + "in-app-subscription": { + "import-receipt": { + "v1": "import_receipt", + "v2": "import_receipt" + }, + "import-subscription": { + "v1": "import_subscription_without_receipt", + "v2": "import_subscription_without_receipt" + }, + "process-receipt": { + "v1": "process_purchase_command", + "v2": "process_purchase_command" + }, + "retrieve-store-subs": { + "v1": "retrieve_store_subscription", + "v2": "retrieve_store_subscription" + } + }, + "invoice": { + "add-addon-charge": { + "v1": "add_non-recurring_addon_to_a_pending_invoice", + "v2": "" + }, + "add-charge": { + "v1": "add_one-time_charge_to_a_pending_invoice", + "v2": "add_one-time_charge_to_a_pending_invoice" + }, + "add-charge-item": { + "v1": "", + "v2": "add_a_charge-item_to_a_pending_invoice" + }, + "apply-credits": { + "v1": "apply_credits_for_an_invoice", + "v2": "apply_credits_for_an_invoice" + }, + "apply-payments": { + "v1": "apply_payments_for_an_invoice", + "v2": "apply_payments_for_an_invoice" + }, + "apply-payment-schedule-scheme": { + "v1": "", + "v2": "apply_payment_schedule_scheme_to_an_invoice" + }, + "charge": { + "v1": "create_invoice_for_a_one-time_charge", + "v2": "" + }, + "charge-addon": { + "v1": "create_invoice_for_a_non-recurring_addon", + "v2": "" + }, + "close": { + "v1": "close_a_pending_invoice", + "v2": "close_a_pending_invoice" + }, + "collect-payment": { + "v1": "collect_payment_for_an_invoice", + "v2": "collect_payment_for_an_invoice" + }, + "create": { + "v1": "create_an_invoice", + "v2": "" + }, + "create-for-charge-item": { + "v1": "", + "v2": "" + }, + "create-for-charge-items-and-charges": { + "v1": "", + "v2": "create_invoice_for_items_and_one-time_charges" + }, + "delete": { + "v1": "delete_an_invoice", + "v2": "delete_an_invoice" + }, + "delete-line-items": { + "v1": "delete_line_items", + "v2": "delete_line_items" + }, + "download-einvoice": { + "v1": "download_e-invoice", + "v2": "download_e-invoice" + }, + "import-invoice": { + "v1": "import_invoice", + "v2": "import_invoice" + }, + "invoices-for-customer": { + "v1": "", + "v2": "" + }, + "invoices-for-subscription": { + "v1": "", + "v2": "" + }, + "list": { + "v1": "list_invoices", + "v2": "list_invoices" + }, + "list-payment-reference-numbers": { + "v1": "list_payment_reference_numbers", + "v2": "list_payment_reference_numbers" + }, + "pause-dunning": { + "v1": "pause_dunning_for_invoice", + "v2": "pause_dunning_for_invoice" + }, + "payment-schedules": { + "v1": "", + "v2": "retrieve_payment_schedules_for_an_invoice" + }, + "pdf": { + "v1": "retrieve_invoice_as_pdf", + "v2": "retrieve_invoice_as_pdf" + }, + "record-payment": { + "v1": "record_an_invoice_payment", + "v2": "record_an_invoice_payment" + }, + "record-refund": { + "v1": "record_refund_for_an_invoice", + "v2": "record_refund_for_an_invoice" + }, + "record-tax-withheld": { + "v1": "record_tax_withheld_for_an_invoice", + "v2": "record_tax_withheld_for_an_invoice" + }, + "refund": { + "v1": "refund_an_invoice", + "v2": "refund_an_invoice" + }, + "remove-credit-note": { + "v1": "remove_credit_note_from_an_invoice", + "v2": "remove_credit_note_from_an_invoice" + }, + "remove-payment": { + "v1": "remove_payment_from_an_invoice", + "v2": "remove_payment_from_an_invoice" + }, + "remove-tax-withheld": { + "v1": "remove_tax_withheld_for_an_invoice", + "v2": "remove_tax_withheld_for_an_invoice" + }, + "resend-einvoice": { + "v1": "resend_failed_einvoice_in_invoices", + "v2": "resend_failed_einvoice_in_invoices" + }, + "resume-dunning": { + "v1": "resume_dunning_for_invoice", + "v2": "resume_dunning_for_invoice" + }, + "retrieve": { + "v1": "retrieve_an_invoice", + "v2": "retrieve_an_invoice" + }, + "send-einvoice": { + "v1": "send_an_einvoice_for_invoices", + "v2": "send_an_einvoice_for_invoices" + }, + "send-email": { + "v1": "send_invoice_email", + "v2": "send_invoice_email" + }, + "stop-dunning": { + "v1": "stop_dunning_for_invoice", + "v2": "stop_dunning_for_invoice" + }, + "sync-usages": { + "v1": "sync_usages", + "v2": "sync_usages" + }, + "update-details": { + "v1": "update_invoice_details", + "v2": "update_invoice_details" + }, + "void-before-capture": { + "v1": "void_authorizations_before_capture", + "v2": "void_authorizations_before_capture" + }, + "void-invoice": { + "v1": "void_an_invoice", + "v2": "void_an_invoice" + }, + "write-off": { + "v1": "write_off_an_invoice", + "v2": "write_off_an_invoice" + } + }, + "item": { + "create": { + "v1": "", + "v2": "create_an_item" + }, + "delete": { + "v1": "", + "v2": "delete_an_item" + }, + "list": { + "v1": "", + "v2": "list_items" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_an_item" + }, + "update": { + "v1": "", + "v2": "update_an_item" + } + }, + "item-entitlement": { + "add-item-entitlements": { + "v1": "", + "v2": "upsert_or_remove_item_entitlements_for_a_feature" + }, + "item-entitlements-for-feature": { + "v1": "", + "v2": "list_item_entitlements_for_a_feature" + }, + "item-entitlements-for-item": { + "v1": "", + "v2": "list_item_entitlements_for_an_item" + }, + "upsert-or-remove-item-entitlements-for-item": { + "v1": "", + "v2": "upsert_or_remove_item_entitlements_for_an_item" + } + }, + "item-family": { + "create": { + "v1": "", + "v2": "create_an_item_family" + }, + "delete": { + "v1": "", + "v2": "delete_an_item_family" + }, + "list": { + "v1": "", + "v2": "list_item_families" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_an_item_family" + }, + "update": { + "v1": "", + "v2": "update_an_item_family" + } + }, + "item-price": { + "create": { + "v1": "", + "v2": "create_an_item_price" + }, + "delete": { + "v1": "", + "v2": "delete_an_item_price" + }, + "find-applicable-item-prices": { + "v1": "", + "v2": "list_applicable_item_prices_for_a_plan-item_price" + }, + "find-applicable-items": { + "v1": "", + "v2": "list_applicable_items_for_a_plan-item_price" + }, + "list": { + "v1": "", + "v2": "list_item_prices" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_an_item_price" + }, + "update": { + "v1": "", + "v2": "update_an_item_price" + } + }, + "ledger-account-balance": { + "list-ledger-account-balances": { + "v1": "", + "v2": "list_ledger_account_balances" + } + }, + "ledger-operation": { + "allocate": { + "v1": "", + "v2": "allocate" + }, + "authorize": { + "v1": "", + "v2": "authorize" + }, + "capture": { + "v1": "", + "v2": "capture" + }, + "capture-authorization": { + "v1": "", + "v2": "capture_authorization" + }, + "list-ledger-operations": { + "v1": "", + "v2": "list_ledger_operations" + }, + "release-authorization": { + "v1": "", + "v2": "release_authorization" + }, + "retrieve-ledger-operation": { + "v1": "", + "v2": "retrieve_ledger_operation" + } + }, + "meter": { + "list": { + "v1": "", + "v2": "list_all_available_meters" + } + }, + "metered-feature": { + "archive": { + "v1": "", + "v2": "archive_a_metered_feature" + }, + "create": { + "v1": "", + "v2": "create_a_metered_feature" + }, + "delete": { + "v1": "", + "v2": "delete_a_metered_feature" + }, + "reactivate": { + "v1": "", + "v2": "reactivate_a_metered_feature" + } + }, + "non-subscription": { + "process-receipt": { + "v1": "one_time_purchase", + "v2": "one_time_purchase" + } + }, + "offer-event": { + "offer-events": { + "v1": "create_an_offer_event", + "v2": "create_an_offer_event" + } + }, + "offer-fulfillment": { + "offer-fulfillments": { + "v1": "create_an_offer_fulfillment", + "v2": "create_an_offer_fulfillment" + }, + "offer-fulfillments-get": { + "v1": "retrieve_an_offer_fulfillment", + "v2": "retrieve_an_offer_fulfillment" + }, + "offer-fulfillments-update": { + "v1": "update_an_offer_fulfillment", + "v2": "update_an_offer_fulfillment" + } + }, + "omnichannel-one-time-order": { + "list": { + "v1": "", + "v2": "list_omnichannel_one_time_orders" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_an_omnichannel_one_time_order" + } + }, + "omnichannel-subscription": { + "list": { + "v1": "", + "v2": "list_omnichannel_subscriptions" + }, + "move": { + "v1": "", + "v2": "move_an_omnichannel_subscription" + }, + "omnichannel-transactions-for-omnichannel-subscription": { + "v1": "", + "v2": "list_omnichannel_transactions_of_an_omnichannel_subscription" + }, + "omnichannel_transactions-for-omnichannel-subscription": { + "v1": "", + "v2": "list_omnichannel_transactions_of_an_omnichannel_subscription" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_an_omnichannel_subscription" + } + }, + "omnichannel-subscription-item": { + "list-omni-sub-item-schedule-changes": { + "v1": "", + "v2": "list_scheduled_changes_for_omnichannel_subscription_item" + } + }, + "order": { + "assign-order-number": { + "v1": "assign_order_number", + "v2": "assign_order_number" + }, + "cancel": { + "v1": "cancel_an_order", + "v2": "cancel_an_order" + }, + "create": { + "v1": "create_an_order", + "v2": "create_an_order" + }, + "create-refundable-credit-note": { + "v1": "create_a_refundable_credit_note", + "v2": "create_a_refundable_credit_note" + }, + "delete": { + "v1": "delete_an_imported_order", + "v2": "delete_an_imported_order" + }, + "import-order": { + "v1": "import_an_order", + "v2": "import_an_order" + }, + "list": { + "v1": "list_orders", + "v2": "list_orders" + }, + "orders-for-invoice": { + "v1": "", + "v2": "" + }, + "reopen": { + "v1": "reopen_a_cancelled_order", + "v2": "reopen_a_cancelled_order" + }, + "resend": { + "v1": "resend_an_order", + "v2": "resend_an_order" + }, + "retrieve": { + "v1": "retrieve_an_order", + "v2": "retrieve_an_order" + }, + "update": { + "v1": "update_an_order", + "v2": "update_an_order" + } + }, + "payment-intent": { + "create": { + "v1": "create_a_payment_intent", + "v2": "create_a_payment_intent" + }, + "retrieve": { + "v1": "retrieve_a_payment_intent", + "v2": "retrieve_a_payment_intent" + }, + "update": { + "v1": "update_a_payment_intent", + "v2": "update_a_payment_intent" + } + }, + "payment-schedule": { + "list": { + "v1": "", + "v2": "list_payment_schedules" + } + }, + "payment-schedule-scheme": { + "create": { + "v1": "", + "v2": "create_a_payment_schedule_scheme" + }, + "delete": { + "v1": "", + "v2": "delete_a_payment_schedule_scheme" + }, + "list": { + "v1": "", + "v2": "list_payment_schedule_schemes" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_payment_schedule_scheme" + } + }, + "payment-source": { + "create-bank-account": { + "v1": "create_a_bank_account_payment_source", + "v2": "create_a_bank_account_payment_source" + }, + "create-card": { + "v1": "create_a_card_payment_source", + "v2": "create_a_card_payment_source" + }, + "create-using-payment-intent": { + "v1": "create_using_payment_intent", + "v2": "create_using_payment_intent" + }, + "create-using-permanent-token": { + "v1": "create_using_permanent_token", + "v2": "create_using_permanent_token" + }, + "create-using-temp-token": { + "v1": "create_using_gateway_temporary_token", + "v2": "create_using_gateway_temporary_token" + }, + "create-using-token": { + "v1": "create_using_chargebee_token", + "v2": "create_using_chargebee_token" + }, + "create-voucher-payment-source": { + "v1": "create_a_voucher_payment_method", + "v2": "create_a_voucher_payment_method" + }, + "delete": { + "v1": "delete_a_payment_source", + "v2": "delete_a_payment_source" + }, + "delete-local": { + "v1": "local_delete_a_payment_source", + "v2": "local_delete_a_payment_source" + }, + "export-payment-source": { + "v1": "export_payment_source", + "v2": "export_payment_source" + }, + "list": { + "v1": "list_payment_sources", + "v2": "list_payment_sources" + }, + "list-gateway-tokens-for-payment-source": { + "v1": "list_gateway_payment_method_tokens_for_a_payment_source", + "v2": "list_gateway_payment_method_tokens_for_a_payment_source" + }, + "retrieve": { + "v1": "retrieve_a_payment_source", + "v2": "retrieve_a_payment_source" + }, + "switch-gateway-account": { + "v1": "switch_gateway_account", + "v2": "switch_gateway_account" + }, + "update-bank-account": { + "v1": "update_a_bank_account_payment_source", + "v2": "update_a_bank_account_payment_source" + }, + "update-card": { + "v1": "update_a_card_payment_source", + "v2": "update_a_card_payment_source" + }, + "verify-bank-account": { + "v1": "verify_bank_account_payment_source", + "v2": "verify_bank_account_payment_source" + } + }, + "payment-voucher": { + "create": { + "v1": "create_a_voucher_for_the_customer_to_initiate_payment", + "v2": "create_a_voucher_for_the_customer_to_initiate_payment" + }, + "payment-vouchers-for-customer": { + "v1": "list_vouchers_for_a_customer", + "v2": "list_vouchers_for_a_customer" + }, + "payment_vouchers-for-customer": { + "v1": "list_vouchers_for_a_customer", + "v2": "list_vouchers_for_a_customer" + }, + "payment-vouchers-for-invoice": { + "v1": "list_vouchers_for_an_invoice", + "v2": "list_vouchers_for_an_invoice" + }, + "payment_vouchers-for-invoice": { + "v1": "list_vouchers_for_an_invoice", + "v2": "list_vouchers_for_an_invoice" + }, + "retrieve": { + "v1": "retrieve_voucher_data", + "v2": "retrieve_voucher_data" + } + }, + "personalized-offer": { + "personalized-offers": { + "v1": "list_personalized_offers", + "v2": "list_personalized_offers" + } + }, + "plan": { + "copy": { + "v1": "copy_a_plan", + "v2": "" + }, + "create": { + "v1": "create_a_plan", + "v2": "" + }, + "delete": { + "v1": "delete_a_plan", + "v2": "" + }, + "list": { + "v1": "list_plans", + "v2": "" + }, + "retrieve": { + "v1": "retrieve_a_plan", + "v2": "" + }, + "unarchive": { + "v1": "unarchive_a_plan", + "v2": "" + }, + "update": { + "v1": "update_a_plan", + "v2": "" + } + }, + "portal-session": { + "activate": { + "v1": "activate_a_portal_session", + "v2": "activate_a_portal_session" + }, + "create": { + "v1": "create_a_portal_session", + "v2": "create_a_portal_session" + }, + "logout": { + "v1": "logout_a_portal_session", + "v2": "logout_a_portal_session" + }, + "retrieve": { + "v1": "retrieve_a_portal_session", + "v2": "retrieve_a_portal_session" + } + }, + "price-variant": { + "create": { + "v1": "", + "v2": "create_a_price_variant" + }, + "delete": { + "v1": "", + "v2": "delete_a_price_variant" + }, + "list": { + "v1": "", + "v2": "list_price_variants" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_price_variant" + }, + "update": { + "v1": "", + "v2": "update_a_price_variant" + } + }, + "pricing-page-session": { + "create-for-existing-subscription": { + "v1": "", + "v2": "create_pricing_page_for_existing_subscription" + }, + "create-for-new-subscription": { + "v1": "", + "v2": "create_pricing_page_for_new_subscription" + } + }, + "promotional-credit": { + "add": { + "v1": "add_promotional_credits", + "v2": "add_promotional_credits" + }, + "deduct": { + "v1": "deduct_promotional_credits", + "v2": "deduct_promotional_credits" + }, + "list": { + "v1": "list_promotional_credits", + "v2": "list_promotional_credits" + }, + "retrieve": { + "v1": "retrieve_a_promotional_credit", + "v2": "retrieve_a_promotional_credit" + }, + "set": { + "v1": "set_promotional_credits", + "v2": "set_promotional_credits" + } + }, + "promotional-grant": { + "promotional-grants": { + "v1": "", + "v2": "create_promotional_grant" + } + }, + "purchase": { + "create": { + "v1": "", + "v2": "create_a_purchase" + }, + "estimate": { + "v1": "", + "v2": "estimates_for_purchase" + } + }, + "quote": { + "convert": { + "v1": "convert_a_quote", + "v2": "convert_a_quote" + }, + "create-for-charge-items-and-charges": { + "v1": "", + "v2": "create_a_quote_for_charge_and_charge_items" + }, + "create-for-onetime-charges": { + "v1": "create_quote_for_one-time_charges", + "v2": "" + }, + "create-signature": { + "v1": "", + "v2": "" + }, + "create-sub-for-customer-quote": { + "v1": "create_quote_for_a_new_subscription", + "v2": "" + }, + "create-sub-items-for-customer-quote": { + "v1": "", + "v2": "create_a_quote_for_a_new_subscription_items" + }, + "delete": { + "v1": "delete_a_quote", + "v2": "delete_a_quote" + }, + "edit-create-sub-customer-quote-for-items": { + "v1": "", + "v2": "edit_create_subscription_quote_for_items" + }, + "edit-create-sub-for-customer-quote": { + "v1": "edit_quote_for_a_new_subscription", + "v2": "" + }, + "edit-for-charge-items-and-charges": { + "v1": "", + "v2": "edit_quote_for_charge_items_and_charges" + }, + "edit-one-time-quote": { + "v1": "edit_quote_for_one-time_charges", + "v2": "" + }, + "edit-update-subscription-quote": { + "v1": "edit_quote_for_updating_a_subscription", + "v2": "" + }, + "edit-update-subscription-quote-for-items": { + "v1": "", + "v2": "edit_update_subscription_quote_for_items" + }, + "extend-expiry-date": { + "v1": "extend_expiry_date", + "v2": "extend_expiry_date" + }, + "list": { + "v1": "list_quotes", + "v2": "list_quotes" + }, + "pdf": { + "v1": "retrieve_quote_as_pdf", + "v2": "retrieve_quote_as_pdf" + }, + "quote-line-groups-for-quote": { + "v1": "list_quote_line_groups", + "v2": "list_quote_line_groups" + }, + "refresh-signature-link": { + "v1": "", + "v2": "" + }, + "retrieve": { + "v1": "retrieve_a_quote", + "v2": "retrieve_a_quote" + }, + "retrieve-signature": { + "v1": "", + "v2": "" + }, + "retrieve-signed-pdf": { + "v1": "", + "v2": "" + }, + "update-signature": { + "v1": "", + "v2": "" + }, + "update-signature-status": { + "v1": "", + "v2": "" + }, + "update-status": { + "v1": "update_quote_status", + "v2": "update_quote_status" + }, + "update-subscription-quote": { + "v1": "create_quote_for_updating_a_subscription", + "v2": "" + }, + "update-subscription-quote-for-items": { + "v1": "", + "v2": "create_a_quote_for_update_subscription_items" + } + }, + "quote-entitlement": { + "list-quote-entitlements": { + "v1": "list_quote_entitlements", + "v2": "list_quote_entitlements" + } + }, + "ramp": { + "create-for-subscription": { + "v1": "", + "v2": "create_a_ramp" + }, + "delete": { + "v1": "", + "v2": "delete_a_ramp" + }, + "list": { + "v1": "", + "v2": "list_ramps" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_ramp" + }, + "update": { + "v1": "", + "v2": "update_a_subscription_ramp" + } + }, + "recorded-purchase": { + "create": { + "v1": "", + "v2": "record_a_purchase" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_recorded_purchase" + } + }, + "resource-migration": { + "retrieve-latest": { + "v1": "retrieve_latest_migration_details", + "v2": "retrieve_latest_migration_details" + } + }, + "rule": { + "retrieve": { + "v1": "retrieve_rule_data", + "v2": "retrieve_rule_data" + } + }, + "site-migration-detail": { + "list": { + "v1": "list_site_migration_details", + "v2": "list_site_migration_details" + } + }, + "subscription": { + "add-charge-at-term-end": { + "v1": "add_charge_at_term_end", + "v2": "add_charge_at_term_end" + }, + "cancel": { + "v1": "cancel_a_subscription", + "v2": "" + }, + "cancel-for-items": { + "v1": "", + "v2": "cancel_subscription_for_items" + }, + "change-term-end": { + "v1": "change_term_end", + "v2": "change_term_end" + }, + "charge-addon-at-term-end": { + "v1": "charge_addon_at_term_end", + "v2": "" + }, + "charge-future-renewals": { + "v1": "charge_future_renewals", + "v2": "charge_future_renewals" + }, + "contract-terms-for-subscription": { + "v1": "list_contract_terms_for_a_subscription", + "v2": "list_contract_terms_for_a_subscription" + }, + "create": { + "v1": "create_a_subscription", + "v2": "" + }, + "create-for-customer": { + "v1": "create_subscription_for_customer", + "v2": "" + }, + "create-with-items": { + "v1": "", + "v2": "create_subscription_for_items" + }, + "delete": { + "v1": "delete_a_subscription", + "v2": "delete_a_subscription" + }, + "edit-advance-invoice-schedule": { + "v1": "edit_advance_invoice_schedule", + "v2": "edit_advance_invoice_schedule" + }, + "import-contract-term": { + "v1": "import_contract_term", + "v2": "import_contract_term" + }, + "import-for-customer": { + "v1": "import_subscription_for_customer", + "v2": "" + }, + "import-for-items": { + "v1": "", + "v2": "import_subscription_for_items" + }, + "import-subscription": { + "v1": "import_a_subscription", + "v2": "" + }, + "import-unbilled-charges": { + "v1": "import_unbilled_charges", + "v2": "import_unbilled_charges" + }, + "list": { + "v1": "list_subscriptions", + "v2": "list_subscriptions" + }, + "list-discounts": { + "v1": "", + "v2": "list_discounts_for_a_subscription" + }, + "move": { + "v1": "move_a_subscription", + "v2": "move_a_subscription" + }, + "override-billing-profile": { + "v1": "override_billing_profile", + "v2": "override_billing_profile" + }, + "pause": { + "v1": "pause_a_subscription", + "v2": "pause_a_subscription" + }, + "reactivate": { + "v1": "reactivate_a_subscription", + "v2": "reactivate_a_subscription" + }, + "regenerate-invoice": { + "v1": "regenerate_an_invoice", + "v2": "regenerate_an_invoice" + }, + "remove-advance-invoice-schedule": { + "v1": "remove_an_advance_invoice_schedules", + "v2": "remove_an_advance_invoice_schedules" + }, + "remove-coupons": { + "v1": "remove_coupons", + "v2": "remove_coupons" + }, + "remove-scheduled-cancellation": { + "v1": "remove_scheduled_cancellation", + "v2": "remove_scheduled_cancellation" + }, + "remove-scheduled-changes": { + "v1": "remove_scheduled_changes", + "v2": "remove_scheduled_changes" + }, + "remove-scheduled-pause": { + "v1": "remove_scheduled_pause", + "v2": "remove_scheduled_pause" + }, + "remove-scheduled-resumption": { + "v1": "remove_scheduled_resumption", + "v2": "remove_scheduled_resumption" + }, + "resume": { + "v1": "resume_a_subscription", + "v2": "resume_a_subscription" + }, + "retrieve": { + "v1": "retrieve_a_subscription", + "v2": "retrieve_a_subscription" + }, + "retrieve-advance-invoice-schedule": { + "v1": "retrieve_advance_invoice", + "v2": "retrieve_advance_invoice" + }, + "retrieve-with-scheduled-changes": { + "v1": "retrieve_with_scheduled_changes", + "v2": "retrieve_with_scheduled_changes" + }, + "subscriptions-for-customer": { + "v1": "", + "v2": "" + }, + "update": { + "v1": "update_a_subscription", + "v2": "" + }, + "update-for-items": { + "v1": "", + "v2": "update_subscription_for_items" + } + }, + "subscription-entitlement": { + "set-subscription-entitlement-availability": { + "v1": "", + "v2": "enable_or_disable_subscription_entitlements" + }, + "subscription-entitlements-for-subscription": { + "v1": "", + "v2": "list_subscription_entitlements" + } + }, + "time-machine": { + "retrieve": { + "v1": "retrieve_a_time_machine", + "v2": "retrieve_a_time_machine" + }, + "start-afresh": { + "v1": "start_afresh", + "v2": "start_afresh" + }, + "travel-forward": { + "v1": "travel_forward", + "v2": "travel_forward" + } + }, + "transaction": { + "create-authorization": { + "v1": "create_an_authorization_payment", + "v2": "create_an_authorization_payment" + }, + "delete-offline-transaction": { + "v1": "delete_an_offline_transaction", + "v2": "delete_an_offline_transaction" + }, + "list": { + "v1": "list_transactions", + "v2": "list_transactions" + }, + "payments-for-invoice": { + "v1": "list_payments_for_an_invoice", + "v2": "list_payments_for_an_invoice" + }, + "reconcile": { + "v1": "reconcile_transaction", + "v2": "reconcile_transaction" + }, + "record-refund": { + "v1": "record_an_offline_refund", + "v2": "record_an_offline_refund" + }, + "refund": { + "v1": "refund_a_payment", + "v2": "refund_a_payment" + }, + "retrieve": { + "v1": "retrieve_a_transaction", + "v2": "retrieve_a_transaction" + }, + "transactions-for-customer": { + "v1": "", + "v2": "" + }, + "transactions-for-subscription": { + "v1": "", + "v2": "" + }, + "void-transaction": { + "v1": "void_an_authorization_transaction", + "v2": "void_an_authorization_transaction" + } + }, + "unbilled-charge": { + "create": { + "v1": "", + "v2": "create_unbilled_charges_for_item_subscription" + }, + "create-unbilled-charge": { + "v1": "create_unbilled_charges_for_a_subscription", + "v2": "" + }, + "delete": { + "v1": "delete_an_unbilled_charge", + "v2": "delete_an_unbilled_charge" + }, + "invoice-now-estimate": { + "v1": "create_an_estimate_for_unbilled_charges", + "v2": "create_an_estimate_for_unbilled_charges" + }, + "invoice-unbilled-charges": { + "v1": "create_an_invoice_for_unbilled_charges", + "v2": "create_an_invoice_for_unbilled_charges" + }, + "list": { + "v1": "list_unbilled_charges", + "v2": "list_unbilled_charges" + } + }, + "usage": { + "create": { + "v1": "", + "v2": "create_a_usage" + }, + "delete": { + "v1": "", + "v2": "delete_a_usage" + }, + "list": { + "v1": "", + "v2": "list_usages" + }, + "pdf": { + "v1": "", + "v2": "retrieve_usages_for_an_invoice_as_pdf" + }, + "retrieve": { + "v1": "", + "v2": "retrieve_a_usage" + } + }, + "usage-charge": { + "retrieve-usage-charges-for-subscription": { + "v1": "", + "v2": "retrieve_usage_charges_for_a_subscription" + } + }, + "usage-event": { + "batch-ingest": { + "v1": "", + "v2": "ingest_usages_in_batch" + }, + "create": { + "v1": "", + "v2": "create_a_usage_event" + } + }, + "usage-file": { + "processing-status": { + "v1": "", + "v2": "get_uploaded_file_processing_status" + }, + "upload-url": { + "v1": "", + "v2": "get_usages_file_upload_url" + } + }, + "usage-summary": { + "retrieve-usage-summary-for-subscription": { + "v1": "", + "v2": "retrieve_usage_summary_for_a_subscription" + } + }, + "vaulted-payment-method": { + "retrieve": { + "v1": "retrieve_vaulted_payment_method", + "v2": "retrieve_vaulted_payment_method" + } + }, + "virtual-bank-account": { + "create": { + "v1": "create_a_virtual_bank_account", + "v2": "create_a_virtual_bank_account" + }, + "create-using-permanent-token": { + "v1": "create_a_virtual_bank_account_using_permanent_token", + "v2": "create_a_virtual_bank_account_using_permanent_token" + }, + "delete": { + "v1": "delete_a_virtual_bank_account", + "v2": "delete_a_virtual_bank_account" + }, + "delete-local": { + "v1": "local_delete_a_virtual_bank_account", + "v2": "local_delete_a_virtual_bank_account" + }, + "list": { + "v1": "list_virtual_bank_accounts", + "v2": "list_virtual_bank_accounts" + }, + "retrieve": { + "v1": "retrieve_a_virtual_bank_account", + "v2": "retrieve_a_virtual_bank_account" + } + }, + "webhook-endpoint": { + "create": { + "v1": "create_a_webhook_endpoint", + "v2": "create_a_webhook_endpoint" + }, + "delete": { + "v1": "delete_a_webhook_endpoint", + "v2": "delete_a_webhook_endpoint" + }, + "list": { + "v1": "list_webhook_endpoints", + "v2": "list_webhook_endpoints" + }, + "retrieve": { + "v1": "retrieve_a_webhook_endpoint", + "v2": "retrieve_a_webhook_endpoint" + }, + "update": { + "v1": "update_a_webhook_endpoint", + "v2": "update_a_webhook_endpoint" + } + } +}; diff --git a/src/commands/generated/omnichannel_subscription.ts b/src/commands/generated/omnichannel_subscription.ts index a50e0fe..b20ad7f 100644 --- a/src/commands/generated/omnichannel_subscription.ts +++ b/src/commands/generated/omnichannel_subscription.ts @@ -65,18 +65,19 @@ export function registerOmnichannelSubscription(parent: Command): void { }); cmd - .command("omnichannel_transactions-for-omnichannel-subscription") + .command("omnichannel-transactions-for-omnichannel-subscription") + .alias("omnichannel_transactions-for-omnichannel-subscription") .argument("[omnichannel-subscription-id]", "The ID generated by Chargebee for the omnichannel subscription.") .argument("[json]", "'-' reads a JSON object from stdin.") .description("List omnichannel transactions of an omnichannel subscription") .option("-d, --data ", "Request parameters in key=value format; repeat for multiple fields") .option("-s, --code-sample ", "Generate code sample (curl, python, nodejs, go, ruby, java, php, dotnet, list)") .addOption(new Option("--pc-version ", "Product catalog version for the code sample (v1 or v2)").hideHelp()) - .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs omnichannel-subscription omnichannel_transactions-for-omnichannel-subscription\n") + .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs omnichannel-subscription omnichannel-transactions-for-omnichannel-subscription\n") .action(async (id: string | undefined, json: string | undefined, opts: { data?: string[]; codeSample?: string; pcVersion?: string }, command: Command) => { const resource = takeResourceId(id, json, command); const params = await loadOperationParams(opts.data ?? [], resource.fromStdin, command, { method: "GET", jsonInput: false, opIdV2: "list_omnichannel_transactions_of_an_omnichannel_subscription", opIdV1: "", pcVersionFlag: opts.pcVersion }); - if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "omnichannel-subscription omnichannel_transactions-for-omnichannel-subscription"); + if (opts.codeSample !== "list") await ensureCatalogAllowed("pc2", "omnichannel-subscription omnichannel-transactions-for-omnichannel-subscription"); if (opts.codeSample) return handleCodeSample({ lang: opts.codeSample, opIdV2: "list_omnichannel_transactions_of_an_omnichannel_subscription", opIdV1: "", method: "GET", uri: "/omnichannel_subscriptions/{id}/omnichannel_transactions", dataFlags: opts.data ?? [], params, resourceId: resource.id, pathParamName: "omnichannel-subscription-id", pcVersionFlag: opts.pcVersion }); if (!resource.id) command.error("error: missing required argument 'omnichannel-subscription-id'"); assertResourceId(resource.id, command); diff --git a/src/commands/generated/payment_voucher.ts b/src/commands/generated/payment_voucher.ts index 165c614..d9d33b9 100644 --- a/src/commands/generated/payment_voucher.ts +++ b/src/commands/generated/payment_voucher.ts @@ -37,14 +37,15 @@ export function registerPaymentVoucher(parent: Command): void { }); cmd - .command("payment_vouchers-for-customer") + .command("payment-vouchers-for-customer") + .alias("payment_vouchers-for-customer") .argument("[customer-id]", "The unique identifier of the customer resource.") .argument("[json]", "'-' reads a JSON object from stdin.") .description("List vouchers for a customer") .option("-d, --data ", "Request parameters in key=value format; repeat for multiple fields") .option("-s, --code-sample ", "Generate code sample (curl, python, nodejs, go, ruby, java, php, dotnet, list)") .addOption(new Option("--pc-version ", "Product catalog version for the code sample (v1 or v2)").hideHelp()) - .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs payment-voucher payment_vouchers-for-customer\n") + .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs payment-voucher payment-vouchers-for-customer\n") .action(async (id: string | undefined, json: string | undefined, opts: { data?: string[]; codeSample?: string; pcVersion?: string }, command: Command) => { const resource = takeResourceId(id, json, command); const params = await loadOperationParams(opts.data ?? [], resource.fromStdin, command, { method: "GET", jsonInput: false, opIdV2: "list_vouchers_for_a_customer", opIdV1: "list_vouchers_for_a_customer", pcVersionFlag: opts.pcVersion }); @@ -59,14 +60,15 @@ export function registerPaymentVoucher(parent: Command): void { }); cmd - .command("payment_vouchers-for-invoice") + .command("payment-vouchers-for-invoice") + .alias("payment_vouchers-for-invoice") .argument("[invoice-id]", "The invoice number.") .argument("[json]", "'-' reads a JSON object from stdin.") .description("List vouchers for an invoice") .option("-d, --data ", "Request parameters in key=value format; repeat for multiple fields") .option("-s, --code-sample ", "Generate code sample (curl, python, nodejs, go, ruby, java, php, dotnet, list)") .addOption(new Option("--pc-version ", "Product catalog version for the code sample (v1 or v2)").hideHelp()) - .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs payment-voucher payment_vouchers-for-invoice\n") + .addHelpText("after", "\n\u001b[1mDOCUMENTATION\u001b[0m\n chargebee docs payment-voucher payment-vouchers-for-invoice\n") .action(async (id: string | undefined, json: string | undefined, opts: { data?: string[]; codeSample?: string; pcVersion?: string }, command: Command) => { const resource = takeResourceId(id, json, command); const params = await loadOperationParams(opts.data ?? [], resource.fromStdin, command, { method: "GET", jsonInput: false, opIdV2: "list_vouchers_for_an_invoice", opIdV1: "list_vouchers_for_an_invoice", pcVersionFlag: opts.pcVersion }); diff --git a/src/lib/docs/index.ts b/src/lib/docs/index.ts index e4953f7..dc93890 100644 --- a/src/lib/docs/index.ts +++ b/src/lib/docs/index.ts @@ -1,6 +1,8 @@ import { join } from "node:path"; import { readFile, stat } from "node:fs/promises"; import { configDir } from "../config/store.js"; +import { resolveCatalogVersion } from "../api/sdk.js"; +import { docsOperationIds } from "../../commands/generated/docs-operations.js"; const DEFAULT_HOST = "https://apidocs.chargebee.com"; const API_PREFIX = "/docs/api"; @@ -58,7 +60,7 @@ interface SitemapIndex { export type DocResult = | { ok: true; url: string; body: string } - | { ok: false; reason: "offline" | "not_found"; operations?: string[] }; + | { ok: false; reason: "offline" | "not_found" | "ambiguous"; operations?: string[]; matches?: string[] }; /** Strip control characters that could inject terminal escape sequences, keeping the whitespace a reader actually wants. */ export function stripControlChars(s: string): string { @@ -221,17 +223,30 @@ function deserialize(json: string): SitemapIndex { /** Map a CLI resource name (often singular, e.g. "customer") to a sitemap segment. @internal */ export function resolveSegment(idx: SitemapIndex, name: string): string | null { const r = idx.resources; + const normalized = name.replace(/-/g, "_"); if (r.has(name)) return name; - for (const cand of [`${name}s`, name.replace(/y$/, "ies"), `${name}es`]) { + if (r.has(normalized)) return normalized; + for (const cand of [`${normalized}s`, normalized.replace(/y$/, "ies"), `${normalized}es`]) { if (r.has(cand)) return cand; } - const want = singular(name); + const want = singular(normalized); for (const seg of r.keys()) { if (singular(seg) === want) return seg; } return null; } +/** Find a docs page by the OpenAPI operation ID, without guessing its resource. */ +function pathsForOperationId(idx: SitemapIndex, id: string): string[] { + const slug = id.replace(/_/g, "-"); + const paths: string[] = []; + for (const ops of idx.resources.values()) { + const path = ops.get(slug); + if (path) paths.push(path); + } + return paths; +} + /** * Resolve an operation to its sitemap op-path. Tries, in order: * 1. exact slug, @@ -313,13 +328,28 @@ export async function fetchOperation(name: string, op: string): Promise 1) return { ok: false, reason: "ambiguous", matches }; + if (matches.length === 0) { + return { ok: false, reason: "not_found", operations: ops ? [...ops.keys()].sort() : [] }; + } + path = matches[0]; + } + if (!path && ops && !ids) { + const opPath = resolveOp(ops, op); + if (opPath) path = ops.get(opPath); + } + if (!path) { + return { ok: false, reason: "not_found", operations: ops ? [...ops.keys()].sort() : undefined }; } - const path = ops.get(opPath)!; const body = await fetchMarkdown(path); if (body === null) return { ok: false, reason: "offline" }; return { ok: true, url: `${resolveHost()}${path}.md`, body }; diff --git a/src/lib/update/index.ts b/src/lib/update/index.ts index c4d15ae..dfe6e76 100644 --- a/src/lib/update/index.ts +++ b/src/lib/update/index.ts @@ -340,9 +340,13 @@ function reportUpdated(currentVersion: string, probe: () => ReturnType { diff --git a/src/tests/integration/docs.test.ts b/src/tests/integration/docs.test.ts index 387748f..749bfea 100644 --- a/src/tests/integration/docs.test.ts +++ b/src/tests/integration/docs.test.ts @@ -10,6 +10,8 @@ const SITEMAP = ` https://apidocs.chargebee.com/docs/api/customers/create-a-customer https://apidocs.chargebee.com/docs/api/customers/list-customers + https://apidocs.chargebee.com/docs/api/customers/add-contacts-to-a-customer + https://apidocs.chargebee.com/docs/api/item_prices/create-an-item-price `; @@ -67,6 +69,16 @@ describe("docs command (mocked fetch)", () => { expect(stdout).toContain("Source:"); }); + it("opens pages named differently from the generated CLI commands", async () => { + const item = await runCli(["docs", "item-price", "create"]); + expect(item.exitCode).toBe(0); + expect(item.stdout).toContain("item_prices/create-an-item-price.md"); + + const customer = await runCli(["docs", "customer", "add-contact"]); + expect(customer.exitCode).toBe(0); + expect(customer.stdout).toContain("customers/add-contacts-to-a-customer.md"); + }); + it("strips control characters from printed pages but caches the raw body", async () => { globalThis.fetch = (async (url: string) => { const href = String(url); diff --git a/src/tests/integration/generated-operation-names.test.ts b/src/tests/integration/generated-operation-names.test.ts new file mode 100644 index 0000000..29f7e5e --- /dev/null +++ b/src/tests/integration/generated-operation-names.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, it } from "bun:test"; + +import { buildProgram } from "../../program.js"; +import { runCli } from "../../lib/test-support/_helpers.js"; +import { docsOperationIds } from "../../commands/generated/docs-operations.js"; + +const previousNames: Record> = { + alert: { + "application-alerts-for-subscription": "application_alerts-for-subscription", + }, + "alert-status": { + "alert-statuses-for-alert": "alert_statuses-for-alert", + "alert-statuses-for-subscription": "alert_statuses-for-subscription", + }, + "payment-voucher": { + "payment-vouchers-for-customer": "payment_vouchers-for-customer", + "payment-vouchers-for-invoice": "payment_vouchers-for-invoice", + }, + "omnichannel-subscription": { + "omnichannel-transactions-for-omnichannel-subscription": + "omnichannel_transactions-for-omnichannel-subscription", + }, +}; + +describe("generated API operation names", () => { + it("maps every generated command and alias to its OpenAPI operation IDs", () => { + const program = buildProgram("test"); + const resources = program.commands.filter((command) => + command.commands.some((operation) => operation.options.some((option) => option.long === "--data")) + ); + for (const resource of resources) { + const mapped = docsOperationIds[resource.name()]; + expect(mapped).toBeDefined(); + for (const operation of resource.commands) { + expect(mapped[operation.name()]).toBeDefined(); + for (const alias of operation.aliases()) { + expect(mapped[alias]).toEqual(mapped[operation.name()]); + } + } + } + }); + + it("uses kebab case for every operation and retains published mixed-name aliases", () => { + const program = buildProgram("test"); + const resources = program.commands.filter((command) => + command.commands.some((operation) => operation.options.some((option) => option.long === "--data")) + ); + const operations = resources.flatMap((resource) => resource.commands); + + expect(operations.length).toBeGreaterThan(0); + for (const operation of operations) { + expect(operation.name()).toMatch(/^[a-z0-9]+(?:-[a-z0-9]+)*$/); + } + + for (const [resourceName, names] of Object.entries(previousNames)) { + const resource = resources.find((command) => command.name() === resourceName); + expect(resource).toBeDefined(); + for (const [canonical, previous] of Object.entries(names)) { + const operation = resource!.commands.find((command) => command.name() === canonical); + expect(operation?.aliases()).toContain(previous); + } + } + }); + + it("runs each command through its canonical and previous name", async () => { + for (const [resource, names] of Object.entries(previousNames)) { + for (const [canonicalName, previousName] of Object.entries(names)) { + const canonical = await runCli([resource, canonicalName, "-s", "list"]); + const previous = await runCli([resource, previousName, "-s", "list"]); + expect(canonical.exitCode).toBe(0); + expect(previous.exitCode).toBe(0); + expect(previous.stdout).toBe(canonical.stdout); + } + } + }); +}); diff --git a/src/tests/integration/install-sh.test.ts b/src/tests/integration/install-sh.test.ts index 2ecb40d..d5eda76 100644 --- a/src/tests/integration/install-sh.test.ts +++ b/src/tests/integration/install-sh.test.ts @@ -198,6 +198,34 @@ main "$@" }); describe.skipIf(process.platform === "win32")("install.sh snapshot mode", () => { + it("rejects a candidate that cannot start and preserves the installed binary", () => { + const root = mkdtempSync(join(tmpdir(), "cb-install-sh-invalid-")); + try { + const binDir = join(root, "bin"); + const configDir = join(root, "config"); + mkdirSync(binDir, { recursive: true }); + const installed = join(binDir, "chargebee"); + writeFileSync(installed, "#!/bin/sh\necho 1.0.0\n", { mode: 0o755 }); + const invalid = join(root, "invalid-binary"); + writeFileSync(invalid, "not an executable binary\n"); + + const result = runInstall({ + CHARGEBEE_CLI_INSTALL_FILE: invalid, + CHARGEBEE_CLI_BIN_DIR: binDir, + CHARGEBEE_CONFIG_DIR: configDir, + HOME: root, + PATH: `${binDir}:${SYSTEM_PATH}`, + }); + expect(result.exitCode).toBe(1); + expect(result.stderr).toContain("cannot start on this system"); + expect(result.stdout).not.toContain("Updated:"); + expect(readFileSync(installed, "utf8")).toContain("echo 1.0.0"); + expect(existsSync(join(configDir, "install-method"))).toBe(false); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + it("copies CHARGEBEE_CLI_INSTALL_FILE into CHARGEBEE_CLI_BIN_DIR and writes github marker", () => { const root = mkdtempSync(join(tmpdir(), "cb-install-sh-")); try { @@ -490,6 +518,122 @@ printf '200' }); }); +describe.skipIf(process.platform === "win32")("install.sh Linux libc selection", () => { + function fakeLinux( + root: string, + withLibraries: boolean, + lddVersion = "musl libc", + hasMuslLoader = false, + ): { bin: string; log: string } { + const bin = join(root, "fake-bin"); + const log = join(root, "curl.log"); + mkdirSync(bin); + writeFakeCurl(bin, log, '{"tag_name":"v9.9.9"}'); + writeFileSync(join(bin, "uname"), "#!/bin/sh\nif [ \"$1\" = -s ]; then echo Linux; else echo x86_64; fi\n", { mode: 0o755 }); + writeFileSync(join(bin, "ldd"), `#!/bin/sh\necho '${lddVersion}'\n`, { mode: 0o755 }); + if (hasMuslLoader) { + writeFileSync(join(bin, "ls"), "#!/bin/sh\necho /lib/ld-musl-x86_64.so.1\n", { mode: 0o755 }); + } + writeFileSync(join(bin, "find"), withLibraries + ? "#!/bin/sh\necho /usr/lib/$4\n" + : "#!/bin/sh\nexit 0\n", { mode: 0o755 }); + return { bin, log }; + } + + it("downloads the musl asset when Linux uses musl", () => { + const root = mkdtempSync(join(tmpdir(), "cb-install-musl-")); + try { + const { bin, log } = fakeLinux(root, true); + const result = runInstall({ + PATH: `${bin}:${SYSTEM_PATH}`, + HOME: root, + CHARGEBEE_CLI_BIN_DIR: join(root, "bin"), + CHARGEBEE_CONFIG_DIR: join(root, "config"), + CHARGEBEE_CLI_SKIP_CHECKSUM: "1", + }); + expect(result.exitCode).toBe(0); + expect(readFileSync(log, "utf8")).toContain("chargebee-cli-linux-x64-musl"); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + it("honors the glibc override", () => { + const root = mkdtempSync(join(tmpdir(), "cb-install-glibc-")); + try { + const { bin, log } = fakeLinux(root, false); + const result = runInstall({ + PATH: `${bin}:${SYSTEM_PATH}`, + HOME: root, + CHARGEBEE_CLI_BIN_DIR: join(root, "bin"), + CHARGEBEE_CONFIG_DIR: join(root, "config"), + CHARGEBEE_CLI_SKIP_CHECKSUM: "1", + CHARGEBEE_CLI_LIBC: "glibc", + }); + expect(result.exitCode).toBe(0); + expect(readFileSync(log, "utf8")).toContain("chargebee-cli-linux-x64"); + expect(readFileSync(log, "utf8")).not.toContain("chargebee-cli-linux-x64-musl"); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + it("selects glibc when ldd reports glibc despite an installed musl loader", () => { + const root = mkdtempSync(join(tmpdir(), "cb-install-glibc-with-musl-")); + try { + const { bin, log } = fakeLinux(root, false, "ldd (GNU libc) 2.39", true); + const result = runInstall({ + PATH: `${bin}:${SYSTEM_PATH}`, + HOME: root, + CHARGEBEE_CLI_BIN_DIR: join(root, "bin"), + CHARGEBEE_CONFIG_DIR: join(root, "config"), + CHARGEBEE_CLI_SKIP_CHECKSUM: "1", + }); + expect(result.exitCode).toBe(0); + expect(readFileSync(log, "utf8")).toContain("chargebee-cli-linux-x64"); + expect(readFileSync(log, "utf8")).not.toContain("chargebee-cli-linux-x64-musl"); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + it("uses the musl loader when ldd cannot identify the active libc", () => { + const root = mkdtempSync(join(tmpdir(), "cb-install-unknown-libc-")); + try { + const { bin, log } = fakeLinux(root, true, "unknown libc", true); + const result = runInstall({ + PATH: `${bin}:${SYSTEM_PATH}`, + HOME: root, + CHARGEBEE_CLI_BIN_DIR: join(root, "bin"), + CHARGEBEE_CONFIG_DIR: join(root, "config"), + CHARGEBEE_CLI_SKIP_CHECKSUM: "1", + }); + expect(result.exitCode).toBe(0); + expect(readFileSync(log, "utf8")).toContain("chargebee-cli-linux-x64-musl"); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + it("explains missing Alpine runtime libraries before downloading", () => { + const root = mkdtempSync(join(tmpdir(), "cb-install-musl-missing-")); + try { + const { bin, log } = fakeLinux(root, false); + const result = runInstall({ + PATH: `${bin}:${SYSTEM_PATH}`, + HOME: root, + CHARGEBEE_CLI_BIN_DIR: join(root, "bin"), + CHARGEBEE_CONFIG_DIR: join(root, "config"), + }); + expect(result.exitCode).toBe(1); + expect(result.stderr).toContain("apk add --no-cache libstdc++ libgcc"); + expect(existsSync(log)).toBe(false); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); +}); + describe.skipIf(process.platform === "win32")("install.sh checksum verification", () => { function setup(): { root: string; fakeBin: string; binDir: string; configDir: string; log: string } { const root = mkdtempSync(join(tmpdir(), "cb-install-sh-checksum-")); diff --git a/src/tests/unit/lib/docs/docs.test.ts b/src/tests/unit/lib/docs/docs.test.ts index 93d1462..e658f4f 100644 --- a/src/tests/unit/lib/docs/docs.test.ts +++ b/src/tests/unit/lib/docs/docs.test.ts @@ -20,6 +20,8 @@ const SITEMAP = ` https://apidocs.chargebee.com/docs/api/customers/create-a-customer https://apidocs.chargebee.com/docs/api/customers/list-customers https://apidocs.chargebee.com/docs/api/customers/change-billing-date + https://apidocs.chargebee.com/docs/api/customers/add-contacts-to-a-customer + https://apidocs.chargebee.com/docs/api/item_prices/create-an-item-price https://apidocs.chargebee.com/docs/api/item_prices/retrieve-an-item-price https://apidocs.chargebee.com/docs/api/hosted_pages/checkout-charge-items-and-one-time-charges https://apidocs.chargebee.com/docs/api/v1/customers/create-a-customer @@ -36,7 +38,7 @@ describe("parseSitemap", () => { "hosted_pages", "item_prices", ]); - expect(idx.resources.get("customers")!.size).toBe(3); + expect(idx.resources.get("customers")!.size).toBe(4); }); it("ignores landing pages and non-api urls", () => { @@ -63,6 +65,7 @@ describe("resolveSegment", () => { it("maps singular CLI names to the plural sitemap segment", () => { expect(resolveSegment(idx, "customer")).toBe("customers"); expect(resolveSegment(idx, "item_price")).toBe("item_prices"); + expect(resolveSegment(idx, "item-price")).toBe("item_prices"); }); it("accepts the exact segment too", () => { @@ -74,6 +77,92 @@ describe("resolveSegment", () => { }); }); +describe("CLI command documentation lookup", () => { + const originalFetch = globalThis.fetch; + const prevConfig = process.env.CHARGEBEE_CONFIG_DIR; + let home: string; + + beforeEach(() => { + home = mkdtempSync(join(tmpdir(), "cb-docs-identity-")); + process.env.CHARGEBEE_CONFIG_DIR = home; + __resetDocsMemoForTest(); + globalThis.fetch = (async (url: string) => { + if (String(url).endsWith("sitemap.xml")) return new Response(SITEMAP); + return new Response(`# ${url}`); + }) as unknown as typeof fetch; + }); + + afterEach(() => { + globalThis.fetch = originalFetch; + __resetDocsMemoForTest(); + rmSync(home, { recursive: true, force: true }); + if (prevConfig === undefined) delete process.env.CHARGEBEE_CONFIG_DIR; + else process.env.CHARGEBEE_CONFIG_DIR = prevConfig; + }); + + it("resolves advertised kebab-case resource and action names by operation ID", async () => { + expect(await fetchOperation("item-price", "create")).toMatchObject({ + ok: true, + url: "https://apidocs.chargebee.com/docs/api/item_prices/create-an-item-price.md", + }); + expect(await fetchOperation("customer", "add-contact")).toMatchObject({ + ok: true, + url: "https://apidocs.chargebee.com/docs/api/customers/add-contacts-to-a-customer.md", + }); + }); + + it("keeps exact Docs slugs working", async () => { + expect(await fetchOperation("customer", "create-a-customer")).toMatchObject({ ok: true }); + }); + + it("does not guess a PC2-only command's page for a PC1 profile", async () => { + const sitemap = SITEMAP.replace( + "", + "https://apidocs.chargebee.com/docs/api/alerts/list-alerts", + ); + globalThis.fetch = (async (url: string) => + new Response(String(url).endsWith("sitemap.xml") ? sitemap : "# Doc")) as typeof fetch; + mkdirSync(join(home, "profiles")); + writeFileSync(join(home, "config"), "CHARGEBEE_ACTIVE_PROFILE=pc1\n"); + writeFileSync(join(home, "profiles", "pc1.json"), JSON.stringify({ product_catalog_version: "v1" })); + + expect(await fetchOperation("alert", "list")).toMatchObject({ ok: false, reason: "not_found" }); + expect(await fetchOperation("alerts", "list-alerts")).toMatchObject({ ok: true }); + + writeFileSync(join(home, "profiles", "pc1.json"), JSON.stringify({ product_catalog_version: "v2" })); + expect(await fetchOperation("alert", "list")).toMatchObject({ + ok: true, + url: "https://apidocs.chargebee.com/docs/api/alerts/list-alerts.md", + }); + }); + + it("finds a known operation when Docs groups it under another resource", async () => { + const regrouped = SITEMAP.replace( + "/docs/api/customers/add-contacts-to-a-customer", + "/docs/api/contacts/add-contacts-to-a-customer", + ); + globalThis.fetch = (async (url: string) => new Response(String(url).endsWith("sitemap.xml") ? regrouped : "# Doc")) as typeof fetch; + expect(await fetchOperation("customer", "add-contact")).toMatchObject({ + ok: true, + url: "https://apidocs.chargebee.com/docs/api/contacts/add-contacts-to-a-customer.md", + }); + }); + + it("reports an ambiguous operation ID instead of choosing a page", async () => { + const duplicate = SITEMAP.replace("", + "https://apidocs.chargebee.com/docs/api/other/add-contacts-to-a-customer"); + globalThis.fetch = (async (url: string) => new Response(String(url).endsWith("sitemap.xml") ? duplicate : "# Doc")) as typeof fetch; + expect(await fetchOperation("customer", "add-contact")).toMatchObject({ + ok: false, + reason: "ambiguous", + matches: [ + "/docs/api/customers/add-contacts-to-a-customer", + "/docs/api/other/add-contacts-to-a-customer", + ], + }); + }); +}); + describe("resolveOp", () => { const ops = parseSitemap(SITEMAP).resources.get("customers")!; diff --git a/src/tests/unit/lib/update/index.test.ts b/src/tests/unit/lib/update/index.test.ts index c989961..115a526 100644 --- a/src/tests/unit/lib/update/index.test.ts +++ b/src/tests/unit/lib/update/index.test.ts @@ -107,8 +107,10 @@ describe("githubAssetName", () => { it("matches the release asset naming used by install.sh / install.ps1", () => { expect(githubAssetName("darwin", "arm64")).toBe("chargebee-cli-darwin-arm64"); expect(githubAssetName("darwin", "x64")).toBe("chargebee-cli-darwin-x64"); - expect(githubAssetName("linux", "x64")).toBe("chargebee-cli-linux-x64"); - expect(githubAssetName("linux", "arm64")).toBe("chargebee-cli-linux-arm64"); + expect(githubAssetName("linux", "x64", "glibc")).toBe("chargebee-cli-linux-x64"); + expect(githubAssetName("linux", "arm64", "glibc")).toBe("chargebee-cli-linux-arm64"); + expect(githubAssetName("linux", "x64", "musl")).toBe("chargebee-cli-linux-x64-musl"); + expect(githubAssetName("linux", "arm64", "musl")).toBe("chargebee-cli-linux-arm64-musl"); expect(githubAssetName("win32", "x64")).toBe("chargebee-cli-windows-x64.exe"); }); }); @@ -469,6 +471,8 @@ describe("update action (mocked spawn + fetch)", () => { "chargebee-cli-darwin-x64", "chargebee-cli-linux-arm64", "chargebee-cli-linux-x64", + "chargebee-cli-linux-arm64-musl", + "chargebee-cli-linux-x64-musl", "chargebee-cli-windows-x64.exe", ] .map((name) => `${ASSET_HASH} ${name}`) @@ -805,6 +809,20 @@ describe("update action (mocked spawn + fetch)", () => { expect(readInstallMethod()).toBe("github"); }); + it("keeps a musl installation on the musl release asset", async () => { + const previousLibc = process.env.CHARGEBEE_CLI_LIBC; + process.env.CHARGEBEE_CLI_LIBC = "musl"; + try { + await runUpdate(); + const assetReq = fetched.find((f) => f.url.includes("/releases/download/")); + expect(assetReq?.url).toContain(`chargebee-cli-linux-${process.arch}-musl`); + expect(readFileSync(execPath, "utf8")).toBe(ASSET_BYTES); + } finally { + if (previousLibc === undefined) delete process.env.CHARGEBEE_CLI_LIBC; + else process.env.CHARGEBEE_CLI_LIBC = previousLibc; + } + }); + it("prefers the release's API asset URL (works for private repos) with an octet-stream Accept", async () => { stubFetch([ { diff --git a/src/tools/build.ts b/src/tools/build.ts index f346ef9..6e85369 100644 --- a/src/tools/build.ts +++ b/src/tools/build.ts @@ -3,7 +3,7 @@ * Compiles the standalone binary. * * Default: one binary for the host platform at `./chargebee-cli`. `--all` - * cross-compiles the five release artifacts into `dist/`; `--target=` builds + * cross-compiles the seven release artifacts into `dist/`; `--target=` builds * just one of them (CI fans these out across runners). * * The version is baked in via `process.env.VERSION` — without it the binary @@ -20,6 +20,8 @@ const TARGETS = [ { target: "bun-darwin-x64", outfile: `dist/${BINARY}-darwin-x64` }, { target: "bun-linux-arm64", outfile: `dist/${BINARY}-linux-arm64` }, { target: "bun-linux-x64", outfile: `dist/${BINARY}-linux-x64` }, + { target: "bun-linux-arm64-musl", outfile: `dist/${BINARY}-linux-arm64-musl` }, + { target: "bun-linux-x64-musl", outfile: `dist/${BINARY}-linux-x64-musl` }, { target: "bun-windows-x64", outfile: `dist/${BINARY}-windows-x64.exe` }, ] as const; @@ -36,6 +38,9 @@ async function compile(outfile: string, target?: string): Promise { outfile, "--define", `process.env.VERSION='${version}'`, + ...(target?.startsWith("bun-linux-") + ? ["--define", `process.env.CHARGEBEE_CLI_LIBC='${target.endsWith("-musl") ? "musl" : "glibc"}'`] + : []), ...(target ? [`--target=${target}`] : []), ]; const proc = Bun.spawn(["bun", ...args], { stdout: "inherit", stderr: "inherit" }); diff --git a/src/tools/generate.ts b/src/tools/generate.ts index d1c95b2..aed4a0a 100644 --- a/src/tools/generate.ts +++ b/src/tools/generate.ts @@ -64,6 +64,7 @@ type CatalogTag = "pc1" | "pc2" | "both"; interface Operation { sdkAction: string; cliCommand: string; + legacyCliCommand?: string; method: string; jsonInput: boolean; hasId: boolean; @@ -119,6 +120,9 @@ function deriveOpCatalog(opIdV2: string, opIdV1: string, key: string): CatalogTa } function camelToKebab(s: string): string { + return s.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase(); +} +function previousCommandName(s: string): string { return s.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); } function camelToSnake(s: string): string { @@ -237,6 +241,8 @@ async function loadEndpoints(): Promise { for (const [sdkName, endpoints] of Object.entries(Endpoints)) { const ops: Operation[] = (endpoints as unknown[]).map((ep: unknown) => { const t = ep as [string, string, string, string | null, boolean, string | null, boolean]; + const cliCommand = camelToKebab(t[0]); + const previousName = previousCommandName(t[0]); const urlPrefix = t[2]; const urlSuffix = t[3] ?? ""; const hasId = t[4] === true; @@ -249,7 +255,8 @@ async function loadEndpoints(): Promise { return { sdkAction: t[0], - cliCommand: camelToKebab(t[0]), + cliCommand, + legacyCliCommand: previousName === cliCommand ? undefined : previousName, method: t[1], jsonInput: t[6] === true, urlPrefix, @@ -270,6 +277,15 @@ async function loadEndpoints(): Promise { ops.sort((a, b) => a.sdkAction.localeCompare(b.sdkAction)); + const commandNames = new Set(); + for (const op of ops) { + for (const name of [op.cliCommand, op.legacyCliCommand]) { + if (!name) continue; + if (commandNames.has(name)) throw new Error(`Duplicate CLI command ${sdkName} ${name}`); + commandNames.add(name); + } + } + // Schema-only SDK keys (token, contact, discount, …) have no operations. // They are valid Chargebee objects / docs pages, not callable CLI commands. @@ -386,6 +402,7 @@ function generateResourceFile(r: Resource): string { L.push(` cmd`); L.push(` .command("${op.cliCommand}")`); + if (op.legacyCliCommand) L.push(` .alias("${op.legacyCliCommand}")`); if (op.hasId) L.push(` .argument(${JSON.stringify(`[${argument.name}]`)}, ${JSON.stringify(argument.description)})`); L.push(` .argument("[json]", "'-' reads a JSON object from stdin.")`); const summary = r.cliName === "subscription" && op.cliCommand === "create-with-items" @@ -476,6 +493,22 @@ function generateRegistry(resources: Resource[]): string { return L.join("\n"); } +function generateDocsOperations(resources: Resource[]): string { + const entries: Record> = {}; + for (const resource of resources) { + const operations: Record = {}; + for (const op of resource.operations) { + const ids = { v1: op.operationIdV1, v2: op.operationIdV2 }; + operations[op.cliCommand] = ids; + if (op.legacyCliCommand) operations[op.legacyCliCommand] = ids; + } + entries[resource.cliName] = operations; + } + return `// Code generated by src/tools/generate.ts from Chargebee SDK endpoints and public OpenAPI specs. DO NOT EDIT.\n` + + `// Regenerate with: bun run generate\n\n` + + `export const docsOperationIds: Record> = ${JSON.stringify(entries, null, 2)};\n`; +} + const resources = await loadEndpoints(); const totalOps = resources.reduce((n, r) => n + r.operations.length, 0); @@ -505,6 +538,7 @@ for (const r of resources) { } writeFileSync(join(outDir, "registry.ts"), generateRegistry(resources)); +writeFileSync(join(outDir, "docs-operations.ts"), generateDocsOperations(resources)); const withSamples = totalOps - unmapped.length; -console.log(`Done. Generated ${resources.length} resource files + registry.ts`); +console.log(`Done. Generated ${resources.length} resource files + registry.ts + docs-operations.ts`); console.log(`Code samples available for ~${withSamples}/${totalOps} operations (${unmapped.length} unmapped in specs).`);