From c6ef7809a2e5d9de0b7c39c7bf8a031ebfed691b Mon Sep 17 00:00:00 2001 From: fireblocks_dx_team Date: Sun, 19 Apr 2026 11:44:32 +0000 Subject: [PATCH] Generated CLI #5771 --- .claude/skills/fireblocks-cli/SKILL.md | 115 + .github/workflows/auto-reply-issue.yml | 35 + .github/workflows/auto-reply-pr.yml | 36 + .github/workflows/draft-release-from-pr.yml | 100 + .github/workflows/publish.yml | 315 ++ .github/workflows/test.yml | 23 + .gitignore | 4 + .prettierrc.json | 1 + README.md | 21 + SKILL.md | 115 + bin/dev.cmd | 3 + bin/dev.js | 5 + bin/run.cmd | 3 + bin/run.js | 5 + eslint.config.mjs | 9 + jest.config.cjs | 31 + package.json | 227 + .../set-admin-quorum-threshold.ts | 63 + src/commands/api-user/create-api-user.ts | 62 + src/commands/api-user/get-api-users.ts | 41 + src/commands/audit-logs/get-audit-logs.ts | 56 + src/commands/blockchains-assets/get-asset.ts | 51 + .../blockchains-assets/get-blockchain.ts | 48 + .../get-supported-assets.ts | 41 + .../blockchains-assets/list-assets.ts | 95 + .../blockchains-assets/list-blockchains.ts | 80 + .../blockchains-assets/register-new-asset.ts | 62 + .../blockchains-assets/set-asset-price.ts | 69 + .../update-asset-user-metadata.ts | 69 + .../get-aml-screening-configuration.ts | 36 + .../get-screening-configuration.ts | 36 + .../compliance/activate-byork-config.ts | 46 + .../add-address-registry-vault-opt-outs.ts | 63 + .../assign-vaults-to-legal-entity.ts | 70 + .../compliance/deactivate-byork-config.ts | 46 + ...ss-registry-tenant-participation-status.ts | 41 + .../get-address-registry-vault-opt-out.ts | 48 + .../get-aml-post-screening-policy.ts | 36 + .../compliance/get-aml-screening-policy.ts | 36 + src/commands/compliance/get-byork-config.ts | 41 + src/commands/compliance/get-byork-verdict.ts | 50 + .../get-legal-entity-for-address.ts | 48 + src/commands/compliance/get-legal-entity.ts | 48 + .../compliance/get-post-screening-policy.ts | 36 + .../compliance/get-screening-full-details.ts | 48 + .../compliance/get-screening-policy.ts | 36 + .../list-address-registry-vault-opt-outs.ts | 62 + .../compliance/list-legal-entities.ts | 77 + .../list-vaults-for-legal-entity.ts | 63 + .../opt-in-address-registry-tenant.ts | 46 + .../opt-out-address-registry-tenant.ts | 43 + .../compliance/register-legal-entity.ts | 63 + .../remove-address-registry-vault-opt-out.ts | 50 + ...ove-all-address-registry-vault-opt-outs.ts | 43 + ...ted-transaction-bypass-screening-checks.ts | 53 + src/commands/compliance/set-aml-verdict.ts | 63 + src/commands/compliance/set-byork-timeouts.ts | 63 + src/commands/compliance/set-byork-verdict.ts | 63 + .../update-aml-screening-configuration.ts | 41 + .../compliance/update-legal-entity.ts | 70 + .../update-screening-configuration.ts | 58 + .../compliance/update-travel-rule-config.ts | 41 + src/commands/configure.ts | 111 + .../disconnect-connected-account.ts | 52 + .../get-connected-account-balances.ts | 64 + .../get-connected-account-rates.ts | 66 + .../get-connected-account-trading-pairs.ts | 65 + .../get-connected-account.ts | 50 + .../get-connected-accounts.ts | 64 + .../rename-connected-account.ts | 72 + .../console-user/create-console-user.ts | 62 + .../console-user/get-console-users.ts | 41 + .../decode-contract-data.ts | 75 + .../get-contract-address.ts | 56 + .../get-deployed-contract-abi.ts | 56 + .../get-transaction-receipt.ts | 53 + .../read-call-function.ts | 75 + .../write-call-function.ts | 75 + .../delete-contract-template-by-id.ts | 50 + .../contract-templates/deploy-contract.ts | 70 + ...get-constructor-by-contract-template-id.ts | 57 + .../get-contract-template-by-id.ts | 48 + .../get-contract-templates.ts | 83 + ...et-function-abi-by-contract-template-id.ts | 57 + ...et-supported-blockchains-by-template-id.ts | 48 + .../upload-contract-template.ts | 63 + src/commands/contracts/add-contract-asset.ts | 74 + src/commands/contracts/create-contract.ts | 62 + .../contracts/delete-contract-asset.ts | 55 + src/commands/contracts/delete-contract.ts | 50 + src/commands/contracts/get-contract-asset.ts | 53 + src/commands/contracts/get-contract.ts | 48 + src/commands/contracts/get-contracts.ts | 41 + src/commands/cosigners/add-cosigner.ts | 65 + src/commands/cosigners/get-api-key.ts | 55 + src/commands/cosigners/get-api-keys.ts | 73 + src/commands/cosigners/get-cosigner.ts | 50 + src/commands/cosigners/get-cosigners.ts | 66 + src/commands/cosigners/get-request-status.ts | 60 + src/commands/cosigners/pair-api-key.ts | 77 + src/commands/cosigners/rename-cosigner.ts | 69 + src/commands/cosigners/unpair-api-key.ts | 57 + .../cosigners/update-callback-handler.ts | 74 + .../deployed-contracts/add-contract-abi.ts | 63 + .../deployed-contracts/fetch-contract-abi.ts | 63 + .../get-deployed-contract-by-address.ts | 53 + .../get-deployed-contract-by-id.ts | 48 + .../get-deployed-contracts.ts | 73 + .../add-embedded-wallet-asset.ts | 63 + .../assign-embedded-wallet.ts | 53 + .../create-embedded-wallet-account.ts | 53 + .../create-embedded-wallet.ts | 46 + .../get-embedded-wallet-account.ts | 53 + .../get-embedded-wallet-addresses.ts | 94 + .../get-embedded-wallet-asset-balance.ts | 58 + .../get-embedded-wallet-asset.ts | 58 + .../get-embedded-wallet-assets.ts | 83 + .../get-embedded-wallet-device-setup-state.ts | 53 + .../get-embedded-wallet-device.ts | 53 + .../get-embedded-wallet-devices-paginated.ts | 78 + .../get-embedded-wallet-latest-backup.ts | 48 + ...dded-wallet-public-key-info-for-address.ts | 76 + .../get-embedded-wallet-setup-status.ts | 48 + .../get-embedded-wallet-supported-assets.ts | 62 + .../embedded-wallets/get-embedded-wallet.ts | 48 + .../embedded-wallets/get-embedded-wallets.ts | 78 + .../get-public-key-info-for-address-ncw.ts | 76 + .../get-public-key-info-ncw.ts | 71 + .../refresh-embedded-wallet-asset-balance.ts | 63 + .../update-embedded-wallet-device-status.ts | 75 + .../update-embedded-wallet-status.ts | 70 + .../exchange-accounts/add-exchange-account.ts | 63 + .../exchange-accounts/convert-assets.ts | 69 + .../get-exchange-account-asset.ts | 53 + .../exchange-accounts/get-exchange-account.ts | 48 + ...xchange-accounts-credentials-public-key.ts | 41 + .../get-exchange-accounts.ts | 41 + .../get-paged-exchange-accounts.ts | 63 + .../exchange-accounts/internal-transfer.ts | 69 + .../add-asset-to-external-wallet.ts | 74 + .../create-external-wallet.ts | 62 + .../delete-external-wallet.ts | 50 + .../get-external-wallet-asset.ts | 53 + .../external-wallets/get-external-wallet.ts | 48 + .../external-wallets/get-external-wallets.ts | 41 + .../remove-asset-from-external-wallet.ts | 55 + .../set-external-wallet-customer-ref-id.ts | 70 + .../deposit-funds-from-linked-dda.ts | 69 + .../fiat-accounts/get-fiat-account.ts | 48 + .../fiat-accounts/get-fiat-accounts.ts | 41 + .../redeem-funds-to-linked-dda.ts | 69 + .../get-gas-station-by-asset-id.ts | 48 + .../gas-stations/get-gas-station-info.ts | 41 + ...e-gas-station-configuration-by-asset-id.ts | 70 + .../update-gas-station-configuration.ts | 63 + src/commands/help-index.ts | 81 + .../create-internal-wallet-asset.ts | 74 + .../create-internal-wallet.ts | 62 + .../delete-internal-wallet-asset.ts | 55 + .../delete-internal-wallet.ts | 50 + .../get-internal-wallet-asset.ts | 53 + .../get-internal-wallet-assets-paginated.ts | 63 + .../internal-wallets/get-internal-wallet.ts | 48 + .../internal-wallets/get-internal-wallets.ts | 41 + ...set-customer-ref-id-for-internal-wallet.ts | 70 + src/commands/key-link/create-signing-key.ts | 65 + .../key-link/create-validation-key.ts | 65 + .../key-link/disable-validation-key.ts | 69 + src/commands/key-link/get-signing-key.ts | 50 + .../key-link/get-signing-keys-list.ts | 117 + src/commands/key-link/get-validation-key.ts | 50 + .../key-link/get-validation-keys-list.ts | 74 + src/commands/key-link/set-agent-id.ts | 69 + src/commands/key-link/update-signing-key.ts | 69 + .../keys/get-mpc-keys-list-by-user.ts | 50 + src/commands/keys/get-mpc-keys-list.ts | 43 + .../check-third-party-routing.ts | 53 + .../create-network-connection.ts | 62 + .../network-connections/create-network-id.ts | 62 + .../delete-network-connection.ts | 50 + .../network-connections/delete-network-id.ts | 50 + .../get-network-connections.ts | 41 + .../network-connections/get-network-id.ts | 48 + .../network-connections/get-network-ids.ts | 41 + .../network-connections/get-network.ts | 48 + .../get-routing-policy-asset-groups.ts | 41 + .../network-connections/search-network-ids.ts | 80 + .../set-network-id-discoverability.ts | 67 + .../set-network-id-name.ts | 67 + .../set-network-id-routing-policy.ts | 66 + .../network-connections/set-routing-policy.ts | 66 + src/commands/nfts/get-nf-ts.ts | 76 + src/commands/nfts/get-nft.ts | 48 + src/commands/nfts/get-ownership-tokens.ts | 135 + src/commands/nfts/list-owned-collections.ts | 97 + src/commands/nfts/list-owned-tokens.ts | 104 + src/commands/nfts/refresh-nft-metadata.ts | 53 + src/commands/nfts/update-ownership-tokens.ts | 63 + .../nfts/update-token-ownership-status.ts | 70 + .../nfts/update-tokens-ownership-spam.ts | 63 + .../nfts/update-tokens-ownership-status.ts | 63 + .../off-exchanges/add-off-exchange.ts | 62 + .../get-off-exchange-collateral-accounts.ts | 48 + ...et-off-exchange-settlement-transactions.ts | 50 + .../off-exchanges/remove-off-exchange.ts | 62 + .../settle-off-exchange-trades.ts | 62 + .../get-access-registry-current-state.ts | 83 + .../get-access-registry-summary.ts | 53 + .../get-active-roles-for-contract.ts | 53 + .../get-contract-balance-history.ts | 108 + .../get-contract-balances-summary.ts | 53 + .../onchain-data/get-contract-total-supply.ts | 103 + .../get-latest-balances-for-contract.ts | 89 + .../onchain-data/get-onchain-transactions.ts | 95 + src/commands/ota/get-ota-status.ts | 38 + src/commands/ota/set-ota-status.ts | 65 + .../create-flow-configuration.ts | 57 + .../payments-flows/create-flow-execution.ts | 57 + .../delete-flow-configuration.ts | 45 + .../payments-flows/get-flow-configuration.ts | 43 + .../payments-flows/get-flow-execution.ts | 43 + .../payments-flows/launch-flow-execution.ts | 48 + src/commands/payments-payout/create-payout.ts | 57 + .../payments-payout/execute-payout-action.ts | 48 + src/commands/payments-payout/get-payout.ts | 43 + .../policy-editor-v2/get-active-policy.ts | 52 + src/commands/policy-editor-v2/get-draft.ts | 52 + .../policy-editor-v2/publish-draft.ts | 65 + src/commands/policy-editor-v2/update-draft.ts | 65 + .../policy-editor/get-active-policy-legacy.ts | 43 + .../policy-editor/get-draft-legacy.ts | 43 + .../policy-editor/publish-draft-legacy.ts | 65 + .../policy-editor/publish-policy-rules.ts | 65 + .../policy-editor/update-draft-legacy.ts | 65 + src/commands/reset-device/reset-device.ts | 53 + .../approve-dv-p-ticket-term.ts | 70 + src/commands/smart-transfer/cancel-ticket.ts | 48 + .../smart-transfer/create-ticket-term.ts | 65 + src/commands/smart-transfer/create-ticket.ts | 58 + .../smart-transfer/find-ticket-by-id.ts | 43 + .../smart-transfer/find-ticket-term-by-id.ts | 48 + src/commands/smart-transfer/fulfill-ticket.ts | 48 + .../smart-transfer/fund-dvp-ticket.ts | 65 + .../smart-transfer/fund-ticket-term.ts | 70 + .../get-smart-transfer-statistic.ts | 41 + .../get-smart-transfer-user-groups.ts | 36 + .../manually-fund-ticket-term.ts | 70 + .../smart-transfer/remove-ticket-term.ts | 50 + src/commands/smart-transfer/search-tickets.ts | 116 + .../smart-transfer/set-external-ref-id.ts | 65 + .../smart-transfer/set-ticket-expiration.ts | 65 + .../smart-transfer/set-user-groups.ts | 58 + src/commands/smart-transfer/submit-ticket.ts | 65 + .../smart-transfer/update-ticket-term.ts | 70 + ...approve-terms-of-service-by-provider-id.ts | 53 + src/commands/staking/claim-rewards.ts | 71 + src/commands/staking/consolidate.ts | 71 + src/commands/staking/get-all-delegations.ts | 55 + src/commands/staking/get-chain-info.ts | 48 + src/commands/staking/get-chains.ts | 41 + src/commands/staking/get-delegation-by-id.ts | 48 + src/commands/staking/get-positions.ts | 77 + src/commands/staking/get-providers.ts | 41 + src/commands/staking/get-summary-by-vault.ts | 41 + src/commands/staking/get-summary.ts | 41 + src/commands/staking/merge-stake-accounts.ts | 71 + src/commands/staking/split.ts | 71 + src/commands/staking/stake.ts | 70 + src/commands/staking/unstake.ts | 70 + src/commands/staking/withdraw.ts | 70 + src/commands/tags/cancel-approval-request.ts | 53 + src/commands/tags/create-tag.ts | 63 + src/commands/tags/delete-tag.ts | 50 + src/commands/tags/get-approval-request.ts | 48 + src/commands/tags/get-tag.ts | 48 + src/commands/tags/get-tags.ts | 81 + src/commands/tags/update-tag.ts | 70 + .../tokenization/burn-collection-token.ts | 70 + .../tokenization/create-new-collection.ts | 63 + .../deactivate-and-unlink-adapters.ts | 58 + .../tokenization/deploy-and-link-adapters.ts | 58 + .../fetch-collection-token-details.ts | 53 + .../tokenization/get-collection-by-id.ts | 48 + .../tokenization/get-deployable-address.ts | 63 + .../tokenization/get-layer-zero-dvn-config.ts | 51 + .../tokenization/get-layer-zero-peers.ts | 43 + .../tokenization/get-linked-collections.ts | 62 + src/commands/tokenization/get-linked-token.ts | 48 + .../tokenization/get-linked-tokens-count.ts | 41 + .../tokenization/get-linked-tokens.ts | 61 + src/commands/tokenization/issue-new-token.ts | 58 + .../tokenization/issue-token-multi-chain.ts | 58 + src/commands/tokenization/link.ts | 63 + .../tokenization/mint-collection-token.ts | 70 + .../re-issue-token-multi-chain.ts | 70 + .../tokenization/remove-layer-zero-peers.ts | 58 + .../tokenization/set-layer-zero-dvn-config.ts | 58 + .../tokenization/set-layer-zero-peers.ts | 58 + .../tokenization/unlink-collection.ts | 50 + src/commands/tokenization/unlink.ts | 50 + .../validate-layer-zero-channel-config.ts | 52 + src/commands/trading/create-order.ts | 65 + src/commands/trading/create-quote.ts | 65 + src/commands/trading/get-order.ts | 50 + src/commands/trading/get-orders.ts | 103 + .../trading/get-trading-provider-by-id.ts | 50 + src/commands/trading/get-trading-providers.ts | 58 + .../transactions/cancel-transaction.ts | 53 + .../transactions/create-transaction.ts | 62 + src/commands/transactions/drop-transaction.ts | 69 + .../transactions/estimate-network-fee.ts | 50 + .../transactions/estimate-transaction-fee.ts | 62 + .../transactions/freeze-transaction.ts | 53 + .../get-transaction-by-external-id.ts | 48 + src/commands/transactions/get-transaction.ts | 48 + src/commands/transactions/get-transactions.ts | 144 + ...firmation-threshold-by-transaction-hash.ts | 69 + .../set-transaction-confirmation-threshold.ts | 69 + .../transactions/unfreeze-transaction.ts | 53 + src/commands/transactions/validate-address.ts | 53 + .../create-trust-proof-of-address.ts | 63 + .../travel-rule/get-trust-proof-of-address.ts | 48 + src/commands/travel-rule/get-vas-ps.ts | 82 + src/commands/travel-rule/get-vasp-by-did.ts | 51 + .../travel-rule/get-vasp-for-vault.ts | 48 + .../travel-rule/set-vasp-for-vault.ts | 70 + src/commands/travel-rule/update-vasp.ts | 58 + .../validate-full-travel-rule-transaction.ts | 71 + .../validate-travel-rule-transaction.ts | 71 + .../assess-tr-link-travel-rule-requirement.ts | 70 + src/commands/trlink/cancel-tr-link-trm.ts | 75 + .../trlink/connect-tr-link-integration.ts | 70 + .../trlink/create-tr-link-customer.ts | 63 + .../trlink/create-tr-link-integration.ts | 63 + src/commands/trlink/create-tr-link-trm.ts | 70 + .../trlink/delete-tr-link-customer.ts | 50 + .../trlink/disconnect-tr-link-integration.ts | 50 + .../trlink/get-tr-link-customer-by-id.ts | 48 + .../get-tr-link-customer-integration-by-id.ts | 53 + .../get-tr-link-customer-integrations.ts | 48 + src/commands/trlink/get-tr-link-customers.ts | 41 + .../get-tr-link-integration-public-key.ts | 48 + src/commands/trlink/get-tr-link-partners.ts | 41 + src/commands/trlink/get-tr-link-policy.ts | 41 + .../trlink/get-tr-link-supported-asset.ts | 53 + src/commands/trlink/get-tr-link-trm-by-id.ts | 53 + src/commands/trlink/get-tr-link-vasp-by-id.ts | 53 + .../trlink/list-tr-link-supported-assets.ts | 63 + src/commands/trlink/list-tr-link-vasps.ts | 63 + src/commands/trlink/redirect-tr-link-trm.ts | 75 + ...link-destination-travel-rule-message-id.ts | 70 + ...link-transaction-travel-rule-message-id.ts | 70 + .../test-tr-link-integration-connection.ts | 53 + .../trlink/update-tr-link-customer.ts | 70 + src/commands/user-groups/create-user-group.ts | 65 + src/commands/user-groups/delete-user-group.ts | 52 + src/commands/user-groups/get-user-group.ts | 50 + src/commands/user-groups/get-user-groups.ts | 43 + src/commands/user-groups/update-user-group.ts | 72 + src/commands/users/get-users.ts | 41 + .../activate-asset-for-vault-account.ts | 66 + ...tach-or-detach-tags-from-vault-accounts.ts | 63 + src/commands/vaults/create-legacy-address.ts | 63 + .../vaults/create-multiple-accounts.ts | 63 + .../create-multiple-deposit-addresses.ts | 63 + .../create-vault-account-asset-address.ts | 74 + .../vaults/create-vault-account-asset.ts | 82 + src/commands/vaults/create-vault-account.ts | 63 + src/commands/vaults/get-asset-wallets.ts | 82 + ...e-multiple-deposit-addresses-job-status.ts | 48 + ...eate-multiple-vault-accounts-job-status.ts | 48 + src/commands/vaults/get-max-bip-index-used.ts | 53 + .../vaults/get-max-spendable-amount.ts | 61 + .../vaults/get-paged-vault-accounts.ts | 112 + .../vaults/get-public-key-info-for-address.ts | 71 + src/commands/vaults/get-public-key-info.ts | 63 + src/commands/vaults/get-unspent-inputs.ts | 53 + ...vault-account-asset-addresses-paginated.ts | 73 + .../get-vault-account-asset-addresses.ts | 53 + .../vaults/get-vault-account-asset.ts | 53 + src/commands/vaults/get-vault-account.ts | 48 + src/commands/vaults/get-vault-accounts.ts | 67 + src/commands/vaults/get-vault-assets.ts | 55 + .../vaults/get-vault-balance-by-asset.ts | 48 + src/commands/vaults/hide-vault-account.ts | 53 + .../vaults/set-customer-ref-id-for-address.ts | 80 + .../vaults/set-vault-account-auto-fuel.ts | 70 + .../set-vault-account-customer-ref-id.ts | 70 + src/commands/vaults/unhide-vault-account.ts | 53 + .../update-vault-account-asset-address.ts | 79 + .../update-vault-account-asset-balance.ts | 58 + src/commands/vaults/update-vault-account.ts | 70 + src/commands/web3-connections/create.ts | 63 + src/commands/web3-connections/get.ts | 78 + src/commands/web3-connections/remove.ts | 50 + src/commands/web3-connections/submit.ts | 70 + src/commands/webhooks-v2/create-webhook.ts | 63 + src/commands/webhooks-v2/delete-webhook.ts | 50 + src/commands/webhooks-v2/get-metrics.ts | 54 + .../webhooks-v2/get-notification-attempts.ts | 68 + src/commands/webhooks-v2/get-notification.ts | 61 + src/commands/webhooks-v2/get-notifications.ts | 109 + .../webhooks-v2/get-resend-job-status.ts | 53 + src/commands/webhooks-v2/get-webhook.ts | 48 + src/commands/webhooks-v2/get-webhooks.ts | 64 + .../resend-failed-notifications.ts | 70 + .../webhooks-v2/resend-notification-by-id.ts | 58 + .../resend-notifications-by-resource-id.ts | 70 + src/commands/webhooks-v2/update-webhook.ts | 67 + .../webhooks/resend-transaction-webhooks.ts | 70 + src/commands/webhooks/resend-webhooks.ts | 46 + .../get-whitelist-ip-addresses.ts | 48 + src/commands/whoami.ts | 49 + .../workspace-status/get-workspace-status.ts | 38 + src/commands/workspace/freeze-workspace.ts | 46 + src/commands/workspace/get-workspace.ts | 41 + src/index.ts | 1 + src/lib/auth/config.test.ts | 235 + src/lib/auth/config.ts | 132 + src/lib/auth/index.ts | 3 + src/lib/auth/signer.test.ts | 174 + src/lib/auth/signer.ts | 40 + src/lib/base-command.ts | 190 + src/lib/errors/mapper.test.ts | 151 + src/lib/errors/mapper.ts | 69 + src/lib/http/client.test.ts | 277 + src/lib/http/client.ts | 87 + src/lib/output/formatter.ts | 8 + src/lib/output/headers.test.ts | 79 + src/lib/output/headers.ts | 19 + src/lib/version.ts | 17 + test/contract.test.ts | 74 + test/e2e.test.ts | 501 ++ tsconfig.json | 20 + yarn.lock | 4739 +++++++++++++++++ 435 files changed, 31803 insertions(+) create mode 100644 .claude/skills/fireblocks-cli/SKILL.md create mode 100644 .github/workflows/auto-reply-issue.yml create mode 100644 .github/workflows/auto-reply-pr.yml create mode 100644 .github/workflows/draft-release-from-pr.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 .prettierrc.json create mode 100644 README.md create mode 100644 SKILL.md create mode 100644 bin/dev.cmd create mode 100755 bin/dev.js create mode 100644 bin/run.cmd create mode 100755 bin/run.js create mode 100644 eslint.config.mjs create mode 100644 jest.config.cjs create mode 100644 package.json create mode 100644 src/commands/admin-quorum/set-admin-quorum-threshold.ts create mode 100644 src/commands/api-user/create-api-user.ts create mode 100644 src/commands/api-user/get-api-users.ts create mode 100644 src/commands/audit-logs/get-audit-logs.ts create mode 100644 src/commands/blockchains-assets/get-asset.ts create mode 100644 src/commands/blockchains-assets/get-blockchain.ts create mode 100644 src/commands/blockchains-assets/get-supported-assets.ts create mode 100644 src/commands/blockchains-assets/list-assets.ts create mode 100644 src/commands/blockchains-assets/list-blockchains.ts create mode 100644 src/commands/blockchains-assets/register-new-asset.ts create mode 100644 src/commands/blockchains-assets/set-asset-price.ts create mode 100644 src/commands/blockchains-assets/update-asset-user-metadata.ts create mode 100644 src/commands/compliance-screening-configuration/get-aml-screening-configuration.ts create mode 100644 src/commands/compliance-screening-configuration/get-screening-configuration.ts create mode 100644 src/commands/compliance/activate-byork-config.ts create mode 100644 src/commands/compliance/add-address-registry-vault-opt-outs.ts create mode 100644 src/commands/compliance/assign-vaults-to-legal-entity.ts create mode 100644 src/commands/compliance/deactivate-byork-config.ts create mode 100644 src/commands/compliance/get-address-registry-tenant-participation-status.ts create mode 100644 src/commands/compliance/get-address-registry-vault-opt-out.ts create mode 100644 src/commands/compliance/get-aml-post-screening-policy.ts create mode 100644 src/commands/compliance/get-aml-screening-policy.ts create mode 100644 src/commands/compliance/get-byork-config.ts create mode 100644 src/commands/compliance/get-byork-verdict.ts create mode 100644 src/commands/compliance/get-legal-entity-for-address.ts create mode 100644 src/commands/compliance/get-legal-entity.ts create mode 100644 src/commands/compliance/get-post-screening-policy.ts create mode 100644 src/commands/compliance/get-screening-full-details.ts create mode 100644 src/commands/compliance/get-screening-policy.ts create mode 100644 src/commands/compliance/list-address-registry-vault-opt-outs.ts create mode 100644 src/commands/compliance/list-legal-entities.ts create mode 100644 src/commands/compliance/list-vaults-for-legal-entity.ts create mode 100644 src/commands/compliance/opt-in-address-registry-tenant.ts create mode 100644 src/commands/compliance/opt-out-address-registry-tenant.ts create mode 100644 src/commands/compliance/register-legal-entity.ts create mode 100644 src/commands/compliance/remove-address-registry-vault-opt-out.ts create mode 100644 src/commands/compliance/remove-all-address-registry-vault-opt-outs.ts create mode 100644 src/commands/compliance/retry-rejected-transaction-bypass-screening-checks.ts create mode 100644 src/commands/compliance/set-aml-verdict.ts create mode 100644 src/commands/compliance/set-byork-timeouts.ts create mode 100644 src/commands/compliance/set-byork-verdict.ts create mode 100644 src/commands/compliance/update-aml-screening-configuration.ts create mode 100644 src/commands/compliance/update-legal-entity.ts create mode 100644 src/commands/compliance/update-screening-configuration.ts create mode 100644 src/commands/compliance/update-travel-rule-config.ts create mode 100644 src/commands/configure.ts create mode 100644 src/commands/connected-accounts/disconnect-connected-account.ts create mode 100644 src/commands/connected-accounts/get-connected-account-balances.ts create mode 100644 src/commands/connected-accounts/get-connected-account-rates.ts create mode 100644 src/commands/connected-accounts/get-connected-account-trading-pairs.ts create mode 100644 src/commands/connected-accounts/get-connected-account.ts create mode 100644 src/commands/connected-accounts/get-connected-accounts.ts create mode 100644 src/commands/connected-accounts/rename-connected-account.ts create mode 100644 src/commands/console-user/create-console-user.ts create mode 100644 src/commands/console-user/get-console-users.ts create mode 100644 src/commands/contract-interactions/decode-contract-data.ts create mode 100644 src/commands/contract-interactions/get-contract-address.ts create mode 100644 src/commands/contract-interactions/get-deployed-contract-abi.ts create mode 100644 src/commands/contract-interactions/get-transaction-receipt.ts create mode 100644 src/commands/contract-interactions/read-call-function.ts create mode 100644 src/commands/contract-interactions/write-call-function.ts create mode 100644 src/commands/contract-templates/delete-contract-template-by-id.ts create mode 100644 src/commands/contract-templates/deploy-contract.ts create mode 100644 src/commands/contract-templates/get-constructor-by-contract-template-id.ts create mode 100644 src/commands/contract-templates/get-contract-template-by-id.ts create mode 100644 src/commands/contract-templates/get-contract-templates.ts create mode 100644 src/commands/contract-templates/get-function-abi-by-contract-template-id.ts create mode 100644 src/commands/contract-templates/get-supported-blockchains-by-template-id.ts create mode 100644 src/commands/contract-templates/upload-contract-template.ts create mode 100644 src/commands/contracts/add-contract-asset.ts create mode 100644 src/commands/contracts/create-contract.ts create mode 100644 src/commands/contracts/delete-contract-asset.ts create mode 100644 src/commands/contracts/delete-contract.ts create mode 100644 src/commands/contracts/get-contract-asset.ts create mode 100644 src/commands/contracts/get-contract.ts create mode 100644 src/commands/contracts/get-contracts.ts create mode 100644 src/commands/cosigners/add-cosigner.ts create mode 100644 src/commands/cosigners/get-api-key.ts create mode 100644 src/commands/cosigners/get-api-keys.ts create mode 100644 src/commands/cosigners/get-cosigner.ts create mode 100644 src/commands/cosigners/get-cosigners.ts create mode 100644 src/commands/cosigners/get-request-status.ts create mode 100644 src/commands/cosigners/pair-api-key.ts create mode 100644 src/commands/cosigners/rename-cosigner.ts create mode 100644 src/commands/cosigners/unpair-api-key.ts create mode 100644 src/commands/cosigners/update-callback-handler.ts create mode 100644 src/commands/deployed-contracts/add-contract-abi.ts create mode 100644 src/commands/deployed-contracts/fetch-contract-abi.ts create mode 100644 src/commands/deployed-contracts/get-deployed-contract-by-address.ts create mode 100644 src/commands/deployed-contracts/get-deployed-contract-by-id.ts create mode 100644 src/commands/deployed-contracts/get-deployed-contracts.ts create mode 100644 src/commands/embedded-wallets/add-embedded-wallet-asset.ts create mode 100644 src/commands/embedded-wallets/assign-embedded-wallet.ts create mode 100644 src/commands/embedded-wallets/create-embedded-wallet-account.ts create mode 100644 src/commands/embedded-wallets/create-embedded-wallet.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-account.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-addresses.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-asset-balance.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-asset.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-assets.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-device-setup-state.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-device.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-devices-paginated.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-latest-backup.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-public-key-info-for-address.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-setup-status.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet-supported-assets.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallet.ts create mode 100644 src/commands/embedded-wallets/get-embedded-wallets.ts create mode 100644 src/commands/embedded-wallets/get-public-key-info-for-address-ncw.ts create mode 100644 src/commands/embedded-wallets/get-public-key-info-ncw.ts create mode 100644 src/commands/embedded-wallets/refresh-embedded-wallet-asset-balance.ts create mode 100644 src/commands/embedded-wallets/update-embedded-wallet-device-status.ts create mode 100644 src/commands/embedded-wallets/update-embedded-wallet-status.ts create mode 100644 src/commands/exchange-accounts/add-exchange-account.ts create mode 100644 src/commands/exchange-accounts/convert-assets.ts create mode 100644 src/commands/exchange-accounts/get-exchange-account-asset.ts create mode 100644 src/commands/exchange-accounts/get-exchange-account.ts create mode 100644 src/commands/exchange-accounts/get-exchange-accounts-credentials-public-key.ts create mode 100644 src/commands/exchange-accounts/get-exchange-accounts.ts create mode 100644 src/commands/exchange-accounts/get-paged-exchange-accounts.ts create mode 100644 src/commands/exchange-accounts/internal-transfer.ts create mode 100644 src/commands/external-wallets/add-asset-to-external-wallet.ts create mode 100644 src/commands/external-wallets/create-external-wallet.ts create mode 100644 src/commands/external-wallets/delete-external-wallet.ts create mode 100644 src/commands/external-wallets/get-external-wallet-asset.ts create mode 100644 src/commands/external-wallets/get-external-wallet.ts create mode 100644 src/commands/external-wallets/get-external-wallets.ts create mode 100644 src/commands/external-wallets/remove-asset-from-external-wallet.ts create mode 100644 src/commands/external-wallets/set-external-wallet-customer-ref-id.ts create mode 100644 src/commands/fiat-accounts/deposit-funds-from-linked-dda.ts create mode 100644 src/commands/fiat-accounts/get-fiat-account.ts create mode 100644 src/commands/fiat-accounts/get-fiat-accounts.ts create mode 100644 src/commands/fiat-accounts/redeem-funds-to-linked-dda.ts create mode 100644 src/commands/gas-stations/get-gas-station-by-asset-id.ts create mode 100644 src/commands/gas-stations/get-gas-station-info.ts create mode 100644 src/commands/gas-stations/update-gas-station-configuration-by-asset-id.ts create mode 100644 src/commands/gas-stations/update-gas-station-configuration.ts create mode 100644 src/commands/help-index.ts create mode 100644 src/commands/internal-wallets/create-internal-wallet-asset.ts create mode 100644 src/commands/internal-wallets/create-internal-wallet.ts create mode 100644 src/commands/internal-wallets/delete-internal-wallet-asset.ts create mode 100644 src/commands/internal-wallets/delete-internal-wallet.ts create mode 100644 src/commands/internal-wallets/get-internal-wallet-asset.ts create mode 100644 src/commands/internal-wallets/get-internal-wallet-assets-paginated.ts create mode 100644 src/commands/internal-wallets/get-internal-wallet.ts create mode 100644 src/commands/internal-wallets/get-internal-wallets.ts create mode 100644 src/commands/internal-wallets/set-customer-ref-id-for-internal-wallet.ts create mode 100644 src/commands/key-link/create-signing-key.ts create mode 100644 src/commands/key-link/create-validation-key.ts create mode 100644 src/commands/key-link/disable-validation-key.ts create mode 100644 src/commands/key-link/get-signing-key.ts create mode 100644 src/commands/key-link/get-signing-keys-list.ts create mode 100644 src/commands/key-link/get-validation-key.ts create mode 100644 src/commands/key-link/get-validation-keys-list.ts create mode 100644 src/commands/key-link/set-agent-id.ts create mode 100644 src/commands/key-link/update-signing-key.ts create mode 100644 src/commands/keys/get-mpc-keys-list-by-user.ts create mode 100644 src/commands/keys/get-mpc-keys-list.ts create mode 100644 src/commands/network-connections/check-third-party-routing.ts create mode 100644 src/commands/network-connections/create-network-connection.ts create mode 100644 src/commands/network-connections/create-network-id.ts create mode 100644 src/commands/network-connections/delete-network-connection.ts create mode 100644 src/commands/network-connections/delete-network-id.ts create mode 100644 src/commands/network-connections/get-network-connections.ts create mode 100644 src/commands/network-connections/get-network-id.ts create mode 100644 src/commands/network-connections/get-network-ids.ts create mode 100644 src/commands/network-connections/get-network.ts create mode 100644 src/commands/network-connections/get-routing-policy-asset-groups.ts create mode 100644 src/commands/network-connections/search-network-ids.ts create mode 100644 src/commands/network-connections/set-network-id-discoverability.ts create mode 100644 src/commands/network-connections/set-network-id-name.ts create mode 100644 src/commands/network-connections/set-network-id-routing-policy.ts create mode 100644 src/commands/network-connections/set-routing-policy.ts create mode 100644 src/commands/nfts/get-nf-ts.ts create mode 100644 src/commands/nfts/get-nft.ts create mode 100644 src/commands/nfts/get-ownership-tokens.ts create mode 100644 src/commands/nfts/list-owned-collections.ts create mode 100644 src/commands/nfts/list-owned-tokens.ts create mode 100644 src/commands/nfts/refresh-nft-metadata.ts create mode 100644 src/commands/nfts/update-ownership-tokens.ts create mode 100644 src/commands/nfts/update-token-ownership-status.ts create mode 100644 src/commands/nfts/update-tokens-ownership-spam.ts create mode 100644 src/commands/nfts/update-tokens-ownership-status.ts create mode 100644 src/commands/off-exchanges/add-off-exchange.ts create mode 100644 src/commands/off-exchanges/get-off-exchange-collateral-accounts.ts create mode 100644 src/commands/off-exchanges/get-off-exchange-settlement-transactions.ts create mode 100644 src/commands/off-exchanges/remove-off-exchange.ts create mode 100644 src/commands/off-exchanges/settle-off-exchange-trades.ts create mode 100644 src/commands/onchain-data/get-access-registry-current-state.ts create mode 100644 src/commands/onchain-data/get-access-registry-summary.ts create mode 100644 src/commands/onchain-data/get-active-roles-for-contract.ts create mode 100644 src/commands/onchain-data/get-contract-balance-history.ts create mode 100644 src/commands/onchain-data/get-contract-balances-summary.ts create mode 100644 src/commands/onchain-data/get-contract-total-supply.ts create mode 100644 src/commands/onchain-data/get-latest-balances-for-contract.ts create mode 100644 src/commands/onchain-data/get-onchain-transactions.ts create mode 100644 src/commands/ota/get-ota-status.ts create mode 100644 src/commands/ota/set-ota-status.ts create mode 100644 src/commands/payments-flows/create-flow-configuration.ts create mode 100644 src/commands/payments-flows/create-flow-execution.ts create mode 100644 src/commands/payments-flows/delete-flow-configuration.ts create mode 100644 src/commands/payments-flows/get-flow-configuration.ts create mode 100644 src/commands/payments-flows/get-flow-execution.ts create mode 100644 src/commands/payments-flows/launch-flow-execution.ts create mode 100644 src/commands/payments-payout/create-payout.ts create mode 100644 src/commands/payments-payout/execute-payout-action.ts create mode 100644 src/commands/payments-payout/get-payout.ts create mode 100644 src/commands/policy-editor-v2/get-active-policy.ts create mode 100644 src/commands/policy-editor-v2/get-draft.ts create mode 100644 src/commands/policy-editor-v2/publish-draft.ts create mode 100644 src/commands/policy-editor-v2/update-draft.ts create mode 100644 src/commands/policy-editor/get-active-policy-legacy.ts create mode 100644 src/commands/policy-editor/get-draft-legacy.ts create mode 100644 src/commands/policy-editor/publish-draft-legacy.ts create mode 100644 src/commands/policy-editor/publish-policy-rules.ts create mode 100644 src/commands/policy-editor/update-draft-legacy.ts create mode 100644 src/commands/reset-device/reset-device.ts create mode 100644 src/commands/smart-transfer/approve-dv-p-ticket-term.ts create mode 100644 src/commands/smart-transfer/cancel-ticket.ts create mode 100644 src/commands/smart-transfer/create-ticket-term.ts create mode 100644 src/commands/smart-transfer/create-ticket.ts create mode 100644 src/commands/smart-transfer/find-ticket-by-id.ts create mode 100644 src/commands/smart-transfer/find-ticket-term-by-id.ts create mode 100644 src/commands/smart-transfer/fulfill-ticket.ts create mode 100644 src/commands/smart-transfer/fund-dvp-ticket.ts create mode 100644 src/commands/smart-transfer/fund-ticket-term.ts create mode 100644 src/commands/smart-transfer/get-smart-transfer-statistic.ts create mode 100644 src/commands/smart-transfer/get-smart-transfer-user-groups.ts create mode 100644 src/commands/smart-transfer/manually-fund-ticket-term.ts create mode 100644 src/commands/smart-transfer/remove-ticket-term.ts create mode 100644 src/commands/smart-transfer/search-tickets.ts create mode 100644 src/commands/smart-transfer/set-external-ref-id.ts create mode 100644 src/commands/smart-transfer/set-ticket-expiration.ts create mode 100644 src/commands/smart-transfer/set-user-groups.ts create mode 100644 src/commands/smart-transfer/submit-ticket.ts create mode 100644 src/commands/smart-transfer/update-ticket-term.ts create mode 100644 src/commands/staking/approve-terms-of-service-by-provider-id.ts create mode 100644 src/commands/staking/claim-rewards.ts create mode 100644 src/commands/staking/consolidate.ts create mode 100644 src/commands/staking/get-all-delegations.ts create mode 100644 src/commands/staking/get-chain-info.ts create mode 100644 src/commands/staking/get-chains.ts create mode 100644 src/commands/staking/get-delegation-by-id.ts create mode 100644 src/commands/staking/get-positions.ts create mode 100644 src/commands/staking/get-providers.ts create mode 100644 src/commands/staking/get-summary-by-vault.ts create mode 100644 src/commands/staking/get-summary.ts create mode 100644 src/commands/staking/merge-stake-accounts.ts create mode 100644 src/commands/staking/split.ts create mode 100644 src/commands/staking/stake.ts create mode 100644 src/commands/staking/unstake.ts create mode 100644 src/commands/staking/withdraw.ts create mode 100644 src/commands/tags/cancel-approval-request.ts create mode 100644 src/commands/tags/create-tag.ts create mode 100644 src/commands/tags/delete-tag.ts create mode 100644 src/commands/tags/get-approval-request.ts create mode 100644 src/commands/tags/get-tag.ts create mode 100644 src/commands/tags/get-tags.ts create mode 100644 src/commands/tags/update-tag.ts create mode 100644 src/commands/tokenization/burn-collection-token.ts create mode 100644 src/commands/tokenization/create-new-collection.ts create mode 100644 src/commands/tokenization/deactivate-and-unlink-adapters.ts create mode 100644 src/commands/tokenization/deploy-and-link-adapters.ts create mode 100644 src/commands/tokenization/fetch-collection-token-details.ts create mode 100644 src/commands/tokenization/get-collection-by-id.ts create mode 100644 src/commands/tokenization/get-deployable-address.ts create mode 100644 src/commands/tokenization/get-layer-zero-dvn-config.ts create mode 100644 src/commands/tokenization/get-layer-zero-peers.ts create mode 100644 src/commands/tokenization/get-linked-collections.ts create mode 100644 src/commands/tokenization/get-linked-token.ts create mode 100644 src/commands/tokenization/get-linked-tokens-count.ts create mode 100644 src/commands/tokenization/get-linked-tokens.ts create mode 100644 src/commands/tokenization/issue-new-token.ts create mode 100644 src/commands/tokenization/issue-token-multi-chain.ts create mode 100644 src/commands/tokenization/link.ts create mode 100644 src/commands/tokenization/mint-collection-token.ts create mode 100644 src/commands/tokenization/re-issue-token-multi-chain.ts create mode 100644 src/commands/tokenization/remove-layer-zero-peers.ts create mode 100644 src/commands/tokenization/set-layer-zero-dvn-config.ts create mode 100644 src/commands/tokenization/set-layer-zero-peers.ts create mode 100644 src/commands/tokenization/unlink-collection.ts create mode 100644 src/commands/tokenization/unlink.ts create mode 100644 src/commands/tokenization/validate-layer-zero-channel-config.ts create mode 100644 src/commands/trading/create-order.ts create mode 100644 src/commands/trading/create-quote.ts create mode 100644 src/commands/trading/get-order.ts create mode 100644 src/commands/trading/get-orders.ts create mode 100644 src/commands/trading/get-trading-provider-by-id.ts create mode 100644 src/commands/trading/get-trading-providers.ts create mode 100644 src/commands/transactions/cancel-transaction.ts create mode 100644 src/commands/transactions/create-transaction.ts create mode 100644 src/commands/transactions/drop-transaction.ts create mode 100644 src/commands/transactions/estimate-network-fee.ts create mode 100644 src/commands/transactions/estimate-transaction-fee.ts create mode 100644 src/commands/transactions/freeze-transaction.ts create mode 100644 src/commands/transactions/get-transaction-by-external-id.ts create mode 100644 src/commands/transactions/get-transaction.ts create mode 100644 src/commands/transactions/get-transactions.ts create mode 100644 src/commands/transactions/set-confirmation-threshold-by-transaction-hash.ts create mode 100644 src/commands/transactions/set-transaction-confirmation-threshold.ts create mode 100644 src/commands/transactions/unfreeze-transaction.ts create mode 100644 src/commands/transactions/validate-address.ts create mode 100644 src/commands/travel-rule/create-trust-proof-of-address.ts create mode 100644 src/commands/travel-rule/get-trust-proof-of-address.ts create mode 100644 src/commands/travel-rule/get-vas-ps.ts create mode 100644 src/commands/travel-rule/get-vasp-by-did.ts create mode 100644 src/commands/travel-rule/get-vasp-for-vault.ts create mode 100644 src/commands/travel-rule/set-vasp-for-vault.ts create mode 100644 src/commands/travel-rule/update-vasp.ts create mode 100644 src/commands/travel-rule/validate-full-travel-rule-transaction.ts create mode 100644 src/commands/travel-rule/validate-travel-rule-transaction.ts create mode 100644 src/commands/trlink/assess-tr-link-travel-rule-requirement.ts create mode 100644 src/commands/trlink/cancel-tr-link-trm.ts create mode 100644 src/commands/trlink/connect-tr-link-integration.ts create mode 100644 src/commands/trlink/create-tr-link-customer.ts create mode 100644 src/commands/trlink/create-tr-link-integration.ts create mode 100644 src/commands/trlink/create-tr-link-trm.ts create mode 100644 src/commands/trlink/delete-tr-link-customer.ts create mode 100644 src/commands/trlink/disconnect-tr-link-integration.ts create mode 100644 src/commands/trlink/get-tr-link-customer-by-id.ts create mode 100644 src/commands/trlink/get-tr-link-customer-integration-by-id.ts create mode 100644 src/commands/trlink/get-tr-link-customer-integrations.ts create mode 100644 src/commands/trlink/get-tr-link-customers.ts create mode 100644 src/commands/trlink/get-tr-link-integration-public-key.ts create mode 100644 src/commands/trlink/get-tr-link-partners.ts create mode 100644 src/commands/trlink/get-tr-link-policy.ts create mode 100644 src/commands/trlink/get-tr-link-supported-asset.ts create mode 100644 src/commands/trlink/get-tr-link-trm-by-id.ts create mode 100644 src/commands/trlink/get-tr-link-vasp-by-id.ts create mode 100644 src/commands/trlink/list-tr-link-supported-assets.ts create mode 100644 src/commands/trlink/list-tr-link-vasps.ts create mode 100644 src/commands/trlink/redirect-tr-link-trm.ts create mode 100644 src/commands/trlink/set-tr-link-destination-travel-rule-message-id.ts create mode 100644 src/commands/trlink/set-tr-link-transaction-travel-rule-message-id.ts create mode 100644 src/commands/trlink/test-tr-link-integration-connection.ts create mode 100644 src/commands/trlink/update-tr-link-customer.ts create mode 100644 src/commands/user-groups/create-user-group.ts create mode 100644 src/commands/user-groups/delete-user-group.ts create mode 100644 src/commands/user-groups/get-user-group.ts create mode 100644 src/commands/user-groups/get-user-groups.ts create mode 100644 src/commands/user-groups/update-user-group.ts create mode 100644 src/commands/users/get-users.ts create mode 100644 src/commands/vaults/activate-asset-for-vault-account.ts create mode 100644 src/commands/vaults/attach-or-detach-tags-from-vault-accounts.ts create mode 100644 src/commands/vaults/create-legacy-address.ts create mode 100644 src/commands/vaults/create-multiple-accounts.ts create mode 100644 src/commands/vaults/create-multiple-deposit-addresses.ts create mode 100644 src/commands/vaults/create-vault-account-asset-address.ts create mode 100644 src/commands/vaults/create-vault-account-asset.ts create mode 100644 src/commands/vaults/create-vault-account.ts create mode 100644 src/commands/vaults/get-asset-wallets.ts create mode 100644 src/commands/vaults/get-create-multiple-deposit-addresses-job-status.ts create mode 100644 src/commands/vaults/get-create-multiple-vault-accounts-job-status.ts create mode 100644 src/commands/vaults/get-max-bip-index-used.ts create mode 100644 src/commands/vaults/get-max-spendable-amount.ts create mode 100644 src/commands/vaults/get-paged-vault-accounts.ts create mode 100644 src/commands/vaults/get-public-key-info-for-address.ts create mode 100644 src/commands/vaults/get-public-key-info.ts create mode 100644 src/commands/vaults/get-unspent-inputs.ts create mode 100644 src/commands/vaults/get-vault-account-asset-addresses-paginated.ts create mode 100644 src/commands/vaults/get-vault-account-asset-addresses.ts create mode 100644 src/commands/vaults/get-vault-account-asset.ts create mode 100644 src/commands/vaults/get-vault-account.ts create mode 100644 src/commands/vaults/get-vault-accounts.ts create mode 100644 src/commands/vaults/get-vault-assets.ts create mode 100644 src/commands/vaults/get-vault-balance-by-asset.ts create mode 100644 src/commands/vaults/hide-vault-account.ts create mode 100644 src/commands/vaults/set-customer-ref-id-for-address.ts create mode 100644 src/commands/vaults/set-vault-account-auto-fuel.ts create mode 100644 src/commands/vaults/set-vault-account-customer-ref-id.ts create mode 100644 src/commands/vaults/unhide-vault-account.ts create mode 100644 src/commands/vaults/update-vault-account-asset-address.ts create mode 100644 src/commands/vaults/update-vault-account-asset-balance.ts create mode 100644 src/commands/vaults/update-vault-account.ts create mode 100644 src/commands/web3-connections/create.ts create mode 100644 src/commands/web3-connections/get.ts create mode 100644 src/commands/web3-connections/remove.ts create mode 100644 src/commands/web3-connections/submit.ts create mode 100644 src/commands/webhooks-v2/create-webhook.ts create mode 100644 src/commands/webhooks-v2/delete-webhook.ts create mode 100644 src/commands/webhooks-v2/get-metrics.ts create mode 100644 src/commands/webhooks-v2/get-notification-attempts.ts create mode 100644 src/commands/webhooks-v2/get-notification.ts create mode 100644 src/commands/webhooks-v2/get-notifications.ts create mode 100644 src/commands/webhooks-v2/get-resend-job-status.ts create mode 100644 src/commands/webhooks-v2/get-webhook.ts create mode 100644 src/commands/webhooks-v2/get-webhooks.ts create mode 100644 src/commands/webhooks-v2/resend-failed-notifications.ts create mode 100644 src/commands/webhooks-v2/resend-notification-by-id.ts create mode 100644 src/commands/webhooks-v2/resend-notifications-by-resource-id.ts create mode 100644 src/commands/webhooks-v2/update-webhook.ts create mode 100644 src/commands/webhooks/resend-transaction-webhooks.ts create mode 100644 src/commands/webhooks/resend-webhooks.ts create mode 100644 src/commands/whitelist-ip-addresses/get-whitelist-ip-addresses.ts create mode 100644 src/commands/whoami.ts create mode 100644 src/commands/workspace-status/get-workspace-status.ts create mode 100644 src/commands/workspace/freeze-workspace.ts create mode 100644 src/commands/workspace/get-workspace.ts create mode 100644 src/index.ts create mode 100644 src/lib/auth/config.test.ts create mode 100644 src/lib/auth/config.ts create mode 100644 src/lib/auth/index.ts create mode 100644 src/lib/auth/signer.test.ts create mode 100644 src/lib/auth/signer.ts create mode 100644 src/lib/base-command.ts create mode 100644 src/lib/errors/mapper.test.ts create mode 100644 src/lib/errors/mapper.ts create mode 100644 src/lib/http/client.test.ts create mode 100644 src/lib/http/client.ts create mode 100644 src/lib/output/formatter.ts create mode 100644 src/lib/output/headers.test.ts create mode 100644 src/lib/output/headers.ts create mode 100644 src/lib/version.ts create mode 100644 test/contract.test.ts create mode 100644 test/e2e.test.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.claude/skills/fireblocks-cli/SKILL.md b/.claude/skills/fireblocks-cli/SKILL.md new file mode 100644 index 0000000..d7e89d7 --- /dev/null +++ b/.claude/skills/fireblocks-cli/SKILL.md @@ -0,0 +1,115 @@ +--- +name: fireblocks-cli +description: Agent-first CLI for Fireblocks infrastructure. Execute any Fireblocks API operation from the command line. +--- + +# Fireblocks CLI + +## Command Pattern +``` +fireblocks [flags] +``` + +## Discovery + +- `fireblocks help-index` -- compact JSON index of all commands (<2K tokens). + Returns: `{commands: [{namespace, action, description, method?, path?, flags: [{name, type, required}]}]}` +- `fireblocks --help` -- list actions in a namespace. +- `fireblocks --help` -- show all flags for one command. +- `fireblocks --dry-run [flags]` -- preview request (method, url, params, body) without executing. +- `fireblocks whoami` -- verify credentials, calls GET /v1/users/me. Returns masked API key, base URL, and verification status. + +## Authentication + +Resolution order (highest priority first): +1. CLI flags: `--api-key`, `--secret-key` +2. Env vars: `FIREBLOCKS_API_KEY` + (`FIREBLOCKS_SECRET_KEY` | `FIREBLOCKS_SECRET_KEY_PATH`) +3. Config profile: `~/.config/fireblocks/config.json` (select with `--profile `) +4. Error if no credentials found. + +`--secret-key` accepts either an inline PEM string (detected by `-----BEGIN` marker) or a file path. + +`fireblocks configure` is interactive-only. Agents must use env vars or flags. + +## Flag Conventions + +- OpenAPI path params (e.g. `{vaultAccountId}`) become required flags: `--vault-account-id` +- OpenAPI query params become optional flags with the same kebab-case conversion. +- Write ops (POST/PUT/PATCH/DELETE) accept `--data ''` for the request body. +- Write ops that support idempotency accept `--idempotency-key ` for safe retries. + +## Global Flags + +| Flag | Env Var | Purpose | +|------|---------|---------| +| `--api-key` | `FIREBLOCKS_API_KEY` | API key | +| `--secret-key` | `FIREBLOCKS_SECRET_KEY` / `FIREBLOCKS_SECRET_KEY_PATH` | RSA private key (PEM or path) | +| `--base-url` | `FIREBLOCKS_BASE_URL` | Override API endpoint (default: `https://api.fireblocks.io`) | +| `--profile` | | Named config profile | +| `--no-confirm` | | Skip write-op confirmation prompt | +| `--dry-run` | | Preview request without executing | +| `--debug` | | Log request/response details to stderr | +| `--json` | | Force structured JSON output (oclif envelope) | + +## Non-Interactive Usage + +Always pass `--no-confirm` on write operations. The CLI auto-skips prompts when stdin is not a TTY, but explicit `--no-confirm` is safer and self-documenting. + +## Output + +- **stdout**: JSON data only. +- **stderr**: warnings, beta notices, errors, debug logs. +- `--debug` output on stderr: `[DEBUG] METHOD URL`, `[DEBUG] Body: ...`, `[DEBUG] Response: STATUS`, `[DEBUG] Request-ID: ...` +- Beta commands print to stderr: `Warning: This command is in beta and may change in future releases.` This is informational, not an error. + +## Exit Codes + +| Code | Meaning | Recovery | +|------|---------|----------| +| 0 | Success | | +| 1 | Client error (400/409/422) | Check request body/params | +| 2 | Usage/parse error | Check flag names and types | +| 3 | Auth error (401/403) | Verify credentials with `fireblocks whoami` | +| 4 | Not found (404) | Verify resource ID exists | +| 5 | Rate limited (429) | Wait `retry_after` seconds from error JSON, then retry | +| 6 | Server error (500+) | Retry after brief delay | +| 7 | Timeout (30s) | Retry; timeout is not configurable | + +## Error Format + +Errors are JSON on stderr: +```json +{"code": 5, "status": 429, "message": "Rate limit exceeded", "request_id": "abc-123", "retry_after": 30} +``` +`request_id` and `retry_after` are present only when applicable. + +## Examples +```bash +# List vault accounts +fireblocks vaults get-paged-vault-accounts --json + +# Get a specific vault +fireblocks vaults get-vault-account --vault-account-id 0 --json + +# Create a transaction (write op: requires --data and --no-confirm) +fireblocks transactions create-transaction \ + --data '{"assetId":"BTC","amount":"0.01","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"VAULT_ACCOUNT","id":"1"}}' \ + --no-confirm + +# Idempotent write with retry safety +fireblocks transactions create-transaction \ + --data '{"assetId":"ETH","amount":"1.0","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"ONE_TIME_ADDRESS","oneTimeAddress":{"address":"0x1234"}}}' \ + --idempotency-key "$(uuidgen)" --no-confirm + +# Preview without executing +fireblocks transactions create-transaction --data '{"assetId":"BTC","amount":"0.01"}' --dry-run + +# Debug a failing request +fireblocks vaults get-vault-account --vault-account-id 0 --debug + +# Use sandbox environment +fireblocks vaults get-paged-vault-accounts --base-url https://sandbox-api.fireblocks.io --json + +# Verify auth setup +fireblocks whoami +``` diff --git a/.github/workflows/auto-reply-issue.yml b/.github/workflows/auto-reply-issue.yml new file mode 100644 index 0000000..cabd42e --- /dev/null +++ b/.github/workflows/auto-reply-issue.yml @@ -0,0 +1,35 @@ +name: Auto Reply On New Issues +on: + issues: + types: [opened] + +jobs: + auto-reply: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v4 + + - name: Choose random reply message + id: choose_message + run: | + reply_messages=( + "Thank you for raising this issue! We will look into it shortly. (Note that this CLI code is auto generated)" + "We appreciate your feedback. Our team will investigate this issue shortly. (Note that this CLI code is auto generated)" + "Your issue has been noted. We'll get back to you soon. (Note that this CLI code is auto generated)" + "Thanks for raising this issue. We'll review it and provide updates soon. (Note that this CLI code is auto generated)" + "Thank you for letting us know about this issue. We'll investigate and get back to you soon. (Note that this CLI code is auto generated)" + "Acknowledged. We'll review the issue and respond soon. (Note that this CLI code is auto generated)" + "Thanks for bringing this to our attention. We'll review it and provide updates soon. (Note that this CLI code is auto generated)" + "We've received your issue. Thanks for your patience. (Note that this CLI code is auto generated)" + "Noted. Expect updates on your issue shortly. (Note that this CLI code is auto generated)" + "Your issue is important to us. We will look into it shortly. (Note that this CLI code is auto generated)" + ) + random_index=$((RANDOM % ${#reply_messages[@]})) + echo "message=${reply_messages[$random_index]}" >> $GITHUB_OUTPUT + + - name: Reply to issue + run: | + gh issue comment ${{ github.event.issue.number }} --body "${{ steps.choose_message.outputs.message }}" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/auto-reply-pr.yml b/.github/workflows/auto-reply-pr.yml new file mode 100644 index 0000000..1722b2d --- /dev/null +++ b/.github/workflows/auto-reply-pr.yml @@ -0,0 +1,36 @@ +name: Auto Reply On New Pull Requests +on: + pull_request: + types: [opened] + +jobs: + auto-reply: + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v4 + + - name: Choose random reply message + id: choose_message + run: | + reply_messages=( + "Thank you for raising this! We will review it shortly. (Note that this CLI code is auto generated)" + "We appreciate your contribution. Our team will investigate this request shortly. (Note that this CLI code is auto generated)" + "Your request has been noted. We'll get back to you soon. (Note that this CLI code is auto generated)" + "Thanks for submitting this request. We'll review it and provide updates soon. (Note that this CLI code is auto generated)" + "Thank you for letting us know about this request. We'll investigate and get back to you soon. (Note that this CLI code is auto generated)" + "Acknowledged. We'll review and respond soon. (Note that this CLI code is auto generated)" + "Thanks for bringing this request to our attention. We'll review and provide updates soon. (Note that this CLI code is auto generated)" + "We've received your request. Thanks for your patience. (Note that this CLI code is auto generated)" + "Noted. Expect updates shortly. (Note that this CLI code is auto generated)" + "Your request is important to us. We will look into it shortly. (Note that this CLI code is auto generated)" + ) + random_index=$((RANDOM % ${#reply_messages[@]})) + echo "message=${reply_messages[$random_index]}" >> $GITHUB_OUTPUT + + - name: Reply to pull request + if: (!contains(fromJSON('["github-actions"]'), github.event.pull_request.user.login)) + run: | + gh pr comment ${{ github.event.number }} --body "${{ steps.choose_message.outputs.message }}" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/draft-release-from-pr.yml b/.github/workflows/draft-release-from-pr.yml new file mode 100644 index 0000000..1e0641a --- /dev/null +++ b/.github/workflows/draft-release-from-pr.yml @@ -0,0 +1,100 @@ +name: Draft Release from PR + +on: + push: + branches: + - master + +permissions: + contents: write + pull-requests: read + +jobs: + draft-release: + runs-on: ubuntu-latest + + steps: + - name: Generate GitHub App token + id: generate-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ vars.CLI_GENERATION_APP_ID }} + private-key: ${{ secrets.CLI_GENERATION_APP_PRIVATE_KEY }} + + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ steps.generate-token.outputs.token }} + + - name: Get last merged PR + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + gh pr list \ + --state merged \ + --base master \ + --limit 1 \ + --json number,title,body,labels \ + > pr.json + + PR_NUM=$(jq -r '.[0].number // "none"' pr.json) + PR_TITLE=$(jq -r '.[0].title // "none"' pr.json) + echo "Found merged PR: #$PR_NUM - $PR_TITLE" + + - name: Get latest release version + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + LAST_TAG=$(gh release list --limit 1 --json tagName -q '.[0].tagName') + + if [[ -z "$LAST_TAG" || "$LAST_TAG" == "null" ]]; then + echo "No existing release found. A release tag is required to calculate the next version." + exit 1 + fi + + echo "Found latest release: $LAST_TAG" + echo "LAST_TAG=$LAST_TAG" >> $GITHUB_ENV + + - name: Calculate next version from labels + run: | + V="${LAST_TAG#v}" + + MAJOR=$(echo $V | cut -d. -f1) + MINOR=$(echo $V | cut -d. -f2) + PATCH=$(echo $V | cut -d. -f3) + + LABELS=$(jq -r '.[0].labels[].name' pr.json) + echo "Found labels: $LABELS" + + if echo "$LABELS" | grep -q "major"; then + echo "Bumping MAJOR version" + MAJOR=$((MAJOR+1)) + MINOR=0 + PATCH=0 + elif echo "$LABELS" | grep -q "minor"; then + echo "Bumping MINOR version" + MINOR=$((MINOR+1)) + PATCH=0 + else + echo "Bumping PATCH version" + PATCH=$((PATCH+1)) + fi + + echo "Calculated next version: v$MAJOR.$MINOR.$PATCH" + echo "VERSION=v$MAJOR.$MINOR.$PATCH" >> $GITHUB_ENV + + - name: Create DRAFT release using PR BODY + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + PR_BODY=$(jq -r '.[0].body // ""' pr.json) + + echo "Creating draft release..." + echo "Version: $VERSION" + + gh release create "$VERSION" \ + --draft \ + --title "$VERSION" \ + --notes "$PR_BODY" + + echo "Draft release created successfully!" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d338801 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,315 @@ +name: Publish + +on: + release: + types: [published] + +jobs: + build-and-test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Test + run: yarn test + + bump-version: + needs: build-and-test + runs-on: ubuntu-latest + steps: + - name: Generate GitHub App token + id: generate-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ vars.CLI_GENERATION_APP_ID }} + private-key: ${{ secrets.CLI_GENERATION_APP_PRIVATE_KEY }} + + - name: Check out repository code + uses: actions/checkout@v4 + with: + token: ${{ steps.generate-token.outputs.token }} + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install dependencies + run: | + yarn install --frozen-lockfile + npm i -g auto-changelog + + - name: Bump version and add changelog + run: | + initialTag=${{ github.event.release.tag_name }} + tag="${initialTag//[v]/}" + echo $tag + git remote update + git fetch + git checkout --track origin/master + git config --global user.email "github-actions@github.com" + git config --global user.name "Github Actions" + npm --no-git-tag-version --allow-same-version version $tag + auto-changelog + git add . + git commit -m "release $tag" + git push + + - name: Move tag + run: | + TAG_NAME=${{ github.event.release.tag_name }} + echo $TAG_NAME + git tag --force $TAG_NAME + git push --force origin $TAG_NAME + + pack-tarballs: + needs: bump-version + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: master + fetch-depth: 0 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Pack tarballs + run: npx oclif pack tarballs + + - name: Upload tarballs + uses: actions/upload-artifact@v4 + with: + name: tarballs + path: dist/*.tar.* + retention-days: 7 + + pack-macos-arm64: + needs: bump-version + runs-on: macos-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: master + fetch-depth: 0 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Pack macOS ARM64 + run: npx oclif pack macos --targets darwin-arm64 + + - name: Upload macOS ARM64 installer + uses: actions/upload-artifact@v4 + with: + name: macos-arm64 + path: dist/macos/*.pkg + retention-days: 7 + + pack-macos-x64: + needs: bump-version + runs-on: macos-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: master + fetch-depth: 0 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Pack macOS x64 + run: npx oclif pack macos --targets darwin-x64 + + - name: Upload macOS x64 installer + uses: actions/upload-artifact@v4 + with: + name: macos-x64 + path: dist/macos/*.pkg + retention-days: 7 + + pack-windows: + needs: bump-version + runs-on: windows-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: master + fetch-depth: 0 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Pack Windows + run: npx oclif pack win + + - name: Upload Windows installer + uses: actions/upload-artifact@v4 + with: + name: windows + path: dist/win32/*.exe + retention-days: 7 + + publish: + needs: bump-version + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + ref: master + fetch-depth: 0 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + cache: yarn + + - name: Ensure npm 11.5.1+ + run: npm install -g npm@^11 + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Publish package + run: npm publish --access public + + publish-to-private-registry: + needs: publish + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + ref: master + fetch-depth: 0 + + - name: Set up Node for dependency installation + uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + cache: yarn + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Set up Node for private registry publishing + uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: ${{ secrets.PRIVATE_NPM_REGISTRY_URL }} + + - name: Build + run: yarn build + + - name: Publish package to private registry + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.PRIVATE_NPM_REGISTRY_TOKEN }} + SKIP_POSTVERSION: true + + upload-release-assets: + needs: [pack-tarballs, pack-macos-arm64, pack-macos-x64, pack-windows] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download tarballs + uses: actions/download-artifact@v4 + with: + name: tarballs + path: dist/tarballs + + - name: Download macOS ARM64 + uses: actions/download-artifact@v4 + with: + name: macos-arm64 + path: dist/macos-arm64 + + - name: Download macOS x64 + uses: actions/download-artifact@v4 + with: + name: macos-x64 + path: dist/macos-x64 + + - name: Download Windows + uses: actions/download-artifact@v4 + with: + name: windows + path: dist/windows + + - name: Upload assets to GitHub release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + run: | + TAG=${{ github.event.release.tag_name }} + echo "Uploading assets to release $TAG..." + for file in dist/tarballs/* dist/macos-arm64/* dist/macos-x64/* dist/windows/*; do + [ -f "$file" ] || continue + echo "Uploading $(basename "$file")..." + gh release upload "$TAG" "$file" --repo "$GH_REPO" --clobber + done + echo "All assets uploaded successfully!" \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4be3a74 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: tests +on: + push: + branches-ignore: [main] + workflow_dispatch: + +jobs: + unit-tests: + strategy: + matrix: + os: ['ubuntu-latest', 'windows-latest', 'macos-latest'] + node_version: ['22.0.0'] + fail-fast: false + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node_version }} + cache: yarn + - run: yarn install --frozen-lockfile + - run: yarn build + - run: yarn test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9efbcd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/dist +/node_modules +/oclif.manifest.json +*.tsbuildinfo diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..6314335 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +"@oclif/prettier-config" diff --git a/README.md b/README.md new file mode 100644 index 0000000..53f1f37 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# @fireblocks/cli + +Agent-first CLI for Fireblocks infrastructure. Execute any Fireblocks API operation from the command line. + +## Installation + +```bash +npm install -g @fireblocks/cli +``` + +## Quick Start + +```bash +fireblocks configure +fireblocks vaults get-vault-accounts-paged --json +fireblocks help-index +``` + +## Documentation + +See [SKILL.md](./.claude/skills/fireblocks-cli/SKILL.md) for usage patterns and examples. diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..d7e89d7 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,115 @@ +--- +name: fireblocks-cli +description: Agent-first CLI for Fireblocks infrastructure. Execute any Fireblocks API operation from the command line. +--- + +# Fireblocks CLI + +## Command Pattern +``` +fireblocks [flags] +``` + +## Discovery + +- `fireblocks help-index` -- compact JSON index of all commands (<2K tokens). + Returns: `{commands: [{namespace, action, description, method?, path?, flags: [{name, type, required}]}]}` +- `fireblocks --help` -- list actions in a namespace. +- `fireblocks --help` -- show all flags for one command. +- `fireblocks --dry-run [flags]` -- preview request (method, url, params, body) without executing. +- `fireblocks whoami` -- verify credentials, calls GET /v1/users/me. Returns masked API key, base URL, and verification status. + +## Authentication + +Resolution order (highest priority first): +1. CLI flags: `--api-key`, `--secret-key` +2. Env vars: `FIREBLOCKS_API_KEY` + (`FIREBLOCKS_SECRET_KEY` | `FIREBLOCKS_SECRET_KEY_PATH`) +3. Config profile: `~/.config/fireblocks/config.json` (select with `--profile `) +4. Error if no credentials found. + +`--secret-key` accepts either an inline PEM string (detected by `-----BEGIN` marker) or a file path. + +`fireblocks configure` is interactive-only. Agents must use env vars or flags. + +## Flag Conventions + +- OpenAPI path params (e.g. `{vaultAccountId}`) become required flags: `--vault-account-id` +- OpenAPI query params become optional flags with the same kebab-case conversion. +- Write ops (POST/PUT/PATCH/DELETE) accept `--data ''` for the request body. +- Write ops that support idempotency accept `--idempotency-key ` for safe retries. + +## Global Flags + +| Flag | Env Var | Purpose | +|------|---------|---------| +| `--api-key` | `FIREBLOCKS_API_KEY` | API key | +| `--secret-key` | `FIREBLOCKS_SECRET_KEY` / `FIREBLOCKS_SECRET_KEY_PATH` | RSA private key (PEM or path) | +| `--base-url` | `FIREBLOCKS_BASE_URL` | Override API endpoint (default: `https://api.fireblocks.io`) | +| `--profile` | | Named config profile | +| `--no-confirm` | | Skip write-op confirmation prompt | +| `--dry-run` | | Preview request without executing | +| `--debug` | | Log request/response details to stderr | +| `--json` | | Force structured JSON output (oclif envelope) | + +## Non-Interactive Usage + +Always pass `--no-confirm` on write operations. The CLI auto-skips prompts when stdin is not a TTY, but explicit `--no-confirm` is safer and self-documenting. + +## Output + +- **stdout**: JSON data only. +- **stderr**: warnings, beta notices, errors, debug logs. +- `--debug` output on stderr: `[DEBUG] METHOD URL`, `[DEBUG] Body: ...`, `[DEBUG] Response: STATUS`, `[DEBUG] Request-ID: ...` +- Beta commands print to stderr: `Warning: This command is in beta and may change in future releases.` This is informational, not an error. + +## Exit Codes + +| Code | Meaning | Recovery | +|------|---------|----------| +| 0 | Success | | +| 1 | Client error (400/409/422) | Check request body/params | +| 2 | Usage/parse error | Check flag names and types | +| 3 | Auth error (401/403) | Verify credentials with `fireblocks whoami` | +| 4 | Not found (404) | Verify resource ID exists | +| 5 | Rate limited (429) | Wait `retry_after` seconds from error JSON, then retry | +| 6 | Server error (500+) | Retry after brief delay | +| 7 | Timeout (30s) | Retry; timeout is not configurable | + +## Error Format + +Errors are JSON on stderr: +```json +{"code": 5, "status": 429, "message": "Rate limit exceeded", "request_id": "abc-123", "retry_after": 30} +``` +`request_id` and `retry_after` are present only when applicable. + +## Examples +```bash +# List vault accounts +fireblocks vaults get-paged-vault-accounts --json + +# Get a specific vault +fireblocks vaults get-vault-account --vault-account-id 0 --json + +# Create a transaction (write op: requires --data and --no-confirm) +fireblocks transactions create-transaction \ + --data '{"assetId":"BTC","amount":"0.01","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"VAULT_ACCOUNT","id":"1"}}' \ + --no-confirm + +# Idempotent write with retry safety +fireblocks transactions create-transaction \ + --data '{"assetId":"ETH","amount":"1.0","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"ONE_TIME_ADDRESS","oneTimeAddress":{"address":"0x1234"}}}' \ + --idempotency-key "$(uuidgen)" --no-confirm + +# Preview without executing +fireblocks transactions create-transaction --data '{"assetId":"BTC","amount":"0.01"}' --dry-run + +# Debug a failing request +fireblocks vaults get-vault-account --vault-account-id 0 --debug + +# Use sandbox environment +fireblocks vaults get-paged-vault-accounts --base-url https://sandbox-api.fireblocks.io --json + +# Verify auth setup +fireblocks whoami +``` diff --git a/bin/dev.cmd b/bin/dev.cmd new file mode 100644 index 0000000..cec553b --- /dev/null +++ b/bin/dev.cmd @@ -0,0 +1,3 @@ +@echo off + +node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %* diff --git a/bin/dev.js b/bin/dev.js new file mode 100755 index 0000000..a937e0c --- /dev/null +++ b/bin/dev.js @@ -0,0 +1,5 @@ +#!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning + +import {execute} from '@oclif/core' + +await execute({development: true, dir: import.meta.url}) diff --git a/bin/run.cmd b/bin/run.cmd new file mode 100644 index 0000000..968fc30 --- /dev/null +++ b/bin/run.cmd @@ -0,0 +1,3 @@ +@echo off + +node "%~dp0\run" %* diff --git a/bin/run.js b/bin/run.js new file mode 100755 index 0000000..dd50271 --- /dev/null +++ b/bin/run.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +import {execute} from '@oclif/core' + +await execute({dir: import.meta.url}) diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..06a09c2 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,9 @@ +import {includeIgnoreFile} from '@eslint/compat' +import oclif from 'eslint-config-oclif' +import prettier from 'eslint-config-prettier' +import path from 'node:path' +import {fileURLToPath} from 'node:url' + +const gitignorePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '.gitignore') + +export default [includeIgnoreFile(gitignorePath), ...oclif, prettier] diff --git a/jest.config.cjs b/jest.config.cjs new file mode 100644 index 0000000..b195836 --- /dev/null +++ b/jest.config.cjs @@ -0,0 +1,31 @@ +/** @type {import('jest').Config} */ +const config = { + testEnvironment: 'node', + testMatch: ['**/src/**/*.test.ts', '**/test/**/*.test.ts'], + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + }, + transformIgnorePatterns: [ + 'node_modules/(?!(jose)/)', + ], + transform: { + '^.+\\.tsx?$': ['ts-jest', { + tsconfig: { + module: 'commonjs', + moduleResolution: 'node', + esModuleInterop: true, + verbatimModuleSyntax: false, + }, + }], + '^.+\\.js$': ['ts-jest', { + tsconfig: { + module: 'commonjs', + moduleResolution: 'node', + esModuleInterop: true, + allowJs: true, + }, + }], + }, +} + +module.exports = config diff --git a/package.json b/package.json new file mode 100644 index 0000000..d56cb1c --- /dev/null +++ b/package.json @@ -0,0 +1,227 @@ +{ + "name": "@fireblocks/fireblocks-cli", + "description": "Agent-first CLI for Fireblocks infrastructure. Execute any Fireblocks API operation from the command line.", + "version": "0.1.0", + "author": "Fireblocks", + "bin": { + "fireblocks": "./bin/run.js" + }, + "dependencies": { + "@oclif/core": "^4", + "@oclif/plugin-help": "^6", + "@oclif/plugin-autocomplete": "^3.2.42", + "chalk": "5", + "jose": "^6.2.1", + "js-yaml": "^4" + }, + "devDependencies": { + "@oclif/test": "^4", + "@types/js-yaml": "^4", + "@types/node": "^22", + "nock": "^14", + "oclif": "^4", + "shx": "^0.3.3", + "tsx": "^4", + "typescript": "^5", + "jest": "^29", + "ts-jest": "^29", + "ts-node": "^10", + "@types/jest": "^29" + }, + "engines": { + "node": ">=18.0.0" + }, + "files": [ + "./bin", + "./dist", + "./oclif.manifest.json" + ], + "keywords": ["oclif", "fireblocks", "cli"], + "license": "MIT", + "main": "dist/index.js", + "type": "module", + "oclif": { + "bin": "fireblocks", + "dirname": "fireblocks-cli", + "commands": { + "strategy": "pattern", + "target": "./dist/commands" + }, + "topicSeparator": " ", + "topics": { + "vaults": { + "description": "Vaults operations" + }, + "embedded-wallets": { + "description": "Embedded Wallets operations" + }, + "workspace": { + "description": "Workspace operations" + }, + "exchange-accounts": { + "description": "Exchange accounts operations" + }, + "fiat-accounts": { + "description": "Fiat accounts operations" + }, + "connected-accounts": { + "description": "Connected Accounts operations (Beta)" + }, + "network-connections": { + "description": "Network connections operations" + }, + "internal-wallets": { + "description": "Internal wallets operations" + }, + "key-link": { + "description": "Key Link operations (Beta)" + }, + "keys": { + "description": "Keys operations (Beta)" + }, + "external-wallets": { + "description": "External wallets operations" + }, + "contracts": { + "description": "Contracts operations" + }, + "blockchains-assets": { + "description": "Blockchains & assets operations" + }, + "transactions": { + "description": "Transactions operations" + }, + "payments-payout": { + "description": "Payments - Payout operations" + }, + "payments-flows": { + "description": "Payments - Flows operations" + }, + "gas-stations": { + "description": "Gas stations operations" + }, + "user-groups": { + "description": "User groups operations (Beta)" + }, + "users": { + "description": "Users operations" + }, + "audit-logs": { + "description": "Audit Logs operations" + }, + "off-exchanges": { + "description": "Off exchanges operations" + }, + "webhooks": { + "description": "Webhooks operations" + }, + "webhooks-v2": { + "description": "Webhooks V2 operations" + }, + "contract-templates": { + "description": "Contract Templates operations" + }, + "deployed-contracts": { + "description": "Deployed Contracts operations" + }, + "tokenization": { + "description": "Tokenization operations" + }, + "contract-interactions": { + "description": "Contract Interactions operations" + }, + "onchain-data": { + "description": "Onchain Data operations" + }, + "staking": { + "description": "Staking operations" + }, + "trading": { + "description": "Trading operations (Beta)" + }, + "admin-quorum": { + "description": "Admin Quorum operations" + }, + "nfts": { + "description": "NFTs operations" + }, + "web3-connections": { + "description": "Web3 connections operations" + }, + "compliance": { + "description": "Compliance operations" + }, + "travel-rule": { + "description": "Travel Rule operations" + }, + "compliance-screening-configuration": { + "description": "Compliance Screening Configuration operations" + }, + "trlink": { + "description": "TRLink operations" + }, + "ota": { + "description": "OTA operations (Beta)" + }, + "workspace-status": { + "description": "Workspace Status operations (Beta)" + }, + "policy-editor": { + "description": "Policy Editor operations (Beta)" + }, + "policy-editor-v2": { + "description": "Policy Editor V2 operations (Beta)" + }, + "console-user": { + "description": "Console User operations" + }, + "api-user": { + "description": "Api User operations" + }, + "reset-device": { + "description": "Reset device operations" + }, + "whitelist-ip-addresses": { + "description": "whitelist ip addresses operations" + }, + "smart-transfer": { + "description": "Smart Transfer operations" + }, + "tags": { + "description": "Tags operations" + }, + "cosigners": { + "description": "Cosigners operations (Beta)" + } +}, + "plugins": [ + "@oclif/plugin-help", + "@oclif/plugin-autocomplete" + ], + "update": { + "node": { + "version": "22.0.0" + } + }, + "targets": [ + "darwin-x64", + "darwin-arm64", + "linux-x64", + "linux-arm64", + "win32-x64" + ], + "macos": { + "identifier": "com.fireblocks.mycli" + } + }, + "scripts": { + "build": "shx rm -rf dist && tsc -b", + "postbuild": "oclif manifest", + "test": "jest", + "pack": "oclif pack tarballs", + "pack:mac-arm64": "oclif pack macos --targets darwin-arm64", + "pack:mac-x64": "oclif pack macos --targets darwin-x64", + "pack:win": "oclif pack win" +}, + "types": "dist/index.d.ts" +} diff --git a/src/commands/admin-quorum/set-admin-quorum-threshold.ts b/src/commands/admin-quorum/set-admin-quorum-threshold.ts new file mode 100644 index 0000000..5d76bb8 --- /dev/null +++ b/src/commands/admin-quorum/set-admin-quorum-threshold.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetAdminQuorumThreshold extends FireblocksBaseCommand { + static summary = 'Update admin quorum threshold' + + static description = 'Update admin quorum threshold\n\nOperation ID: setAdminQuorumThreshold\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Admin%20Quorum/setAdminQuorumThreshold' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/admin_quorum' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetAdminQuorumThreshold) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/admin_quorum') + + const result = await this.makeRequest( + 'PUT', + '/v1/admin_quorum', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/api-user/create-api-user.ts b/src/commands/api-user/create-api-user.ts new file mode 100644 index 0000000..b46751a --- /dev/null +++ b/src/commands/api-user/create-api-user.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateApiUser extends FireblocksBaseCommand { + static summary = 'Create API Key' + + static description = 'Create a new API key in your workspace.\nLearn more about Fireblocks API Keys management in the following [guide](https://developers.fireblocks.com/docs/manage-api-keys).\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: createApiUser\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Api%20User/createApiUser' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/management/api_users' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateApiUser) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/management/api_users') + + const result = await this.makeRequest( + 'POST', + '/v1/management/api_users', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/api-user/get-api-users.ts b/src/commands/api-user/get-api-users.ts new file mode 100644 index 0000000..2ec0a74 --- /dev/null +++ b/src/commands/api-user/get-api-users.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetApiUsers extends FireblocksBaseCommand { + static summary = 'Get API Keys' + + static description = 'List all API keys in your workspace.\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getApiUsers\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Api%20User/getApiUsers' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/management/api_users' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetApiUsers) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/management/api_users', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/audit-logs/get-audit-logs.ts b/src/commands/audit-logs/get-audit-logs.ts new file mode 100644 index 0000000..5db02f4 --- /dev/null +++ b/src/commands/audit-logs/get-audit-logs.ts @@ -0,0 +1,56 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAuditLogs extends FireblocksBaseCommand { + static summary = 'Get audit logs' + + static description = 'Get Audit logs for the last Day/Week.\n\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getAuditLogs\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Audit%20Logs/getAuditLogs' + + static enableJsonFlag = false + + static flags = { + 'time-period': Flags.string({ + description: 'The last time period to fetch audit logs', + options: ['DAY', 'WEEK'], + }), + 'cursor': Flags.string({ + description: 'The next id to start fetch audit logs from', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/management/audit_logs' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAuditLogs) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['time-period'] !== undefined && flags['time-period'] !== null) { + queryParams['timePeriod'] = String(flags['time-period']) + } + if (flags['cursor'] !== undefined && flags['cursor'] !== null) { + queryParams['cursor'] = String(flags['cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/management/audit_logs', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/get-asset.ts b/src/commands/blockchains-assets/get-asset.ts new file mode 100644 index 0000000..727f8d5 --- /dev/null +++ b/src/commands/blockchains-assets/get-asset.ts @@ -0,0 +1,51 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAsset extends FireblocksBaseCommand { + static summary = 'Get an asset' + + static description = 'Returns an asset by ID or legacyID.\n\n**Note**:\n\n - We will continue displaying and supporting the legacy ID (API ID). Since not all Fireblocks services fully support the new Assets UUID, please use only the legacy ID until further notice.\n\nOperation ID: getAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/getAsset' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The ID or legacyId of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/assets/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAsset) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/assets/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/get-blockchain.ts b/src/commands/blockchains-assets/get-blockchain.ts new file mode 100644 index 0000000..e764f22 --- /dev/null +++ b/src/commands/blockchains-assets/get-blockchain.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetBlockchain extends FireblocksBaseCommand { + static summary = 'Get a Blockchain by ID' + + static description = 'Returns a blockchain by ID or legacyID.\n\nOperation ID: getBlockchain\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/getBlockchain' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The ID or legacyId of the blockchain', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/blockchains/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetBlockchain) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/blockchains/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/get-supported-assets.ts b/src/commands/blockchains-assets/get-supported-assets.ts new file mode 100644 index 0000000..f92528f --- /dev/null +++ b/src/commands/blockchains-assets/get-supported-assets.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSupportedAssets extends FireblocksBaseCommand { + static summary = 'List assets (Legacy)' + + static description = '**This legacy endpoint has not been deprecated but it should not be used in your operations. Instead, use the new [List assets](https://developers.fireblocks.com/reference/listassets) endpoint for better performance and to retrieve more detailed asset information.**\n\nRetrieves all assets supported by Fireblocks in your workspace.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getSupportedAssets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/getSupportedAssets' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/supported_assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetSupportedAssets) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/supported_assets', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/list-assets.ts b/src/commands/blockchains-assets/list-assets.ts new file mode 100644 index 0000000..5ffad99 --- /dev/null +++ b/src/commands/blockchains-assets/list-assets.ts @@ -0,0 +1,95 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListAssets extends FireblocksBaseCommand { + static summary = 'List assets' + + static description = 'Retrieves a paginated list of all assets supported by Fireblocks in your workspace\n\n**Note:** We will continue to support and display the legacy ID (API ID). Since not all Fireblocks services fully support the new Assets UUID, please use only the legacy ID until further notice.\n\nOperation ID: listAssets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/listAssets' + + static enableJsonFlag = false + + static flags = { + 'blockchain-id': Flags.string({ + description: 'Blockchain id of the assets', + }), + 'asset-class': Flags.string({ + description: 'Assets class', + }), + 'symbol': Flags.string({ + description: 'Assets onchain symbol', + }), + 'scope': Flags.string({ + description: 'Scope of the assets', + }), + 'deprecated': Flags.boolean({ + description: 'Are assets deprecated', + }), + 'ids': Flags.string({ + description: 'A list of asset IDs (max 100)', + }), + 'page-cursor': Flags.string({ + description: 'Next page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page', + default: '500', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListAssets) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + const queryParams: Record = {} + if (flags['blockchain-id'] !== undefined && flags['blockchain-id'] !== null) { + queryParams['blockchainId'] = String(flags['blockchain-id']) + } + if (flags['asset-class'] !== undefined && flags['asset-class'] !== null) { + queryParams['assetClass'] = String(flags['asset-class']) + } + if (flags['symbol'] !== undefined && flags['symbol'] !== null) { + queryParams['symbol'] = String(flags['symbol']) + } + if (flags['scope'] !== undefined && flags['scope'] !== null) { + queryParams['scope'] = String(flags['scope']) + } + if (flags['deprecated'] !== undefined && flags['deprecated'] !== null) { + queryParams['deprecated'] = String(flags['deprecated']) + } + if (flags['ids'] !== undefined && flags['ids'] !== null) { + queryParams['ids'] = String(flags['ids']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/assets', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/list-blockchains.ts b/src/commands/blockchains-assets/list-blockchains.ts new file mode 100644 index 0000000..4995713 --- /dev/null +++ b/src/commands/blockchains-assets/list-blockchains.ts @@ -0,0 +1,80 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListBlockchains extends FireblocksBaseCommand { + static summary = 'List blockchains' + + static description = 'Returns all blockchains supported by Fireblocks.\n\nOperation ID: listBlockchains\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/listBlockchains' + + static enableJsonFlag = false + + static flags = { + 'protocol': Flags.string({ + description: 'Blockchain protocol', + }), + 'deprecated': Flags.boolean({ + description: 'Is blockchain deprecated', + }), + 'test': Flags.boolean({ + description: 'Is test blockchain', + }), + 'ids': Flags.string({ + description: 'A list of blockchain IDs (max 100)', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page (max 500)', + default: '500', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/blockchains' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListBlockchains) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['protocol'] !== undefined && flags['protocol'] !== null) { + queryParams['protocol'] = String(flags['protocol']) + } + if (flags['deprecated'] !== undefined && flags['deprecated'] !== null) { + queryParams['deprecated'] = String(flags['deprecated']) + } + if (flags['test'] !== undefined && flags['test'] !== null) { + queryParams['test'] = String(flags['test']) + } + if (flags['ids'] !== undefined && flags['ids'] !== null) { + queryParams['ids'] = String(flags['ids']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/blockchains', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/register-new-asset.ts b/src/commands/blockchains-assets/register-new-asset.ts new file mode 100644 index 0000000..bfadd63 --- /dev/null +++ b/src/commands/blockchains-assets/register-new-asset.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RegisterNewAsset extends FireblocksBaseCommand { + static summary = 'Register an asset' + + static description = 'Register a new asset to a workspace and return the newly created asset\'s details. Currently supported chains are:\n- EVM based chains\n- Stellar\n- Algorand\n- TRON\n- NEAR\n- Solana\n- Sui\n- TON\n\nOperation ID: registerNewAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/registerNewAsset' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RegisterNewAsset) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/assets') + + const result = await this.makeRequest( + 'POST', + '/v1/assets', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/set-asset-price.ts b/src/commands/blockchains-assets/set-asset-price.ts new file mode 100644 index 0000000..f63d4a4 --- /dev/null +++ b/src/commands/blockchains-assets/set-asset-price.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetAssetPrice extends FireblocksBaseCommand { + static summary = 'Set asset price' + + static description = 'Set asset price for the given asset id. Returns the asset price response.\n\nOperation ID: setAssetPrice\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/setAssetPrice' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/assets/prices/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetAssetPrice) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('POST', '/v1/assets/prices/{id}') + + const result = await this.makeRequest( + 'POST', + '/v1/assets/prices/{id}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/blockchains-assets/update-asset-user-metadata.ts b/src/commands/blockchains-assets/update-asset-user-metadata.ts new file mode 100644 index 0000000..92fd329 --- /dev/null +++ b/src/commands/blockchains-assets/update-asset-user-metadata.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateAssetUserMetadata extends FireblocksBaseCommand { + static summary = 'Update the user’s metadata for an asset' + + static description = 'Update the user’s metadata for an asset.\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, NCW Admin, Signer, Editor.\n\nOperation ID: updateAssetUserMetadata\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Blockchains%20%26%20assets/updateAssetUserMetadata' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The ID or legacyId of the asset', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/assets/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateAssetUserMetadata) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('PATCH', '/v1/assets/{id}') + + const result = await this.makeRequest( + 'PATCH', + '/v1/assets/{id}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance-screening-configuration/get-aml-screening-configuration.ts b/src/commands/compliance-screening-configuration/get-aml-screening-configuration.ts new file mode 100644 index 0000000..c1e6d07 --- /dev/null +++ b/src/commands/compliance-screening-configuration/get-aml-screening-configuration.ts @@ -0,0 +1,36 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAmlScreeningConfiguration extends FireblocksBaseCommand { + static summary = 'Get AML Screening Policy Configuration' + + static description = 'Retrieves the configuration for Travel Rule screening policy.\n\nOperation ID: getAmlScreeningConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance%20Screening%20Configuration/getAmlScreeningConfiguration' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/screening/aml/policy_configuration' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetAmlScreeningConfiguration) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/aml/policy_configuration', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance-screening-configuration/get-screening-configuration.ts b/src/commands/compliance-screening-configuration/get-screening-configuration.ts new file mode 100644 index 0000000..aa16fd0 --- /dev/null +++ b/src/commands/compliance-screening-configuration/get-screening-configuration.ts @@ -0,0 +1,36 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetScreeningConfiguration extends FireblocksBaseCommand { + static summary = 'Get Travel Rule Screening Policy Configuration' + + static description = 'Retrieves the configuration for Travel Rule screening policy.\n\nOperation ID: getScreeningConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance%20Screening%20Configuration/getScreeningConfiguration' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/screening/travel_rule/policy_configuration' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetScreeningConfiguration) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/travel_rule/policy_configuration', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/activate-byork-config.ts b/src/commands/compliance/activate-byork-config.ts new file mode 100644 index 0000000..d1f0cf3 --- /dev/null +++ b/src/commands/compliance/activate-byork-config.ts @@ -0,0 +1,46 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ActivateByorkConfig extends FireblocksBaseCommand { + static summary = 'Activate BYORK Light' + + static description = 'Activates BYORK Light for the authenticated tenant (sets config.active to true). Once activated, BYORK screening applies to matching transactions. Requires BYORK Light to be enabled for the tenant (contact your CSM to enable).\n\nOperation ID: activateByorkConfig\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/activateByorkConfig' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/byork/config/activate' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ActivateByorkConfig) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/screening/byork/config/activate') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/byork/config/activate', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/add-address-registry-vault-opt-outs.ts b/src/commands/compliance/add-address-registry-vault-opt-outs.ts new file mode 100644 index 0000000..e5d3570 --- /dev/null +++ b/src/commands/compliance/add-address-registry-vault-opt-outs.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddAddressRegistryVaultOptOuts extends FireblocksBaseCommand { + static summary = 'Add vault accounts to the address registry opt-out list' + + static description = 'Adds one or more vault account ids to the workspace opt-out list for the address registry.\n\nOperation ID: addAddressRegistryVaultOptOuts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/addAddressRegistryVaultOptOuts' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/address_registry/vaults' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddAddressRegistryVaultOptOuts) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/address_registry/vaults') + + const result = await this.makeRequest( + 'POST', + '/v1/address_registry/vaults', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/assign-vaults-to-legal-entity.ts b/src/commands/compliance/assign-vaults-to-legal-entity.ts new file mode 100644 index 0000000..2ead6ca --- /dev/null +++ b/src/commands/compliance/assign-vaults-to-legal-entity.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AssignVaultsToLegalEntity extends FireblocksBaseCommand { + static summary = 'Assign vault accounts to a legal entity' + + static description = 'Assigns one or more vault accounts to a specific legal entity registration. Explicitly mapped vault accounts take precedence over the workspace default legal entity.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: assignVaultsToLegalEntity\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/assignVaultsToLegalEntity' + + static enableJsonFlag = false + + static flags = { + 'legal-entity-id': Flags.string({ + description: 'The unique ID of the legal entity registration', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/legal_entities/{legalEntityId}/vaults' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AssignVaultsToLegalEntity) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['legalEntityId'] = String(flags['legal-entity-id']) + + + await this.confirmOrAbort('POST', '/v1/legal_entities/{legalEntityId}/vaults') + + const result = await this.makeRequest( + 'POST', + '/v1/legal_entities/{legalEntityId}/vaults', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/deactivate-byork-config.ts b/src/commands/compliance/deactivate-byork-config.ts new file mode 100644 index 0000000..6b2f399 --- /dev/null +++ b/src/commands/compliance/deactivate-byork-config.ts @@ -0,0 +1,46 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeactivateByorkConfig extends FireblocksBaseCommand { + static summary = 'Deactivate BYORK Light' + + static description = 'Deactivates BYORK Light for the authenticated tenant (sets config.active to false). Once deactivated, BYORK screening no longer applies until activated again. Requires BYORK Light to be enabled for the tenant (contact your CSM to enable).\n\nOperation ID: deactivateByorkConfig\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/deactivateByorkConfig' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/byork/config/deactivate' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeactivateByorkConfig) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/screening/byork/config/deactivate') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/byork/config/deactivate', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-address-registry-tenant-participation-status.ts b/src/commands/compliance/get-address-registry-tenant-participation-status.ts new file mode 100644 index 0000000..613f3c5 --- /dev/null +++ b/src/commands/compliance/get-address-registry-tenant-participation-status.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAddressRegistryTenantParticipationStatus extends FireblocksBaseCommand { + static summary = 'Get address registry participation status for the authenticated workspace' + + static description = 'Returns whether the workspace is \`OPTED_IN\` or \`OPTED_OUT\` of the address registry.\n\nOperation ID: getAddressRegistryTenantParticipationStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getAddressRegistryTenantParticipationStatus' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/address_registry/tenant' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAddressRegistryTenantParticipationStatus) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/address_registry/tenant', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-address-registry-vault-opt-out.ts b/src/commands/compliance/get-address-registry-vault-opt-out.ts new file mode 100644 index 0000000..44d9023 --- /dev/null +++ b/src/commands/compliance/get-address-registry-vault-opt-out.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAddressRegistryVaultOptOut extends FireblocksBaseCommand { + static summary = 'Get whether a vault account is opted out of the address registry' + + static description = 'Returns whether this vault account is on the workspace opt-out list (\`optedOut\` true or false). List, add, and clear-all are available on \`/v1/address_registry/vaults\`; this path reads or removes one vault.\n\nOperation ID: getAddressRegistryVaultOptOut\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getAddressRegistryVaultOptOut' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.integer({ + description: 'Vault account id (non-negative integer).', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/address_registry/vaults/{vaultAccountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAddressRegistryVaultOptOut) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/address_registry/vaults/{vaultAccountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-aml-post-screening-policy.ts b/src/commands/compliance/get-aml-post-screening-policy.ts new file mode 100644 index 0000000..fb4ac37 --- /dev/null +++ b/src/commands/compliance/get-aml-post-screening-policy.ts @@ -0,0 +1,36 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAmlPostScreeningPolicy extends FireblocksBaseCommand { + static summary = 'AML - View Post-Screening Policy' + + static description = 'Get the post-screening policy for AML.\n\nOperation ID: getAmlPostScreeningPolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getAmlPostScreeningPolicy' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/screening/aml/post_screening_policy' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetAmlPostScreeningPolicy) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/aml/post_screening_policy', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-aml-screening-policy.ts b/src/commands/compliance/get-aml-screening-policy.ts new file mode 100644 index 0000000..f28f82c --- /dev/null +++ b/src/commands/compliance/get-aml-screening-policy.ts @@ -0,0 +1,36 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAmlScreeningPolicy extends FireblocksBaseCommand { + static summary = 'AML - View Screening Policy' + + static description = 'Get the screening policy for AML.\n\nOperation ID: getAmlScreeningPolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getAmlScreeningPolicy' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/screening/aml/screening_policy' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetAmlScreeningPolicy) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/aml/screening_policy', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-byork-config.ts b/src/commands/compliance/get-byork-config.ts new file mode 100644 index 0000000..b7457ab --- /dev/null +++ b/src/commands/compliance/get-byork-config.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetByorkConfig extends FireblocksBaseCommand { + static summary = 'Get BYORK Light configuration' + + static description = 'Retrieves BYORK Light configuration for the authenticated tenant (timeouts, active flag, allowed timeout ranges). Returns default config when none exists. Requires BYORK Light to be enabled for the tenant.\n\nOperation ID: getByorkConfig\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getByorkConfig' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/byork/config' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetByorkConfig) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/byork/config', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-byork-verdict.ts b/src/commands/compliance/get-byork-verdict.ts new file mode 100644 index 0000000..9bddf11 --- /dev/null +++ b/src/commands/compliance/get-byork-verdict.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetByorkVerdict extends FireblocksBaseCommand { + static summary = 'Get BYORK Light verdict' + + static description = 'Returns the current BYORK verdict and status for a transaction. Status can be PRE_ACCEPTED, PENDING, RECEIVED (verdict is final but processing not yet complete), or COMPLETED. Requires BYORK Light to be enabled for the tenant. Returns 404 if no BYORK verdict is found for the transaction.\n\nOperation ID: getByorkVerdict\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getByorkVerdict' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'Transaction ID', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/byork/verdict' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetByorkVerdict) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['tx-id'] !== undefined && flags['tx-id'] !== null) { + queryParams['txId'] = String(flags['tx-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/screening/byork/verdict', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-legal-entity-for-address.ts b/src/commands/compliance/get-legal-entity-for-address.ts new file mode 100644 index 0000000..b37311f --- /dev/null +++ b/src/commands/compliance/get-legal-entity-for-address.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLegalEntityForAddress extends FireblocksBaseCommand { + static summary = 'Look up legal entity by blockchain address' + + static description = 'Returns legal entity information for the given blockchain address (verification status, LEI, Travel Rule providers, contact email, and related fields — see response schema). URL-encode \`{address}\` when required.\n\nOperation ID: getLegalEntityForAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getLegalEntityForAddress' + + static enableJsonFlag = false + + static flags = { + 'address': Flags.string({ + description: 'Blockchain address to look up', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/address_registry/legal_entities/{address}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetLegalEntityForAddress) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['address'] = String(flags['address']) + + + const result = await this.makeRequest( + 'GET', + '/v1/address_registry/legal_entities/{address}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-legal-entity.ts b/src/commands/compliance/get-legal-entity.ts new file mode 100644 index 0000000..da29983 --- /dev/null +++ b/src/commands/compliance/get-legal-entity.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLegalEntity extends FireblocksBaseCommand { + static summary = 'Get a legal entity' + + static description = 'Returns details of a specific legal entity registration, including GLEIF data when available.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getLegalEntity\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getLegalEntity' + + static enableJsonFlag = false + + static flags = { + 'legal-entity-id': Flags.string({ + description: 'The unique ID of the legal entity registration', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/legal_entities/{legalEntityId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetLegalEntity) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['legalEntityId'] = String(flags['legal-entity-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/legal_entities/{legalEntityId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-post-screening-policy.ts b/src/commands/compliance/get-post-screening-policy.ts new file mode 100644 index 0000000..35d0063 --- /dev/null +++ b/src/commands/compliance/get-post-screening-policy.ts @@ -0,0 +1,36 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPostScreeningPolicy extends FireblocksBaseCommand { + static summary = 'Travel Rule - View Post-Screening Policy' + + static description = 'Get the post-screening policy for Travel Rule.\n\nOperation ID: getPostScreeningPolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getPostScreeningPolicy' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/screening/travel_rule/post_screening_policy' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetPostScreeningPolicy) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/travel_rule/post_screening_policy', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-screening-full-details.ts b/src/commands/compliance/get-screening-full-details.ts new file mode 100644 index 0000000..4b0ed37 --- /dev/null +++ b/src/commands/compliance/get-screening-full-details.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetScreeningFullDetails extends FireblocksBaseCommand { + static summary = 'Provides all the compliance details for the given screened transaction.' + + static description = 'Provides all the compliance details for the given screened transaction.\n\nOperation ID: getScreeningFullDetails\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getScreeningFullDetails' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'Fireblocks transaction ID of the screened transaction', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/transaction/{txId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetScreeningFullDetails) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/transaction/{txId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/get-screening-policy.ts b/src/commands/compliance/get-screening-policy.ts new file mode 100644 index 0000000..8417738 --- /dev/null +++ b/src/commands/compliance/get-screening-policy.ts @@ -0,0 +1,36 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetScreeningPolicy extends FireblocksBaseCommand { + static summary = 'Travel Rule - View Screening Policy' + + static description = 'Get the screening policy for Travel Rule.\n\nOperation ID: getScreeningPolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/getScreeningPolicy' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/screening/travel_rule/screening_policy' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetScreeningPolicy) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/travel_rule/screening_policy', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/list-address-registry-vault-opt-outs.ts b/src/commands/compliance/list-address-registry-vault-opt-outs.ts new file mode 100644 index 0000000..87e2a26 --- /dev/null +++ b/src/commands/compliance/list-address-registry-vault-opt-outs.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListAddressRegistryVaultOptOuts extends FireblocksBaseCommand { + static summary = 'List vault-level address registry opt-outs (paginated)' + + static description = 'Lists vault accounts that are opted out of the address registry for this workspace. Pagination uses \`next\` and \`prev\` cursors from the response. If \`pageSize\` is omitted, **50** items are returned per page; allowed range is **1–100** per request.\n\nOperation ID: listAddressRegistryVaultOptOuts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/listAddressRegistryVaultOptOuts' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Opaque cursor from a previous response (\`next\` or \`prev\`). Omit for the first page.', + }), + 'page-size': Flags.integer({ + description: 'Page size. Default **50** if omitted; must be between **1** and **100**.', + default: 50, + }), + 'order': Flags.string({ + description: 'Sort direction by vault account id. Omit for ascending; use the enum value for descending.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/address_registry/vaults' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListAddressRegistryVaultOptOuts) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/address_registry/vaults', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/list-legal-entities.ts b/src/commands/compliance/list-legal-entities.ts new file mode 100644 index 0000000..be33edc --- /dev/null +++ b/src/commands/compliance/list-legal-entities.ts @@ -0,0 +1,77 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListLegalEntities extends FireblocksBaseCommand { + static summary = 'List legal entities (Paginated)' + + static description = 'Returns legal entity registrations for the workspace with cursor-based pagination.\nIf query parameter vaultAccountId is used it returns the legal entity registration associated with a specific vault account. If no explicit mapping exists for the vault, the workspace default legal entity is returned. Returns an empty response if neither a vault mapping nor a default legal entity is configured.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: listLegalEntities\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/listLegalEntities' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account. When provided, returns the legal entity associated with that vault account and pagination parameters are ignored.', + }), + 'page-cursor': Flags.string({ + description: 'Cursor string returned in \`next\` or \`prev\` of a previous response. Ignored when \`vaultAccountId\` is provided.', + }), + 'page-size': Flags.integer({ + description: 'Maximum number of registrations to return. Ignored when \`vaultAccountId\` is provided.', + default: 50, + }), + 'sort-by': Flags.string({ + description: 'Field to sort results by. Ignored when \`vaultAccountId\` is provided.', + options: ['createdAt', 'updatedAt'], + }), + 'order': Flags.string({ + description: 'Sort order. Ignored when \`vaultAccountId\` is provided.', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/legal_entities' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListLegalEntities) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['vault-account-id'] !== undefined && flags['vault-account-id'] !== null) { + queryParams['vaultAccountId'] = String(flags['vault-account-id']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/legal_entities', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/list-vaults-for-legal-entity.ts b/src/commands/compliance/list-vaults-for-legal-entity.ts new file mode 100644 index 0000000..5f01c31 --- /dev/null +++ b/src/commands/compliance/list-vaults-for-legal-entity.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListVaultsForLegalEntity extends FireblocksBaseCommand { + static summary = 'List vault accounts for a legal entity (Paginated)' + + static description = 'Returns vault account IDs explicitly assigned to a specific legal entity registration, with cursor-based pagination.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: listVaultsForLegalEntity\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/listVaultsForLegalEntity' + + static enableJsonFlag = false + + static flags = { + 'legal-entity-id': Flags.string({ + description: 'The unique ID of the legal entity registration', + required: true, + }), + 'page-cursor': Flags.string({ + description: 'Cursor string returned in \`next\` or \`prev\` of a previous response', + }), + 'page-size': Flags.integer({ + description: 'Maximum number of registrations to return', + default: 50, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/legal_entities/{legalEntityId}/vaults' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListVaultsForLegalEntity) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['legalEntityId'] = String(flags['legal-entity-id']) + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/legal_entities/{legalEntityId}/vaults', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/opt-in-address-registry-tenant.ts b/src/commands/compliance/opt-in-address-registry-tenant.ts new file mode 100644 index 0000000..ae244bf --- /dev/null +++ b/src/commands/compliance/opt-in-address-registry-tenant.ts @@ -0,0 +1,46 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class OptInAddressRegistryTenant extends FireblocksBaseCommand { + static summary = 'Opt the workspace in to the address registry' + + static description = 'Opts the workspace in. No request body. Response uses the same JSON shape as GET; status is OPTED_IN.\n\nOperation ID: optInAddressRegistryTenant\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/optInAddressRegistryTenant' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/address_registry/tenant' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(OptInAddressRegistryTenant) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/address_registry/tenant') + + const result = await this.makeRequest( + 'POST', + '/v1/address_registry/tenant', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/opt-out-address-registry-tenant.ts b/src/commands/compliance/opt-out-address-registry-tenant.ts new file mode 100644 index 0000000..d04dca8 --- /dev/null +++ b/src/commands/compliance/opt-out-address-registry-tenant.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class OptOutAddressRegistryTenant extends FireblocksBaseCommand { + static summary = 'Opt the workspace out of the address registry' + + static description = 'Opts the workspace out. No request body. Response uses the same JSON shape as GET; status is OPTED_OUT.\n\nOperation ID: optOutAddressRegistryTenant\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/optOutAddressRegistryTenant' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/address_registry/tenant' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(OptOutAddressRegistryTenant) + + + const headers: Record = {} + + + + await this.confirmOrAbort('DELETE', '/v1/address_registry/tenant') + + const result = await this.makeRequest( + 'DELETE', + '/v1/address_registry/tenant', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/register-legal-entity.ts b/src/commands/compliance/register-legal-entity.ts new file mode 100644 index 0000000..e81cb32 --- /dev/null +++ b/src/commands/compliance/register-legal-entity.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RegisterLegalEntity extends FireblocksBaseCommand { + static summary = 'Register a new legal entity' + + static description = 'Registers a new legal entity for the workspace using its LEI (Legal Entity Identifier) code. The LEI is validated against the GLEIF registry. Each workspace can register multiple legal entities.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: registerLegalEntity\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/registerLegalEntity' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/legal_entities' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RegisterLegalEntity) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/legal_entities') + + const result = await this.makeRequest( + 'POST', + '/v1/legal_entities', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/remove-address-registry-vault-opt-out.ts b/src/commands/compliance/remove-address-registry-vault-opt-out.ts new file mode 100644 index 0000000..85b102c --- /dev/null +++ b/src/commands/compliance/remove-address-registry-vault-opt-out.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RemoveAddressRegistryVaultOptOut extends FireblocksBaseCommand { + static summary = 'Remove a single vault account from the address registry opt-out list' + + static description = 'Removes this vault account id from the workspace opt-out list if it is present; otherwise the call still succeeds. Response body matches GET (\`optedOut\` is \`false\` after success). To clear the whole list, use \`DELETE /v1/address_registry/vaults\`.\n\nOperation ID: removeAddressRegistryVaultOptOut\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/removeAddressRegistryVaultOptOut' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.integer({ + description: 'Vault account id (non-negative integer).', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/address_registry/vaults/{vaultAccountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RemoveAddressRegistryVaultOptOut) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + await this.confirmOrAbort('DELETE', '/v1/address_registry/vaults/{vaultAccountId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/address_registry/vaults/{vaultAccountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/remove-all-address-registry-vault-opt-outs.ts b/src/commands/compliance/remove-all-address-registry-vault-opt-outs.ts new file mode 100644 index 0000000..a6235ee --- /dev/null +++ b/src/commands/compliance/remove-all-address-registry-vault-opt-outs.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RemoveAllAddressRegistryVaultOptOuts extends FireblocksBaseCommand { + static summary = 'Remove all vault-level address registry opt-outs for the workspace' + + static description = 'Removes all vault accounts from the workspace opt-out list.\n\nOperation ID: removeAllAddressRegistryVaultOptOuts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/removeAllAddressRegistryVaultOptOuts' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/address_registry/vaults' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RemoveAllAddressRegistryVaultOptOuts) + + + const headers: Record = {} + + + + await this.confirmOrAbort('DELETE', '/v1/address_registry/vaults') + + const result = await this.makeRequest( + 'DELETE', + '/v1/address_registry/vaults', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/retry-rejected-transaction-bypass-screening-checks.ts b/src/commands/compliance/retry-rejected-transaction-bypass-screening-checks.ts new file mode 100644 index 0000000..9ff750f --- /dev/null +++ b/src/commands/compliance/retry-rejected-transaction-bypass-screening-checks.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RetryRejectedTransactionBypassScreeningChecks extends FireblocksBaseCommand { + static summary = 'Calling the "Bypass Screening Policy" API endpoint triggers a new transaction, with the API user as the initiator, bypassing the screening policy check' + + static description = 'This endpoint is restricted to Admin API users and is only applicable to outgoing transactions.\n\nOperation ID: retryRejectedTransactionBypassScreeningChecks\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/retryRejectedTransactionBypassScreeningChecks' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The transaction id that was rejected by screening checks', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/transaction/{txId}/bypass_screening_policy' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RetryRejectedTransactionBypassScreeningChecks) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/transaction/{txId}/bypass_screening_policy') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/transaction/{txId}/bypass_screening_policy', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/set-aml-verdict.ts b/src/commands/compliance/set-aml-verdict.ts new file mode 100644 index 0000000..c5e092d --- /dev/null +++ b/src/commands/compliance/set-aml-verdict.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetAmlVerdict extends FireblocksBaseCommand { + static summary = 'Set AML Verdict (BYORK Super Light)' + + static description = 'Set AML verdict for incoming transactions when **BYORK Super Light** (Manual Screening Verdict) is enabled. This endpoint is for Super Light only. For **BYORK Light**, use POST /screening/byork/verdict instead. When Super Light is retired, this endpoint will be deprecated; use the BYORK Light verdict API for new integrations.\n\nOperation ID: setAmlVerdict\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/setAmlVerdict' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/aml/verdict/manual' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetAmlVerdict) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/screening/aml/verdict/manual') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/aml/verdict/manual', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/set-byork-timeouts.ts b/src/commands/compliance/set-byork-timeouts.ts new file mode 100644 index 0000000..d65b9ec --- /dev/null +++ b/src/commands/compliance/set-byork-timeouts.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetByorkTimeouts extends FireblocksBaseCommand { + static summary = 'Set BYORK Light timeouts' + + static description = 'Updates timeout values for BYORK wait-for-response (incoming and/or outgoing). At least one of incomingTimeoutSeconds or outgoingTimeoutSeconds is required. Values must be within the ranges returned in GET config (timeoutRangeIncoming for incomingTimeoutSeconds, timeoutRangeOutgoing for outgoingTimeoutSeconds). Requires BYORK Light to be enabled for the tenant (contact your CSM to enable).\n\nOperation ID: setByorkTimeouts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/setByorkTimeouts' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/screening/byork/config/timeouts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetByorkTimeouts) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/screening/byork/config/timeouts') + + const result = await this.makeRequest( + 'PUT', + '/v1/screening/byork/config/timeouts', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/set-byork-verdict.ts b/src/commands/compliance/set-byork-verdict.ts new file mode 100644 index 0000000..1fa51ab --- /dev/null +++ b/src/commands/compliance/set-byork-verdict.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetByorkVerdict extends FireblocksBaseCommand { + static summary = 'Set BYORK Light verdict' + + static description = 'Submit verdict (ACCEPT or REJECT) for a transaction in the BYORK Light flow. If the transaction is awaiting your decision, the verdict is applied immediately (response status COMPLETED). If processing has not yet reached that point, the verdict is stored and applied when it does (response status PRE_ACCEPTED). Requires BYORK Light to be enabled for the tenant.\n\nOperation ID: setByorkVerdict\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/setByorkVerdict' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/byork/verdict' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetByorkVerdict) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/screening/byork/verdict') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/byork/verdict', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/update-aml-screening-configuration.ts b/src/commands/compliance/update-aml-screening-configuration.ts new file mode 100644 index 0000000..0b7ddf4 --- /dev/null +++ b/src/commands/compliance/update-aml-screening-configuration.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateAmlScreeningConfiguration extends FireblocksBaseCommand { + static summary = 'Update AML Configuration' + + static description = 'Updates bypass screening, inbound delay, or outbound delay configurations for AML.\n\nOperation ID: updateAmlScreeningConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/updateAmlScreeningConfiguration' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'PUT' + static path = '/v1/screening/aml/policy_configuration' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(UpdateAmlScreeningConfiguration) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/screening/aml/policy_configuration') + + const result = await this.makeRequest( + 'PUT', + '/v1/screening/aml/policy_configuration', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/update-legal-entity.ts b/src/commands/compliance/update-legal-entity.ts new file mode 100644 index 0000000..7c2ea04 --- /dev/null +++ b/src/commands/compliance/update-legal-entity.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateLegalEntity extends FireblocksBaseCommand { + static summary = 'Update legal entity' + + static description = 'Updates the status of a legal entity registration. Setting isDefault to true marks the registration as the workspace default, which is applied to vault accounts that have no explicit legal entity mapping.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: updateLegalEntity\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/updateLegalEntity' + + static enableJsonFlag = false + + static flags = { + 'legal-entity-id': Flags.string({ + description: 'The unique ID of the legal entity registration', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/legal_entities/{legalEntityId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateLegalEntity) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['legalEntityId'] = String(flags['legal-entity-id']) + + + await this.confirmOrAbort('PUT', '/v1/legal_entities/{legalEntityId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/legal_entities/{legalEntityId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/update-screening-configuration.ts b/src/commands/compliance/update-screening-configuration.ts new file mode 100644 index 0000000..6460059 --- /dev/null +++ b/src/commands/compliance/update-screening-configuration.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateScreeningConfiguration extends FireblocksBaseCommand { + static summary = 'Tenant - Screening Configuration' + + static description = 'Update tenant screening configuration.\n\nOperation ID: updateScreeningConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/updateScreeningConfiguration' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/screening/configurations' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(UpdateScreeningConfiguration) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/screening/configurations') + + const result = await this.makeRequest( + 'PUT', + '/v1/screening/configurations', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/compliance/update-travel-rule-config.ts b/src/commands/compliance/update-travel-rule-config.ts new file mode 100644 index 0000000..2cc44e4 --- /dev/null +++ b/src/commands/compliance/update-travel-rule-config.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateTravelRuleConfig extends FireblocksBaseCommand { + static summary = 'Update Travel Rule Configuration' + + static description = 'Updates bypass screening, inbound delay, or outbound delay configurations for Travel Rule.\n\nOperation ID: updateTravelRuleConfig\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Compliance/updateTravelRuleConfig' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'PUT' + static path = '/v1/screening/travel_rule/policy_configuration' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(UpdateTravelRuleConfig) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/screening/travel_rule/policy_configuration') + + const result = await this.makeRequest( + 'PUT', + '/v1/screening/travel_rule/policy_configuration', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/configure.ts b/src/commands/configure.ts new file mode 100644 index 0000000..c0a6e5e --- /dev/null +++ b/src/commands/configure.ts @@ -0,0 +1,111 @@ +import {Command, Flags} from '@oclif/core' +import {createInterface} from 'node:readline' +import {access, constants} from 'node:fs/promises' +import {resolve} from 'node:path' +import {readConfig, writeConfig, getConfigPath, DEFAULT_BASE_URL} from '../lib/auth/config.js' +import type {CliConfig} from '../lib/auth/config.js' + +const BASE_URL_OPTIONS = [ + {label: 'Production (US) https://api.fireblocks.io', value: 'https://api.fireblocks.io'}, + {label: 'Production (EU) https://eu-api.fireblocks.io', value: 'https://api.eu.fireblocks.io'}, + {label: 'Production (EU2) https://eu2-api.fireblocks.io', value: 'https://api.eu2.fireblocks.io'}, + {label: 'Sandbox https://sandbox-api.fireblocks.io', value: 'https://sandbox-api.fireblocks.io'}, +] + +function prompt(rl: ReturnType, question: string): Promise { + return new Promise((res) => { + rl.question(question, (answer) => res(answer.trim())) + }) +} + +async function promptBaseUrl(rl: ReturnType): Promise { + const lines = BASE_URL_OPTIONS.map((opt, i) => ` ${i + 1}) ${opt.label}`).join('\n') + process.stderr.write(`Select base URL:\n${lines}\n`) + const defaultIndex = BASE_URL_OPTIONS.findIndex((o) => o.value === DEFAULT_BASE_URL) + while (true) { + const answer = await prompt(rl, `Choice [${defaultIndex + 1}]: `) + if (answer === '') return DEFAULT_BASE_URL + const idx = parseInt(answer, 10) - 1 + if (idx >= 0 && idx < BASE_URL_OPTIONS.length) return BASE_URL_OPTIONS[idx].value + process.stderr.write(`Please enter a number between 1 and ${BASE_URL_OPTIONS.length}.\n`) + } +} + +export default class Configure extends Command { + static override description = 'Set up Fireblocks API credentials interactively' + + static override examples = [ + '$ fireblocks configure', + '$ fireblocks configure --profile staging', + ] + + static override flags = { + profile: Flags.string({ + description: 'Named credential profile to configure', + default: 'default', + }), + } + + async run(): Promise { + const {flags} = await this.parse(Configure) + const profileName = flags.profile + + const rl = createInterface({input: process.stdin, output: process.stderr}) + + try { + // Check for existing config and warn if overwriting + const existing = await readConfig() + if (existing?.profiles[profileName]) { + const answer = await prompt( + rl, + `Profile "${profileName}" already exists in ${getConfigPath()}. Overwrite? (y/N) `, + ) + if (answer.toLowerCase() !== 'y') { + this.log('Aborted.') + return + } + } + + // Prompt for credentials + const apiKey = await prompt(rl, 'Fireblocks API key: ') + if (!apiKey) { + this.error('API key is required.') + } + + const privateKeyPath = await prompt(rl, 'Path to RSA private key file: ') + if (!privateKeyPath) { + this.error('Private key path is required.') + } + + // Resolve and validate the private key file + const resolvedKeyPath = resolve(privateKeyPath) + try { + await access(resolvedKeyPath, constants.R_OK) + } catch { + this.error(`Cannot read private key file: ${resolvedKeyPath}`) + } + + const baseUrl = await promptBaseUrl(rl) + + // Build config + const config: CliConfig = existing ?? {profiles: {}, defaultProfile: 'default'} + config.profiles[profileName] = { + apiKey, + privateKeyPath: resolvedKeyPath, + ...(baseUrl !== DEFAULT_BASE_URL ? {baseUrl} : {}), + } + + // If this is the first profile, make it the default + if (Object.keys(config.profiles).length === 1) { + config.defaultProfile = profileName + } + + await writeConfig(config) + + this.log(`Profile "${profileName}" configured successfully.`) + this.log(`Config written to ${getConfigPath()}`) + } finally { + rl.close() + } + } +} diff --git a/src/commands/connected-accounts/disconnect-connected-account.ts b/src/commands/connected-accounts/disconnect-connected-account.ts new file mode 100644 index 0000000..36de7d7 --- /dev/null +++ b/src/commands/connected-accounts/disconnect-connected-account.ts @@ -0,0 +1,52 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DisconnectConnectedAccount extends FireblocksBaseCommand { + static summary = 'Disconnect connected account' + + static description = 'Disconnect a connected account by ID. \n**Note**:\n- This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: disconnectConnectedAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Connected%20Accounts/disconnectConnectedAccount' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the account to disconnect.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/connected_accounts/{accountId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DisconnectConnectedAccount) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + + await this.confirmOrAbort('DELETE', '/v1/connected_accounts/{accountId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/connected_accounts/{accountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/connected-accounts/get-connected-account-balances.ts b/src/commands/connected-accounts/get-connected-account-balances.ts new file mode 100644 index 0000000..bfa8984 --- /dev/null +++ b/src/commands/connected-accounts/get-connected-account-balances.ts @@ -0,0 +1,64 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetConnectedAccountBalances extends FireblocksBaseCommand { + static summary = 'Get balances for an account' + + static description = 'Retrieve current asset balances for a specific connected account as a flat list (one row per \`assetId\`, \`balanceType\`).\n\n**Note:** This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: getConnectedAccountBalances\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Connected%20Accounts/getConnectedAccountBalances' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the account to fetch balances for.', + required: true, + }), + 'page-size': Flags.integer({ + description: 'Page size for pagination.', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor for pagination.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/connected_accounts/{accountId}/balances' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetConnectedAccountBalances) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + const queryParams: Record = {} + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/connected_accounts/{accountId}/balances', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/connected-accounts/get-connected-account-rates.ts b/src/commands/connected-accounts/get-connected-account-rates.ts new file mode 100644 index 0000000..94b539d --- /dev/null +++ b/src/commands/connected-accounts/get-connected-account-rates.ts @@ -0,0 +1,66 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetConnectedAccountRates extends FireblocksBaseCommand { + static summary = 'Get exchange rates for an account' + + static description = 'Retrieve current exchange rates for converting between specific assets in a connected account.\n\n**Note:** This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: getConnectedAccountRates\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Connected%20Accounts/getConnectedAccountRates' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the account to fetch rates for.', + required: true, + }), + 'base-asset-id': Flags.string({ + description: 'The ID of the asset to fetch rates for.', + required: true, + }), + 'quote-asset-id': Flags.string({ + description: 'The ID of the asset to get the rates nominally.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/connected_accounts/{accountId}/rates' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetConnectedAccountRates) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + const queryParams: Record = {} + if (flags['base-asset-id'] !== undefined && flags['base-asset-id'] !== null) { + queryParams['baseAssetId'] = String(flags['base-asset-id']) + } + if (flags['quote-asset-id'] !== undefined && flags['quote-asset-id'] !== null) { + queryParams['quoteAssetId'] = String(flags['quote-asset-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/connected_accounts/{accountId}/rates', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/connected-accounts/get-connected-account-trading-pairs.ts b/src/commands/connected-accounts/get-connected-account-trading-pairs.ts new file mode 100644 index 0000000..bf1a9f7 --- /dev/null +++ b/src/commands/connected-accounts/get-connected-account-trading-pairs.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetConnectedAccountTradingPairs extends FireblocksBaseCommand { + static summary = 'Get supported trading pairs for an account' + + static description = 'Retrieve all asset trading pairs supported by a specific connected account, including the pair type (\`quote\`, \`market\`, \`onOffRamp\`).\n\n**Note:** This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: getConnectedAccountTradingPairs\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Connected%20Accounts/getConnectedAccountTradingPairs' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the account to fetch supported pairs for.', + required: true, + }), + 'page-size': Flags.integer({ + description: 'Page size for pagination.', + default: 100, + }), + 'page-cursor': Flags.string({ + description: 'Page cursor for pagination.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/connected_accounts/{accountId}/manifest/capabilities/trading/pairs' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetConnectedAccountTradingPairs) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + const queryParams: Record = {} + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/connected_accounts/{accountId}/manifest/capabilities/trading/pairs', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/connected-accounts/get-connected-account.ts b/src/commands/connected-accounts/get-connected-account.ts new file mode 100644 index 0000000..1385e8a --- /dev/null +++ b/src/commands/connected-accounts/get-connected-account.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetConnectedAccount extends FireblocksBaseCommand { + static summary = 'Get connected account' + + static description = 'Retrieve detailed information about a specific connected account by ID.\n\n**Note:** This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: getConnectedAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Connected%20Accounts/getConnectedAccount' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the account to fetch.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/connected_accounts/{accountId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetConnectedAccount) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/connected_accounts/{accountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/connected-accounts/get-connected-accounts.ts b/src/commands/connected-accounts/get-connected-accounts.ts new file mode 100644 index 0000000..10bf35a --- /dev/null +++ b/src/commands/connected-accounts/get-connected-accounts.ts @@ -0,0 +1,64 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetConnectedAccounts extends FireblocksBaseCommand { + static summary = 'Get connected accounts' + + static description = 'Returns all connected accounts.\n\n**Note:** This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: getConnectedAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Connected%20Accounts/getConnectedAccounts' + + static enableJsonFlag = false + + static flags = { + 'main-accounts': Flags.boolean({ + description: 'Whether to include only main accounts in the response.', + default: false, + }), + 'page-size': Flags.integer({ + description: 'Page size for pagination.', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor for pagination.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/connected_accounts' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetConnectedAccounts) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['main-accounts'] !== undefined && flags['main-accounts'] !== null) { + queryParams['mainAccounts'] = String(flags['main-accounts']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/connected_accounts', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/connected-accounts/rename-connected-account.ts b/src/commands/connected-accounts/rename-connected-account.ts new file mode 100644 index 0000000..c41b99f --- /dev/null +++ b/src/commands/connected-accounts/rename-connected-account.ts @@ -0,0 +1,72 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RenameConnectedAccount extends FireblocksBaseCommand { + static summary = 'Rename Connected Account' + + static description = 'Rename a connected account by account ID.\n\n**Note:** This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: renameConnectedAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Connected%20Accounts/renameConnectedAccount' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The unique identifier of the connected account', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/connected_accounts/{accountId}/rename' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RenameConnectedAccount) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + + await this.confirmOrAbort('POST', '/v1/connected_accounts/{accountId}/rename') + + const result = await this.makeRequest( + 'POST', + '/v1/connected_accounts/{accountId}/rename', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/console-user/create-console-user.ts b/src/commands/console-user/create-console-user.ts new file mode 100644 index 0000000..a7affa3 --- /dev/null +++ b/src/commands/console-user/create-console-user.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateConsoleUser extends FireblocksBaseCommand { + static summary = 'Create console user' + + static description = 'Create console users in your workspace\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\nLearn more about Fireblocks Users management in the following [guide](https://developers.fireblocks.com/docs/manage-users).\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: createConsoleUser\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Console%20User/createConsoleUser' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/management/users' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateConsoleUser) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/management/users') + + const result = await this.makeRequest( + 'POST', + '/v1/management/users', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/console-user/get-console-users.ts b/src/commands/console-user/get-console-users.ts new file mode 100644 index 0000000..ea41fd3 --- /dev/null +++ b/src/commands/console-user/get-console-users.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetConsoleUsers extends FireblocksBaseCommand { + static summary = 'Get console users' + + static description = 'Get console users for your workspace.\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getConsoleUsers\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Console%20User/getConsoleUsers' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/management/users' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetConsoleUsers) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/management/users', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/contract-interactions/decode-contract-data.ts b/src/commands/contract-interactions/decode-contract-data.ts new file mode 100644 index 0000000..018fcbf --- /dev/null +++ b/src/commands/contract-interactions/decode-contract-data.ts @@ -0,0 +1,75 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DecodeContractData extends FireblocksBaseCommand { + static summary = 'Decode a function call data, error, or event log' + + static description = 'Decode a function call data, error, or event log from a deployed contract by blockchain native asset id and contract address.\n\nOperation ID: decodeContractData\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Interactions/decodeContractData' + + static enableJsonFlag = false + + static flags = { + 'contract-address': Flags.string({ + description: 'The contract\'s onchain address', + required: true, + }), + 'base-asset-id': Flags.string({ + description: 'The blockchain native asset identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/decode' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DecodeContractData) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['contractAddress'] = String(flags['contract-address']) + pathParams['baseAssetId'] = String(flags['base-asset-id']) + + + await this.confirmOrAbort('POST', '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/decode') + + const result = await this.makeRequest( + 'POST', + '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/decode', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-interactions/get-contract-address.ts b/src/commands/contract-interactions/get-contract-address.ts new file mode 100644 index 0000000..e6a76fc --- /dev/null +++ b/src/commands/contract-interactions/get-contract-address.ts @@ -0,0 +1,56 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContractAddress extends FireblocksBaseCommand { + static summary = 'Get contract address by transaction hash' + + static description = 'Retrieve the contract address by blockchain native asset ID and transaction hash\n\nOperation ID: getContractAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Interactions/getContractAddress' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'tx-hash': Flags.string({ + description: 'The transaction hash', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/contract_interactions/base_asset_id/{baseAssetId}/tx_hash/{txHash}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContractAddress) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['txHash'] = String(flags['tx-hash']) + + + const result = await this.makeRequest( + 'GET', + '/v1/contract_interactions/base_asset_id/{baseAssetId}/tx_hash/{txHash}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-interactions/get-deployed-contract-abi.ts b/src/commands/contract-interactions/get-deployed-contract-abi.ts new file mode 100644 index 0000000..74050b6 --- /dev/null +++ b/src/commands/contract-interactions/get-deployed-contract-abi.ts @@ -0,0 +1,56 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDeployedContractAbi extends FireblocksBaseCommand { + static summary = 'Return deployed contract\'s ABI' + + static description = 'Return deployed contract\'s ABI by blockchain native asset id and contract address.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, and Viewer.\n\nOperation ID: getDeployedContractAbi\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Interactions/getDeployedContractAbi' + + static enableJsonFlag = false + + static flags = { + 'contract-address': Flags.string({ + description: 'The contract\'s onchain address', + required: true, + }), + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDeployedContractAbi) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['contractAddress'] = String(flags['contract-address']) + pathParams['baseAssetId'] = String(flags['base-asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-interactions/get-transaction-receipt.ts b/src/commands/contract-interactions/get-transaction-receipt.ts new file mode 100644 index 0000000..601a88e --- /dev/null +++ b/src/commands/contract-interactions/get-transaction-receipt.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTransactionReceipt extends FireblocksBaseCommand { + static summary = 'Get transaction receipt' + + static description = 'Retrieve the transaction receipt by blockchain native asset ID and transaction hash\n> **Note** > This functionality is exclusively available for EVM (Ethereum Virtual Machine) compatible chains. \nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, and Viewer.\n\nOperation ID: getTransactionReceipt\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Interactions/getTransactionReceipt' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'tx-hash': Flags.string({ + description: 'The transaction hash', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/contract_interactions/base_asset_id/{baseAssetId}/tx_hash/{txHash}/receipt' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTransactionReceipt) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['txHash'] = String(flags['tx-hash']) + + + const result = await this.makeRequest( + 'GET', + '/v1/contract_interactions/base_asset_id/{baseAssetId}/tx_hash/{txHash}/receipt', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-interactions/read-call-function.ts b/src/commands/contract-interactions/read-call-function.ts new file mode 100644 index 0000000..c1a4b8f --- /dev/null +++ b/src/commands/contract-interactions/read-call-function.ts @@ -0,0 +1,75 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ReadCallFunction extends FireblocksBaseCommand { + static summary = 'Call a read function on a deployed contract' + + static description = 'Call a read function on a deployed contract by blockchain native asset id and contract address\n\nOperation ID: readCallFunction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Interactions/readCallFunction' + + static enableJsonFlag = false + + static flags = { + 'contract-address': Flags.string({ + description: 'The contract\'s onchain address', + required: true, + }), + 'base-asset-id': Flags.string({ + description: 'The baseAssetId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/read' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ReadCallFunction) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['contractAddress'] = String(flags['contract-address']) + pathParams['baseAssetId'] = String(flags['base-asset-id']) + + + await this.confirmOrAbort('POST', '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/read') + + const result = await this.makeRequest( + 'POST', + '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/read', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-interactions/write-call-function.ts b/src/commands/contract-interactions/write-call-function.ts new file mode 100644 index 0000000..b88a1c3 --- /dev/null +++ b/src/commands/contract-interactions/write-call-function.ts @@ -0,0 +1,75 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class WriteCallFunction extends FireblocksBaseCommand { + static summary = 'Call a write function on a deployed contract' + + static description = 'Call a write function on a deployed contract by blockchain native asset id and contract address. This creates an onchain transaction, thus it is an async operation. It returns a transaction id that can be polled for status check\n\nOperation ID: writeCallFunction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Interactions/writeCallFunction' + + static enableJsonFlag = false + + static flags = { + 'contract-address': Flags.string({ + description: 'The contract\'s onchain address', + required: true, + }), + 'base-asset-id': Flags.string({ + description: 'The baseAssetId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/write' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(WriteCallFunction) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['contractAddress'] = String(flags['contract-address']) + pathParams['baseAssetId'] = String(flags['base-asset-id']) + + + await this.confirmOrAbort('POST', '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/write') + + const result = await this.makeRequest( + 'POST', + '/v1/contract_interactions/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/functions/write', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/delete-contract-template-by-id.ts b/src/commands/contract-templates/delete-contract-template-by-id.ts new file mode 100644 index 0000000..5f83785 --- /dev/null +++ b/src/commands/contract-templates/delete-contract-template-by-id.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteContractTemplateById extends FireblocksBaseCommand { + static summary = 'Delete a contract template by id' + + static description = 'Delete a contract by id. allowed only for private contract templates. Notice: it is irreversible!\n\nOperation ID: deleteContractTemplateById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/deleteContractTemplateById' + + static enableJsonFlag = false + + static flags = { + 'contract-template-id': Flags.string({ + description: 'The Contract Template identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/tokenization/templates/{contractTemplateId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteContractTemplateById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractTemplateId'] = String(flags['contract-template-id']) + + + await this.confirmOrAbort('DELETE', '/v1/tokenization/templates/{contractTemplateId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/tokenization/templates/{contractTemplateId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/deploy-contract.ts b/src/commands/contract-templates/deploy-contract.ts new file mode 100644 index 0000000..74768a4 --- /dev/null +++ b/src/commands/contract-templates/deploy-contract.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeployContract extends FireblocksBaseCommand { + static summary = 'Deploy contract' + + static description = 'Deploy a new contract by contract template id. If you wish to deploy a token (ERC20, ERC721 etc), and create asset please use POST /tokenization\n\nOperation ID: deployContract\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/deployContract' + + static enableJsonFlag = false + + static flags = { + 'contract-template-id': Flags.string({ + description: 'The Contract Template identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/templates/{contractTemplateId}/deploy' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeployContract) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['contractTemplateId'] = String(flags['contract-template-id']) + + + await this.confirmOrAbort('POST', '/v1/tokenization/templates/{contractTemplateId}/deploy') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/templates/{contractTemplateId}/deploy', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/get-constructor-by-contract-template-id.ts b/src/commands/contract-templates/get-constructor-by-contract-template-id.ts new file mode 100644 index 0000000..273bec2 --- /dev/null +++ b/src/commands/contract-templates/get-constructor-by-contract-template-id.ts @@ -0,0 +1,57 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetConstructorByContractTemplateId extends FireblocksBaseCommand { + static summary = 'Return contract template\'s constructor' + + static description = 'Return contract template\'s constructor ABI\n\nOperation ID: getConstructorByContractTemplateId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/getConstructorByContractTemplateId' + + static enableJsonFlag = false + + static flags = { + 'contract-template-id': Flags.string({ + description: 'The Contract Template identifier', + required: true, + }), + 'with-docs': Flags.boolean({ + description: 'true if you want to get the abi with its docs', + default: false, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/templates/{contractTemplateId}/constructor' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetConstructorByContractTemplateId) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractTemplateId'] = String(flags['contract-template-id']) + + const queryParams: Record = {} + if (flags['with-docs'] !== undefined && flags['with-docs'] !== null) { + queryParams['withDocs'] = String(flags['with-docs']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/templates/{contractTemplateId}/constructor', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/get-contract-template-by-id.ts b/src/commands/contract-templates/get-contract-template-by-id.ts new file mode 100644 index 0000000..db5fe79 --- /dev/null +++ b/src/commands/contract-templates/get-contract-template-by-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContractTemplateById extends FireblocksBaseCommand { + static summary = 'Return contract template by id' + + static description = 'Return detailed information about the contract template\n\nOperation ID: getContractTemplateById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/getContractTemplateById' + + static enableJsonFlag = false + + static flags = { + 'contract-template-id': Flags.string({ + description: 'The Contract Template identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/templates/{contractTemplateId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContractTemplateById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractTemplateId'] = String(flags['contract-template-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/templates/{contractTemplateId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/get-contract-templates.ts b/src/commands/contract-templates/get-contract-templates.ts new file mode 100644 index 0000000..58448af --- /dev/null +++ b/src/commands/contract-templates/get-contract-templates.ts @@ -0,0 +1,83 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContractTemplates extends FireblocksBaseCommand { + static summary = 'List all contract templates' + + static description = 'Return minimal representation of all the contract templates available for the workspace.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getContractTemplates\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/getContractTemplates' + + static enableJsonFlag = false + + static flags = { + 'limit': Flags.string({ + description: 'Items per page (max 100)', + default: '100', + }), + 'offset': Flags.string({ + description: 'Paging offset', + default: '0', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page', + }), + 'page-size': Flags.string({ + description: 'Number of items per page, requesting more then max will return max items', + }), + 'type': Flags.string({ + description: 'The type of the contract templates you wish to retrieve. Can accept one type, more or none', + options: ['FUNGIBLE_TOKEN', 'NON_FUNGIBLE_TOKEN', 'TOKEN_UTILITY'], + }), + 'initialization-phase': Flags.string({ + description: 'For standalone contracts use ON_DEPLOYMENT and for contracts that are behind proxies use POST_DEPLOYMENT', + options: ['ON_DEPLOYMENT', 'POST_DEPLOYMENT'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/templates' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContractTemplates) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['limit'] !== undefined && flags['limit'] !== null) { + queryParams['limit'] = String(flags['limit']) + } + if (flags['offset'] !== undefined && flags['offset'] !== null) { + queryParams['offset'] = String(flags['offset']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['type'] !== undefined && flags['type'] !== null) { + queryParams['type'] = String(flags['type']) + } + if (flags['initialization-phase'] !== undefined && flags['initialization-phase'] !== null) { + queryParams['initializationPhase'] = String(flags['initialization-phase']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/templates', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/get-function-abi-by-contract-template-id.ts b/src/commands/contract-templates/get-function-abi-by-contract-template-id.ts new file mode 100644 index 0000000..0cfe1a2 --- /dev/null +++ b/src/commands/contract-templates/get-function-abi-by-contract-template-id.ts @@ -0,0 +1,57 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetFunctionAbiByContractTemplateId extends FireblocksBaseCommand { + static summary = 'Return contract template\'s function' + + static description = 'Return contract template\`s function ABI by signature\n\nOperation ID: getFunctionAbiByContractTemplateId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/getFunctionAbiByContractTemplateId' + + static enableJsonFlag = false + + static flags = { + 'contract-template-id': Flags.string({ + description: 'The Contract Template identifier', + required: true, + }), + 'function-signature': Flags.string({ + description: 'The functionSignature parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/templates/{contractTemplateId}/function' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetFunctionAbiByContractTemplateId) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractTemplateId'] = String(flags['contract-template-id']) + + const queryParams: Record = {} + if (flags['function-signature'] !== undefined && flags['function-signature'] !== null) { + queryParams['functionSignature'] = String(flags['function-signature']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/templates/{contractTemplateId}/function', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/get-supported-blockchains-by-template-id.ts b/src/commands/contract-templates/get-supported-blockchains-by-template-id.ts new file mode 100644 index 0000000..a57ffb9 --- /dev/null +++ b/src/commands/contract-templates/get-supported-blockchains-by-template-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSupportedBlockchainsByTemplateId extends FireblocksBaseCommand { + static summary = 'Get supported blockchains for the template' + + static description = 'Get supported blockchains for the template\n\nOperation ID: getSupportedBlockchainsByTemplateId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/getSupportedBlockchainsByTemplateId' + + static enableJsonFlag = false + + static flags = { + 'contract-template-id': Flags.string({ + description: 'The Contract Template identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/templates/{contractTemplateId}/supported_blockchains' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetSupportedBlockchainsByTemplateId) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractTemplateId'] = String(flags['contract-template-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/templates/{contractTemplateId}/supported_blockchains', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contract-templates/upload-contract-template.ts b/src/commands/contract-templates/upload-contract-template.ts new file mode 100644 index 0000000..427c0a0 --- /dev/null +++ b/src/commands/contract-templates/upload-contract-template.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UploadContractTemplate extends FireblocksBaseCommand { + static summary = 'Upload contract template' + + static description = 'Upload a new contract template. This contract template will be available for the workspace\n\nOperation ID: uploadContractTemplate\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contract%20Templates/uploadContractTemplate' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/templates' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UploadContractTemplate) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/templates') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/templates', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/contracts/add-contract-asset.ts b/src/commands/contracts/add-contract-asset.ts new file mode 100644 index 0000000..3f5c229 --- /dev/null +++ b/src/commands/contracts/add-contract-asset.ts @@ -0,0 +1,74 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddContractAsset extends FireblocksBaseCommand { + static summary = 'Add an asset to a whitelisted contract' + + static description = 'Adds an asset to a whitelisted contract. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: addContractAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contracts/addContractAsset' + + static enableJsonFlag = false + + static flags = { + 'contract-id': Flags.string({ + description: 'The ID of the contract', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to add', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/contracts/{contractId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddContractAsset) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['contractId'] = String(flags['contract-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('POST', '/v1/contracts/{contractId}/{assetId}') + + const result = await this.makeRequest( + 'POST', + '/v1/contracts/{contractId}/{assetId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contracts/create-contract.ts b/src/commands/contracts/create-contract.ts new file mode 100644 index 0000000..363fcd4 --- /dev/null +++ b/src/commands/contracts/create-contract.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateContract extends FireblocksBaseCommand { + static summary = 'Add a contract' + + static description = 'Adds a contract to the workspace whitelist. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createContract\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contracts/createContract' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/contracts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateContract) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/contracts') + + const result = await this.makeRequest( + 'POST', + '/v1/contracts', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/contracts/delete-contract-asset.ts b/src/commands/contracts/delete-contract-asset.ts new file mode 100644 index 0000000..a6d5c26 --- /dev/null +++ b/src/commands/contracts/delete-contract-asset.ts @@ -0,0 +1,55 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteContractAsset extends FireblocksBaseCommand { + static summary = 'Delete an asset from a whitelisted contract' + + static description = 'Deletes a whitelisted contract asset by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: deleteContractAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contracts/deleteContractAsset' + + static enableJsonFlag = false + + static flags = { + 'contract-id': Flags.string({ + description: 'The ID of the contract', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to delete', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/contracts/{contractId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteContractAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractId'] = String(flags['contract-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('DELETE', '/v1/contracts/{contractId}/{assetId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/contracts/{contractId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contracts/delete-contract.ts b/src/commands/contracts/delete-contract.ts new file mode 100644 index 0000000..0527ad6 --- /dev/null +++ b/src/commands/contracts/delete-contract.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteContract extends FireblocksBaseCommand { + static summary = 'Delete a contract' + + static description = 'Deletes a contract by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: deleteContract\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contracts/deleteContract' + + static enableJsonFlag = false + + static flags = { + 'contract-id': Flags.string({ + description: 'The ID of the contract to delete', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/contracts/{contractId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteContract) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractId'] = String(flags['contract-id']) + + + await this.confirmOrAbort('DELETE', '/v1/contracts/{contractId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/contracts/{contractId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contracts/get-contract-asset.ts b/src/commands/contracts/get-contract-asset.ts new file mode 100644 index 0000000..7308815 --- /dev/null +++ b/src/commands/contracts/get-contract-asset.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContractAsset extends FireblocksBaseCommand { + static summary = 'Find a whitelisted contract\'s asset' + + static description = 'Returns a whitelisted contract\'s asset by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getContractAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contracts/getContractAsset' + + static enableJsonFlag = false + + static flags = { + 'contract-id': Flags.string({ + description: 'The ID of the contract', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/contracts/{contractId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContractAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractId'] = String(flags['contract-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/contracts/{contractId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contracts/get-contract.ts b/src/commands/contracts/get-contract.ts new file mode 100644 index 0000000..244c23f --- /dev/null +++ b/src/commands/contracts/get-contract.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContract extends FireblocksBaseCommand { + static summary = 'Find a Specific Whitelisted Contract' + + static description = 'Returns a whitelisted contract by Fireblocks Contract ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getContract\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contracts/getContract' + + static enableJsonFlag = false + + static flags = { + 'contract-id': Flags.string({ + description: 'The ID of the contract to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/contracts/{contractId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContract) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractId'] = String(flags['contract-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/contracts/{contractId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/contracts/get-contracts.ts b/src/commands/contracts/get-contracts.ts new file mode 100644 index 0000000..d8aa4e4 --- /dev/null +++ b/src/commands/contracts/get-contracts.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContracts extends FireblocksBaseCommand { + static summary = 'List Whitelisted Contracts' + + static description = 'Gets a list of whitelisted contracts. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getContracts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Contracts/getContracts' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/contracts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContracts) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/contracts', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/add-cosigner.ts b/src/commands/cosigners/add-cosigner.ts new file mode 100644 index 0000000..a5bbac3 --- /dev/null +++ b/src/commands/cosigners/add-cosigner.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddCosigner extends FireblocksBaseCommand { + static summary = 'Add cosigner' + + static description = 'Add a new cosigner. The cosigner will be pending pairing until the API key is manually paired\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: addCosigner\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/addCosigner' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/cosigners' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddCosigner) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/cosigners') + + const result = await this.makeRequest( + 'POST', + '/v1/cosigners', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/get-api-key.ts b/src/commands/cosigners/get-api-key.ts new file mode 100644 index 0000000..c240eac --- /dev/null +++ b/src/commands/cosigners/get-api-key.ts @@ -0,0 +1,55 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetApiKey extends FireblocksBaseCommand { + static summary = 'Get API key' + + static description = 'Get an API key by ID.\n**Note:** These endpoints are currently in beta and might be subject to changes.\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: getApiKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/getApiKey' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + 'api-key-id': Flags.string({ + description: 'The unique identifier of the API key', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetApiKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + pathParams['apiKeyId'] = String(flags['api-key-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/get-api-keys.ts b/src/commands/cosigners/get-api-keys.ts new file mode 100644 index 0000000..e05d280 --- /dev/null +++ b/src/commands/cosigners/get-api-keys.ts @@ -0,0 +1,73 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetApiKeys extends FireblocksBaseCommand { + static summary = 'Get all API keys' + + static description = 'Get all cosigner paired API keys (paginated).\n**Note:** These endpoints are currently in beta and might be subject to changes.\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: getApiKeys\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/getApiKeys' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'page-cursor': Flags.string({ + description: 'Cursor of the required page', + }), + 'page-size': Flags.string({ + description: 'Maximum number of items in the page', + default: '10', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/cosigners/{cosignerId}/api_keys' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetApiKeys) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + + const queryParams: Record = {} + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/cosigners/{cosignerId}/api_keys', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/get-cosigner.ts b/src/commands/cosigners/get-cosigner.ts new file mode 100644 index 0000000..0e82323 --- /dev/null +++ b/src/commands/cosigners/get-cosigner.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetCosigner extends FireblocksBaseCommand { + static summary = 'Get cosigner' + + static description = 'Get a cosigner by ID.\n**Note:** These endpoints are currently in beta and might be subject to changes.\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: getCosigner\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/getCosigner' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/cosigners/{cosignerId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetCosigner) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/cosigners/{cosignerId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/get-cosigners.ts b/src/commands/cosigners/get-cosigners.ts new file mode 100644 index 0000000..97aabbe --- /dev/null +++ b/src/commands/cosigners/get-cosigners.ts @@ -0,0 +1,66 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetCosigners extends FireblocksBaseCommand { + static summary = 'Get all cosigners' + + static description = 'Get all workspace cosigners (paginated).\n**Note:** These endpoints are currently in beta and might be subject to changes.\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: getCosigners\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/getCosigners' + + static enableJsonFlag = false + + static flags = { + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'page-cursor': Flags.string({ + description: 'Cursor of the required page', + }), + 'page-size': Flags.string({ + description: 'Maximum number of items in the page', + default: '10', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/cosigners' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetCosigners) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/cosigners', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/get-request-status.ts b/src/commands/cosigners/get-request-status.ts new file mode 100644 index 0000000..2ca62a0 --- /dev/null +++ b/src/commands/cosigners/get-request-status.ts @@ -0,0 +1,60 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetRequestStatus extends FireblocksBaseCommand { + static summary = 'Get request status' + + static description = 'Get the status of an asynchronous request\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: getRequestStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/getRequestStatus' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + 'api-key-id': Flags.string({ + description: 'The unique identifier of the API key', + required: true, + }), + 'request-id': Flags.string({ + description: 'The requestId parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}/{requestId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetRequestStatus) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + pathParams['apiKeyId'] = String(flags['api-key-id']) + pathParams['requestId'] = String(flags['request-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}/{requestId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/pair-api-key.ts b/src/commands/cosigners/pair-api-key.ts new file mode 100644 index 0000000..ff6366c --- /dev/null +++ b/src/commands/cosigners/pair-api-key.ts @@ -0,0 +1,77 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class PairApiKey extends FireblocksBaseCommand { + static summary = 'Pair API key' + + static description = 'Pair an API key to a cosigner\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: pairApiKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/pairApiKey' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + 'api-key-id': Flags.string({ + description: 'The unique identifier of the API key', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID","Location"] + + async run(): Promise { + const {flags} = await this.parse(PairApiKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + pathParams['apiKeyId'] = String(flags['api-key-id']) + + + await this.confirmOrAbort('PUT', '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/rename-cosigner.ts b/src/commands/cosigners/rename-cosigner.ts new file mode 100644 index 0000000..c405ef9 --- /dev/null +++ b/src/commands/cosigners/rename-cosigner.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RenameCosigner extends FireblocksBaseCommand { + static summary = 'Rename cosigner' + + static description = 'Rename a cosigner by ID.\n**Note:** These endpoints are currently in beta and might be subject to changes.\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: renameCosigner\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/renameCosigner' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/cosigners/{cosignerId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RenameCosigner) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + + + await this.confirmOrAbort('PATCH', '/v1/cosigners/{cosignerId}') + + const result = await this.makeRequest( + 'PATCH', + '/v1/cosigners/{cosignerId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/unpair-api-key.ts b/src/commands/cosigners/unpair-api-key.ts new file mode 100644 index 0000000..e0b0e3c --- /dev/null +++ b/src/commands/cosigners/unpair-api-key.ts @@ -0,0 +1,57 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UnpairApiKey extends FireblocksBaseCommand { + static summary = 'Unpair API key' + + static description = 'Unpair an API key from a cosigner\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: unpairApiKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/unpairApiKey' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + 'api-key-id': Flags.string({ + description: 'The unique identifier of the API key', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID","Location"] + + async run(): Promise { + const {flags} = await this.parse(UnpairApiKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + pathParams['apiKeyId'] = String(flags['api-key-id']) + + + await this.confirmOrAbort('DELETE', '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/cosigners/update-callback-handler.ts b/src/commands/cosigners/update-callback-handler.ts new file mode 100644 index 0000000..74cc9ad --- /dev/null +++ b/src/commands/cosigners/update-callback-handler.ts @@ -0,0 +1,74 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateCallbackHandler extends FireblocksBaseCommand { + static summary = 'Update API key callback handler' + + static description = 'Update the callback handler of an API key\nEndpoint Permission: Admin and Non-Signing Admin.\n\nOperation ID: updateCallbackHandler\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Cosigners/updateCallbackHandler' + + static enableJsonFlag = false + + static flags = { + 'cosigner-id': Flags.string({ + description: 'The unique identifier of the cosigner', + required: true, + }), + 'api-key-id': Flags.string({ + description: 'The unique identifier of the API key', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID","Location"] + + async run(): Promise { + const {flags} = await this.parse(UpdateCallbackHandler) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['cosignerId'] = String(flags['cosigner-id']) + pathParams['apiKeyId'] = String(flags['api-key-id']) + + + await this.confirmOrAbort('PATCH', '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}') + + const result = await this.makeRequest( + 'PATCH', + '/v1/cosigners/{cosignerId}/api_keys/{apiKeyId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/deployed-contracts/add-contract-abi.ts b/src/commands/deployed-contracts/add-contract-abi.ts new file mode 100644 index 0000000..97d537e --- /dev/null +++ b/src/commands/deployed-contracts/add-contract-abi.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddContractABI extends FireblocksBaseCommand { + static summary = 'Save contract ABI' + + static description = 'Save contract ABI for the tenant\n\nOperation ID: addContractABI\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Deployed%20Contracts/addContractABI' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/contracts/abi' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddContractABI) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/contracts/abi') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/contracts/abi', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/deployed-contracts/fetch-contract-abi.ts b/src/commands/deployed-contracts/fetch-contract-abi.ts new file mode 100644 index 0000000..f187a24 --- /dev/null +++ b/src/commands/deployed-contracts/fetch-contract-abi.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FetchContractAbi extends FireblocksBaseCommand { + static summary = 'Fetch the contract ABI' + + static description = 'Fetch the ABI. If not found fetch the ABI from the block explorer\n\nOperation ID: fetchContractAbi\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Deployed%20Contracts/fetchContractAbi' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/contracts/fetch_abi' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(FetchContractAbi) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/contracts/fetch_abi') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/contracts/fetch_abi', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/deployed-contracts/get-deployed-contract-by-address.ts b/src/commands/deployed-contracts/get-deployed-contract-by-address.ts new file mode 100644 index 0000000..ae92d2e --- /dev/null +++ b/src/commands/deployed-contracts/get-deployed-contract-by-address.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDeployedContractByAddress extends FireblocksBaseCommand { + static summary = 'Return deployed contract data' + + static description = 'Return deployed contract data by blockchain native asset id and contract address\n\nOperation ID: getDeployedContractByAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Deployed%20Contracts/getDeployedContractByAddress' + + static enableJsonFlag = false + + static flags = { + 'contract-address': Flags.string({ + description: 'The contract\'s onchain address', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The assetId parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/contracts/{assetId}/{contractAddress}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDeployedContractByAddress) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['contractAddress'] = String(flags['contract-address']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/contracts/{assetId}/{contractAddress}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/deployed-contracts/get-deployed-contract-by-id.ts b/src/commands/deployed-contracts/get-deployed-contract-by-id.ts new file mode 100644 index 0000000..28011d2 --- /dev/null +++ b/src/commands/deployed-contracts/get-deployed-contract-by-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDeployedContractById extends FireblocksBaseCommand { + static summary = 'Return deployed contract data by id' + + static description = 'Return deployed contract data by id\n\nOperation ID: getDeployedContractById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Deployed%20Contracts/getDeployedContractById' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The deployed contract data identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/contracts/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDeployedContractById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/contracts/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/deployed-contracts/get-deployed-contracts.ts b/src/commands/deployed-contracts/get-deployed-contracts.ts new file mode 100644 index 0000000..9e887dd --- /dev/null +++ b/src/commands/deployed-contracts/get-deployed-contracts.ts @@ -0,0 +1,73 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDeployedContracts extends FireblocksBaseCommand { + static summary = 'List deployed contracts data' + + static description = 'Return a filtered lean representation of the deployed contracts data on all blockchains (paginated)\n\nOperation ID: getDeployedContracts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Deployed%20Contracts/getDeployedContracts' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page', + }), + 'page-size': Flags.string({ + description: 'Number of items per page, requesting more then max will return max items', + }), + 'contract-address': Flags.string({ + description: 'The contract\'s onchain address', + }), + 'base-asset-id': Flags.string({ + description: 'The baseAssetId parameter', + }), + 'contract-template-id': Flags.string({ + description: 'The contractTemplateId parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/contracts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDeployedContracts) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['contract-address'] !== undefined && flags['contract-address'] !== null) { + queryParams['contractAddress'] = String(flags['contract-address']) + } + if (flags['base-asset-id'] !== undefined && flags['base-asset-id'] !== null) { + queryParams['baseAssetId'] = String(flags['base-asset-id']) + } + if (flags['contract-template-id'] !== undefined && flags['contract-template-id'] !== null) { + queryParams['contractTemplateId'] = String(flags['contract-template-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/contracts', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/add-embedded-wallet-asset.ts b/src/commands/embedded-wallets/add-embedded-wallet-asset.ts new file mode 100644 index 0000000..598bbbb --- /dev/null +++ b/src/commands/embedded-wallets/add-embedded-wallet-asset.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddEmbeddedWalletAsset extends FireblocksBaseCommand { + static summary = 'Add asset to account' + + static description = 'Get the addresses of a specific asset, under a specific account, under a specific Non Custodial Wallet\n\nOperation ID: AddEmbeddedWalletAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/AddEmbeddedWalletAsset' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddEmbeddedWalletAsset) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('POST', '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}') + + const result = await this.makeRequest( + 'POST', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/assign-embedded-wallet.ts b/src/commands/embedded-wallets/assign-embedded-wallet.ts new file mode 100644 index 0000000..45ae104 --- /dev/null +++ b/src/commands/embedded-wallets/assign-embedded-wallet.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AssignEmbeddedWallet extends FireblocksBaseCommand { + static summary = 'Assign a wallet' + + static description = 'Assign a specific Non Custodial Wallet to a user\n\nOperation ID: assignEmbeddedWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/assignEmbeddedWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/ncw/wallets/{walletId}/assign' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AssignEmbeddedWallet) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + await this.confirmOrAbort('POST', '/v1/ncw/wallets/{walletId}/assign') + + const result = await this.makeRequest( + 'POST', + '/v1/ncw/wallets/{walletId}/assign', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/create-embedded-wallet-account.ts b/src/commands/embedded-wallets/create-embedded-wallet-account.ts new file mode 100644 index 0000000..34c2997 --- /dev/null +++ b/src/commands/embedded-wallets/create-embedded-wallet-account.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateEmbeddedWalletAccount extends FireblocksBaseCommand { + static summary = 'Create a new account' + + static description = 'Create a new account under a specific Non Custodial Wallet\n\nOperation ID: CreateEmbeddedWalletAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/CreateEmbeddedWalletAccount' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/ncw/wallets/{walletId}/accounts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateEmbeddedWalletAccount) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + await this.confirmOrAbort('POST', '/v1/ncw/wallets/{walletId}/accounts') + + const result = await this.makeRequest( + 'POST', + '/v1/ncw/wallets/{walletId}/accounts', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/create-embedded-wallet.ts b/src/commands/embedded-wallets/create-embedded-wallet.ts new file mode 100644 index 0000000..7448f2b --- /dev/null +++ b/src/commands/embedded-wallets/create-embedded-wallet.ts @@ -0,0 +1,46 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateEmbeddedWallet extends FireblocksBaseCommand { + static summary = 'Create a new wallet' + + static description = 'Create new Non Custodial Wallet\n\nOperation ID: CreateEmbeddedWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/CreateEmbeddedWallet' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/ncw/wallets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateEmbeddedWallet) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/ncw/wallets') + + const result = await this.makeRequest( + 'POST', + '/v1/ncw/wallets', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-account.ts b/src/commands/embedded-wallets/get-embedded-wallet-account.ts new file mode 100644 index 0000000..392de64 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-account.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletAccount extends FireblocksBaseCommand { + static summary = 'Get a account' + + static description = 'Get a specific account under a specific Non Custodial Wallet\n\nOperation ID: GetEmbeddedWalletAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletAccount' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'WalletId', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletAccount) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-addresses.ts b/src/commands/embedded-wallets/get-embedded-wallet-addresses.ts new file mode 100644 index 0000000..a4be6fe --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-addresses.ts @@ -0,0 +1,94 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletAddresses extends FireblocksBaseCommand { + static summary = 'Retrieve asset addresses' + + static description = 'Get the addresses of a specific asset, under a specific account, under a specific Non Custodial Wallet\n\nOperation ID: GetEmbeddedWalletAddresses\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletAddresses' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'page-cursor': Flags.string({ + description: 'Cursor to the next page', + }), + 'page-size': Flags.string({ + description: 'Items per page', + }), + 'sort': Flags.string({ + description: 'Sort by address', + default: 'createdAt', + options: ['address', 'createdAt'], + }), + 'order': Flags.string({ + description: 'Is the order ascending or descending', + default: 'ASC', + options: ['DESC', 'ASC'], + }), + 'enabled': Flags.boolean({ + description: 'Enabled', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/addresses' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletAddresses) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['enabled'] !== undefined && flags['enabled'] !== null) { + queryParams['enabled'] = String(flags['enabled']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/addresses', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-asset-balance.ts b/src/commands/embedded-wallets/get-embedded-wallet-asset-balance.ts new file mode 100644 index 0000000..a0b3473 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-asset-balance.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletAssetBalance extends FireblocksBaseCommand { + static summary = 'Retrieve asset balance' + + static description = 'Get balance for specific asset, under a specific account\n\nOperation ID: GetEmbeddedWalletAssetBalance\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletAssetBalance' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/balance' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletAssetBalance) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/balance', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-asset.ts b/src/commands/embedded-wallets/get-embedded-wallet-asset.ts new file mode 100644 index 0000000..ed162b2 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-asset.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletAsset extends FireblocksBaseCommand { + static summary = 'Retrieve asset' + + static description = 'Get asset under a specific account, under a specific Non Custodial Wallet\n\nOperation ID: GetEmbeddedWalletAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletAsset' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-assets.ts b/src/commands/embedded-wallets/get-embedded-wallet-assets.ts new file mode 100644 index 0000000..00ec932 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-assets.ts @@ -0,0 +1,83 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletAssets extends FireblocksBaseCommand { + static summary = 'Retrieve assets' + + static description = 'Retrieve assets for a specific account under a specific Non Custodial Wallet\n\nOperation ID: getEmbeddedWalletAssets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/getEmbeddedWalletAssets' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'sort': Flags.string({ + description: 'Sort by fields', + default: 'assetId', + }), + 'page-cursor': Flags.string({ + description: 'Cursor to the next page', + }), + 'page-size': Flags.string({ + description: 'Amount of results to return in the next page', + default: '200', + }), + 'order': Flags.string({ + description: 'Is the order ascending or descending', + default: 'ASC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletAssets) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + + const queryParams: Record = {} + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-device-setup-state.ts b/src/commands/embedded-wallets/get-embedded-wallet-device-setup-state.ts new file mode 100644 index 0000000..7faef3a --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-device-setup-state.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletDeviceSetupState extends FireblocksBaseCommand { + static summary = 'Get device key setup state' + + static description = 'Get the state of the specific device setup key under a specific Non Custodial Wallet\n\nOperation ID: GetEmbeddedWalletDeviceSetupState\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletDeviceSetupState' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'device-id': Flags.string({ + description: 'Device Id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/devices/{deviceId}/setup_status' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletDeviceSetupState) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['deviceId'] = String(flags['device-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/devices/{deviceId}/setup_status', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-device.ts b/src/commands/embedded-wallets/get-embedded-wallet-device.ts new file mode 100644 index 0000000..b898720 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-device.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletDevice extends FireblocksBaseCommand { + static summary = 'Get Embedded Wallet Device' + + static description = 'Get specific device for a specific s Wallet\n\nOperation ID: GetEmbeddedWalletDevice\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletDevice' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'device-id': Flags.string({ + description: 'Device Id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/devices/{deviceId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletDevice) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['deviceId'] = String(flags['device-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/devices/{deviceId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-devices-paginated.ts b/src/commands/embedded-wallets/get-embedded-wallet-devices-paginated.ts new file mode 100644 index 0000000..90bc6ae --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-devices-paginated.ts @@ -0,0 +1,78 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletDevicesPaginated extends FireblocksBaseCommand { + static summary = 'Get registered devices - paginated' + + static description = 'Get a paginated list of registered devices for a specific Non Custodial Wallet\n\nOperation ID: getEmbeddedWalletDevicesPaginated\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/getEmbeddedWalletDevicesPaginated' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'sort': Flags.string({ + description: 'Sort by fields', + default: 'createdAt', + }), + 'page-cursor': Flags.string({ + description: 'Cursor to the next page', + }), + 'page-size': Flags.string({ + description: 'Amount of results to return in the next page', + default: '200', + }), + 'order': Flags.string({ + description: 'Is the order ascending or descending', + default: 'ASC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/devices_paginated' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletDevicesPaginated) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + const queryParams: Record = {} + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/devices_paginated', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-latest-backup.ts b/src/commands/embedded-wallets/get-embedded-wallet-latest-backup.ts new file mode 100644 index 0000000..41c05e4 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-latest-backup.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletLatestBackup extends FireblocksBaseCommand { + static summary = 'Get wallet Latest Backup details' + + static description = 'Get wallet Latest Backup details, including the deviceId, and backup time\n\nOperation ID: GetEmbeddedWalletLatestBackup\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletLatestBackup' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/backup/latest' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletLatestBackup) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/backup/latest', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-public-key-info-for-address.ts b/src/commands/embedded-wallets/get-embedded-wallet-public-key-info-for-address.ts new file mode 100644 index 0000000..583b11f --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-public-key-info-for-address.ts @@ -0,0 +1,76 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletPublicKeyInfoForAddress extends FireblocksBaseCommand { + static summary = 'Get the public key of an asset' + + static description = 'Gets the public key of an asset associated with a specific account within a Non-Custodial Wallet\n\nOperation ID: GetEmbeddedWalletPublicKeyInfoForAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletPublicKeyInfoForAddress' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the Non-Custodial wallet', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'change': Flags.string({ + description: 'BIP44 derivation path - change value', + required: true, + }), + 'address-index': Flags.string({ + description: 'BIP44 derivation path - index value', + required: true, + }), + 'compressed': Flags.boolean({ + description: 'Compressed/Uncompressed public key format', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/{change}/{addressIndex}/public_key_info' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletPublicKeyInfoForAddress) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + pathParams['assetId'] = String(flags['asset-id']) + pathParams['change'] = String(flags['change']) + pathParams['addressIndex'] = String(flags['address-index']) + + const queryParams: Record = {} + if (flags['compressed'] !== undefined && flags['compressed'] !== null) { + queryParams['compressed'] = String(flags['compressed']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/{change}/{addressIndex}/public_key_info', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-setup-status.ts b/src/commands/embedded-wallets/get-embedded-wallet-setup-status.ts new file mode 100644 index 0000000..dc1c7e8 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-setup-status.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletSetupStatus extends FireblocksBaseCommand { + static summary = 'Get wallet key setup state' + + static description = 'Get the key setup state for a specific Non Custodial Wallet, including required algorithms and device setup status\n\nOperation ID: getEmbeddedWalletSetupStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/getEmbeddedWalletSetupStatus' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/setup_status' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletSetupStatus) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/setup_status', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet-supported-assets.ts b/src/commands/embedded-wallets/get-embedded-wallet-supported-assets.ts new file mode 100644 index 0000000..7cb784e --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet-supported-assets.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWalletSupportedAssets extends FireblocksBaseCommand { + static summary = 'Retrieve supported assets' + + static description = 'Get all the available supported assets for the Non-Custodial Wallet\n\nOperation ID: GetEmbeddedWalletSupportedAssets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWalletSupportedAssets' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Next page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page', + default: '200', + }), + 'only-base-assets': Flags.boolean({ + description: 'Only base assets', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/supported_assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWalletSupportedAssets) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['only-base-assets'] !== undefined && flags['only-base-assets'] !== null) { + queryParams['onlyBaseAssets'] = String(flags['only-base-assets']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/supported_assets', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallet.ts b/src/commands/embedded-wallets/get-embedded-wallet.ts new file mode 100644 index 0000000..366ecc3 --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallet.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWallet extends FireblocksBaseCommand { + static summary = 'Get a wallet' + + static description = 'Get a wallet\n\nOperation ID: GetEmbeddedWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWallet) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-embedded-wallets.ts b/src/commands/embedded-wallets/get-embedded-wallets.ts new file mode 100644 index 0000000..7dd75cb --- /dev/null +++ b/src/commands/embedded-wallets/get-embedded-wallets.ts @@ -0,0 +1,78 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetEmbeddedWallets extends FireblocksBaseCommand { + static summary = 'List wallets' + + static description = 'Get all Non Custodial Wallets\n\nOperation ID: GetEmbeddedWallets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/GetEmbeddedWallets' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Next page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page', + default: '200', + }), + 'sort': Flags.string({ + description: 'Field(s) to use for sorting', + default: 'createdAt', + options: ['createdAt'], + }), + 'order': Flags.string({ + description: 'Is the order ascending or descending', + default: 'ASC', + options: ['ASC', 'DESC'], + }), + 'enabled': Flags.boolean({ + description: 'Enabled Wallets', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetEmbeddedWallets) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['enabled'] !== undefined && flags['enabled'] !== null) { + queryParams['enabled'] = String(flags['enabled']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-public-key-info-for-address-ncw.ts b/src/commands/embedded-wallets/get-public-key-info-for-address-ncw.ts new file mode 100644 index 0000000..21a80fd --- /dev/null +++ b/src/commands/embedded-wallets/get-public-key-info-for-address-ncw.ts @@ -0,0 +1,76 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPublicKeyInfoForAddressNcw extends FireblocksBaseCommand { + static summary = 'Get the public key of an asset' + + static description = 'Gets the public key of an asset associated with a specific account within a Non-Custodial Wallet\n\nOperation ID: getPublicKeyInfoForAddressNcw\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/getPublicKeyInfoForAddressNcw' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the Non-Custodial wallet', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'change': Flags.string({ + description: 'BIP44 derivation path - change value', + required: true, + }), + 'address-index': Flags.string({ + description: 'BIP44 derivation path - index value', + required: true, + }), + 'compressed': Flags.boolean({ + description: 'Compressed/Uncompressed public key format', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/{walletId}/accounts/{accountId}/{assetId}/{change}/{addressIndex}/public_key_info' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetPublicKeyInfoForAddressNcw) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + pathParams['assetId'] = String(flags['asset-id']) + pathParams['change'] = String(flags['change']) + pathParams['addressIndex'] = String(flags['address-index']) + + const queryParams: Record = {} + if (flags['compressed'] !== undefined && flags['compressed'] !== null) { + queryParams['compressed'] = String(flags['compressed']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/{walletId}/accounts/{accountId}/{assetId}/{change}/{addressIndex}/public_key_info', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/get-public-key-info-ncw.ts b/src/commands/embedded-wallets/get-public-key-info-ncw.ts new file mode 100644 index 0000000..d5bbced --- /dev/null +++ b/src/commands/embedded-wallets/get-public-key-info-ncw.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPublicKeyInfoNcw extends FireblocksBaseCommand { + static summary = 'Get the public key for a derivation path' + + static description = 'Gets the public key information based on derivation path and signing algorithm within a Non-Custodial Wallet\n\nOperation ID: getPublicKeyInfoNcw\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/getPublicKeyInfoNcw' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the Non-Custodial wallet', + required: true, + }), + 'derivation-path': Flags.string({ + description: 'An array of integers (passed as JSON stringified array) representing the full BIP44 derivation path of the requested public key. \nThe first element must always be 44.\n', + required: true, + }), + 'algorithm': Flags.string({ + description: 'Elliptic Curve', + required: true, + options: ['MPC_ECDSA_SECP256K1', 'MPC_ECDSA_SECP256R1', 'MPC_EDDSA_ED25519'], + }), + 'compressed': Flags.boolean({ + description: 'Compressed/Uncompressed public key format', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/ncw/wallets/{walletId}/public_key_info' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetPublicKeyInfoNcw) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + const queryParams: Record = {} + if (flags['derivation-path'] !== undefined && flags['derivation-path'] !== null) { + queryParams['derivationPath'] = String(flags['derivation-path']) + } + if (flags['algorithm'] !== undefined && flags['algorithm'] !== null) { + queryParams['algorithm'] = String(flags['algorithm']) + } + if (flags['compressed'] !== undefined && flags['compressed'] !== null) { + queryParams['compressed'] = String(flags['compressed']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/ncw/wallets/{walletId}/public_key_info', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/refresh-embedded-wallet-asset-balance.ts b/src/commands/embedded-wallets/refresh-embedded-wallet-asset-balance.ts new file mode 100644 index 0000000..7353899 --- /dev/null +++ b/src/commands/embedded-wallets/refresh-embedded-wallet-asset-balance.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RefreshEmbeddedWalletAssetBalance extends FireblocksBaseCommand { + static summary = 'Refresh asset balance' + + static description = 'Refresh the balance of an asset in a specific account\n\nOperation ID: RefreshEmbeddedWalletAssetBalance\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/RefreshEmbeddedWalletAssetBalance' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'account-id': Flags.string({ + description: 'The ID of the account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/balance' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RefreshEmbeddedWalletAssetBalance) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['accountId'] = String(flags['account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('PUT', '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/balance') + + const result = await this.makeRequest( + 'PUT', + '/v1/ncw/wallets/{walletId}/accounts/{accountId}/assets/{assetId}/balance', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/update-embedded-wallet-device-status.ts b/src/commands/embedded-wallets/update-embedded-wallet-device-status.ts new file mode 100644 index 0000000..9ec9509 --- /dev/null +++ b/src/commands/embedded-wallets/update-embedded-wallet-device-status.ts @@ -0,0 +1,75 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateEmbeddedWalletDeviceStatus extends FireblocksBaseCommand { + static summary = 'Update device status' + + static description = 'Update the enabled/disabled status of a specific device for a Non Custodial Wallet\n\nOperation ID: updateEmbeddedWalletDeviceStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/updateEmbeddedWalletDeviceStatus' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + 'device-id': Flags.string({ + description: 'Device Id', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/ncw/wallets/{walletId}/devices/{deviceId}/status' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateEmbeddedWalletDeviceStatus) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['deviceId'] = String(flags['device-id']) + + + await this.confirmOrAbort('PATCH', '/v1/ncw/wallets/{walletId}/devices/{deviceId}/status') + + const result = await this.makeRequest( + 'PATCH', + '/v1/ncw/wallets/{walletId}/devices/{deviceId}/status', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/embedded-wallets/update-embedded-wallet-status.ts b/src/commands/embedded-wallets/update-embedded-wallet-status.ts new file mode 100644 index 0000000..3378858 --- /dev/null +++ b/src/commands/embedded-wallets/update-embedded-wallet-status.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateEmbeddedWalletStatus extends FireblocksBaseCommand { + static summary = 'Update wallet status' + + static description = 'Update the enabled/disabled status of a specific Non Custodial Wallet\n\nOperation ID: updateEmbeddedWalletStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Embedded%20Wallets/updateEmbeddedWalletStatus' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'Wallet Id', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/ncw/wallets/{walletId}/status' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateEmbeddedWalletStatus) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + await this.confirmOrAbort('PATCH', '/v1/ncw/wallets/{walletId}/status') + + const result = await this.makeRequest( + 'PATCH', + '/v1/ncw/wallets/{walletId}/status', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/add-exchange-account.ts b/src/commands/exchange-accounts/add-exchange-account.ts new file mode 100644 index 0000000..6a1aac5 --- /dev/null +++ b/src/commands/exchange-accounts/add-exchange-account.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddExchangeAccount extends FireblocksBaseCommand { + static summary = 'Add an exchange account' + + static description = 'Add an exchange account to exchanges. \n\nNote: This endpoint currently only supports the following exchanges \`INDEPENDENT_RESERVE\`,\`BIT\`, \`BITHUMB\`, \`BITSO\`, \`CRYPTOCOM\`, \`BYBIT_V2\`, \`WHITEBIT\`, \`HITBTC\`, \`GEMINI\`, \`HUOBI\`, \`GATEIO\`, \`COINHAKO\`, \`BULLISH\`, \`BITGET\`, and \`LUNO\`\n\nTo add an exchange account, please use the following [guide](https://developers.fireblocks.com/docs/add-an-exchange-account).\n\nOperation ID: addExchangeAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/addExchangeAccount' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/exchange_accounts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddExchangeAccount) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/exchange_accounts') + + const result = await this.makeRequest( + 'POST', + '/v1/exchange_accounts', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/convert-assets.ts b/src/commands/exchange-accounts/convert-assets.ts new file mode 100644 index 0000000..2142715 --- /dev/null +++ b/src/commands/exchange-accounts/convert-assets.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ConvertAssets extends FireblocksBaseCommand { + static summary = 'Convert exchange account funds' + + static description = 'Convert exchange account funds from the source asset to the destination asset. Coinbase (USD to USDC, USDC to USD) and Bitso (MXN to USD) are supported conversions.\nLearn more about Fireblocks Exchange Connectivity in the following [guide](https://developers.fireblocks.com/docs/connect-to-exchanges-and-fiat-providers).\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: convertAssets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/convertAssets' + + static enableJsonFlag = false + + static flags = { + 'exchange-account-id': Flags.string({ + description: 'The ID of the exchange account. Please make sure the exchange supports conversions. To find the ID of your exchange account, use GET/exchange_accounts.', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/exchange_accounts/{exchangeAccountId}/convert' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ConvertAssets) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['exchangeAccountId'] = String(flags['exchange-account-id']) + + + await this.confirmOrAbort('POST', '/v1/exchange_accounts/{exchangeAccountId}/convert') + + const result = await this.makeRequest( + 'POST', + '/v1/exchange_accounts/{exchangeAccountId}/convert', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/get-exchange-account-asset.ts b/src/commands/exchange-accounts/get-exchange-account-asset.ts new file mode 100644 index 0000000..f5e3fee --- /dev/null +++ b/src/commands/exchange-accounts/get-exchange-account-asset.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetExchangeAccountAsset extends FireblocksBaseCommand { + static summary = 'Get an asset for an exchange account' + + static description = 'Returns an asset for an exchange account.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getExchangeAccountAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/getExchangeAccountAsset' + + static enableJsonFlag = false + + static flags = { + 'exchange-account-id': Flags.string({ + description: 'The ID of the exchange account to return', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/exchange_accounts/{exchangeAccountId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetExchangeAccountAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['exchangeAccountId'] = String(flags['exchange-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/exchange_accounts/{exchangeAccountId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/get-exchange-account.ts b/src/commands/exchange-accounts/get-exchange-account.ts new file mode 100644 index 0000000..72bd6d2 --- /dev/null +++ b/src/commands/exchange-accounts/get-exchange-account.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetExchangeAccount extends FireblocksBaseCommand { + static summary = 'Get a specific exchange account' + + static description = 'Returns an exchange account by ID.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getExchangeAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/getExchangeAccount' + + static enableJsonFlag = false + + static flags = { + 'exchange-account-id': Flags.string({ + description: 'The ID of the exchange account to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/exchange_accounts/{exchangeAccountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetExchangeAccount) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['exchangeAccountId'] = String(flags['exchange-account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/exchange_accounts/{exchangeAccountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/get-exchange-accounts-credentials-public-key.ts b/src/commands/exchange-accounts/get-exchange-accounts-credentials-public-key.ts new file mode 100644 index 0000000..0894ccb --- /dev/null +++ b/src/commands/exchange-accounts/get-exchange-accounts-credentials-public-key.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetExchangeAccountsCredentialsPublicKey extends FireblocksBaseCommand { + static summary = 'Get public key to encrypt exchange credentials' + + static description = 'Return public key\n\nOperation ID: getExchangeAccountsCredentialsPublicKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/getExchangeAccountsCredentialsPublicKey' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/exchange_accounts/credentials_public_key' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetExchangeAccountsCredentialsPublicKey) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/exchange_accounts/credentials_public_key', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/get-exchange-accounts.ts b/src/commands/exchange-accounts/get-exchange-accounts.ts new file mode 100644 index 0000000..11eefc4 --- /dev/null +++ b/src/commands/exchange-accounts/get-exchange-accounts.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetExchangeAccounts extends FireblocksBaseCommand { + static summary = 'List exchange accounts' + + static description = 'DEPRECATED - Please use the \`/exchange_accounts/paged\` endpoint.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getExchangeAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/getExchangeAccounts' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/exchange_accounts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetExchangeAccounts) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/exchange_accounts', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/get-paged-exchange-accounts.ts b/src/commands/exchange-accounts/get-paged-exchange-accounts.ts new file mode 100644 index 0000000..3013945 --- /dev/null +++ b/src/commands/exchange-accounts/get-paged-exchange-accounts.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPagedExchangeAccounts extends FireblocksBaseCommand { + static summary = 'List connected exchange accounts' + + static description = 'Returns a list of the connected exchange accounts in your workspace. Endpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getPagedExchangeAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/getPagedExchangeAccounts' + + static enableJsonFlag = false + + static flags = { + 'before': Flags.string({ + description: 'The before parameter', + }), + 'after': Flags.string({ + description: 'The after parameter', + }), + 'limit': Flags.string({ + description: 'number of exchanges per page', + required: true, + default: '3', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/exchange_accounts/paged' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetPagedExchangeAccounts) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['before'] !== undefined && flags['before'] !== null) { + queryParams['before'] = String(flags['before']) + } + if (flags['after'] !== undefined && flags['after'] !== null) { + queryParams['after'] = String(flags['after']) + } + if (flags['limit'] !== undefined && flags['limit'] !== null) { + queryParams['limit'] = String(flags['limit']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/exchange_accounts/paged', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/exchange-accounts/internal-transfer.ts b/src/commands/exchange-accounts/internal-transfer.ts new file mode 100644 index 0000000..d8cdd43 --- /dev/null +++ b/src/commands/exchange-accounts/internal-transfer.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class InternalTransfer extends FireblocksBaseCommand { + static summary = 'Internal transfer for exchange accounts' + + static description = 'Transfers funds between trading accounts under the same exchange account.\nLearn more about Fireblocks Exchange Connectivity in the following [guide](https://developers.fireblocks.com/docs/connect-to-exchanges-and-fiat-providers).\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: internalTransfer\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Exchange%20accounts/internalTransfer' + + static enableJsonFlag = false + + static flags = { + 'exchange-account-id': Flags.string({ + description: 'The ID of the exchange account to return', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/exchange_accounts/{exchangeAccountId}/internal_transfer' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(InternalTransfer) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['exchangeAccountId'] = String(flags['exchange-account-id']) + + + await this.confirmOrAbort('POST', '/v1/exchange_accounts/{exchangeAccountId}/internal_transfer') + + const result = await this.makeRequest( + 'POST', + '/v1/exchange_accounts/{exchangeAccountId}/internal_transfer', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/add-asset-to-external-wallet.ts b/src/commands/external-wallets/add-asset-to-external-wallet.ts new file mode 100644 index 0000000..8b14cb7 --- /dev/null +++ b/src/commands/external-wallets/add-asset-to-external-wallet.ts @@ -0,0 +1,74 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddAssetToExternalWallet extends FireblocksBaseCommand { + static summary = 'Add an asset to an external wallet.' + + static description = 'Adds an asset to an existing external wallet. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: addAssetToExternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/addAssetToExternalWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to add', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/external_wallets/{walletId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddAssetToExternalWallet) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('POST', '/v1/external_wallets/{walletId}/{assetId}') + + const result = await this.makeRequest( + 'POST', + '/v1/external_wallets/{walletId}/{assetId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/create-external-wallet.ts b/src/commands/external-wallets/create-external-wallet.ts new file mode 100644 index 0000000..72c4bc5 --- /dev/null +++ b/src/commands/external-wallets/create-external-wallet.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateExternalWallet extends FireblocksBaseCommand { + static summary = 'Create an external wallet' + + static description = 'Creates a new external wallet with the requested name.\n\nExternal Wallet is a whitelisted address of a wallet that belongs to your users/counterparties.\n\n- You cannot see the balance of the external wallet.\n- You cannot initiate transactions from an external wallet as the source via Fireblocks.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createExternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/createExternalWallet' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/external_wallets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateExternalWallet) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/external_wallets') + + const result = await this.makeRequest( + 'POST', + '/v1/external_wallets', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/delete-external-wallet.ts b/src/commands/external-wallets/delete-external-wallet.ts new file mode 100644 index 0000000..8163657 --- /dev/null +++ b/src/commands/external-wallets/delete-external-wallet.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteExternalWallet extends FireblocksBaseCommand { + static summary = 'Delete an external wallet' + + static description = 'Deletes an external wallet by ID. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: deleteExternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/deleteExternalWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet to delete', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/external_wallets/{walletId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteExternalWallet) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + await this.confirmOrAbort('DELETE', '/v1/external_wallets/{walletId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/external_wallets/{walletId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/get-external-wallet-asset.ts b/src/commands/external-wallets/get-external-wallet-asset.ts new file mode 100644 index 0000000..8443fc7 --- /dev/null +++ b/src/commands/external-wallets/get-external-wallet-asset.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetExternalWalletAsset extends FireblocksBaseCommand { + static summary = 'Get an asset from an external wallet' + + static description = 'Returns an external wallet by wallet ID and asset ID. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getExternalWalletAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/getExternalWalletAsset' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/external_wallets/{walletId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetExternalWalletAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/external_wallets/{walletId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/get-external-wallet.ts b/src/commands/external-wallets/get-external-wallet.ts new file mode 100644 index 0000000..abeb256 --- /dev/null +++ b/src/commands/external-wallets/get-external-wallet.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetExternalWallet extends FireblocksBaseCommand { + static summary = 'Find an external wallet' + + static description = 'Returns an external wallet by ID. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getExternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/getExternalWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/external_wallets/{walletId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetExternalWallet) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/external_wallets/{walletId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/get-external-wallets.ts b/src/commands/external-wallets/get-external-wallets.ts new file mode 100644 index 0000000..8533b8f --- /dev/null +++ b/src/commands/external-wallets/get-external-wallets.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetExternalWallets extends FireblocksBaseCommand { + static summary = 'List external wallets' + + static description = 'Gets a list of external wallets under the workspace.\n\nExternal Wallet is a whitelisted address of a wallet that belongs to your users/counterparties.\n\n- You cannot see the balance of the external wallet.\n- You cannot initiate transactions from an external wallet as the source via Fireblocks.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getExternalWallets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/getExternalWallets' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/external_wallets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetExternalWallets) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/external_wallets', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/remove-asset-from-external-wallet.ts b/src/commands/external-wallets/remove-asset-from-external-wallet.ts new file mode 100644 index 0000000..65e208d --- /dev/null +++ b/src/commands/external-wallets/remove-asset-from-external-wallet.ts @@ -0,0 +1,55 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RemoveAssetFromExternalWallet extends FireblocksBaseCommand { + static summary = 'Delete an asset from an external wallet' + + static description = 'Deletes an external wallet asset by ID. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: removeAssetFromExternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/removeAssetFromExternalWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to delete', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/external_wallets/{walletId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RemoveAssetFromExternalWallet) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('DELETE', '/v1/external_wallets/{walletId}/{assetId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/external_wallets/{walletId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/external-wallets/set-external-wallet-customer-ref-id.ts b/src/commands/external-wallets/set-external-wallet-customer-ref-id.ts new file mode 100644 index 0000000..10a042c --- /dev/null +++ b/src/commands/external-wallets/set-external-wallet-customer-ref-id.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetExternalWalletCustomerRefId extends FireblocksBaseCommand { + static summary = 'Set an AML customer reference ID for an external wallet' + + static description = 'Sets an AML/KYT customer reference ID for the specific external wallet. External Wallet is a whitelisted address of a wallet that belongs to your users/counterparties. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: setExternalWalletCustomerRefId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/External%20wallets/setExternalWalletCustomerRefId' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The wallet ID', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/external_wallets/{walletId}/set_customer_ref_id' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetExternalWalletCustomerRefId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + await this.confirmOrAbort('POST', '/v1/external_wallets/{walletId}/set_customer_ref_id') + + const result = await this.makeRequest( + 'POST', + '/v1/external_wallets/{walletId}/set_customer_ref_id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/fiat-accounts/deposit-funds-from-linked-dda.ts b/src/commands/fiat-accounts/deposit-funds-from-linked-dda.ts new file mode 100644 index 0000000..e6d4e71 --- /dev/null +++ b/src/commands/fiat-accounts/deposit-funds-from-linked-dda.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DepositFundsFromLinkedDDA extends FireblocksBaseCommand { + static summary = 'Deposit funds from DDA' + + static description = 'Deposits funds from the linked DDA.\n\nOperation ID: depositFundsFromLinkedDDA\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Fiat%20accounts/depositFundsFromLinkedDDA' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the fiat account to use', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/fiat_accounts/{accountId}/deposit_from_linked_dda' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DepositFundsFromLinkedDDA) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + + await this.confirmOrAbort('POST', '/v1/fiat_accounts/{accountId}/deposit_from_linked_dda') + + const result = await this.makeRequest( + 'POST', + '/v1/fiat_accounts/{accountId}/deposit_from_linked_dda', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/fiat-accounts/get-fiat-account.ts b/src/commands/fiat-accounts/get-fiat-account.ts new file mode 100644 index 0000000..87310a7 --- /dev/null +++ b/src/commands/fiat-accounts/get-fiat-account.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetFiatAccount extends FireblocksBaseCommand { + static summary = 'Find a specific fiat account' + + static description = 'Returns a fiat account by ID.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getFiatAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Fiat%20accounts/getFiatAccount' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the fiat account to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/fiat_accounts/{accountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetFiatAccount) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/fiat_accounts/{accountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/fiat-accounts/get-fiat-accounts.ts b/src/commands/fiat-accounts/get-fiat-accounts.ts new file mode 100644 index 0000000..40cfdc2 --- /dev/null +++ b/src/commands/fiat-accounts/get-fiat-accounts.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetFiatAccounts extends FireblocksBaseCommand { + static summary = 'List fiat accounts' + + static description = 'Returns all fiat accounts.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getFiatAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Fiat%20accounts/getFiatAccounts' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/fiat_accounts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetFiatAccounts) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/fiat_accounts', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/fiat-accounts/redeem-funds-to-linked-dda.ts b/src/commands/fiat-accounts/redeem-funds-to-linked-dda.ts new file mode 100644 index 0000000..91ec972 --- /dev/null +++ b/src/commands/fiat-accounts/redeem-funds-to-linked-dda.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RedeemFundsToLinkedDDA extends FireblocksBaseCommand { + static summary = 'Redeem funds to DDA' + + static description = 'Redeems funds to the linked DDA.\n\nOperation ID: redeemFundsToLinkedDDA\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Fiat%20accounts/redeemFundsToLinkedDDA' + + static enableJsonFlag = false + + static flags = { + 'account-id': Flags.string({ + description: 'The ID of the fiat account to use', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/fiat_accounts/{accountId}/redeem_to_linked_dda' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RedeemFundsToLinkedDDA) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['accountId'] = String(flags['account-id']) + + + await this.confirmOrAbort('POST', '/v1/fiat_accounts/{accountId}/redeem_to_linked_dda') + + const result = await this.makeRequest( + 'POST', + '/v1/fiat_accounts/{accountId}/redeem_to_linked_dda', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/gas-stations/get-gas-station-by-asset-id.ts b/src/commands/gas-stations/get-gas-station-by-asset-id.ts new file mode 100644 index 0000000..d3fe886 --- /dev/null +++ b/src/commands/gas-stations/get-gas-station-by-asset-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetGasStationByAssetId extends FireblocksBaseCommand { + static summary = 'Get gas station settings by asset' + + static description = 'Returns gas station settings and balances for a requested asset.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getGasStationByAssetId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Gas%20stations/getGasStationByAssetId' + + static enableJsonFlag = false + + static flags = { + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/gas_station/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetGasStationByAssetId) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/gas_station/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/gas-stations/get-gas-station-info.ts b/src/commands/gas-stations/get-gas-station-info.ts new file mode 100644 index 0000000..13928d7 --- /dev/null +++ b/src/commands/gas-stations/get-gas-station-info.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetGasStationInfo extends FireblocksBaseCommand { + static summary = 'Get gas station settings' + + static description = 'Returns gas station settings and ETH balance.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getGasStationInfo\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Gas%20stations/getGasStationInfo' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/gas_station' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetGasStationInfo) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/gas_station', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/gas-stations/update-gas-station-configuration-by-asset-id.ts b/src/commands/gas-stations/update-gas-station-configuration-by-asset-id.ts new file mode 100644 index 0000000..d486c0a --- /dev/null +++ b/src/commands/gas-stations/update-gas-station-configuration-by-asset-id.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateGasStationConfigurationByAssetId extends FireblocksBaseCommand { + static summary = 'Edit gas station settings for an asset' + + static description = 'Configures gas station settings for a requested asset.\nLearn more about the Fireblocks Gas Station in the following [guide](https://developers.fireblocks.com/docs/work-with-gas-station).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: updateGasStationConfigurationByAssetId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Gas%20stations/updateGasStationConfigurationByAssetId' + + static enableJsonFlag = false + + static flags = { + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/gas_station/configuration/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateGasStationConfigurationByAssetId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('PUT', '/v1/gas_station/configuration/{assetId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/gas_station/configuration/{assetId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/gas-stations/update-gas-station-configuration.ts b/src/commands/gas-stations/update-gas-station-configuration.ts new file mode 100644 index 0000000..b225dff --- /dev/null +++ b/src/commands/gas-stations/update-gas-station-configuration.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateGasStationConfiguration extends FireblocksBaseCommand { + static summary = 'Edit gas station settings' + + static description = 'Configures gas station settings for ETH.\nLearn more about the Fireblocks Gas Station in the following [guide](https://developers.fireblocks.com/docs/work-with-gas-station).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: updateGasStationConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Gas%20stations/updateGasStationConfiguration' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/gas_station/configuration' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateGasStationConfiguration) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/gas_station/configuration') + + const result = await this.makeRequest( + 'PUT', + '/v1/gas_station/configuration', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/help-index.ts b/src/commands/help-index.ts new file mode 100644 index 0000000..4e9e3fb --- /dev/null +++ b/src/commands/help-index.ts @@ -0,0 +1,81 @@ +import {Command} from '@oclif/core' + +interface CompactFlag { + name: string + type: string + required: boolean +} + +interface CompactCommand { + namespace: string + action: string + description: string + method?: string + path?: string + flags: CompactFlag[] +} + +export default class HelpIndex extends Command { + static override description = 'Machine-readable command index for AI agents' + + static override examples = [ + '$ fireblocks help-index', + '$ fireblocks help-index --json', + ] + + static override enableJsonFlag = true + + async run(): Promise<{commands: CompactCommand[]}> { + const commands: CompactCommand[] = [] + + for (const cmd of this.config.commands) { + // Split command id into namespace and action + // e.g. "vaults list" -> namespace="vaults", action="list" + // e.g. "configure" -> namespace="configure", action="" + const parts = cmd.id.split(' ') + const namespace = parts.length > 1 ? parts.slice(0, -1).join(' ') : cmd.id + const action = parts.length > 1 ? parts[parts.length - 1] : '' + + // Extract HTTP method and path from description or aliases if available + // Commands generated from OpenAPI typically encode method/path in metadata + let method: string | undefined + let path: string | undefined + + const pluginData = cmd as Record + + // Check if command stores http metadata (convention from generated commands) + if (typeof pluginData.method === 'string') method = pluginData.method + if (typeof pluginData.path === 'string') path = pluginData.path + + // Build compact flags list — only include required flags to keep output small + const flags: CompactFlag[] = [] + if (cmd.flags) { + for (const [name, flag] of Object.entries(cmd.flags)) { + // Skip base flags that every command has (output, debug, etc.) + if (['output', 'debug', 'json'].includes(name)) continue + + const flagDef = flag as Record + flags.push({ + name, + type: (flagDef.type as string) ?? 'string', + required: (flagDef.required as boolean) ?? false, + }) + } + } + + const entry: CompactCommand = { + namespace, + action, + description: cmd.summary ?? cmd.description ?? '', + flags, + } + + if (method) entry.method = method + if (path) entry.path = path + + commands.push(entry) + } + + return {commands} + } +} diff --git a/src/commands/internal-wallets/create-internal-wallet-asset.ts b/src/commands/internal-wallets/create-internal-wallet-asset.ts new file mode 100644 index 0000000..e617375 --- /dev/null +++ b/src/commands/internal-wallets/create-internal-wallet-asset.ts @@ -0,0 +1,74 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateInternalWalletAsset extends FireblocksBaseCommand { + static summary = 'Add an asset to an internal wallet' + + static description = 'Adds an asset to an existing internal wallet.\n\nOperation ID: createInternalWalletAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/createInternalWalletAsset' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to add', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/internal_wallets/{walletId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateInternalWalletAsset) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('POST', '/v1/internal_wallets/{walletId}/{assetId}') + + const result = await this.makeRequest( + 'POST', + '/v1/internal_wallets/{walletId}/{assetId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/create-internal-wallet.ts b/src/commands/internal-wallets/create-internal-wallet.ts new file mode 100644 index 0000000..bb0edee --- /dev/null +++ b/src/commands/internal-wallets/create-internal-wallet.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateInternalWallet extends FireblocksBaseCommand { + static summary = 'Create an internal wallet' + + static description = 'Creates a new internal wallet with the requested name.\nLearn more about Whitelisted Internal Addresses [here](https://developers.fireblocks.com/docs/whitelist-addresses#internal-wallets)\n\nOperation ID: createInternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/createInternalWallet' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/internal_wallets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateInternalWallet) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/internal_wallets') + + const result = await this.makeRequest( + 'POST', + '/v1/internal_wallets', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/delete-internal-wallet-asset.ts b/src/commands/internal-wallets/delete-internal-wallet-asset.ts new file mode 100644 index 0000000..bb3e659 --- /dev/null +++ b/src/commands/internal-wallets/delete-internal-wallet-asset.ts @@ -0,0 +1,55 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteInternalWalletAsset extends FireblocksBaseCommand { + static summary = 'Delete a whitelisted address' + + static description = 'Deletes a whitelisted address (for an asset) from an internal wallet.\n\nOperation ID: deleteInternalWalletAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/deleteInternalWalletAsset' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to delete', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/internal_wallets/{walletId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteInternalWalletAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('DELETE', '/v1/internal_wallets/{walletId}/{assetId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/internal_wallets/{walletId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/delete-internal-wallet.ts b/src/commands/internal-wallets/delete-internal-wallet.ts new file mode 100644 index 0000000..64d5df1 --- /dev/null +++ b/src/commands/internal-wallets/delete-internal-wallet.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteInternalWallet extends FireblocksBaseCommand { + static summary = 'Delete an internal wallet' + + static description = 'Deletes an internal wallet by ID.\n\nOperation ID: deleteInternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/deleteInternalWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet to delete', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/internal_wallets/{walletId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteInternalWallet) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + await this.confirmOrAbort('DELETE', '/v1/internal_wallets/{walletId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/internal_wallets/{walletId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/get-internal-wallet-asset.ts b/src/commands/internal-wallets/get-internal-wallet-asset.ts new file mode 100644 index 0000000..fbcdcae --- /dev/null +++ b/src/commands/internal-wallets/get-internal-wallet-asset.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetInternalWalletAsset extends FireblocksBaseCommand { + static summary = 'Get an asset from an internal wallet' + + static description = 'Returns information for an asset in an internal wallet.\n\nOperation ID: getInternalWalletAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/getInternalWalletAsset' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/internal_wallets/{walletId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetInternalWalletAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/internal_wallets/{walletId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/get-internal-wallet-assets-paginated.ts b/src/commands/internal-wallets/get-internal-wallet-assets-paginated.ts new file mode 100644 index 0000000..e426b2e --- /dev/null +++ b/src/commands/internal-wallets/get-internal-wallet-assets-paginated.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetInternalWalletAssetsPaginated extends FireblocksBaseCommand { + static summary = 'List assets in an internal wallet (Paginated)' + + static description = 'Returns a paginated response of assets in an internal wallet.\n\nOperation ID: getInternalWalletAssetsPaginated\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/getInternalWalletAssetsPaginated' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the internal wallet to return assets for', + required: true, + }), + 'page-size': Flags.string({ + description: 'The pageSize parameter', + default: '50', + }), + 'page-cursor': Flags.string({ + description: 'The pageCursor parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/internal_wallets/{walletId}/assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetInternalWalletAssetsPaginated) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + const queryParams: Record = {} + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/internal_wallets/{walletId}/assets', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/get-internal-wallet.ts b/src/commands/internal-wallets/get-internal-wallet.ts new file mode 100644 index 0000000..849c5bc --- /dev/null +++ b/src/commands/internal-wallets/get-internal-wallet.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetInternalWallet extends FireblocksBaseCommand { + static summary = 'Get assets for internal wallet' + + static description = 'Returns information for an internal wallet.\n\nOperation ID: getInternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/getInternalWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The ID of the wallet to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/internal_wallets/{walletId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetInternalWallet) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/internal_wallets/{walletId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/get-internal-wallets.ts b/src/commands/internal-wallets/get-internal-wallets.ts new file mode 100644 index 0000000..f30de2c --- /dev/null +++ b/src/commands/internal-wallets/get-internal-wallets.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetInternalWallets extends FireblocksBaseCommand { + static summary = 'List internal wallets' + + static description = 'Gets a list of internal wallets.\n\nOperation ID: getInternalWallets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/getInternalWallets' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/internal_wallets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetInternalWallets) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/internal_wallets', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/internal-wallets/set-customer-ref-id-for-internal-wallet.ts b/src/commands/internal-wallets/set-customer-ref-id-for-internal-wallet.ts new file mode 100644 index 0000000..aff9f72 --- /dev/null +++ b/src/commands/internal-wallets/set-customer-ref-id-for-internal-wallet.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetCustomerRefIdForInternalWallet extends FireblocksBaseCommand { + static summary = 'Set an AML/KYT customer reference ID for internal wallet' + + static description = 'Sets an AML/KYT customer reference ID for the specific internal wallet.\n\nOperation ID: setCustomerRefIdForInternalWallet\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Internal%20wallets/setCustomerRefIdForInternalWallet' + + static enableJsonFlag = false + + static flags = { + 'wallet-id': Flags.string({ + description: 'The wallet ID', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/internal_wallets/{walletId}/set_customer_ref_id' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetCustomerRefIdForInternalWallet) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['walletId'] = String(flags['wallet-id']) + + + await this.confirmOrAbort('POST', '/v1/internal_wallets/{walletId}/set_customer_ref_id') + + const result = await this.makeRequest( + 'POST', + '/v1/internal_wallets/{walletId}/set_customer_ref_id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/create-signing-key.ts b/src/commands/key-link/create-signing-key.ts new file mode 100644 index 0000000..552e2bc --- /dev/null +++ b/src/commands/key-link/create-signing-key.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateSigningKey extends FireblocksBaseCommand { + static summary = 'Add a new signing key' + + static description = 'Adds a new signing key to the workspace. The added key will be linked to the specific Fireblocks agent user ID. The same user will receive the proof of ownership message to be signed, and upon successful proof, the key will become enabled.\n\nOperation ID: createSigningKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/createSigningKey' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/key_link/signing_keys' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateSigningKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/key_link/signing_keys') + + const result = await this.makeRequest( + 'POST', + '/v1/key_link/signing_keys', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/create-validation-key.ts b/src/commands/key-link/create-validation-key.ts new file mode 100644 index 0000000..3a127e3 --- /dev/null +++ b/src/commands/key-link/create-validation-key.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateValidationKey extends FireblocksBaseCommand { + static summary = 'Add a new validation key' + + static description = 'Adds a new validation key used to validate signing keys. The new validation key will undergo an approval process by the workspace quorum.\n\nOperation ID: createValidationKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/createValidationKey' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/key_link/validation_keys' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateValidationKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/key_link/validation_keys') + + const result = await this.makeRequest( + 'POST', + '/v1/key_link/validation_keys', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/disable-validation-key.ts b/src/commands/key-link/disable-validation-key.ts new file mode 100644 index 0000000..5bb1889 --- /dev/null +++ b/src/commands/key-link/disable-validation-key.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DisableValidationKey extends FireblocksBaseCommand { + static summary = 'Disables a validation key' + + static description = 'Allows disabling validation key even if it has not expired yet. It is not allowed to enable the validation key back. Another key has to be used for future validations.\n\nOperation ID: disableValidationKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/disableValidationKey' + + static enableJsonFlag = false + + static flags = { + 'key-id': Flags.string({ + description: 'The unique identifier for the validation key provided by Fireblocks', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/key_link/validation_keys/{keyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DisableValidationKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['keyId'] = String(flags['key-id']) + + + await this.confirmOrAbort('PATCH', '/v1/key_link/validation_keys/{keyId}') + + const result = await this.makeRequest( + 'PATCH', + '/v1/key_link/validation_keys/{keyId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/get-signing-key.ts b/src/commands/key-link/get-signing-key.ts new file mode 100644 index 0000000..b6e5e21 --- /dev/null +++ b/src/commands/key-link/get-signing-key.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSigningKey extends FireblocksBaseCommand { + static summary = 'Get a signing key by \`keyId\`' + + static description = 'Returns a signing key if it exists, identified by the specified \`keyId\`.\n\nOperation ID: getSigningKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/getSigningKey' + + static enableJsonFlag = false + + static flags = { + 'key-id': Flags.string({ + description: 'The unique identifier for the signing key provided by Fireblocks', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/key_link/signing_keys/{keyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetSigningKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['keyId'] = String(flags['key-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/key_link/signing_keys/{keyId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/get-signing-keys-list.ts b/src/commands/key-link/get-signing-keys-list.ts new file mode 100644 index 0000000..2b5c548 --- /dev/null +++ b/src/commands/key-link/get-signing-keys-list.ts @@ -0,0 +1,117 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSigningKeysList extends FireblocksBaseCommand { + static summary = 'Get list of signing keys' + + static description = 'Returns the list of signing keys in the workspace\n\nOperation ID: getSigningKeysList\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/getSigningKeysList' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Cursor to the next page', + }), + 'page-size': Flags.string({ + description: 'Amount of results to return in the next page', + default: '10', + }), + 'sort-by': Flags.string({ + description: 'Field(s) to use for sorting', + default: 'createdAt', + options: ['createdAt'], + }), + 'order': Flags.string({ + description: 'Is the order ascending or descending', + default: 'ASC', + options: ['ASC', 'DESC'], + }), + 'vault-account-id': Flags.string({ + description: 'Return keys assigned to a specific vault', + }), + 'agent-user-id': Flags.string({ + description: 'Return keys associated with a specific agent user', + }), + 'algorithm': Flags.string({ + description: 'Return only keys with a specific algorithm', + options: ['ECDSA_SECP256K1', 'EDDSA_ED25519'], + }), + 'enabled': Flags.boolean({ + description: 'Return keys that have been proof of ownership', + }), + 'available': Flags.boolean({ + description: 'Return keys that are proof of ownership but not assigned. Available filter can be used only when vaultAccountId and enabled filters are not set', + }), + 'is-assigned': Flags.boolean({ + description: 'Return keys that are assigned to a vault account', + }), + 'key-prefix': Flags.string({ + description: 'A case-insensitive prefix filter that matches records where either keyId or signingDeviceKeyID starts with the specified value.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/key_link/signing_keys' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetSigningKeysList) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['vault-account-id'] !== undefined && flags['vault-account-id'] !== null) { + queryParams['vaultAccountId'] = String(flags['vault-account-id']) + } + if (flags['agent-user-id'] !== undefined && flags['agent-user-id'] !== null) { + queryParams['agentUserId'] = String(flags['agent-user-id']) + } + if (flags['algorithm'] !== undefined && flags['algorithm'] !== null) { + queryParams['algorithm'] = String(flags['algorithm']) + } + if (flags['enabled'] !== undefined && flags['enabled'] !== null) { + queryParams['enabled'] = String(flags['enabled']) + } + if (flags['available'] !== undefined && flags['available'] !== null) { + queryParams['available'] = String(flags['available']) + } + if (flags['is-assigned'] !== undefined && flags['is-assigned'] !== null) { + queryParams['isAssigned'] = String(flags['is-assigned']) + } + if (flags['key-prefix'] !== undefined && flags['key-prefix'] !== null) { + queryParams['keyPrefix'] = String(flags['key-prefix']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/key_link/signing_keys', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/get-validation-key.ts b/src/commands/key-link/get-validation-key.ts new file mode 100644 index 0000000..8323901 --- /dev/null +++ b/src/commands/key-link/get-validation-key.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetValidationKey extends FireblocksBaseCommand { + static summary = 'Get a validation key by \`keyId\`' + + static description = 'Returns a validation key if it exists, identified by the specified \`keyId\`.\n\nOperation ID: getValidationKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/getValidationKey' + + static enableJsonFlag = false + + static flags = { + 'key-id': Flags.string({ + description: 'The keyId parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/key_link/validation_keys/{keyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetValidationKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['keyId'] = String(flags['key-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/key_link/validation_keys/{keyId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/get-validation-keys-list.ts b/src/commands/key-link/get-validation-keys-list.ts new file mode 100644 index 0000000..97a1d24 --- /dev/null +++ b/src/commands/key-link/get-validation-keys-list.ts @@ -0,0 +1,74 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetValidationKeysList extends FireblocksBaseCommand { + static summary = 'Get list of registered validation keys' + + static description = 'Returns the list of validation keys in the workspace\n\nOperation ID: getValidationKeysList\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/getValidationKeysList' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Cursor to the next page', + }), + 'page-size': Flags.string({ + description: 'Amount of results to return in the next page', + default: '10', + }), + 'sort-by': Flags.string({ + description: 'Field(s) to use for sorting', + default: 'createdAt', + options: ['createdAt'], + }), + 'order': Flags.string({ + description: 'Is the order ascending or descending', + default: 'ASC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/key_link/validation_keys' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetValidationKeysList) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/key_link/validation_keys', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/set-agent-id.ts b/src/commands/key-link/set-agent-id.ts new file mode 100644 index 0000000..6d111ed --- /dev/null +++ b/src/commands/key-link/set-agent-id.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetAgentId extends FireblocksBaseCommand { + static summary = 'Set agent user id' + + static description = 'Can modify existing signing key id if the key is not enabled. The change done in background and will be visible once applied. If key is already enabled (after proof of ownership) the user cannot be changed.\n\nOperation ID: setAgentId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/setAgentId' + + static enableJsonFlag = false + + static flags = { + 'key-id': Flags.string({ + description: 'The unique identifier for the signing key provided by Fireblocks', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/key_link/signing_keys/{keyId}/agent_user_id' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetAgentId) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['keyId'] = String(flags['key-id']) + + + await this.confirmOrAbort('PATCH', '/v1/key_link/signing_keys/{keyId}/agent_user_id') + + const result = await this.makeRequest( + 'PATCH', + '/v1/key_link/signing_keys/{keyId}/agent_user_id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/key-link/update-signing-key.ts b/src/commands/key-link/update-signing-key.ts new file mode 100644 index 0000000..8ed07e5 --- /dev/null +++ b/src/commands/key-link/update-signing-key.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateSigningKey extends FireblocksBaseCommand { + static summary = 'Modify the signing keyId' + + static description = 'Allows assigning the signing key to a vault account, if it hasn\'t been assigned to any other vault accounts yet.\n\nOperation ID: updateSigningKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Key%20Link/updateSigningKey' + + static enableJsonFlag = false + + static flags = { + 'key-id': Flags.string({ + description: 'The unique identifier for the signing key provided by Fireblocks', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/key_link/signing_keys/{keyId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateSigningKey) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['keyId'] = String(flags['key-id']) + + + await this.confirmOrAbort('PATCH', '/v1/key_link/signing_keys/{keyId}') + + const result = await this.makeRequest( + 'PATCH', + '/v1/key_link/signing_keys/{keyId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/keys/get-mpc-keys-list-by-user.ts b/src/commands/keys/get-mpc-keys-list-by-user.ts new file mode 100644 index 0000000..4c0612c --- /dev/null +++ b/src/commands/keys/get-mpc-keys-list-by-user.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetMpcKeysListByUser extends FireblocksBaseCommand { + static summary = 'Get list of mpc keys by \`userId\`' + + static description = 'Returns a list of MPC signing keys of a specific user. For each key, the list of players associated with it is attached.\n**Note:**\nThis endpoint is currently in beta and might be subject to changes.\n\nOperation ID: getMpcKeysListByUser\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Keys/getMpcKeysListByUser' + + static enableJsonFlag = false + + static flags = { + 'user-id': Flags.string({ + description: 'The id for the user', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/keys/mpc/list/{userId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetMpcKeysListByUser) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['userId'] = String(flags['user-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/keys/mpc/list/{userId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/keys/get-mpc-keys-list.ts b/src/commands/keys/get-mpc-keys-list.ts new file mode 100644 index 0000000..62196ef --- /dev/null +++ b/src/commands/keys/get-mpc-keys-list.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetMpcKeysList extends FireblocksBaseCommand { + static summary = 'Get list of mpc keys' + + static description = 'Returns a list of MPC signing keys of the workspace. For each key, the list of players associated with it is attached.\n**Note:** \nThis endpoint is currently in beta and might be subject to changes.\n\nOperation ID: getMpcKeysList\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Keys/getMpcKeysList' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/keys/mpc/list' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetMpcKeysList) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/keys/mpc/list', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/check-third-party-routing.ts b/src/commands/network-connections/check-third-party-routing.ts new file mode 100644 index 0000000..cb2c51c --- /dev/null +++ b/src/commands/network-connections/check-third-party-routing.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CheckThirdPartyRouting extends FireblocksBaseCommand { + static summary = 'Retrieve third-party network routing validation' + + static description = 'The Fireblocks Network allows for flexibility around incoming deposits. A receiver can receive network deposits to locations other than Fireblocks. This endpoint validates whether future transactions are routed to the displayed recipient or to a 3rd party.\n\nOperation ID: checkThirdPartyRouting\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/checkThirdPartyRouting' + + static enableJsonFlag = false + + static flags = { + 'connection-id': Flags.string({ + description: 'The ID of the network connection', + required: true, + }), + 'asset-type': Flags.string({ + description: 'The destination asset type', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/network_connections/{connectionId}/is_third_party_routing/{assetType}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CheckThirdPartyRouting) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['connectionId'] = String(flags['connection-id']) + pathParams['assetType'] = String(flags['asset-type']) + + + const result = await this.makeRequest( + 'GET', + '/v1/network_connections/{connectionId}/is_third_party_routing/{assetType}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/create-network-connection.ts b/src/commands/network-connections/create-network-connection.ts new file mode 100644 index 0000000..7ae3145 --- /dev/null +++ b/src/commands/network-connections/create-network-connection.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateNetworkConnection extends FireblocksBaseCommand { + static summary = 'Create a new network connection' + + static description = 'Initiates a new network connection.\n**Note:** This API call is subject to Flexible Routing Schemes.\n\nYour routing policy defines how your transactions are routed.\nYou can choose 1 of the 3 different schemes mentioned below for each asset type:\n - **None**; Defines the profile routing to no destination for that asset type. Incoming transactions to asset types routed to \`None\` will fail.\n - **Custom**; Route to an account that you choose. If you remove the account, incoming transactions will fail until you choose another one.\n - **Default**; Use the routing specified by the network profile the connection is connected to. This scheme is also referred to as "Profile Routing"\n\nDefault Workspace Presets:\n - Network Profile Crypto → **Custom**\n - Network Profile FIAT → **None**\n - Network Connection Crypto → **Default**\n - Network Connection FIAT → **Default**\n\nSupported asset groups for routing police can be found at \`/network_ids/routing_policy_asset_groups\`\n\n - **Note**: By default, Custom routing scheme uses (\`dstId\` = \`0\`, \`dstType\` = \`VAULT\`).\n\nOperation ID: createNetworkConnection\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/createNetworkConnection' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/network_connections' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateNetworkConnection) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/network_connections') + + const result = await this.makeRequest( + 'POST', + '/v1/network_connections', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/create-network-id.ts b/src/commands/network-connections/create-network-id.ts new file mode 100644 index 0000000..fedc4b1 --- /dev/null +++ b/src/commands/network-connections/create-network-id.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateNetworkId extends FireblocksBaseCommand { + static summary = 'Creates a new Network ID' + + static description = 'Create a new Network ID.\n\nOperation ID: createNetworkId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/createNetworkId' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/network_ids' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateNetworkId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/network_ids') + + const result = await this.makeRequest( + 'POST', + '/v1/network_ids', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/delete-network-connection.ts b/src/commands/network-connections/delete-network-connection.ts new file mode 100644 index 0000000..38cc808 --- /dev/null +++ b/src/commands/network-connections/delete-network-connection.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteNetworkConnection extends FireblocksBaseCommand { + static summary = 'Delete a network connection by ID' + + static description = 'Deletes an existing network connection specified by its connection ID.\n\nOperation ID: deleteNetworkConnection\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/deleteNetworkConnection' + + static enableJsonFlag = false + + static flags = { + 'connection-id': Flags.string({ + description: 'The ID of the network connection to delete', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/network_connections/{connectionId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteNetworkConnection) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['connectionId'] = String(flags['connection-id']) + + + await this.confirmOrAbort('DELETE', '/v1/network_connections/{connectionId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/network_connections/{connectionId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/delete-network-id.ts b/src/commands/network-connections/delete-network-id.ts new file mode 100644 index 0000000..117cad0 --- /dev/null +++ b/src/commands/network-connections/delete-network-id.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteNetworkId extends FireblocksBaseCommand { + static summary = 'Delete specific network ID.' + + static description = 'Deletes a network by its ID.\n\nOperation ID: deleteNetworkId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/deleteNetworkId' + + static enableJsonFlag = false + + static flags = { + 'network-id': Flags.string({ + description: 'The ID of the network', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/network_ids/{networkId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteNetworkId) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['networkId'] = String(flags['network-id']) + + + await this.confirmOrAbort('DELETE', '/v1/network_ids/{networkId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/network_ids/{networkId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/get-network-connections.ts b/src/commands/network-connections/get-network-connections.ts new file mode 100644 index 0000000..2bcce7c --- /dev/null +++ b/src/commands/network-connections/get-network-connections.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNetworkConnections extends FireblocksBaseCommand { + static summary = 'List network connections' + + static description = 'Returns all network connections.\n\n**Note:** This API call is subject to Flexible Routing Schemes.\n\nYour routing policy defines how your transactions are routed.\nYou can choose 1 of the 3 different schemes mentioned below for each asset type:\n - **None**; Defines the profile routing to no destination for that asset type. Incoming transactions to asset types routed to \`None\` will fail.\n - **Custom**; Route to an account that you choose. If you remove the account, incoming transactions will fail until you choose another one.\n - **Default**; Use the routing specified by the network profile the connection is connected to. This scheme is also referred to as "Profile Routing"\n\nDefault Workspace Presets:\n - Network Profile Crypto → **Custom**\n - Network Profile FIAT → **None**\n - Network Connection Crypto → **Default**\n - Network Connection FIAT → **Default**\n\nOperation ID: getNetworkConnections\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/getNetworkConnections' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/network_connections' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNetworkConnections) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/network_connections', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/get-network-id.ts b/src/commands/network-connections/get-network-id.ts new file mode 100644 index 0000000..e7ba93e --- /dev/null +++ b/src/commands/network-connections/get-network-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNetworkId extends FireblocksBaseCommand { + static summary = 'Return specific network ID.' + + static description = 'Returns specific network ID.\n\nOperation ID: getNetworkId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/getNetworkId' + + static enableJsonFlag = false + + static flags = { + 'network-id': Flags.string({ + description: 'The ID of the network', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/network_ids/{networkId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNetworkId) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['networkId'] = String(flags['network-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/network_ids/{networkId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/get-network-ids.ts b/src/commands/network-connections/get-network-ids.ts new file mode 100644 index 0000000..4db58eb --- /dev/null +++ b/src/commands/network-connections/get-network-ids.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNetworkIds extends FireblocksBaseCommand { + static summary = 'Get all network IDs' + + static description = 'Retrieves a list of all local and discoverable remote network IDs.\n\nOperation ID: getNetworkIds\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/getNetworkIds' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/network_ids' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNetworkIds) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/network_ids', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/get-network.ts b/src/commands/network-connections/get-network.ts new file mode 100644 index 0000000..7391d17 --- /dev/null +++ b/src/commands/network-connections/get-network.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNetwork extends FireblocksBaseCommand { + static summary = 'Get a network connection' + + static description = 'Gets a network connection by ID.\n\nOperation ID: getNetwork\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/getNetwork' + + static enableJsonFlag = false + + static flags = { + 'connection-id': Flags.string({ + description: 'The ID of the connection', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/network_connections/{connectionId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNetwork) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['connectionId'] = String(flags['connection-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/network_connections/{connectionId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/get-routing-policy-asset-groups.ts b/src/commands/network-connections/get-routing-policy-asset-groups.ts new file mode 100644 index 0000000..736b319 --- /dev/null +++ b/src/commands/network-connections/get-routing-policy-asset-groups.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetRoutingPolicyAssetGroups extends FireblocksBaseCommand { + static summary = 'Return all enabled routing policy asset groups' + + static description = 'Returns all enabled routing policy asset groups\n\nOperation ID: getRoutingPolicyAssetGroups\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/getRoutingPolicyAssetGroups' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/network_ids/routing_policy_asset_groups' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetRoutingPolicyAssetGroups) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/network_ids/routing_policy_asset_groups', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/search-network-ids.ts b/src/commands/network-connections/search-network-ids.ts new file mode 100644 index 0000000..5af5f39 --- /dev/null +++ b/src/commands/network-connections/search-network-ids.ts @@ -0,0 +1,80 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SearchNetworkIds extends FireblocksBaseCommand { + static summary = 'Get both local IDs and discoverable remote IDs' + + static description = 'Retrieves a list of all local and discoverable remote network IDs. Can be filtered.\n\nOperation ID: searchNetworkIds\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/searchNetworkIds' + + static enableJsonFlag = false + + static flags = { + 'search': Flags.string({ + description: 'Search string - displayName networkId. Optional', + }), + 'exclude-self': Flags.boolean({ + description: 'Exclude your networkIds. Optional, default false', + }), + 'only-self': Flags.boolean({ + description: 'Include just your networkIds. Optional, default false', + }), + 'exclude-connected': Flags.boolean({ + description: 'Exclude connected networkIds. Optional, default false', + }), + 'page-cursor': Flags.string({ + description: 'ID of the record after which to fetch $limit records', + }), + 'page-size': Flags.string({ + description: 'Number of records to fetch. By default, it is 50', + default: '50', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/network_ids/search' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SearchNetworkIds) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['search'] !== undefined && flags['search'] !== null) { + queryParams['search'] = String(flags['search']) + } + if (flags['exclude-self'] !== undefined && flags['exclude-self'] !== null) { + queryParams['excludeSelf'] = String(flags['exclude-self']) + } + if (flags['only-self'] !== undefined && flags['only-self'] !== null) { + queryParams['onlySelf'] = String(flags['only-self']) + } + if (flags['exclude-connected'] !== undefined && flags['exclude-connected'] !== null) { + queryParams['excludeConnected'] = String(flags['exclude-connected']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/network_ids/search', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/set-network-id-discoverability.ts b/src/commands/network-connections/set-network-id-discoverability.ts new file mode 100644 index 0000000..dc05a50 --- /dev/null +++ b/src/commands/network-connections/set-network-id-discoverability.ts @@ -0,0 +1,67 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetNetworkIdDiscoverability extends FireblocksBaseCommand { + static summary = 'Update network ID\'s discoverability.' + + static description = 'Update whether or not the network ID is discoverable by others.\n\nOperation ID: setNetworkIdDiscoverability\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/setNetworkIdDiscoverability' + + static enableJsonFlag = false + + static flags = { + 'network-id': Flags.string({ + description: 'The ID of the network', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/network_ids/{networkId}/set_discoverability' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetNetworkIdDiscoverability) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['networkId'] = String(flags['network-id']) + + + await this.confirmOrAbort('PATCH', '/v1/network_ids/{networkId}/set_discoverability') + + const result = await this.makeRequest( + 'PATCH', + '/v1/network_ids/{networkId}/set_discoverability', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/set-network-id-name.ts b/src/commands/network-connections/set-network-id-name.ts new file mode 100644 index 0000000..35a2c37 --- /dev/null +++ b/src/commands/network-connections/set-network-id-name.ts @@ -0,0 +1,67 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetNetworkIdName extends FireblocksBaseCommand { + static summary = 'Update network ID\'s name.' + + static description = 'Updates name of a specified network ID.\n\nOperation ID: setNetworkIdName\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/setNetworkIdName' + + static enableJsonFlag = false + + static flags = { + 'network-id': Flags.string({ + description: 'The ID of the network', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/network_ids/{networkId}/set_name' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetNetworkIdName) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['networkId'] = String(flags['network-id']) + + + await this.confirmOrAbort('PATCH', '/v1/network_ids/{networkId}/set_name') + + const result = await this.makeRequest( + 'PATCH', + '/v1/network_ids/{networkId}/set_name', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/set-network-id-routing-policy.ts b/src/commands/network-connections/set-network-id-routing-policy.ts new file mode 100644 index 0000000..27aa5e0 --- /dev/null +++ b/src/commands/network-connections/set-network-id-routing-policy.ts @@ -0,0 +1,66 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetNetworkIdRoutingPolicy extends FireblocksBaseCommand { + static summary = 'Update network id routing policy.' + + static description = 'Updates the routing policy of a specified network ID.\n\nOperation ID: setNetworkIdRoutingPolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/setNetworkIdRoutingPolicy' + + static enableJsonFlag = false + + static flags = { + 'network-id': Flags.string({ + description: 'The ID of the network', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/network_ids/{networkId}/set_routing_policy' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetNetworkIdRoutingPolicy) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['networkId'] = String(flags['network-id']) + + + await this.confirmOrAbort('PATCH', '/v1/network_ids/{networkId}/set_routing_policy') + + const result = await this.makeRequest( + 'PATCH', + '/v1/network_ids/{networkId}/set_routing_policy', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/network-connections/set-routing-policy.ts b/src/commands/network-connections/set-routing-policy.ts new file mode 100644 index 0000000..bb1806c --- /dev/null +++ b/src/commands/network-connections/set-routing-policy.ts @@ -0,0 +1,66 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetRoutingPolicy extends FireblocksBaseCommand { + static summary = 'Update network connection routing policy.' + + static description = 'Updates an existing network connection\'s routing policy.\n\nOperation ID: setRoutingPolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Network%20connections/setRoutingPolicy' + + static enableJsonFlag = false + + static flags = { + 'connection-id': Flags.string({ + description: 'The ID of the network connection', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/network_connections/{connectionId}/set_routing_policy' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetRoutingPolicy) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['connectionId'] = String(flags['connection-id']) + + + await this.confirmOrAbort('PATCH', '/v1/network_connections/{connectionId}/set_routing_policy') + + const result = await this.makeRequest( + 'PATCH', + '/v1/network_connections/{connectionId}/set_routing_policy', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/get-nf-ts.ts b/src/commands/nfts/get-nf-ts.ts new file mode 100644 index 0000000..ded37b6 --- /dev/null +++ b/src/commands/nfts/get-nf-ts.ts @@ -0,0 +1,76 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNFTs extends FireblocksBaseCommand { + static summary = 'List tokens by IDs' + + static description = 'Returns the requested tokens data.\n\nOperation ID: getNFTs\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/getNFTs' + + static enableJsonFlag = false + + static flags = { + 'ids': Flags.string({ + description: 'A comma separated list of NFT IDs. Up to 100 are allowed in a single request.', + required: true, + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page (max 100)', + }), + 'sort': Flags.string({ + description: 'Sort by param, it can be one param or a list of params separated by comma', + }), + 'order': Flags.string({ + description: 'Order direction, it can be \`ASC\` for ascending or \`DESC\` for descending', + default: 'ASC', + options: ['DESC', 'ASC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/nfts/tokens' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNFTs) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['ids'] !== undefined && flags['ids'] !== null) { + queryParams['ids'] = String(flags['ids']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/nfts/tokens', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/get-nft.ts b/src/commands/nfts/get-nft.ts new file mode 100644 index 0000000..6e5ff9f --- /dev/null +++ b/src/commands/nfts/get-nft.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNFT extends FireblocksBaseCommand { + static summary = 'List token data by ID' + + static description = 'Returns the requested token data.\n\nOperation ID: getNFT\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/getNFT' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'NFT ID', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/nfts/tokens/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNFT) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/nfts/tokens/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/get-ownership-tokens.ts b/src/commands/nfts/get-ownership-tokens.ts new file mode 100644 index 0000000..ad60e08 --- /dev/null +++ b/src/commands/nfts/get-ownership-tokens.ts @@ -0,0 +1,135 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetOwnershipTokens extends FireblocksBaseCommand { + static summary = 'List all owned tokens (paginated)' + + static description = 'Returns all tokens and their data in your workspace.\n\nOperation ID: getOwnershipTokens\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/getOwnershipTokens' + + static enableJsonFlag = false + + static flags = { + 'blockchain-descriptor': Flags.string({ + description: 'Blockchain descriptor filter', + options: ['ETH', 'ETH_TEST3', 'ETH_TEST5', 'ETH_TEST6', 'POLYGON', 'POLYGON_TEST_MUMBAI', 'AMOY_POLYGON_TEST', 'XTZ', 'XTZ_TEST', 'BASECHAIN_ETH', 'BASECHAIN_ETH_TEST3', 'BASECHAIN_ETH_TEST5', 'ETHERLINK', 'ETHERLINK_TEST', 'MANTLE', 'MANTLE_TEST', 'GUN_GUNZILLA', 'GUN_GUNZILLA_TEST', 'ETH_SONEIUM', 'SONEIUM_MINATO_TEST', 'IOTX_IOTEX', 'KLAY_KAIA', 'KLAY_KAIA_TEST', 'APECHAIN', 'APECHAIN_TEST', 'CRONOS', 'CRONOS_TEST', 'ROBINHOOD_CHAIN_TESTNET_TEST'], + }), + 'vault-account-ids': Flags.string({ + description: 'A comma separated list of Vault Account IDs. Up to 100 are allowed in a single request. This field will be ignored when walletType=END_USER_WALLET or ncwId is provided.', + }), + 'ncw-id': Flags.string({ + description: 'Tenant\'s Non-Custodial Wallet ID', + }), + 'ncw-account-ids': Flags.string({ + description: 'A comma separated list of Non-Custodial account IDs. Up to 100 are allowed in a single request. This field will be ignored when walletType=VAULT_ACCOUNT or ncwId is not provided.', + }), + 'wallet-type': Flags.string({ + description: 'Wallet type, it can be \`VAULT_ACCOUNT\` or \`END_USER_WALLET\`', + default: 'VAULT_ACCOUNT', + options: ['VAULT_ACCOUNT', 'END_USER_WALLET'], + }), + 'ids': Flags.string({ + description: 'A comma separated list of NFT IDs. Up to 100 are allowed in a single request.', + }), + 'collection-ids': Flags.string({ + description: 'A comma separated list of collection IDs. Up to 100 are allowed in a single request.', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page (max 100)', + }), + 'sort': Flags.string({ + description: 'Sort by param, it can be one param or a list of params separated by comma', + }), + 'order': Flags.string({ + description: 'Order direction, it can be \`ASC\` for ascending or \`DESC\` for descending', + default: 'ASC', + options: ['DESC', 'ASC'], + }), + 'status': Flags.string({ + description: 'Token ownership status', + default: 'LISTED', + options: ['LISTED', 'ARCHIVED'], + }), + 'search': Flags.string({ + description: 'Search owned tokens and their collections. Possible criteria for search: token name and id within the contract/collection, collection name, blockchain descriptor and name.', + }), + 'spam': Flags.string({ + description: 'Token ownership spam status.', + options: ['true', 'false', 'all'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/nfts/ownership/tokens' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetOwnershipTokens) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['blockchain-descriptor'] !== undefined && flags['blockchain-descriptor'] !== null) { + queryParams['blockchainDescriptor'] = String(flags['blockchain-descriptor']) + } + if (flags['vault-account-ids'] !== undefined && flags['vault-account-ids'] !== null) { + queryParams['vaultAccountIds'] = String(flags['vault-account-ids']) + } + if (flags['ncw-id'] !== undefined && flags['ncw-id'] !== null) { + queryParams['ncwId'] = String(flags['ncw-id']) + } + if (flags['ncw-account-ids'] !== undefined && flags['ncw-account-ids'] !== null) { + queryParams['ncwAccountIds'] = String(flags['ncw-account-ids']) + } + if (flags['wallet-type'] !== undefined && flags['wallet-type'] !== null) { + queryParams['walletType'] = String(flags['wallet-type']) + } + if (flags['ids'] !== undefined && flags['ids'] !== null) { + queryParams['ids'] = String(flags['ids']) + } + if (flags['collection-ids'] !== undefined && flags['collection-ids'] !== null) { + queryParams['collectionIds'] = String(flags['collection-ids']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['status'] !== undefined && flags['status'] !== null) { + queryParams['status'] = String(flags['status']) + } + if (flags['search'] !== undefined && flags['search'] !== null) { + queryParams['search'] = String(flags['search']) + } + if (flags['spam'] !== undefined && flags['spam'] !== null) { + queryParams['spam'] = String(flags['spam']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/nfts/ownership/tokens', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/list-owned-collections.ts b/src/commands/nfts/list-owned-collections.ts new file mode 100644 index 0000000..1f4f280 --- /dev/null +++ b/src/commands/nfts/list-owned-collections.ts @@ -0,0 +1,97 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListOwnedCollections extends FireblocksBaseCommand { + static summary = 'List owned collections (paginated)' + + static description = 'Returns all collections in your workspace\n\nOperation ID: listOwnedCollections\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/listOwnedCollections' + + static enableJsonFlag = false + + static flags = { + 'ncw-id': Flags.string({ + description: 'Tenant\'s Non-Custodial Wallet ID', + }), + 'wallet-type': Flags.string({ + description: 'Wallet type, it can be \`VAULT_ACCOUNT\` or \`END_USER_WALLET\`', + default: 'VAULT_ACCOUNT', + options: ['VAULT_ACCOUNT', 'END_USER_WALLET'], + }), + 'search': Flags.string({ + description: 'Search owned collections. Possible criteria for search: collection name, collection contract address.', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page (max 100)', + }), + 'sort': Flags.string({ + description: 'Sort by param, it can be one param or a list of params separated by comma', + }), + 'order': Flags.string({ + description: 'Order direction, it can be \`ASC\` for ascending or \`DESC\` for descending', + default: 'ASC', + options: ['DESC', 'ASC'], + }), + 'status': Flags.string({ + description: 'Token ownership status', + default: 'LISTED', + options: ['LISTED', 'ARCHIVED'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/nfts/ownership/collections' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListOwnedCollections) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['ncw-id'] !== undefined && flags['ncw-id'] !== null) { + queryParams['ncwId'] = String(flags['ncw-id']) + } + if (flags['wallet-type'] !== undefined && flags['wallet-type'] !== null) { + queryParams['walletType'] = String(flags['wallet-type']) + } + if (flags['search'] !== undefined && flags['search'] !== null) { + queryParams['search'] = String(flags['search']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['status'] !== undefined && flags['status'] !== null) { + queryParams['status'] = String(flags['status']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/nfts/ownership/collections', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/list-owned-tokens.ts b/src/commands/nfts/list-owned-tokens.ts new file mode 100644 index 0000000..d40be1d --- /dev/null +++ b/src/commands/nfts/list-owned-tokens.ts @@ -0,0 +1,104 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListOwnedTokens extends FireblocksBaseCommand { + static summary = 'List all distinct owned tokens (paginated)' + + static description = 'Returns all owned distinct tokens (for your tenant) and their data in your workspace.\n\nOperation ID: listOwnedTokens\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/listOwnedTokens' + + static enableJsonFlag = false + + static flags = { + 'ncw-id': Flags.string({ + description: 'Tenant\'s Non-Custodial Wallet ID', + }), + 'wallet-type': Flags.string({ + description: 'Wallet type, it can be \`VAULT_ACCOUNT\` or \`END_USER_WALLET\`', + default: 'VAULT_ACCOUNT', + options: ['VAULT_ACCOUNT', 'END_USER_WALLET'], + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to fetch', + }), + 'page-size': Flags.string({ + description: 'Items per page (max 100)', + }), + 'sort': Flags.string({ + description: 'Sort by param, it can be one param or a list of params separated by comma', + }), + 'order': Flags.string({ + description: 'Order direction, it can be \`ASC\` for ascending or \`DESC\` for descending', + default: 'ASC', + options: ['DESC', 'ASC'], + }), + 'status': Flags.string({ + description: 'Token ownership status', + default: 'LISTED', + options: ['LISTED', 'ARCHIVED'], + }), + 'search': Flags.string({ + description: 'Search owned tokens by token name', + }), + 'spam': Flags.string({ + description: 'Token ownership spam status.', + options: ['true', 'false', 'all'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/nfts/ownership/assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListOwnedTokens) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['ncw-id'] !== undefined && flags['ncw-id'] !== null) { + queryParams['ncwId'] = String(flags['ncw-id']) + } + if (flags['wallet-type'] !== undefined && flags['wallet-type'] !== null) { + queryParams['walletType'] = String(flags['wallet-type']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['status'] !== undefined && flags['status'] !== null) { + queryParams['status'] = String(flags['status']) + } + if (flags['search'] !== undefined && flags['search'] !== null) { + queryParams['search'] = String(flags['search']) + } + if (flags['spam'] !== undefined && flags['spam'] !== null) { + queryParams['spam'] = String(flags['spam']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/nfts/ownership/assets', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/refresh-nft-metadata.ts b/src/commands/nfts/refresh-nft-metadata.ts new file mode 100644 index 0000000..0b586b6 --- /dev/null +++ b/src/commands/nfts/refresh-nft-metadata.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RefreshNFTMetadata extends FireblocksBaseCommand { + static summary = 'Refresh token metadata' + + static description = 'Updates the latest token metadata.\n\nOperation ID: refreshNFTMetadata\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/refreshNFTMetadata' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'NFT ID', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/nfts/tokens/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RefreshNFTMetadata) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('PUT', '/v1/nfts/tokens/{id}') + + const result = await this.makeRequest( + 'PUT', + '/v1/nfts/tokens/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/update-ownership-tokens.ts b/src/commands/nfts/update-ownership-tokens.ts new file mode 100644 index 0000000..04a8ea8 --- /dev/null +++ b/src/commands/nfts/update-ownership-tokens.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateOwnershipTokens extends FireblocksBaseCommand { + static summary = 'Refresh vault account tokens' + + static description = 'Updates all tokens and balances per blockchain and vault account.\nLearn more about Fireblocks NFT management in the following [guide](https://developers.fireblocks.com/reference/deploy-an-nft-collection).\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: updateOwnershipTokens\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/updateOwnershipTokens' + + static enableJsonFlag = false + + static flags = { + 'blockchain-descriptor': Flags.string({ + description: 'Blockchain descriptor filter', + required: true, + options: ['ETH', 'ETH_TEST5', 'ETH_TEST6', 'POLYGON', 'POLYGON_TEST_MUMBAI', 'AMOY_POLYGON_TEST', 'BASECHAIN_ETH', 'BASECHAIN_ETH_TEST5', 'ETHERLINK', 'ETHERLINK_TEST', 'MANTLE', 'MANTLE_TEST', 'GUN_GUNZILLA', 'GUN_GUNZILLA_TEST', 'ETH_SONEIUM', 'SONEIUM_MINATO_TEST', 'IOTX_IOTEX', 'KLAY_KAIA', 'KLAY_KAIA_TEST', 'APECHAIN', 'APECHAIN_TEST', 'ROBINHOOD_CHAIN_TESTNET_TEST'], + }), + 'vault-account-id': Flags.string({ + description: 'Vault account filter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/nfts/ownership/tokens' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateOwnershipTokens) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + const queryParams: Record = {} + if (flags['blockchain-descriptor'] !== undefined && flags['blockchain-descriptor'] !== null) { + queryParams['blockchainDescriptor'] = String(flags['blockchain-descriptor']) + } + if (flags['vault-account-id'] !== undefined && flags['vault-account-id'] !== null) { + queryParams['vaultAccountId'] = String(flags['vault-account-id']) + } + + await this.confirmOrAbort('PUT', '/v1/nfts/ownership/tokens') + + const result = await this.makeRequest( + 'PUT', + '/v1/nfts/ownership/tokens', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/update-token-ownership-status.ts b/src/commands/nfts/update-token-ownership-status.ts new file mode 100644 index 0000000..d457745 --- /dev/null +++ b/src/commands/nfts/update-token-ownership-status.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateTokenOwnershipStatus extends FireblocksBaseCommand { + static summary = 'Update token ownership status' + + static description = 'Updates token status for a tenant, in all tenant vaults.\n\nOperation ID: updateTokenOwnershipStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/updateTokenOwnershipStatus' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'NFT ID', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/nfts/ownership/tokens/{id}/status' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateTokenOwnershipStatus) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('PUT', '/v1/nfts/ownership/tokens/{id}/status') + + const result = await this.makeRequest( + 'PUT', + '/v1/nfts/ownership/tokens/{id}/status', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/update-tokens-ownership-spam.ts b/src/commands/nfts/update-tokens-ownership-spam.ts new file mode 100644 index 0000000..fdc443c --- /dev/null +++ b/src/commands/nfts/update-tokens-ownership-spam.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateTokensOwnershipSpam extends FireblocksBaseCommand { + static summary = 'Update tokens ownership spam property' + + static description = 'Updates tokens spam property for a tenant\'s token ownerships, in all tenant vaults.\n\nOperation ID: updateTokensOwnershipSpam\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/updateTokensOwnershipSpam' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/nfts/ownership/tokens/spam' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateTokensOwnershipSpam) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/nfts/ownership/tokens/spam') + + const result = await this.makeRequest( + 'PUT', + '/v1/nfts/ownership/tokens/spam', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/nfts/update-tokens-ownership-status.ts b/src/commands/nfts/update-tokens-ownership-status.ts new file mode 100644 index 0000000..7c7d497 --- /dev/null +++ b/src/commands/nfts/update-tokens-ownership-status.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateTokensOwnershipStatus extends FireblocksBaseCommand { + static summary = 'Update tokens ownership status' + + static description = 'Updates tokens status for a tenant, in all tenant vaults.\n\nOperation ID: updateTokensOwnershipStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/NFTs/updateTokensOwnershipStatus' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/nfts/ownership/tokens/status' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateTokensOwnershipStatus) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/nfts/ownership/tokens/status') + + const result = await this.makeRequest( + 'PUT', + '/v1/nfts/ownership/tokens/status', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/off-exchanges/add-off-exchange.ts b/src/commands/off-exchanges/add-off-exchange.ts new file mode 100644 index 0000000..ea37078 --- /dev/null +++ b/src/commands/off-exchanges/add-off-exchange.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AddOffExchange extends FireblocksBaseCommand { + static summary = 'Add Collateral' + + static description = 'Add collateral and create deposit request.\nLearn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: addOffExchange\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Off%20exchanges/addOffExchange' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/off_exchange/add' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AddOffExchange) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/off_exchange/add') + + const result = await this.makeRequest( + 'POST', + '/v1/off_exchange/add', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/off-exchanges/get-off-exchange-collateral-accounts.ts b/src/commands/off-exchanges/get-off-exchange-collateral-accounts.ts new file mode 100644 index 0000000..0e19676 --- /dev/null +++ b/src/commands/off-exchanges/get-off-exchange-collateral-accounts.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetOffExchangeCollateralAccounts extends FireblocksBaseCommand { + static summary = 'Find a specific collateral exchange account' + + static description = 'Returns a collateral account by mainExchangeAccountId.\nLearn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getOffExchangeCollateralAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Off%20exchanges/getOffExchangeCollateralAccounts' + + static enableJsonFlag = false + + static flags = { + 'main-exchange-account-id': Flags.string({ + description: 'The id of the main exchange account for which the requested collateral account is associated with', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/off_exchange/collateral_accounts/{mainExchangeAccountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetOffExchangeCollateralAccounts) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['mainExchangeAccountId'] = String(flags['main-exchange-account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/off_exchange/collateral_accounts/{mainExchangeAccountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/off-exchanges/get-off-exchange-settlement-transactions.ts b/src/commands/off-exchanges/get-off-exchange-settlement-transactions.ts new file mode 100644 index 0000000..a2dbe11 --- /dev/null +++ b/src/commands/off-exchanges/get-off-exchange-settlement-transactions.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetOffExchangeSettlementTransactions extends FireblocksBaseCommand { + static summary = 'Get Settlements Transactions' + + static description = 'Get settlements transactions from exchange.\nLearn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getOffExchangeSettlementTransactions\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Off%20exchanges/getOffExchangeSettlementTransactions' + + static enableJsonFlag = false + + static flags = { + 'main-exchange-account-id': Flags.string({ + description: 'The mainExchangeAccountId parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/off_exchange/settlements/transactions' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetOffExchangeSettlementTransactions) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['main-exchange-account-id'] !== undefined && flags['main-exchange-account-id'] !== null) { + queryParams['mainExchangeAccountId'] = String(flags['main-exchange-account-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/off_exchange/settlements/transactions', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/off-exchanges/remove-off-exchange.ts b/src/commands/off-exchanges/remove-off-exchange.ts new file mode 100644 index 0000000..dbc5c1e --- /dev/null +++ b/src/commands/off-exchanges/remove-off-exchange.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RemoveOffExchange extends FireblocksBaseCommand { + static summary = 'Remove Collateral' + + static description = 'Remove collateral, create withdraw request.\nLearn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: removeOffExchange\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Off%20exchanges/removeOffExchange' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/off_exchange/remove' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RemoveOffExchange) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/off_exchange/remove') + + const result = await this.makeRequest( + 'POST', + '/v1/off_exchange/remove', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/off-exchanges/settle-off-exchange-trades.ts b/src/commands/off-exchanges/settle-off-exchange-trades.ts new file mode 100644 index 0000000..9ea6c24 --- /dev/null +++ b/src/commands/off-exchanges/settle-off-exchange-trades.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SettleOffExchangeTrades extends FireblocksBaseCommand { + static summary = 'Create Settlement for a Trader' + + static description = 'Create settlement for a trader.\nLearn more about Fireblocks Off Exchange in the following [guide](https://developers.fireblocks.com/docs/off-exchange).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: settleOffExchangeTrades\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Off%20exchanges/settleOffExchangeTrades' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/off_exchange/settlements/trader' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SettleOffExchangeTrades) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/off_exchange/settlements/trader') + + const result = await this.makeRequest( + 'POST', + '/v1/off_exchange/settlements/trader', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-access-registry-current-state.ts b/src/commands/onchain-data/get-access-registry-current-state.ts new file mode 100644 index 0000000..2be4175 --- /dev/null +++ b/src/commands/onchain-data/get-access-registry-current-state.ts @@ -0,0 +1,83 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAccessRegistryCurrentState extends FireblocksBaseCommand { + static summary = 'Get the current state of addresses in an access registry' + + static description = 'Returns the current state of addresses in the specified access registry. Only addresses that are currently active (added but not removed) are included.\n\nOperation ID: getAccessRegistryCurrentState\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getAccessRegistryCurrentState' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'access-registry-address': Flags.string({ + description: 'The access registry address', + required: true, + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page"', + }), + 'page-size': Flags.integer({ + description: 'Number of items per page (max 100), requesting more then 100 will return 100 items', + }), + 'sort-by': Flags.string({ + description: 'Sorting field (enum).', + default: 'dateAdded', + options: ['dateAdded', 'address'], + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/access_registry_address/{accessRegistryAddress}/list' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAccessRegistryCurrentState) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['accessRegistryAddress'] = String(flags['access-registry-address']) + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/access_registry_address/{accessRegistryAddress}/list', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-access-registry-summary.ts b/src/commands/onchain-data/get-access-registry-summary.ts new file mode 100644 index 0000000..2a2e9f9 --- /dev/null +++ b/src/commands/onchain-data/get-access-registry-summary.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAccessRegistrySummary extends FireblocksBaseCommand { + static summary = 'Summary of access registry state' + + static description = 'Returns a summary of the current state of the access registry for the specified baseAssetId and accessRegistryAddress.\n\nOperation ID: getAccessRegistrySummary\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getAccessRegistrySummary' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'access-registry-address': Flags.string({ + description: 'The access registry address', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/access_registry_address/{accessRegistryAddress}/summary' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAccessRegistrySummary) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['accessRegistryAddress'] = String(flags['access-registry-address']) + + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/access_registry_address/{accessRegistryAddress}/summary', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-active-roles-for-contract.ts b/src/commands/onchain-data/get-active-roles-for-contract.ts new file mode 100644 index 0000000..c0a6be7 --- /dev/null +++ b/src/commands/onchain-data/get-active-roles-for-contract.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetActiveRolesForContract extends FireblocksBaseCommand { + static summary = 'List of active roles for a given contract address and base asset ID' + + static description = 'Returns a list of currently active roles for the specified baseAssetId and contractAddress.\n\nOperation ID: getActiveRolesForContract\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getActiveRolesForContract' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'contract-address': Flags.string({ + description: 'The contract address', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/roles' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetActiveRolesForContract) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['contractAddress'] = String(flags['contract-address']) + + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/roles', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-contract-balance-history.ts b/src/commands/onchain-data/get-contract-balance-history.ts new file mode 100644 index 0000000..b651ae7 --- /dev/null +++ b/src/commands/onchain-data/get-contract-balance-history.ts @@ -0,0 +1,108 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContractBalanceHistory extends FireblocksBaseCommand { + static summary = 'Get historical balance data for a specific account in a contract' + + static description = 'Returns the paginated balance history of the specified account in a contract with optional date range and interval filtering.\n\nOperation ID: getContractBalanceHistory\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getContractBalanceHistory' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'contract-address': Flags.string({ + description: 'The contract address', + required: true, + }), + 'account-address': Flags.string({ + description: 'The account address to get balance history for', + required: true, + }), + 'start-date': Flags.string({ + description: 'Start date of the time range in ISO 8601 format', + }), + 'end-date': Flags.string({ + description: 'End date of the time range in ISO 8601 format', + }), + 'interval': Flags.string({ + description: 'Time interval for grouping data', + default: 'day', + options: ['hour', 'day', 'week', 'month'], + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page"', + }), + 'page-size': Flags.integer({ + description: 'Number of items per page (max 100), requesting more then 100 will return 100 items', + }), + 'sort-by': Flags.string({ + description: 'Sorting field (enum). Sorting only supported by \'blockTimestamp\'', + default: 'blockTimestamp', + options: ['blockTimestamp'], + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/account_address/{accountAddress}/balance_history' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContractBalanceHistory) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['contractAddress'] = String(flags['contract-address']) + pathParams['accountAddress'] = String(flags['account-address']) + + const queryParams: Record = {} + if (flags['start-date'] !== undefined && flags['start-date'] !== null) { + queryParams['startDate'] = String(flags['start-date']) + } + if (flags['end-date'] !== undefined && flags['end-date'] !== null) { + queryParams['endDate'] = String(flags['end-date']) + } + if (flags['interval'] !== undefined && flags['interval'] !== null) { + queryParams['interval'] = String(flags['interval']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/account_address/{accountAddress}/balance_history', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-contract-balances-summary.ts b/src/commands/onchain-data/get-contract-balances-summary.ts new file mode 100644 index 0000000..612c1d9 --- /dev/null +++ b/src/commands/onchain-data/get-contract-balances-summary.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContractBalancesSummary extends FireblocksBaseCommand { + static summary = 'Get summary for the token contract' + + static description = 'Returns the total number of unique addresses holding balances and the total supply for the specified contract.\n\nOperation ID: getContractBalancesSummary\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getContractBalancesSummary' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'contract-address': Flags.string({ + description: 'The contract address', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/summary' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContractBalancesSummary) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['contractAddress'] = String(flags['contract-address']) + + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/summary', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-contract-total-supply.ts b/src/commands/onchain-data/get-contract-total-supply.ts new file mode 100644 index 0000000..2268f4c --- /dev/null +++ b/src/commands/onchain-data/get-contract-total-supply.ts @@ -0,0 +1,103 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetContractTotalSupply extends FireblocksBaseCommand { + static summary = 'Get historical total supply data for a contract' + + static description = 'Returns the paginated total supply history of the specified contract with optional date range and interval filtering.\n\nOperation ID: getContractTotalSupply\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getContractTotalSupply' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'contract-address': Flags.string({ + description: 'The contract address', + required: true, + }), + 'start-date': Flags.string({ + description: 'Start date of the time range in ISO 8601 format', + }), + 'end-date': Flags.string({ + description: 'End date of the time range in ISO 8601 format', + }), + 'interval': Flags.string({ + description: 'Time interval for grouping data', + default: 'day', + options: ['hour', 'day', 'week', 'month'], + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page"', + }), + 'page-size': Flags.integer({ + description: 'Number of items per page (max 100), requesting more then 100 will return 100 items', + }), + 'sort-by': Flags.string({ + description: 'Sorting field (enum). Sorting only supported by \'blockTimestamp\'', + default: 'blockTimestamp', + options: ['blockTimestamp'], + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/total_supply' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetContractTotalSupply) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['contractAddress'] = String(flags['contract-address']) + + const queryParams: Record = {} + if (flags['start-date'] !== undefined && flags['start-date'] !== null) { + queryParams['startDate'] = String(flags['start-date']) + } + if (flags['end-date'] !== undefined && flags['end-date'] !== null) { + queryParams['endDate'] = String(flags['end-date']) + } + if (flags['interval'] !== undefined && flags['interval'] !== null) { + queryParams['interval'] = String(flags['interval']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/total_supply', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-latest-balances-for-contract.ts b/src/commands/onchain-data/get-latest-balances-for-contract.ts new file mode 100644 index 0000000..1a3fe10 --- /dev/null +++ b/src/commands/onchain-data/get-latest-balances-for-contract.ts @@ -0,0 +1,89 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLatestBalancesForContract extends FireblocksBaseCommand { + static summary = 'Get latest balances for all addresses holding tokens from a contract' + + static description = 'Returns the latest balance for each unique address with support for numeric balance sorting. The \`prev\` cursor is reserved for future support.\n\nOperation ID: getLatestBalancesForContract\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getLatestBalancesForContract' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'contract-address': Flags.string({ + description: 'The contract address', + required: true, + }), + 'account-address': Flags.string({ + description: 'Optional filter to get balance for a specific account address', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page"', + }), + 'page-size': Flags.integer({ + description: 'Number of items per page (max 100), requesting more then 100 will return 100 items', + }), + 'sort-by': Flags.string({ + description: 'Sorting field for balances', + default: 'blockTimestamp', + options: ['accountAddress', 'blockTimestamp'], + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/balances' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetLatestBalancesForContract) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['contractAddress'] = String(flags['contract-address']) + + const queryParams: Record = {} + if (flags['account-address'] !== undefined && flags['account-address'] !== null) { + queryParams['accountAddress'] = String(flags['account-address']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/balances', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/onchain-data/get-onchain-transactions.ts b/src/commands/onchain-data/get-onchain-transactions.ts new file mode 100644 index 0000000..d9f4c9a --- /dev/null +++ b/src/commands/onchain-data/get-onchain-transactions.ts @@ -0,0 +1,95 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetOnchainTransactions extends FireblocksBaseCommand { + static summary = 'Fetch onchain transactions for a contract' + + static description = 'Returns a paginated list of onchain transactions for the specified contract address and base asset ID, optionally filtered by date range.\n\nOperation ID: getOnchainTransactions\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Onchain%20Data/getOnchainTransactions' + + static enableJsonFlag = false + + static flags = { + 'base-asset-id': Flags.string({ + description: 'The blockchain base assetId', + required: true, + }), + 'contract-address': Flags.string({ + description: 'The contract address', + required: true, + }), + 'start-date': Flags.string({ + description: 'Start date of the time range in ISO 8601 format', + }), + 'end-date': Flags.string({ + description: 'End date of the time range in ISO 8601 format', + }), + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page"', + }), + 'page-size': Flags.integer({ + description: 'Number of items per page (max 100), requesting more then 100 will return 100 items', + }), + 'sort-by': Flags.string({ + description: 'Sorting field (enum).', + default: 'blockTimestamp', + options: ['blockTimestamp', 'blockNumber', 'transactionHash'], + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/transactions' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetOnchainTransactions) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['baseAssetId'] = String(flags['base-asset-id']) + pathParams['contractAddress'] = String(flags['contract-address']) + + const queryParams: Record = {} + if (flags['start-date'] !== undefined && flags['start-date'] !== null) { + queryParams['startDate'] = String(flags['start-date']) + } + if (flags['end-date'] !== undefined && flags['end-date'] !== null) { + queryParams['endDate'] = String(flags['end-date']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/onchain_data/base_asset_id/{baseAssetId}/contract_address/{contractAddress}/transactions', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/ota/get-ota-status.ts b/src/commands/ota/get-ota-status.ts new file mode 100644 index 0000000..5a0b8fb --- /dev/null +++ b/src/commands/ota/get-ota-status.ts @@ -0,0 +1,38 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetOtaStatus extends FireblocksBaseCommand { + static summary = 'Returns current OTA status' + + static description = 'Returns current OTA status\n\nOperation ID: getOtaStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/OTA/getOtaStatus' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/management/ota' + static isBeta = true + + async run(): Promise { + const {flags} = await this.parse(GetOtaStatus) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/management/ota', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/ota/set-ota-status.ts b/src/commands/ota/set-ota-status.ts new file mode 100644 index 0000000..ee7e2d9 --- /dev/null +++ b/src/commands/ota/set-ota-status.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetOtaStatus extends FireblocksBaseCommand { + static summary = 'Enable or disable transactions to OTA' + + static description = 'Enable or disable transactions to One Time Addresses (Non Whitelisted addresses).\nLearn more about [One Time Addresses](https://support.fireblocks.io/hc/en-us/articles/4409104568338-One-Time-Address-OTA-feature)\n\nOperation ID: setOtaStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/OTA/setOtaStatus' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/management/ota' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetOtaStatus) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/management/ota') + + const result = await this.makeRequest( + 'PUT', + '/v1/management/ota', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/payments-flows/create-flow-configuration.ts b/src/commands/payments-flows/create-flow-configuration.ts new file mode 100644 index 0000000..272f151 --- /dev/null +++ b/src/commands/payments-flows/create-flow-configuration.ts @@ -0,0 +1,57 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateFlowConfiguration extends FireblocksBaseCommand { + static summary = 'Create payment flow configuration' + + static description = 'Generate a new configuration ID to be used for initiating executions in subsequent phases. This configuration should include the operations you intend to incorporate into the workflow, such as TRANSFER, CONVERT, and DISBURSE, in addition to your pre-screening preferences, which are disabled by default.\n\nOperation ID: createFlowConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Flows/createFlowConfiguration' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + } + + static method = 'POST' + static path = '/v1/payments/workflow_config' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(CreateFlowConfiguration) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/payments/workflow_config') + + const result = await this.makeRequest( + 'POST', + '/v1/payments/workflow_config', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/payments-flows/create-flow-execution.ts b/src/commands/payments-flows/create-flow-execution.ts new file mode 100644 index 0000000..50e4699 --- /dev/null +++ b/src/commands/payments-flows/create-flow-execution.ts @@ -0,0 +1,57 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateFlowExecution extends FireblocksBaseCommand { + static summary = 'Create workflow execution' + + static description = 'Validate the "workflow-config" previously created by utilizing the unique "configId". This step requires the mandatory field amount, and allows for modifications to other fields defined via the "workflow-config" endpoint, including pre-screening preferences. A response containing the "workflowExecutionId" and detailing the validation status will be provided. Execution is ready when the "workflow-execution" status is READY_FOR_LAUNCH, at which point it can be initiated with "POST /workflow-execution/{workflowExecutionId}/actions/execute".\n\nOperation ID: createFlowExecution\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Flows/createFlowExecution' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + } + + static method = 'POST' + static path = '/v1/payments/workflow_execution' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(CreateFlowExecution) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/payments/workflow_execution') + + const result = await this.makeRequest( + 'POST', + '/v1/payments/workflow_execution', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/payments-flows/delete-flow-configuration.ts b/src/commands/payments-flows/delete-flow-configuration.ts new file mode 100644 index 0000000..5246a97 --- /dev/null +++ b/src/commands/payments-flows/delete-flow-configuration.ts @@ -0,0 +1,45 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteFlowConfiguration extends FireblocksBaseCommand { + static summary = 'Delete workflow configuration' + + static description = 'Delete a configuration using the specified "configId".\n\nOperation ID: deleteFlowConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Flows/deleteFlowConfiguration' + + static enableJsonFlag = false + + static flags = { + 'config-id': Flags.string({ + description: 'The configId parameter', + required: true, + }), + } + + static method = 'DELETE' + static path = '/v1/payments/workflow_config/{configId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(DeleteFlowConfiguration) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['configId'] = String(flags['config-id']) + + + await this.confirmOrAbort('DELETE', '/v1/payments/workflow_config/{configId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/payments/workflow_config/{configId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/payments-flows/get-flow-configuration.ts b/src/commands/payments-flows/get-flow-configuration.ts new file mode 100644 index 0000000..49aeb50 --- /dev/null +++ b/src/commands/payments-flows/get-flow-configuration.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetFlowConfiguration extends FireblocksBaseCommand { + static summary = 'Retrieve workflow configuration' + + static description = 'Retrieve a previously created workflow configuration using the specified "configId".\n\nOperation ID: getFlowConfiguration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Flows/getFlowConfiguration' + + static enableJsonFlag = false + + static flags = { + 'config-id': Flags.string({ + description: 'The configId parameter', + required: true, + }), + } + + static method = 'GET' + static path = '/v1/payments/workflow_config/{configId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetFlowConfiguration) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['configId'] = String(flags['config-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/payments/workflow_config/{configId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/payments-flows/get-flow-execution.ts b/src/commands/payments-flows/get-flow-execution.ts new file mode 100644 index 0000000..6682cf4 --- /dev/null +++ b/src/commands/payments-flows/get-flow-execution.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetFlowExecution extends FireblocksBaseCommand { + static summary = 'Get workflow execution details' + + static description = 'Retrieve details of a previously initiated workflow execution by specifying the "workflowExecutionId"\n\nOperation ID: getFlowExecution\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Flows/getFlowExecution' + + static enableJsonFlag = false + + static flags = { + 'workflow-execution-id': Flags.string({ + description: 'The workflowExecutionId parameter', + required: true, + }), + } + + static method = 'GET' + static path = '/v1/payments/workflow_execution/{workflowExecutionId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetFlowExecution) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['workflowExecutionId'] = String(flags['workflow-execution-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/payments/workflow_execution/{workflowExecutionId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/payments-flows/launch-flow-execution.ts b/src/commands/payments-flows/launch-flow-execution.ts new file mode 100644 index 0000000..c3e7825 --- /dev/null +++ b/src/commands/payments-flows/launch-flow-execution.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class LaunchFlowExecution extends FireblocksBaseCommand { + static summary = 'Execute the payments workflow' + + static description = 'Launch the execution of a pre-configured workflow, identified by "workflowExecutionId", once it reaches the READY_FOR_LAUNCH state. The workflow undergoes several phases during execution - EXECUTION_IN_PROGRESS - Marks the start of the workflow execution. EXECUTION_COMPLETED or EXECUTION_FAILED - Indicates the execution has reached a final state.\n\nOperation ID: launchFlowExecution\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Flows/launchFlowExecution' + + static enableJsonFlag = false + + static flags = { + 'workflow-execution-id': Flags.string({ + description: 'The workflowExecutionId parameter', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/payments/workflow_execution/{workflowExecutionId}/actions/execute' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(LaunchFlowExecution) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['workflowExecutionId'] = String(flags['workflow-execution-id']) + + + await this.confirmOrAbort('POST', '/v1/payments/workflow_execution/{workflowExecutionId}/actions/execute') + + const result = await this.makeRequest( + 'POST', + '/v1/payments/workflow_execution/{workflowExecutionId}/actions/execute', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/payments-payout/create-payout.ts b/src/commands/payments-payout/create-payout.ts new file mode 100644 index 0000000..b96aeed --- /dev/null +++ b/src/commands/payments-payout/create-payout.ts @@ -0,0 +1,57 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreatePayout extends FireblocksBaseCommand { + static summary = 'Create a payout instruction set' + + static description = '**Note:** The reference content in this section documents the Payments Engine endpoint. The Payments Engine endpoints include APIs available only for customers with Payments Engine enabled on their accounts. \nThese endpoints are currently in beta and might be subject to changes.\nIf you want to learn more about Fireblocks Payments Engine, please contact your Fireblocks Customer Success Manager or email CSM@fireblocks.com. \n Create a payout instruction set. \nA payout instruction set is a set of instructions for distributing payments from a single payment account to a list of payee accounts. \nThe instruction set defines: \n\nthe payment account and its account type (vault, exchange, or fiat). \nthe account type (vault account, exchange account, whitelisted address, network connection, fiat account, or merchant account), the amount, and the asset of payment for each payee account.\n\nLearn more about Fireblocks Payments - Payouts in the following [guide](https://developers.fireblocks.com/docs/create-payouts).\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: createPayout\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Payout/createPayout' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + } + + static method = 'POST' + static path = '/v1/payments/payout' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(CreatePayout) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/payments/payout') + + const result = await this.makeRequest( + 'POST', + '/v1/payments/payout', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/payments-payout/execute-payout-action.ts b/src/commands/payments-payout/execute-payout-action.ts new file mode 100644 index 0000000..2371c74 --- /dev/null +++ b/src/commands/payments-payout/execute-payout-action.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ExecutePayoutAction extends FireblocksBaseCommand { + static summary = 'Execute a payout instruction set' + + static description = '**Note:** The reference content in this section documents the Payments Engine endpoint. The Payments Engine endpoints include APIs available only for customers with Payments Engine enabled on their accounts. \nThese endpoints are currently in beta and might be subject to changes.\nIf you want to learn more about Fireblocks Payments Engine, please contact your Fireblocks Customer Success Manager or email CSM@fireblocks.com. \nExecute a payout instruction set. \nThe instruction set will be verified and executed.\nSource locking \nIf you are executing a payout instruction set from a payment account with an already active payout the active payout will complete before the new payout instruction set can be executed. \nYou cannot execute the same payout instruction set more than once.\n\nOperation ID: executePayoutAction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Payout/executePayoutAction' + + static enableJsonFlag = false + + static flags = { + 'payout-id': Flags.string({ + description: 'the payout id received from the creation of the payout instruction set', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/payments/payout/{payoutId}/actions/execute' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(ExecutePayoutAction) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['payoutId'] = String(flags['payout-id']) + + + await this.confirmOrAbort('POST', '/v1/payments/payout/{payoutId}/actions/execute') + + const result = await this.makeRequest( + 'POST', + '/v1/payments/payout/{payoutId}/actions/execute', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/payments-payout/get-payout.ts b/src/commands/payments-payout/get-payout.ts new file mode 100644 index 0000000..142b49f --- /dev/null +++ b/src/commands/payments-payout/get-payout.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPayout extends FireblocksBaseCommand { + static summary = 'Get the status of a payout instruction set' + + static description = '**Note:** The reference content in this section documents the Payments Engine endpoint. The Payments Engine endpoints include APIs available only for customers with Payments Engine enabled on their accounts. \nThese endpoints are currently in beta and might be subject to changes.\nIf you want to learn more about Fireblocks Payments Engine, please contact your Fireblocks Customer Success Manager or email CSM@fireblocks.com. \nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getPayout\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Payments%20-%20Payout/getPayout' + + static enableJsonFlag = false + + static flags = { + 'payout-id': Flags.string({ + description: 'the payout id received from the creation of the payout instruction set', + required: true, + }), + } + + static method = 'GET' + static path = '/v1/payments/payout/{payoutId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetPayout) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['payoutId'] = String(flags['payout-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/payments/payout/{payoutId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor-v2/get-active-policy.ts b/src/commands/policy-editor-v2/get-active-policy.ts new file mode 100644 index 0000000..b4a4ca8 --- /dev/null +++ b/src/commands/policy-editor-v2/get-active-policy.ts @@ -0,0 +1,52 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetActivePolicy extends FireblocksBaseCommand { + static summary = 'Get the active policy and its validation by policy type' + + static description = 'Returns the active policy and its validation for a specific policy type.\n\n**Note:** This endpoint is currently in beta and subject to change. If you want to participate in the Policies beta, contact your Fireblocks Customer Success Manager or send an email to csm@fireblocks.com.\n\nEndpoint Permissions: Owner, Admin, Non-Signing Admin.\n\nOperation ID: getActivePolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor%20V2/getActivePolicy' + + static enableJsonFlag = false + + static flags = { + 'policy-type': Flags.string({ + description: 'The policy type(s) to retrieve. Can be a single type or multiple types by repeating the parameter (e.g., ?policyType=TRANSFER&policyType=MINT).', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/policy/active_policy' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetActivePolicy) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['policy-type'] !== undefined && flags['policy-type'] !== null) { + queryParams['policyType'] = String(flags['policy-type']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/policy/active_policy', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor-v2/get-draft.ts b/src/commands/policy-editor-v2/get-draft.ts new file mode 100644 index 0000000..b791c99 --- /dev/null +++ b/src/commands/policy-editor-v2/get-draft.ts @@ -0,0 +1,52 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDraft extends FireblocksBaseCommand { + static summary = 'Get the active draft by policy type' + + static description = 'Returns the active draft and its validation for a specific policy type. \n**Note:** These endpoints are currently in beta and might be subject to changes.\n\nOperation ID: getDraft\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor%20V2/getDraft' + + static enableJsonFlag = false + + static flags = { + 'policy-type': Flags.string({ + description: 'The policy type(s) to retrieve. Can be a single type or multiple types by repeating the parameter (e.g., ?policyType=TRANSFER&policyType=MINT).', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/policy/draft' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDraft) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['policy-type'] !== undefined && flags['policy-type'] !== null) { + queryParams['policyType'] = String(flags['policy-type']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/policy/draft', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor-v2/publish-draft.ts b/src/commands/policy-editor-v2/publish-draft.ts new file mode 100644 index 0000000..3c0bcd2 --- /dev/null +++ b/src/commands/policy-editor-v2/publish-draft.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class PublishDraft extends FireblocksBaseCommand { + static summary = 'Send publish request for a certain draft id' + + static description = 'Send publish request of certain draft id and returns the response. \n**Note:** These endpoints are currently in beta and might be subject to changes.\nIf you want to participate and learn more about the Fireblocks Policy Editor, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nOperation ID: publishDraft\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor%20V2/publishDraft' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/policy/draft' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(PublishDraft) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/policy/draft') + + const result = await this.makeRequest( + 'POST', + '/v1/policy/draft', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor-v2/update-draft.ts b/src/commands/policy-editor-v2/update-draft.ts new file mode 100644 index 0000000..07ee0f1 --- /dev/null +++ b/src/commands/policy-editor-v2/update-draft.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateDraft extends FireblocksBaseCommand { + static summary = 'Update the draft with a new set of rules by policy types' + + static description = 'Update the draft and return its validation for specific policy types. \n**Note:** These endpoints are currently in beta and might be subject to changes.\n\nOperation ID: updateDraft\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor%20V2/updateDraft' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/policy/draft' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateDraft) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/policy/draft') + + const result = await this.makeRequest( + 'PUT', + '/v1/policy/draft', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor/get-active-policy-legacy.ts b/src/commands/policy-editor/get-active-policy-legacy.ts new file mode 100644 index 0000000..5f15660 --- /dev/null +++ b/src/commands/policy-editor/get-active-policy-legacy.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetActivePolicyLegacy extends FireblocksBaseCommand { + static summary = 'Get the active policy and its validation' + + static description = 'Legacy Endpoint – Returns the active policy and its validation. \n**Note:** \n- This endpoint will remain available for the foreseeable future and is not deprecated. - The \`getActivePolicy\` endpoint under policy/paths provides policy type-specific operations and improved functionality. - These endpoints are currently in beta and might be subject to changes.\nIf you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nOperation ID: getActivePolicyLegacy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor/getActivePolicyLegacy' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tap/active_policy' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetActivePolicyLegacy) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/tap/active_policy', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor/get-draft-legacy.ts b/src/commands/policy-editor/get-draft-legacy.ts new file mode 100644 index 0000000..41d3e33 --- /dev/null +++ b/src/commands/policy-editor/get-draft-legacy.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDraftLegacy extends FireblocksBaseCommand { + static summary = 'Get the active draft' + + static description = 'Legacy Endpoint – Returns the active draft and its validation. \n**Note:** \n- This endpoint will remain available for the foreseeable future and is not deprecated. - The \`getDraft\` endpoint under policy/paths provides policy type-specific operations and improved functionality. - These endpoints are currently in beta and might be subject to changes.\nIf you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nOperation ID: getDraftLegacy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor/getDraftLegacy' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tap/draft' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDraftLegacy) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/tap/draft', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor/publish-draft-legacy.ts b/src/commands/policy-editor/publish-draft-legacy.ts new file mode 100644 index 0000000..91f19ca --- /dev/null +++ b/src/commands/policy-editor/publish-draft-legacy.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class PublishDraftLegacy extends FireblocksBaseCommand { + static summary = 'Send publish request for a certain draft id' + + static description = 'Legacy Endpoint – Send publish request of certain draft id and returns the response. \n**Note:** \n- This endpoint will remain available for the foreseeable future and is not deprecated. - The \`publishDraft\` endpoint under policy/paths provides improved functionality and better performance. - These endpoints are currently in beta and might be subject to changes.\nIf you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nOperation ID: publishDraftLegacy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor/publishDraftLegacy' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tap/draft' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(PublishDraftLegacy) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tap/draft') + + const result = await this.makeRequest( + 'POST', + '/v1/tap/draft', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor/publish-policy-rules.ts b/src/commands/policy-editor/publish-policy-rules.ts new file mode 100644 index 0000000..0ba0f35 --- /dev/null +++ b/src/commands/policy-editor/publish-policy-rules.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class PublishPolicyRules extends FireblocksBaseCommand { + static summary = 'Send publish request for a set of policy rules' + + static description = 'Send publish request of set of policy rules and returns the response. \n**Note:** These endpoints are currently in beta and might be subject to changes.\nIf you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nOperation ID: publishPolicyRules\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor/publishPolicyRules' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tap/publish' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(PublishPolicyRules) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tap/publish') + + const result = await this.makeRequest( + 'POST', + '/v1/tap/publish', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/policy-editor/update-draft-legacy.ts b/src/commands/policy-editor/update-draft-legacy.ts new file mode 100644 index 0000000..366d53d --- /dev/null +++ b/src/commands/policy-editor/update-draft-legacy.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateDraftLegacy extends FireblocksBaseCommand { + static summary = 'Update the draft with a new set of rules' + + static description = 'Legacy Endpoint – Update the draft and return its validation. \n**Note:** \n- This endpoint will remain available for the foreseeable future and is not deprecated. - The \`updateDraft\` endpoint under policy/paths provides policy type-specific operations and improved functionality. - These endpoints are currently in beta and might be subject to changes.\nIf you want to participate and learn more about the Fireblocks TAP, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nOperation ID: updateDraftLegacy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Policy%20Editor/updateDraftLegacy' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/tap/draft' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateDraftLegacy) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/tap/draft') + + const result = await this.makeRequest( + 'PUT', + '/v1/tap/draft', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/reset-device/reset-device.ts b/src/commands/reset-device/reset-device.ts new file mode 100644 index 0000000..dd1b168 --- /dev/null +++ b/src/commands/reset-device/reset-device.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ResetDevice extends FireblocksBaseCommand { + static summary = 'Resets device' + + static description = 'Resets mobile device for given console user, that user will need to do mobile onboarding again.\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: resetDevice\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Reset%20device/resetDevice' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The ID of the console user', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/management/users/{id}/reset_device' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ResetDevice) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('POST', '/v1/management/users/{id}/reset_device') + + const result = await this.makeRequest( + 'POST', + '/v1/management/users/{id}/reset_device', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/approve-dv-p-ticket-term.ts b/src/commands/smart-transfer/approve-dv-p-ticket-term.ts new file mode 100644 index 0000000..2ad075d --- /dev/null +++ b/src/commands/smart-transfer/approve-dv-p-ticket-term.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ApproveDvPTicketTerm extends FireblocksBaseCommand { + static summary = 'Set funding source and approval' + + static description = 'Set funding source for ticket term and creating approving transaction for contract to transfer asset\n\nOperation ID: approveDvPTicketTerm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/approveDvPTicketTerm' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + 'term-id': Flags.string({ + description: 'The termId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart_transfers/{ticketId}/terms/{termId}/dvp/approve' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(ApproveDvPTicketTerm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + pathParams['termId'] = String(flags['term-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart_transfers/{ticketId}/terms/{termId}/dvp/approve') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart_transfers/{ticketId}/terms/{termId}/dvp/approve', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/cancel-ticket.ts b/src/commands/smart-transfer/cancel-ticket.ts new file mode 100644 index 0000000..c4877e0 --- /dev/null +++ b/src/commands/smart-transfer/cancel-ticket.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CancelTicket extends FireblocksBaseCommand { + static summary = 'Cancel Ticket' + + static description = 'Cancel Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: cancelTicket\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/cancelTicket' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/cancel' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(CancelTicket) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/cancel') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/cancel', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/create-ticket-term.ts b/src/commands/smart-transfer/create-ticket-term.ts new file mode 100644 index 0000000..6bfe60b --- /dev/null +++ b/src/commands/smart-transfer/create-ticket-term.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTicketTerm extends FireblocksBaseCommand { + static summary = 'Create leg (term)' + + static description = 'Creates new smart transfer ticket term (when the ticket status is DRAFT). Learn more about Fireblocks Smart Transfers in the following [guide](https://developers.fireblocks.com/docs/execute-smart-transfers). Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createTicketTerm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/createTicketTerm' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/smart-transfers/{ticketId}/terms' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(CreateTicketTerm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + await this.confirmOrAbort('POST', '/v1/smart-transfers/{ticketId}/terms') + + const result = await this.makeRequest( + 'POST', + '/v1/smart-transfers/{ticketId}/terms', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/create-ticket.ts b/src/commands/smart-transfer/create-ticket.ts new file mode 100644 index 0000000..b87e90f --- /dev/null +++ b/src/commands/smart-transfer/create-ticket.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTicket extends FireblocksBaseCommand { + static summary = 'Create Ticket' + + static description = 'Creates a new Smart Transfer ticket. Learn more about Fireblocks Smart Transfers [here](https://developers.fireblocks.com/docs/execute-smart-transfers).\n\n**Note:** The \`DVP\` value is in Early Access and should only be used if Fireblocks has enabled it in your workspace. Contact your Customer Success Manager for more information.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createTicket\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/createTicket' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/smart-transfers' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(CreateTicket) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/smart-transfers') + + const result = await this.makeRequest( + 'POST', + '/v1/smart-transfers', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/find-ticket-by-id.ts b/src/commands/smart-transfer/find-ticket-by-id.ts new file mode 100644 index 0000000..cbc98d1 --- /dev/null +++ b/src/commands/smart-transfer/find-ticket-by-id.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FindTicketById extends FireblocksBaseCommand { + static summary = 'Search Ticket by ID' + + static description = 'Find Smart Transfer ticket by id. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: findTicketById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/findTicketById' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + } + + static method = 'GET' + static path = '/v1/smart-transfers/{ticketId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(FindTicketById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/smart-transfers/{ticketId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/find-ticket-term-by-id.ts b/src/commands/smart-transfer/find-ticket-term-by-id.ts new file mode 100644 index 0000000..c426e96 --- /dev/null +++ b/src/commands/smart-transfer/find-ticket-term-by-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FindTicketTermById extends FireblocksBaseCommand { + static summary = 'Get Smart Transfer ticket term' + + static description = 'Find a specific term of a specific Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: findTicketTermById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/findTicketTermById' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + 'term-id': Flags.string({ + description: 'The termId parameter', + required: true, + }), + } + + static method = 'GET' + static path = '/v1/smart-transfers/{ticketId}/terms/{termId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(FindTicketTermById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + pathParams['termId'] = String(flags['term-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/smart-transfers/{ticketId}/terms/{termId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/fulfill-ticket.ts b/src/commands/smart-transfer/fulfill-ticket.ts new file mode 100644 index 0000000..b4dbe81 --- /dev/null +++ b/src/commands/smart-transfer/fulfill-ticket.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FulfillTicket extends FireblocksBaseCommand { + static summary = 'Fund ticket manually' + + static description = 'Manually fulfill ticket, in case when all terms (legs) are funded manually. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: fulfillTicket\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/fulfillTicket' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/fulfill' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(FulfillTicket) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/fulfill') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/fulfill', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/fund-dvp-ticket.ts b/src/commands/smart-transfer/fund-dvp-ticket.ts new file mode 100644 index 0000000..cdde2f1 --- /dev/null +++ b/src/commands/smart-transfer/fund-dvp-ticket.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FundDvpTicket extends FireblocksBaseCommand { + static summary = 'Fund dvp ticket' + + static description = 'Create or fulfill dvp ticket order\n\nOperation ID: fundDvpTicket\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/fundDvpTicket' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart_transfers/{ticketId}/dvp/fund' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(FundDvpTicket) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart_transfers/{ticketId}/dvp/fund') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart_transfers/{ticketId}/dvp/fund', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/fund-ticket-term.ts b/src/commands/smart-transfer/fund-ticket-term.ts new file mode 100644 index 0000000..6a4064a --- /dev/null +++ b/src/commands/smart-transfer/fund-ticket-term.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FundTicketTerm extends FireblocksBaseCommand { + static summary = 'Define funding source' + + static description = 'Set funding source for ticket term (in case of ASYNC tickets, this will execute transfer immediately). Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: fundTicketTerm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/fundTicketTerm' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + 'term-id': Flags.string({ + description: 'The termId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/terms/{termId}/fund' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(FundTicketTerm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + pathParams['termId'] = String(flags['term-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/terms/{termId}/fund') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/terms/{termId}/fund', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/get-smart-transfer-statistic.ts b/src/commands/smart-transfer/get-smart-transfer-statistic.ts new file mode 100644 index 0000000..ef64b94 --- /dev/null +++ b/src/commands/smart-transfer/get-smart-transfer-statistic.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSmartTransferStatistic extends FireblocksBaseCommand { + static summary = 'Get smart transfers statistic' + + static description = 'Get smart transfer statistic\n\nOperation ID: getSmartTransferStatistic\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/getSmartTransferStatistic' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/smart_transfers/statistic' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetSmartTransferStatistic) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/smart_transfers/statistic', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/get-smart-transfer-user-groups.ts b/src/commands/smart-transfer/get-smart-transfer-user-groups.ts new file mode 100644 index 0000000..06609e1 --- /dev/null +++ b/src/commands/smart-transfer/get-smart-transfer-user-groups.ts @@ -0,0 +1,36 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSmartTransferUserGroups extends FireblocksBaseCommand { + static summary = 'Get user group' + + static description = 'Get Smart Transfer user groups.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getSmartTransferUserGroups\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/getSmartTransferUserGroups' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/smart-transfers/settings/user-groups' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetSmartTransferUserGroups) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/smart-transfers/settings/user-groups', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/manually-fund-ticket-term.ts b/src/commands/smart-transfer/manually-fund-ticket-term.ts new file mode 100644 index 0000000..54e5971 --- /dev/null +++ b/src/commands/smart-transfer/manually-fund-ticket-term.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ManuallyFundTicketTerm extends FireblocksBaseCommand { + static summary = 'Manually add term transaction' + + static description = 'Manually set ticket term transaction.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: manuallyFundTicketTerm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/manuallyFundTicketTerm' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + 'term-id': Flags.string({ + description: 'The termId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/terms/{termId}/manually-fund' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(ManuallyFundTicketTerm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + pathParams['termId'] = String(flags['term-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/terms/{termId}/manually-fund') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/terms/{termId}/manually-fund', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/remove-ticket-term.ts b/src/commands/smart-transfer/remove-ticket-term.ts new file mode 100644 index 0000000..b1d75f6 --- /dev/null +++ b/src/commands/smart-transfer/remove-ticket-term.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RemoveTicketTerm extends FireblocksBaseCommand { + static summary = 'Delete ticket leg (term)' + + static description = 'Delete ticket term when ticket is in DRAFT status\n\nOperation ID: removeTicketTerm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/removeTicketTerm' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + 'term-id': Flags.string({ + description: 'The termId parameter', + required: true, + }), + } + + static method = 'DELETE' + static path = '/v1/smart-transfers/{ticketId}/terms/{termId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(RemoveTicketTerm) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + pathParams['termId'] = String(flags['term-id']) + + + await this.confirmOrAbort('DELETE', '/v1/smart-transfers/{ticketId}/terms/{termId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/smart-transfers/{ticketId}/terms/{termId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/search-tickets.ts b/src/commands/smart-transfer/search-tickets.ts new file mode 100644 index 0000000..e56c2fc --- /dev/null +++ b/src/commands/smart-transfer/search-tickets.ts @@ -0,0 +1,116 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SearchTickets extends FireblocksBaseCommand { + static summary = 'Find Ticket' + + static description = 'Find tickets by their title or ticker. You can also query all tickets without filters by not providing any input parameters.\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: searchTickets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/searchTickets' + + static enableJsonFlag = false + + static flags = { + 'q': Flags.string({ + description: 'Search string - counterparty name or asset or ticketId. Optional', + }), + 'statuses': Flags.string({ + description: 'Ticket statuses for Smart Transfer tickets. Optional', + default: '', + }), + 'network-id': Flags.string({ + description: 'NetworkId that is used in the ticket . Optional', + }), + 'created-by-me': Flags.boolean({ + description: 'Filter created tickets by created by self or by others. Optional', + }), + 'expires-after': Flags.string({ + description: 'Lower bound of search range. Optional', + }), + 'expires-before': Flags.string({ + description: 'Upper bound of search range. Optional', + }), + 'type': Flags.string({ + description: 'Type of transfer. ASYNC executes transfers as they are funded, DVP executes all terms (legs) as one dvp transfer', + options: ['ASYNC', 'DVP'], + }), + 'external-ref-id': Flags.string({ + description: 'External ref. ID that workspace can use to identify ticket outside of Fireblocks system.', + }), + 'after': Flags.string({ + description: 'ID of the record after which to fetch $limit records', + }), + 'limit': Flags.string({ + description: 'Number of records to fetch. By default, it is 100', + }), + 'sort-by': Flags.string({ + description: 'Sort by field', + default: 'createdAt', + options: ['createdAt', 'updatedAt', 'submittedAt'], + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + } + + static method = 'GET' + static path = '/v1/smart-transfers' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(SearchTickets) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['q'] !== undefined && flags['q'] !== null) { + queryParams['q'] = String(flags['q']) + } + if (flags['statuses'] !== undefined && flags['statuses'] !== null) { + queryParams['statuses'] = String(flags['statuses']) + } + if (flags['network-id'] !== undefined && flags['network-id'] !== null) { + queryParams['networkId'] = String(flags['network-id']) + } + if (flags['created-by-me'] !== undefined && flags['created-by-me'] !== null) { + queryParams['createdByMe'] = String(flags['created-by-me']) + } + if (flags['expires-after'] !== undefined && flags['expires-after'] !== null) { + queryParams['expiresAfter'] = String(flags['expires-after']) + } + if (flags['expires-before'] !== undefined && flags['expires-before'] !== null) { + queryParams['expiresBefore'] = String(flags['expires-before']) + } + if (flags['type'] !== undefined && flags['type'] !== null) { + queryParams['type'] = String(flags['type']) + } + if (flags['external-ref-id'] !== undefined && flags['external-ref-id'] !== null) { + queryParams['externalRefId'] = String(flags['external-ref-id']) + } + if (flags['after'] !== undefined && flags['after'] !== null) { + queryParams['after'] = String(flags['after']) + } + if (flags['limit'] !== undefined && flags['limit'] !== null) { + queryParams['limit'] = String(flags['limit']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/smart-transfers', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/set-external-ref-id.ts b/src/commands/smart-transfer/set-external-ref-id.ts new file mode 100644 index 0000000..87890b6 --- /dev/null +++ b/src/commands/smart-transfer/set-external-ref-id.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetExternalRefId extends FireblocksBaseCommand { + static summary = 'Add external ref. ID' + + static description = 'Set external id Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: setExternalRefId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/setExternalRefId' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/external-id' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(SetExternalRefId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/external-id') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/external-id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/set-ticket-expiration.ts b/src/commands/smart-transfer/set-ticket-expiration.ts new file mode 100644 index 0000000..1de2eb7 --- /dev/null +++ b/src/commands/smart-transfer/set-ticket-expiration.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetTicketExpiration extends FireblocksBaseCommand { + static summary = 'Set expiration' + + static description = 'Set expiration date on Smart Transfer ticket. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: setTicketExpiration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/setTicketExpiration' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/expires-in' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(SetTicketExpiration) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/expires-in') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/expires-in', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/set-user-groups.ts b/src/commands/smart-transfer/set-user-groups.ts new file mode 100644 index 0000000..1c61fa0 --- /dev/null +++ b/src/commands/smart-transfer/set-user-groups.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetUserGroups extends FireblocksBaseCommand { + static summary = 'Set user group' + + static description = 'Set Smart Transfers user group to receive email notifications for Smart Transfers.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: setUserGroups\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/setUserGroups' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/smart-transfers/settings/user-groups' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(SetUserGroups) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/smart-transfers/settings/user-groups') + + const result = await this.makeRequest( + 'POST', + '/v1/smart-transfers/settings/user-groups', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/submit-ticket.ts b/src/commands/smart-transfer/submit-ticket.ts new file mode 100644 index 0000000..11d7880 --- /dev/null +++ b/src/commands/smart-transfer/submit-ticket.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SubmitTicket extends FireblocksBaseCommand { + static summary = 'Submit ticket' + + static description = 'Submit Smart Transfer ticket - change status into ready for approval if auto approval is not turned on, or OPEN if auto approval is on. Endpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: submitTicket\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/submitTicket' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/submit' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(SubmitTicket) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/submit') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/submit', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/smart-transfer/update-ticket-term.ts b/src/commands/smart-transfer/update-ticket-term.ts new file mode 100644 index 0000000..331b2fd --- /dev/null +++ b/src/commands/smart-transfer/update-ticket-term.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateTicketTerm extends FireblocksBaseCommand { + static summary = 'Update ticket leg (term)' + + static description = 'Update ticket term (when ticket status is DRAFT)\n\nOperation ID: updateTicketTerm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Smart%20Transfer/updateTicketTerm' + + static enableJsonFlag = false + + static flags = { + 'ticket-id': Flags.string({ + description: 'The ticketId parameter', + required: true, + }), + 'term-id': Flags.string({ + description: 'The termId parameter', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/smart-transfers/{ticketId}/terms/{termId}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(UpdateTicketTerm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['ticketId'] = String(flags['ticket-id']) + pathParams['termId'] = String(flags['term-id']) + + + await this.confirmOrAbort('PUT', '/v1/smart-transfers/{ticketId}/terms/{termId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/smart-transfers/{ticketId}/terms/{termId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/approve-terms-of-service-by-provider-id.ts b/src/commands/staking/approve-terms-of-service-by-provider-id.ts new file mode 100644 index 0000000..c9c0950 --- /dev/null +++ b/src/commands/staking/approve-terms-of-service-by-provider-id.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ApproveTermsOfServiceByProviderId extends FireblocksBaseCommand { + static summary = 'Approve provider terms of service' + + static description = 'Approves the provider\'s terms of service. Must be called once before performing any staking operation with this provider.\n\nOperation ID: approveTermsOfServiceByProviderId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/approveTermsOfServiceByProviderId' + + static enableJsonFlag = false + + static flags = { + 'provider-id': Flags.string({ + description: 'Unique identifier of the staking provider.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/providers/{providerId}/approveTermsOfService' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ApproveTermsOfServiceByProviderId) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['providerId'] = String(flags['provider-id']) + + + await this.confirmOrAbort('POST', '/v1/staking/providers/{providerId}/approveTermsOfService') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/providers/{providerId}/approveTermsOfService', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/claim-rewards.ts b/src/commands/staking/claim-rewards.ts new file mode 100644 index 0000000..32bb6c3 --- /dev/null +++ b/src/commands/staking/claim-rewards.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ClaimRewards extends FireblocksBaseCommand { + static summary = 'Claim accrued rewards' + + static description = 'Claims available staking rewards for the specified chain and vault. Supported chains: Solana and Polygon (Matic). Behavior depends on protocol reward distribution.\n\nOperation ID: claimRewards\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/claimRewards' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the claim rewards staking operation (e.g., MATIC/SOL).', + required: true, + options: ['SOL', 'SOL_TEST', 'MATIC'], + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/chains/{chainDescriptor}/claim_rewards' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ClaimRewards) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + await this.confirmOrAbort('POST', '/v1/staking/chains/{chainDescriptor}/claim_rewards') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/chains/{chainDescriptor}/claim_rewards', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/consolidate.ts b/src/commands/staking/consolidate.ts new file mode 100644 index 0000000..1554c88 --- /dev/null +++ b/src/commands/staking/consolidate.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Consolidate extends FireblocksBaseCommand { + static summary = 'Consolidate staking positions (ETH validator consolidation)' + + static description = 'Consolidates the source staking position into the destination, merging the balance into the destination and closing the source position once complete. Both positions must be from the same funding vaults account (i.e. same withdrawals credentials). On chain, this translates into a consolidation transaction, where the source validator is consolidated into the destination validator. Supported chains: Ethereum (ETH) only.\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor.\n**Note:** This endpoint is currently in beta and might be subject to changes.\n\nOperation ID: consolidate\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/consolidate' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the staking operation (e.g., ETH).', + required: true, + options: ['ETH', 'ETH_TEST6', 'ETH_TEST_HOODI'], + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/chains/{chainDescriptor}/consolidate' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Consolidate) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + await this.confirmOrAbort('POST', '/v1/staking/chains/{chainDescriptor}/consolidate') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/chains/{chainDescriptor}/consolidate', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-all-delegations.ts b/src/commands/staking/get-all-delegations.ts new file mode 100644 index 0000000..05ace68 --- /dev/null +++ b/src/commands/staking/get-all-delegations.ts @@ -0,0 +1,55 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAllDelegations extends FireblocksBaseCommand { + static summary = 'List staking positions' + + static description = 'Returns all staking positions with core details: amounts, rewards, status, chain, and vault.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getAllDelegations\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getAllDelegations' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier to filter positions (e.g., ATOM_COS/AXL/CELESTIA}). If omitted, positions across all supported chains are returned.', + }), + 'vault-account-id': Flags.string({ + description: 'Filter positions by vault account ID.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/positions' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAllDelegations) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['chain-descriptor'] !== undefined && flags['chain-descriptor'] !== null) { + queryParams['chainDescriptor'] = String(flags['chain-descriptor']) + } + if (flags['vault-account-id'] !== undefined && flags['vault-account-id'] !== null) { + queryParams['vaultAccountId'] = String(flags['vault-account-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/staking/positions', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-chain-info.ts b/src/commands/staking/get-chain-info.ts new file mode 100644 index 0000000..2121652 --- /dev/null +++ b/src/commands/staking/get-chain-info.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetChainInfo extends FireblocksBaseCommand { + static summary = 'Get chain-level staking parameters' + + static description = 'Returns chain-specific staking information such as epoch/slot cadence, lockup or unbonding periods, fee/reward mechanics, and other operational constraints.\n\nOperation ID: getChainInfo\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getChainInfo' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the chain info staking operation (e.g., ETH/MATIC/SOL).', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/chains/{chainDescriptor}/chainInfo' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetChainInfo) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + const result = await this.makeRequest( + 'GET', + '/v1/staking/chains/{chainDescriptor}/chainInfo', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-chains.ts b/src/commands/staking/get-chains.ts new file mode 100644 index 0000000..0b67d6f --- /dev/null +++ b/src/commands/staking/get-chains.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetChains extends FireblocksBaseCommand { + static summary = 'List supported staking chains' + + static description = 'Returns an alphabetical list of blockchains supported for staking by the current workspace context.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getChains\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getChains' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/chains' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetChains) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/staking/chains', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-delegation-by-id.ts b/src/commands/staking/get-delegation-by-id.ts new file mode 100644 index 0000000..10ed022 --- /dev/null +++ b/src/commands/staking/get-delegation-by-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDelegationById extends FireblocksBaseCommand { + static summary = 'Get position details' + + static description = 'Returns full details for a single staking position: amounts, rewards, status, chain, and vault.\n\nOperation ID: getDelegationById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getDelegationById' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'Unique identifier of the staking position.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/positions/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDelegationById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/staking/positions/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-positions.ts b/src/commands/staking/get-positions.ts new file mode 100644 index 0000000..d16c9c7 --- /dev/null +++ b/src/commands/staking/get-positions.ts @@ -0,0 +1,77 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPositions extends FireblocksBaseCommand { + static summary = 'List staking positions (Paginated)' + + static description = 'Returns staking positions with core details: amounts, rewards, status, chain, and vault. It supports cursor-based pagination for efficient data retrieval. This endpoint always returns a paginated response with {data, next} structure.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getPositions\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getPositions' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier to filter positions (e.g., ATOM_COS/AXL/CELESTIA}). If omitted, positions across all supported chains are returned.', + }), + 'vault-account-id': Flags.string({ + description: 'Filter positions by Fireblocks vault account ID. If omitted, positions across all vault accounts are returned.', + }), + 'page-size': Flags.integer({ + description: 'Number of results per page. When provided, the response returns a paginated object with {data, next}. If omitted, all results are returned as an array.', + required: true, + default: 10, + }), + 'page-cursor': Flags.string({ + description: 'Cursor for the next page of results. Use the value from the \'next\' field in the previous response.', + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/positions_paginated' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetPositions) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['chain-descriptor'] !== undefined && flags['chain-descriptor'] !== null) { + queryParams['chainDescriptor'] = String(flags['chain-descriptor']) + } + if (flags['vault-account-id'] !== undefined && flags['vault-account-id'] !== null) { + queryParams['vaultAccountId'] = String(flags['vault-account-id']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/staking/positions_paginated', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-providers.ts b/src/commands/staking/get-providers.ts new file mode 100644 index 0000000..8391d65 --- /dev/null +++ b/src/commands/staking/get-providers.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetProviders extends FireblocksBaseCommand { + static summary = 'List staking providers' + + static description = 'Returns all available staking providers with metadata such as name, ID, and supported chains.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: getProviders\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getProviders' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/providers' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetProviders) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/staking/providers', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-summary-by-vault.ts b/src/commands/staking/get-summary-by-vault.ts new file mode 100644 index 0000000..f19522c --- /dev/null +++ b/src/commands/staking/get-summary-by-vault.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSummaryByVault extends FireblocksBaseCommand { + static summary = 'Get positions summary by vault' + + static description = 'Returns per-vault aggregates: status breakdown, total staked, and total rewards per chain.\n\nOperation ID: getSummaryByVault\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getSummaryByVault' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/positions/summary/vaults' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetSummaryByVault) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/staking/positions/summary/vaults', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/staking/get-summary.ts b/src/commands/staking/get-summary.ts new file mode 100644 index 0000000..7405c36 --- /dev/null +++ b/src/commands/staking/get-summary.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetSummary extends FireblocksBaseCommand { + static summary = 'Get positions summary' + + static description = 'Returns an aggregated cross-vault summary: active/inactive counts, total staked, and total rewards per chain.\n\nOperation ID: getSummary\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/getSummary' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/staking/positions/summary' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetSummary) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/staking/positions/summary', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/staking/merge-stake-accounts.ts b/src/commands/staking/merge-stake-accounts.ts new file mode 100644 index 0000000..745a274 --- /dev/null +++ b/src/commands/staking/merge-stake-accounts.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class MergeStakeAccounts extends FireblocksBaseCommand { + static summary = 'Merge staking positions' + + static description = 'Merges the source stake account into the destination, consolidating the balance into the destination and closing the source account once complete. Both accounts must be from the same validator provider and of same vault account.. Supported chains: Solana (SOL).\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: mergeStakeAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/mergeStakeAccounts' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the merge staking operation (e.g., SOL).', + required: true, + options: ['SOL', 'SOL_TEST'], + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/chains/{chainDescriptor}/merge' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(MergeStakeAccounts) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + await this.confirmOrAbort('POST', '/v1/staking/chains/{chainDescriptor}/merge') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/chains/{chainDescriptor}/merge', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/split.ts b/src/commands/staking/split.ts new file mode 100644 index 0000000..3eb7f11 --- /dev/null +++ b/src/commands/staking/split.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Split extends FireblocksBaseCommand { + static summary = 'Split a staking position' + + static description = 'Splits a staking position by creating a new stake account with the requested amount, while keeping the original account with the remaining balance. Supported chains: Solana (SOL).\n\nOperation ID: split\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/split' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the staking operation (e.g., SOL).', + required: true, + options: ['SOL', 'SOL_TEST'], + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/chains/{chainDescriptor}/split' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Split) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + await this.confirmOrAbort('POST', '/v1/staking/chains/{chainDescriptor}/split') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/chains/{chainDescriptor}/split', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/stake.ts b/src/commands/staking/stake.ts new file mode 100644 index 0000000..df3d9a9 --- /dev/null +++ b/src/commands/staking/stake.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Stake extends FireblocksBaseCommand { + static summary = 'Initiate or add to existing stake' + + static description = 'Creates a new staking position and returns its unique ID. For Ethereum compounding validator (EIP-7251): when the \'id\' of an existing compounding validator position is provided, adds to that position; otherwise creates a new position. For Ethereum legacy validator: creates a new position regardless of existing delegations. For Cosmos chains and Ethereum liquid staking (Lido): automatically add to existing positions for the same validator provider and same vault account if one exists, otherwise create a new position. For Solana and Polygon: always create new positions regardless of existing delegations.\n\nOperation ID: stake\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/stake' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the stake staking operation (e.g., ATOM_COS/AXL/CELESTIA).', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/chains/{chainDescriptor}/stake' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Stake) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + await this.confirmOrAbort('POST', '/v1/staking/chains/{chainDescriptor}/stake') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/chains/{chainDescriptor}/stake', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/unstake.ts b/src/commands/staking/unstake.ts new file mode 100644 index 0000000..5c29340 --- /dev/null +++ b/src/commands/staking/unstake.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Unstake extends FireblocksBaseCommand { + static summary = 'Initiate unstake' + + static description = 'Submits a chain-specific unstake request.\n\nOperation ID: unstake\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/unstake' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the unstake staking operation (e.g., SOL/SOL_TEST/MATIC).', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/chains/{chainDescriptor}/unstake' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Unstake) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + await this.confirmOrAbort('POST', '/v1/staking/chains/{chainDescriptor}/unstake') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/chains/{chainDescriptor}/unstake', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/staking/withdraw.ts b/src/commands/staking/withdraw.ts new file mode 100644 index 0000000..b6eb8cf --- /dev/null +++ b/src/commands/staking/withdraw.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Withdraw extends FireblocksBaseCommand { + static summary = 'Withdraw staked funds' + + static description = 'Withdraws funds that have completed the unbonding period. Typically requires the position to be deactivated first (unstake → unbond → withdraw). Amount and timing vary by chain protocol.\n\nOperation ID: withdraw\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Staking/withdraw' + + static enableJsonFlag = false + + static flags = { + 'chain-descriptor': Flags.string({ + description: 'Protocol identifier for the withdraw staking operation (e.g., ATOM_COS/ETH/STETH_ETH).', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/staking/chains/{chainDescriptor}/withdraw' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Withdraw) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['chainDescriptor'] = String(flags['chain-descriptor']) + + + await this.confirmOrAbort('POST', '/v1/staking/chains/{chainDescriptor}/withdraw') + + const result = await this.makeRequest( + 'POST', + '/v1/staking/chains/{chainDescriptor}/withdraw', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tags/cancel-approval-request.ts b/src/commands/tags/cancel-approval-request.ts new file mode 100644 index 0000000..903abd2 --- /dev/null +++ b/src/commands/tags/cancel-approval-request.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CancelApprovalRequest extends FireblocksBaseCommand { + static summary = 'Cancel an approval request by id' + + static description = 'Cancel an approval request by id. Can only cancel requests in PENDING status. Returns 202 Accepted when the cancellation is processed.\n\nOperation ID: cancelApprovalRequest\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tags/cancelApprovalRequest' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The id parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tags/approval_requests/{id}/cancel' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CancelApprovalRequest) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('POST', '/v1/tags/approval_requests/{id}/cancel') + + const result = await this.makeRequest( + 'POST', + '/v1/tags/approval_requests/{id}/cancel', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tags/create-tag.ts b/src/commands/tags/create-tag.ts new file mode 100644 index 0000000..2a98865 --- /dev/null +++ b/src/commands/tags/create-tag.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTag extends FireblocksBaseCommand { + static summary = 'Create a new tag' + + static description = 'Create a new tag.\nEndpoint Permissions: For protected tags: ADMIN,NON_SIGNING_ADMIN,OWNER. For non protected tags: ADMIN,NON_SIGNING_ADMIN,OWNER,SIGNER,EDITOR,APPROVER.\n\nOperation ID: createTag\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tags/createTag' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tags' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateTag) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tags') + + const result = await this.makeRequest( + 'POST', + '/v1/tags', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tags/delete-tag.ts b/src/commands/tags/delete-tag.ts new file mode 100644 index 0000000..326fe75 --- /dev/null +++ b/src/commands/tags/delete-tag.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteTag extends FireblocksBaseCommand { + static summary = 'Delete a tag' + + static description = 'Delete the specified tag.\nEndpoint Permission: For protected tags: Owner, Admin, Non-Signing Admin. For non protected tags: Owner, Admin, Non-Signing Admin, Signer, Editor, Approver.\n\nOperation ID: deleteTag\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tags/deleteTag' + + static enableJsonFlag = false + + static flags = { + 'tag-id': Flags.string({ + description: 'The ID of the tag to retrieve', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/tags/{tagId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteTag) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['tagId'] = String(flags['tag-id']) + + + await this.confirmOrAbort('DELETE', '/v1/tags/{tagId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/tags/{tagId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tags/get-approval-request.ts b/src/commands/tags/get-approval-request.ts new file mode 100644 index 0000000..287327f --- /dev/null +++ b/src/commands/tags/get-approval-request.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetApprovalRequest extends FireblocksBaseCommand { + static summary = 'Get an approval request by id' + + static description = 'Get an approval request by id\n\nOperation ID: getApprovalRequest\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tags/getApprovalRequest' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The id parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tags/approval_requests/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetApprovalRequest) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tags/approval_requests/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tags/get-tag.ts b/src/commands/tags/get-tag.ts new file mode 100644 index 0000000..ad2e06c --- /dev/null +++ b/src/commands/tags/get-tag.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTag extends FireblocksBaseCommand { + static summary = 'Get a tag' + + static description = 'Retrieve an existing tag by ID.\n\nOperation ID: getTag\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tags/getTag' + + static enableJsonFlag = false + + static flags = { + 'tag-id': Flags.string({ + description: 'The ID of the tag to retrieve', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tags/{tagId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTag) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['tagId'] = String(flags['tag-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tags/{tagId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tags/get-tags.ts b/src/commands/tags/get-tags.ts new file mode 100644 index 0000000..f5b18ee --- /dev/null +++ b/src/commands/tags/get-tags.ts @@ -0,0 +1,81 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTags extends FireblocksBaseCommand { + static summary = 'Get list of tags' + + static description = 'Retrieve a paged list of all tags according to filters.\n\nOperation ID: getTags\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tags/getTags' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page.', + }), + 'page-size': Flags.string({ + description: 'Maximum number of items in the page', + default: '100', + }), + 'label': Flags.string({ + description: 'Label prefix to filter by.', + }), + 'tag-ids': Flags.string({ + description: 'List of tag IDs to filter by.', + }), + 'include-pending-approvals-info': Flags.boolean({ + description: 'Whether to include pending approval requests info.', + default: false, + }), + 'is-protected': Flags.boolean({ + description: 'The isProtected parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tags' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTags) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['label'] !== undefined && flags['label'] !== null) { + queryParams['label'] = String(flags['label']) + } + if (flags['tag-ids'] !== undefined && flags['tag-ids'] !== null) { + queryParams['tagIds'] = String(flags['tag-ids']) + } + if (flags['include-pending-approvals-info'] !== undefined && flags['include-pending-approvals-info'] !== null) { + queryParams['includePendingApprovalsInfo'] = String(flags['include-pending-approvals-info']) + } + if (flags['is-protected'] !== undefined && flags['is-protected'] !== null) { + queryParams['isProtected'] = String(flags['is-protected']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tags', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/tags/update-tag.ts b/src/commands/tags/update-tag.ts new file mode 100644 index 0000000..b847bc5 --- /dev/null +++ b/src/commands/tags/update-tag.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateTag extends FireblocksBaseCommand { + static summary = 'Update a tag' + + static description = 'Update an existing specified tag.\nEndpoint Permission: For protected tags: Owner, Admin, Non-Signing Admin. For non protected tags: Owner, Admin, Non-Signing Admin, Signer, Editor, Approver.\n\nOperation ID: updateTag\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tags/updateTag' + + static enableJsonFlag = false + + static flags = { + 'tag-id': Flags.string({ + description: 'The ID of the tag to update', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/tags/{tagId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateTag) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['tagId'] = String(flags['tag-id']) + + + await this.confirmOrAbort('PATCH', '/v1/tags/{tagId}') + + const result = await this.makeRequest( + 'PATCH', + '/v1/tags/{tagId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/burn-collection-token.ts b/src/commands/tokenization/burn-collection-token.ts new file mode 100644 index 0000000..bde40e7 --- /dev/null +++ b/src/commands/tokenization/burn-collection-token.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class BurnCollectionToken extends FireblocksBaseCommand { + static summary = 'Burn tokens' + + static description = 'Burn tokens in a collection\n\nOperation ID: burnCollectionToken\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/burnCollectionToken' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The collection link id', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/collections/{id}/tokens/burn' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(BurnCollectionToken) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('POST', '/v1/tokenization/collections/{id}/tokens/burn') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/collections/{id}/tokens/burn', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/create-new-collection.ts b/src/commands/tokenization/create-new-collection.ts new file mode 100644 index 0000000..ebf3c61 --- /dev/null +++ b/src/commands/tokenization/create-new-collection.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateNewCollection extends FireblocksBaseCommand { + static summary = 'Create a new collection' + + static description = 'Create a new collection and link it as a token.\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, and Editor.\n\nOperation ID: createNewCollection\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/createNewCollection' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/collections' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateNewCollection) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/collections') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/collections', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/deactivate-and-unlink-adapters.ts b/src/commands/tokenization/deactivate-and-unlink-adapters.ts new file mode 100644 index 0000000..f85faa3 --- /dev/null +++ b/src/commands/tokenization/deactivate-and-unlink-adapters.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeactivateAndUnlinkAdapters extends FireblocksBaseCommand { + static summary = 'Remove LayerZero adapters' + + static description = 'Remove LayerZero adapters by deactivating and unlinking them. This endpoint revokes roles and deactivates the specified adapter contracts.\n\nOperation ID: deactivateAndUnlinkAdapters\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/deactivateAndUnlinkAdapters' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'DELETE' + static path = '/v1/tokenization/multichain/bridge/layerzero' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(DeactivateAndUnlinkAdapters) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('DELETE', '/v1/tokenization/multichain/bridge/layerzero') + + const result = await this.makeRequest( + 'DELETE', + '/v1/tokenization/multichain/bridge/layerzero', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/deploy-and-link-adapters.ts b/src/commands/tokenization/deploy-and-link-adapters.ts new file mode 100644 index 0000000..71fc651 --- /dev/null +++ b/src/commands/tokenization/deploy-and-link-adapters.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeployAndLinkAdapters extends FireblocksBaseCommand { + static summary = 'Deploy LayerZero adapters' + + static description = 'Deploy LayerZero adapters for multichain token bridging functionality. This endpoint creates adapter contracts that enable cross-chain token transfers.\n\nOperation ID: deployAndLinkAdapters\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/deployAndLinkAdapters' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/multichain/bridge/layerzero' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(DeployAndLinkAdapters) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/multichain/bridge/layerzero') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/multichain/bridge/layerzero', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/fetch-collection-token-details.ts b/src/commands/tokenization/fetch-collection-token-details.ts new file mode 100644 index 0000000..b2ed055 --- /dev/null +++ b/src/commands/tokenization/fetch-collection-token-details.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FetchCollectionTokenDetails extends FireblocksBaseCommand { + static summary = 'Get collection token details' + + static description = 'Get collection token details by id\n\nOperation ID: fetchCollectionTokenDetails\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/fetchCollectionTokenDetails' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The collection link id', + required: true, + }), + 'token-id': Flags.string({ + description: 'The tokenId as it appears on the blockchain', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/collections/{id}/tokens/{tokenId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(FetchCollectionTokenDetails) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + pathParams['tokenId'] = String(flags['token-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/collections/{id}/tokens/{tokenId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-collection-by-id.ts b/src/commands/tokenization/get-collection-by-id.ts new file mode 100644 index 0000000..df28655 --- /dev/null +++ b/src/commands/tokenization/get-collection-by-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetCollectionById extends FireblocksBaseCommand { + static summary = 'Get a collection by id' + + static description = 'Get a collection by id\n\nOperation ID: getCollectionById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getCollectionById' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The token link id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/collections/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetCollectionById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/collections/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-deployable-address.ts b/src/commands/tokenization/get-deployable-address.ts new file mode 100644 index 0000000..c3b2681 --- /dev/null +++ b/src/commands/tokenization/get-deployable-address.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetDeployableAddress extends FireblocksBaseCommand { + static summary = 'Get deterministic address for contract deployment' + + static description = 'Get a deterministic address for contract deployment. The address is derived from the contract\'s bytecode and provided salt. This endpoint is used to get the address of a contract that will be deployed in the future.\n\nOperation ID: getDeployableAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getDeployableAddress' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/multichain/deterministic_address' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetDeployableAddress) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/multichain/deterministic_address') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/multichain/deterministic_address', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-layer-zero-dvn-config.ts b/src/commands/tokenization/get-layer-zero-dvn-config.ts new file mode 100644 index 0000000..fda2f11 --- /dev/null +++ b/src/commands/tokenization/get-layer-zero-dvn-config.ts @@ -0,0 +1,51 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLayerZeroDvnConfig extends FireblocksBaseCommand { + static summary = 'Get LayerZero DVN configuration' + + static description = 'Retrieve the DVN (Data Verification Network) configuration for a specific adapter. Returns DVN configurations for channels between the source adapter and its peers.\n\nOperation ID: getLayerZeroDvnConfig\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getLayerZeroDvnConfig' + + static enableJsonFlag = false + + static flags = { + 'adapter-token-link-id': Flags.string({ + description: 'The token link id of the adapter token link', + required: true, + }), + 'peer-adapter-token-link-id': Flags.string({ + description: 'Optional peer adapter token link ID to filter results', + }), + } + + static method = 'GET' + static path = '/v1/tokenization/multichain/bridge/layerzero/config/{adapterTokenLinkId}/dvns' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetLayerZeroDvnConfig) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['adapterTokenLinkId'] = String(flags['adapter-token-link-id']) + + const queryParams: Record = {} + if (flags['peer-adapter-token-link-id'] !== undefined && flags['peer-adapter-token-link-id'] !== null) { + queryParams['peerAdapterTokenLinkId'] = String(flags['peer-adapter-token-link-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/multichain/bridge/layerzero/config/{adapterTokenLinkId}/dvns', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-layer-zero-peers.ts b/src/commands/tokenization/get-layer-zero-peers.ts new file mode 100644 index 0000000..06a627f --- /dev/null +++ b/src/commands/tokenization/get-layer-zero-peers.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLayerZeroPeers extends FireblocksBaseCommand { + static summary = 'Get LayerZero peers' + + static description = 'Retrieve the LayerZero peers configured for a specific adapter. Returns information about peer relationships for cross-chain communication.\n\nOperation ID: getLayerZeroPeers\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getLayerZeroPeers' + + static enableJsonFlag = false + + static flags = { + 'adapter-token-link-id': Flags.string({ + description: 'The token link id of the adapter token link', + required: true, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/multichain/bridge/layerzero/config/{adapterTokenLinkId}/peers' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetLayerZeroPeers) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['adapterTokenLinkId'] = String(flags['adapter-token-link-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/multichain/bridge/layerzero/config/{adapterTokenLinkId}/peers', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-linked-collections.ts b/src/commands/tokenization/get-linked-collections.ts new file mode 100644 index 0000000..f5e1ba1 --- /dev/null +++ b/src/commands/tokenization/get-linked-collections.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLinkedCollections extends FireblocksBaseCommand { + static summary = 'Get collections' + + static description = 'Get collections (paginated).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getLinkedCollections\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getLinkedCollections' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page, for example - "MjAyMy0xMi0xMyAyMDozNjowOC4zMDI=:MTEwMA=="', + }), + 'page-size': Flags.string({ + description: 'Number of items per page (max 100), requesting more then 100 will return 100 items', + default: '100', + }), + 'status': Flags.string({ + description: 'A comma separated list of statuses to filter. Default is "COMPLETED"', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/collections' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetLinkedCollections) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['status'] !== undefined && flags['status'] !== null) { + queryParams['status'] = String(flags['status']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/collections', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-linked-token.ts b/src/commands/tokenization/get-linked-token.ts new file mode 100644 index 0000000..194466c --- /dev/null +++ b/src/commands/tokenization/get-linked-token.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLinkedToken extends FireblocksBaseCommand { + static summary = 'Return a linked token' + + static description = 'Return a linked token, with its status and metadata.\n\nOperation ID: getLinkedToken\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getLinkedToken' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The token link id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/tokens/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetLinkedToken) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/tokens/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-linked-tokens-count.ts b/src/commands/tokenization/get-linked-tokens-count.ts new file mode 100644 index 0000000..26ce442 --- /dev/null +++ b/src/commands/tokenization/get-linked-tokens-count.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLinkedTokensCount extends FireblocksBaseCommand { + static summary = 'Get the total count of linked tokens' + + static description = 'Get the total count of linked tokens\n\nOperation ID: getLinkedTokensCount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getLinkedTokensCount' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/tokens/count' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetLinkedTokensCount) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/tokens/count', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/get-linked-tokens.ts b/src/commands/tokenization/get-linked-tokens.ts new file mode 100644 index 0000000..ba31b86 --- /dev/null +++ b/src/commands/tokenization/get-linked-tokens.ts @@ -0,0 +1,61 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetLinkedTokens extends FireblocksBaseCommand { + static summary = 'List all linked tokens' + + static description = 'Return all linked tokens (paginated)\n\nOperation ID: getLinkedTokens\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/getLinkedTokens' + + static enableJsonFlag = false + + static flags = { + 'page-cursor': Flags.string({ + description: 'Page cursor to get the next page', + }), + 'page-size': Flags.string({ + description: 'Number of items per page, requesting more then max will return max items', + }), + 'status': Flags.string({ + description: 'A comma separated list of statuses to filter. Default is "COMPLETED"', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/tokens' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetLinkedTokens) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['status'] !== undefined && flags['status'] !== null) { + queryParams['status'] = String(flags['status']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/tokens', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/issue-new-token.ts b/src/commands/tokenization/issue-new-token.ts new file mode 100644 index 0000000..f1ba4ed --- /dev/null +++ b/src/commands/tokenization/issue-new-token.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class IssueNewToken extends FireblocksBaseCommand { + static summary = 'Issue a new token' + + static description = 'Facilitates the creation of a new token, supporting both EVM-based and Stellar/Ripple platforms. For EVM, it deploys the corresponding contract template to the blockchain and links the token to the workspace. For Stellar/Ripple, it links a newly created token directly to the workspace without deploying a contract. Returns the token link with status "PENDING" until the token is deployed or "SUCCESS" if no deployment is needed.\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, and Editor.\n\nOperation ID: issueNewToken\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/issueNewToken' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/tokens' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(IssueNewToken) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/tokens') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/tokens', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/issue-token-multi-chain.ts b/src/commands/tokenization/issue-token-multi-chain.ts new file mode 100644 index 0000000..dcd72eb --- /dev/null +++ b/src/commands/tokenization/issue-token-multi-chain.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class IssueTokenMultiChain extends FireblocksBaseCommand { + static summary = 'Issue a token on one or more blockchains' + + static description = 'Facilitates the creation of a new token on one or more blockchains.\n\nOperation ID: issueTokenMultiChain\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/issueTokenMultiChain' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/multichain/tokens' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(IssueTokenMultiChain) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/multichain/tokens') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/multichain/tokens', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/link.ts b/src/commands/tokenization/link.ts new file mode 100644 index 0000000..968009e --- /dev/null +++ b/src/commands/tokenization/link.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Link extends FireblocksBaseCommand { + static summary = 'Link a contract' + + static description = 'Link an a contract\n\nOperation ID: link\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/link' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/tokens/link' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Link) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/tokens/link') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/tokens/link', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/mint-collection-token.ts b/src/commands/tokenization/mint-collection-token.ts new file mode 100644 index 0000000..7e8fe52 --- /dev/null +++ b/src/commands/tokenization/mint-collection-token.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class MintCollectionToken extends FireblocksBaseCommand { + static summary = 'Mint tokens' + + static description = 'Mint tokens and upload metadata\n\nOperation ID: mintCollectionToken\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/mintCollectionToken' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The collection link id', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/collections/{id}/tokens/mint' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(MintCollectionToken) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('POST', '/v1/tokenization/collections/{id}/tokens/mint') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/collections/{id}/tokens/mint', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/re-issue-token-multi-chain.ts b/src/commands/tokenization/re-issue-token-multi-chain.ts new file mode 100644 index 0000000..aef563c --- /dev/null +++ b/src/commands/tokenization/re-issue-token-multi-chain.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ReIssueTokenMultiChain extends FireblocksBaseCommand { + static summary = 'Reissue a multichain token' + + static description = 'Reissue a multichain token. This endpoint allows you to reissue a token on one or more blockchains. The token must be initially issued using the issueTokenMultiChain endpoint.\n\nOperation ID: reIssueTokenMultiChain\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/reIssueTokenMultiChain' + + static enableJsonFlag = false + + static flags = { + 'token-link-id': Flags.string({ + description: 'The ID of the token link', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/multichain/reissue/token/{tokenLinkId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ReIssueTokenMultiChain) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['tokenLinkId'] = String(flags['token-link-id']) + + + await this.confirmOrAbort('POST', '/v1/tokenization/multichain/reissue/token/{tokenLinkId}') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/multichain/reissue/token/{tokenLinkId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/remove-layer-zero-peers.ts b/src/commands/tokenization/remove-layer-zero-peers.ts new file mode 100644 index 0000000..7742e55 --- /dev/null +++ b/src/commands/tokenization/remove-layer-zero-peers.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RemoveLayerZeroPeers extends FireblocksBaseCommand { + static summary = 'Remove LayerZero peers' + + static description = 'Remove LayerZero peers to disconnect adapter contracts. This endpoint removes peer relationships between LayerZero adapters.\n\nOperation ID: removeLayerZeroPeers\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/removeLayerZeroPeers' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'DELETE' + static path = '/v1/tokenization/multichain/bridge/layerzero/config/peers' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(RemoveLayerZeroPeers) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('DELETE', '/v1/tokenization/multichain/bridge/layerzero/config/peers') + + const result = await this.makeRequest( + 'DELETE', + '/v1/tokenization/multichain/bridge/layerzero/config/peers', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/set-layer-zero-dvn-config.ts b/src/commands/tokenization/set-layer-zero-dvn-config.ts new file mode 100644 index 0000000..efda40c --- /dev/null +++ b/src/commands/tokenization/set-layer-zero-dvn-config.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetLayerZeroDvnConfig extends FireblocksBaseCommand { + static summary = 'Set LayerZero DVN configuration' + + static description = 'Configure DVN settings for LayerZero adapters. This endpoint sets up the DVN configuration for message verification between source and destination adapters.\n\nOperation ID: setLayerZeroDvnConfig\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/setLayerZeroDvnConfig' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/multichain/bridge/layerzero/config/dvns' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(SetLayerZeroDvnConfig) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/multichain/bridge/layerzero/config/dvns') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/multichain/bridge/layerzero/config/dvns', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/set-layer-zero-peers.ts b/src/commands/tokenization/set-layer-zero-peers.ts new file mode 100644 index 0000000..ac0004e --- /dev/null +++ b/src/commands/tokenization/set-layer-zero-peers.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetLayerZeroPeers extends FireblocksBaseCommand { + static summary = 'Set LayerZero peers' + + static description = 'Set LayerZero peers to establish connections between adapter contracts. This endpoint creates peer relationships that enable cross-chain communication. It sets the destination adapter as a peer of the source adapter. If \`bidirectional\` is true, it also sets the source adapter as a peer of the destination adapter(s).\n\nOperation ID: setLayerZeroPeers\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/setLayerZeroPeers' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'POST' + static path = '/v1/tokenization/multichain/bridge/layerzero/config/peers' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(SetLayerZeroPeers) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/tokenization/multichain/bridge/layerzero/config/peers') + + const result = await this.makeRequest( + 'POST', + '/v1/tokenization/multichain/bridge/layerzero/config/peers', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/unlink-collection.ts b/src/commands/tokenization/unlink-collection.ts new file mode 100644 index 0000000..2bfa274 --- /dev/null +++ b/src/commands/tokenization/unlink-collection.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UnlinkCollection extends FireblocksBaseCommand { + static summary = 'Delete a collection link' + + static description = 'Delete a collection link\n\nOperation ID: unlinkCollection\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/unlinkCollection' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The token link id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/tokenization/collections/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UnlinkCollection) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('DELETE', '/v1/tokenization/collections/{id}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/tokenization/collections/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/unlink.ts b/src/commands/tokenization/unlink.ts new file mode 100644 index 0000000..3446acc --- /dev/null +++ b/src/commands/tokenization/unlink.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Unlink extends FireblocksBaseCommand { + static summary = 'Unlink a token' + + static description = 'Unlink a token. The token will be unlinked from the workspace. The token will not be deleted on chain nor the refId, only the link to the workspace will be removed.\n\nOperation ID: unlink\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/unlink' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The token link id', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/tokenization/tokens/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Unlink) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('DELETE', '/v1/tokenization/tokens/{id}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/tokenization/tokens/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/tokenization/validate-layer-zero-channel-config.ts b/src/commands/tokenization/validate-layer-zero-channel-config.ts new file mode 100644 index 0000000..fdf75b8 --- /dev/null +++ b/src/commands/tokenization/validate-layer-zero-channel-config.ts @@ -0,0 +1,52 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ValidateLayerZeroChannelConfig extends FireblocksBaseCommand { + static summary = 'Validate LayerZero channel configuration' + + static description = 'Validate the LayerZero channel configuration between adapters. This endpoint checks if the channel configuration is correct and returns any validation errors.\n\nOperation ID: validateLayerZeroChannelConfig\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Tokenization/validateLayerZeroChannelConfig' + + static enableJsonFlag = false + + static flags = { + 'adapter-token-link-id': Flags.string({ + description: 'The token link ID of the adapter', + required: true, + }), + 'peer-adapter-token-link-id': Flags.string({ + description: 'Peer adapter token link ID to validate against', + required: true, + }), + } + + static method = 'GET' + static path = '/v1/tokenization/multichain/bridge/layerzero/validate' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(ValidateLayerZeroChannelConfig) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['adapter-token-link-id'] !== undefined && flags['adapter-token-link-id'] !== null) { + queryParams['adapterTokenLinkId'] = String(flags['adapter-token-link-id']) + } + if (flags['peer-adapter-token-link-id'] !== undefined && flags['peer-adapter-token-link-id'] !== null) { + queryParams['peerAdapterTokenLinkId'] = String(flags['peer-adapter-token-link-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/tokenization/multichain/bridge/layerzero/validate', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/trading/create-order.ts b/src/commands/trading/create-order.ts new file mode 100644 index 0000000..ce78f05 --- /dev/null +++ b/src/commands/trading/create-order.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateOrder extends FireblocksBaseCommand { + static summary = 'Create an order' + + static description = 'Create an order to buy or sell an asset. If no source is given, an external source will be use.\n\nNote: These endpoints are currently in beta and might be subject to changes.\n\nIf you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Editor.\n\nFor detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).\n\nOperation ID: createOrder\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Trading/createOrder' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/trading/orders' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateOrder) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/trading/orders') + + const result = await this.makeRequest( + 'POST', + '/v1/trading/orders', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/trading/create-quote.ts b/src/commands/trading/create-quote.ts new file mode 100644 index 0000000..f4921b9 --- /dev/null +++ b/src/commands/trading/create-quote.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateQuote extends FireblocksBaseCommand { + static summary = 'Create a quote' + + static description = 'Generate a time-limited quote for asset conversion, providing exchange rate and amount calculations.\n\nNote: These endpoints are currently in beta and might be subject to changes.\n\nIf you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Editor.\n\nFor detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).\n\nOperation ID: createQuote\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Trading/createQuote' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/trading/quotes' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateQuote) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/trading/quotes') + + const result = await this.makeRequest( + 'POST', + '/v1/trading/quotes', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/trading/get-order.ts b/src/commands/trading/get-order.ts new file mode 100644 index 0000000..010b748 --- /dev/null +++ b/src/commands/trading/get-order.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetOrder extends FireblocksBaseCommand { + static summary = 'Get order details' + + static description = 'Retrieve detailed information about a specific order by its ID.\n\nNote:These endpoints are currently in beta and might be subject to changes.\n\nIf you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nFor detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).\n\nOperation ID: getOrder\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Trading/getOrder' + + static enableJsonFlag = false + + static flags = { + 'order-id': Flags.string({ + description: 'The ID of the order to fetch.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/trading/orders/{orderId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetOrder) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['orderId'] = String(flags['order-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/trading/orders/{orderId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trading/get-orders.ts b/src/commands/trading/get-orders.ts new file mode 100644 index 0000000..b3cb903 --- /dev/null +++ b/src/commands/trading/get-orders.ts @@ -0,0 +1,103 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetOrders extends FireblocksBaseCommand { + static summary = 'Get orders' + + static description = 'Retrieve a paginated list of orders with optional filtering by account, provider, status, and time range.\n\nNote:These endpoints are currently in beta and might be subject to changes.\n\nIf you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nFor detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).\n\nOperation ID: getOrders\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Trading/getOrders' + + static enableJsonFlag = false + + static flags = { + 'page-size': Flags.integer({ + description: 'pageSize for pagination.', + required: true, + }), + 'page-cursor': Flags.string({ + description: 'The pageCursor parameter', + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'account-id': Flags.string({ + description: 'Filter by accountId.', + }), + 'provider-id': Flags.string({ + description: 'Filter by providerId.', + }), + 'statuses': Flags.string({ + description: 'Filter by order status.', + }), + 'start-time': Flags.integer({ + description: 'The startTime parameter', + }), + 'end-time': Flags.integer({ + description: 'The endTime parameter', + }), + 'asset-conversion-type': Flags.string({ + description: 'The assetConversionType parameter', + options: ['DIGITAL_ONLY', 'FIAT'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/trading/orders' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetOrders) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['account-id'] !== undefined && flags['account-id'] !== null) { + queryParams['accountId'] = String(flags['account-id']) + } + if (flags['provider-id'] !== undefined && flags['provider-id'] !== null) { + queryParams['providerId'] = String(flags['provider-id']) + } + if (flags['statuses'] !== undefined && flags['statuses'] !== null) { + queryParams['statuses'] = String(flags['statuses']) + } + if (flags['start-time'] !== undefined && flags['start-time'] !== null) { + queryParams['startTime'] = String(flags['start-time']) + } + if (flags['end-time'] !== undefined && flags['end-time'] !== null) { + queryParams['endTime'] = String(flags['end-time']) + } + if (flags['asset-conversion-type'] !== undefined && flags['asset-conversion-type'] !== null) { + queryParams['assetConversionType'] = String(flags['asset-conversion-type']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/trading/orders', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/trading/get-trading-provider-by-id.ts b/src/commands/trading/get-trading-provider-by-id.ts new file mode 100644 index 0000000..8afa2fe --- /dev/null +++ b/src/commands/trading/get-trading-provider-by-id.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTradingProviderById extends FireblocksBaseCommand { + static summary = 'Get trading provider by ID' + + static description = 'Retrieve detailed information about a specific provider including its full manifest with order/quote requirements.\n\n**Note:** These endpoints are currently in beta and might be subject to changes. If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\n**Endpoint Permission:** Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nFor detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).\n\nOperation ID: getTradingProviderById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Trading/getTradingProviderById' + + static enableJsonFlag = false + + static flags = { + 'provider-id': Flags.string({ + description: 'The unique identifier of the provider.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/trading/providers/{providerId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTradingProviderById) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['providerId'] = String(flags['provider-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/trading/providers/{providerId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trading/get-trading-providers.ts b/src/commands/trading/get-trading-providers.ts new file mode 100644 index 0000000..2d5a7bc --- /dev/null +++ b/src/commands/trading/get-trading-providers.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTradingProviders extends FireblocksBaseCommand { + static summary = 'Get providers' + + static description = 'Retrieve a list of all available external providers supporting trading activities through the platform.\n\n**Note:** These endpoints are currently in beta and might be subject to changes. If you want to participate and learn more about the Fireblocks Trading, please contact your Fireblocks Customer Success Manager or send an email to CSM@fireblocks.com.\n\n**Endpoint Permission:** Owner, Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nFor detailed information about error codes and troubleshooting, please refer to our [API Error Codes documentation](https://developers.fireblocks.com/reference/api-error-codes).\n\nOperation ID: getTradingProviders\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Trading/getTradingProviders' + + static enableJsonFlag = false + + static flags = { + 'page-size': Flags.integer({ + description: 'Page size for pagination.', + default: 20, + }), + 'page-cursor': Flags.string({ + description: 'Page cursor for pagination.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/trading/providers' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTradingProviders) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/trading/providers', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/cancel-transaction.ts b/src/commands/transactions/cancel-transaction.ts new file mode 100644 index 0000000..994af76 --- /dev/null +++ b/src/commands/transactions/cancel-transaction.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CancelTransaction extends FireblocksBaseCommand { + static summary = 'Cancel a transaction' + + static description = 'Cancels a transaction by Fireblocks Transaction ID.\n\nCan be used only for transactions that did not get to the BROADCASTING state.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: cancelTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/cancelTransaction' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The ID of the transaction to cancel', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/transactions/{txId}/cancel' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CancelTransaction) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/transactions/{txId}/cancel') + + const result = await this.makeRequest( + 'POST', + '/v1/transactions/{txId}/cancel', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/create-transaction.ts b/src/commands/transactions/create-transaction.ts new file mode 100644 index 0000000..bf7d172 --- /dev/null +++ b/src/commands/transactions/create-transaction.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTransaction extends FireblocksBaseCommand { + static summary = 'Create a new transaction' + + static description = 'Creates a new transaction. This endpoint can be used for regular Transfers, Contract Calls, Raw & Typed message signing. - For Transfers, the required parameters are: \`assetId\`, \`source\`, \`destination\` and \`amount\`. - For Contract Calls, the required parameters are: \`operation.CONTRACT_CALL\`, \`assetId\` (Base Asset), \`source\`,\n\nOperation ID: createTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/createTransaction' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/transactions' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateTransaction) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/transactions') + + const result = await this.makeRequest( + 'POST', + '/v1/transactions', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/drop-transaction.ts b/src/commands/transactions/drop-transaction.ts new file mode 100644 index 0000000..35d8b92 --- /dev/null +++ b/src/commands/transactions/drop-transaction.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DropTransaction extends FireblocksBaseCommand { + static summary = 'Drop ETH (EVM) transaction by ID' + + static description = 'Drops a stuck ETH (EVM) transaction and creates a replacement transaction with 0 amount.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: dropTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/dropTransaction' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The ID of the transaction', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/transactions/{txId}/drop' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DropTransaction) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/transactions/{txId}/drop') + + const result = await this.makeRequest( + 'POST', + '/v1/transactions/{txId}/drop', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/estimate-network-fee.ts b/src/commands/transactions/estimate-network-fee.ts new file mode 100644 index 0000000..8df87d0 --- /dev/null +++ b/src/commands/transactions/estimate-network-fee.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class EstimateNetworkFee extends FireblocksBaseCommand { + static summary = 'Estimate the required fee for an asset' + + static description = 'Gets the estimated required fee for an asset.\nFireblocks fetches, calculates and caches the result every 30 seconds.\nCustomers should query this API while taking the caching interval into consideration.\nNotes:\n- The \`networkFee\` parameter is the \`gasPrice\` with a given delta added, multiplied by the gasLimit plus the delta. - The estimation provided depends on the asset type.\n - For UTXO-based assets, the response contains the \`feePerByte\` parameter\n - For ETH-based and all EVM based assets, the response will contain \`gasPrice\` parameter. This is calculated by adding the \`baseFee\` to the \`actualPriority\` based on the latest 12 blocks. The response for ETH-based contains the \`baseFee\`, \`gasPrice\`, and \`priorityFee\` parameters.\n - For ADA-based assets, the response will contain the parameter \`networkFee\` and \`feePerByte\` parameters.\n - For XRP and XLM, the response will contain the transaction fee.\n - For other assets, the response will contain the \`networkFee\` parameter.\n\nLearn more about Fireblocks Fee Management in the following [guide](https://developers.fireblocks.com/reference/estimate-transaction-fee).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: estimateNetworkFee\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/estimateNetworkFee' + + static enableJsonFlag = false + + static flags = { + 'asset-id': Flags.string({ + description: 'The asset for which to estimate the fee', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/estimate_network_fee' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(EstimateNetworkFee) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['asset-id'] !== undefined && flags['asset-id'] !== null) { + queryParams['assetId'] = String(flags['asset-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/estimate_network_fee', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/estimate-transaction-fee.ts b/src/commands/transactions/estimate-transaction-fee.ts new file mode 100644 index 0000000..c72028b --- /dev/null +++ b/src/commands/transactions/estimate-transaction-fee.ts @@ -0,0 +1,62 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class EstimateTransactionFee extends FireblocksBaseCommand { + static summary = 'Estimate transaction fee' + + static description = 'Estimates the transaction fee for a specific transaction request.\nThis endpoint simulates a transaction which means that the system will expect to have the requested asset and balance in the specified wallet.\n\n**Note**: Supports all Fireblocks assets except ZCash (ZEC).\nLearn more about Fireblocks Fee Management in the following [guide](https://developers.fireblocks.com/reference/estimate-transaction-fee).\nEndpoint Permission: Admin, Signer, Approver, Editor.\n\nOperation ID: estimateTransactionFee\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/estimateTransactionFee' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/transactions/estimate_fee' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(EstimateTransactionFee) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/transactions/estimate_fee') + + const result = await this.makeRequest( + 'POST', + '/v1/transactions/estimate_fee', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/freeze-transaction.ts b/src/commands/transactions/freeze-transaction.ts new file mode 100644 index 0000000..62cacf7 --- /dev/null +++ b/src/commands/transactions/freeze-transaction.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FreezeTransaction extends FireblocksBaseCommand { + static summary = 'Freeze a transaction' + + static description = 'Freezes a transaction by ID.\n\nUsually used for AML integrations when the incoming funds should be quarantined.\nFor account based assets - the entire amount of the transaction is frozen \nFor UTXO based assets - all UTXOs of the specified transaction are frozen\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: freezeTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/freezeTransaction' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The ID of the transaction to freeze', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/transactions/{txId}/freeze' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(FreezeTransaction) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/transactions/{txId}/freeze') + + const result = await this.makeRequest( + 'POST', + '/v1/transactions/{txId}/freeze', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/get-transaction-by-external-id.ts b/src/commands/transactions/get-transaction-by-external-id.ts new file mode 100644 index 0000000..67e7401 --- /dev/null +++ b/src/commands/transactions/get-transaction-by-external-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTransactionByExternalId extends FireblocksBaseCommand { + static summary = 'Get a specific transaction by external transaction ID' + + static description = 'Returns transaction by external transaction ID.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getTransactionByExternalId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/getTransactionByExternalId' + + static enableJsonFlag = false + + static flags = { + 'external-tx-id': Flags.string({ + description: 'The external ID of the transaction to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/transactions/external_tx_id/{externalTxId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTransactionByExternalId) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['externalTxId'] = String(flags['external-tx-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/transactions/external_tx_id/{externalTxId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/get-transaction.ts b/src/commands/transactions/get-transaction.ts new file mode 100644 index 0000000..a588c8a --- /dev/null +++ b/src/commands/transactions/get-transaction.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTransaction extends FireblocksBaseCommand { + static summary = 'Get a specific transaction by Fireblocks transaction ID' + + static description = 'Get a specific transaction data by Fireblocks Transaction ID\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/getTransaction' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The ID of the transaction to return', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/transactions/{txId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTransaction) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/transactions/{txId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/get-transactions.ts b/src/commands/transactions/get-transactions.ts new file mode 100644 index 0000000..b31e16a --- /dev/null +++ b/src/commands/transactions/get-transactions.ts @@ -0,0 +1,144 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTransactions extends FireblocksBaseCommand { + static summary = 'Get transaction history' + + static description = 'Get the transaction history for your workspace.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getTransactions\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/getTransactions' + + static enableJsonFlag = false + + static flags = { + 'next': Flags.string({ + description: 'Cursor returned in next-page header that can be used to fetch the next page of results', + }), + 'prev': Flags.string({ + description: 'Cursor returned in prev-page header that can be used to fetch the previous page of results', + }), + 'before': Flags.string({ + description: 'Unix timestamp in milliseconds. Returns only transactions created before the specified date.\nProvides an explicit end time. If not provided, default value will be applied, and may change over time. \nThe current default value is the past 90 days.\n', + }), + 'after': Flags.string({ + description: 'Unix timestamp in milliseconds. Returns only transactions created after the specified date.\nProvides an explicit start time. If not provided, default value will be applied, and may change over time. \nThe current default value is the past 90 days.\n', + }), + 'status': Flags.string({ + description: 'You can filter by one of the statuses.', + }), + 'order-by': Flags.string({ + description: 'The field to order the results by.\n\n**Note:** Ordering by a field that is not \`createdAt\` may result in transactions that receive updates as you request the next or previous pages of results, resulting in missing those transactions.\n', + options: ['createdAt', 'lastUpdated'], + }), + 'sort': Flags.string({ + description: 'The direction to order the results by', + options: ['ASC', 'DESC'], + }), + 'limit': Flags.integer({ + description: 'Limits the number of results. If not provided, a limit of 200 will be used. The maximum allowed limit is 500', + default: 200, + }), + 'source-type': Flags.string({ + description: 'The source type of the transaction', + options: ['VAULT_ACCOUNT', 'EXCHANGE_ACCOUNT', 'INTERNAL_WALLET', 'EXTERNAL_WALLET', 'CONTRACT', 'FIAT_ACCOUNT', 'NETWORK_CONNECTION', 'COMPOUND', 'UNKNOWN', 'GAS_STATION', 'END_USER_WALLET'], + }), + 'source-id': Flags.string({ + description: 'The source ID of the transaction', + }), + 'dest-type': Flags.string({ + description: 'The destination type of the transaction', + options: ['VAULT_ACCOUNT', 'EXCHANGE_ACCOUNT', 'INTERNAL_WALLET', 'EXTERNAL_WALLET', 'CONTRACT', 'FIAT_ACCOUNT', 'NETWORK_CONNECTION', 'COMPOUND', 'ONE_TIME_ADDRESS', 'END_USER_WALLET'], + }), + 'dest-id': Flags.string({ + description: 'The destination ID of the transaction', + }), + 'assets': Flags.string({ + description: 'A list of assets to filter by, seperated by commas', + }), + 'tx-hash': Flags.string({ + description: 'Returns only results with a specified txHash', + }), + 'source-wallet-id': Flags.string({ + description: 'Returns only results where the source is a specific end user wallet', + }), + 'dest-wallet-id': Flags.string({ + description: 'Returns only results where the destination is a specific end user wallet', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/transactions' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID","next-page","prev-page"] + + async run(): Promise { + const {flags} = await this.parse(GetTransactions) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['next'] !== undefined && flags['next'] !== null) { + queryParams['next'] = String(flags['next']) + } + if (flags['prev'] !== undefined && flags['prev'] !== null) { + queryParams['prev'] = String(flags['prev']) + } + if (flags['before'] !== undefined && flags['before'] !== null) { + queryParams['before'] = String(flags['before']) + } + if (flags['after'] !== undefined && flags['after'] !== null) { + queryParams['after'] = String(flags['after']) + } + if (flags['status'] !== undefined && flags['status'] !== null) { + queryParams['status'] = String(flags['status']) + } + if (flags['order-by'] !== undefined && flags['order-by'] !== null) { + queryParams['orderBy'] = String(flags['order-by']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['limit'] !== undefined && flags['limit'] !== null) { + queryParams['limit'] = String(flags['limit']) + } + if (flags['source-type'] !== undefined && flags['source-type'] !== null) { + queryParams['sourceType'] = String(flags['source-type']) + } + if (flags['source-id'] !== undefined && flags['source-id'] !== null) { + queryParams['sourceId'] = String(flags['source-id']) + } + if (flags['dest-type'] !== undefined && flags['dest-type'] !== null) { + queryParams['destType'] = String(flags['dest-type']) + } + if (flags['dest-id'] !== undefined && flags['dest-id'] !== null) { + queryParams['destId'] = String(flags['dest-id']) + } + if (flags['assets'] !== undefined && flags['assets'] !== null) { + queryParams['assets'] = String(flags['assets']) + } + if (flags['tx-hash'] !== undefined && flags['tx-hash'] !== null) { + queryParams['txHash'] = String(flags['tx-hash']) + } + if (flags['source-wallet-id'] !== undefined && flags['source-wallet-id'] !== null) { + queryParams['sourceWalletId'] = String(flags['source-wallet-id']) + } + if (flags['dest-wallet-id'] !== undefined && flags['dest-wallet-id'] !== null) { + queryParams['destWalletId'] = String(flags['dest-wallet-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/transactions', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/set-confirmation-threshold-by-transaction-hash.ts b/src/commands/transactions/set-confirmation-threshold-by-transaction-hash.ts new file mode 100644 index 0000000..2ce0103 --- /dev/null +++ b/src/commands/transactions/set-confirmation-threshold-by-transaction-hash.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetConfirmationThresholdByTransactionHash extends FireblocksBaseCommand { + static summary = 'Set confirmation threshold by transaction hash' + + static description = 'Overrides the required number of confirmations for transaction completion by transaction hash.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: setConfirmationThresholdByTransactionHash\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/setConfirmationThresholdByTransactionHash' + + static enableJsonFlag = false + + static flags = { + 'tx-hash': Flags.string({ + description: 'The TxHash', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/txHash/{txHash}/set_confirmation_threshold' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetConfirmationThresholdByTransactionHash) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txHash'] = String(flags['tx-hash']) + + + await this.confirmOrAbort('POST', '/v1/txHash/{txHash}/set_confirmation_threshold') + + const result = await this.makeRequest( + 'POST', + '/v1/txHash/{txHash}/set_confirmation_threshold', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/set-transaction-confirmation-threshold.ts b/src/commands/transactions/set-transaction-confirmation-threshold.ts new file mode 100644 index 0000000..1909452 --- /dev/null +++ b/src/commands/transactions/set-transaction-confirmation-threshold.ts @@ -0,0 +1,69 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetTransactionConfirmationThreshold extends FireblocksBaseCommand { + static summary = 'Set confirmation threshold by Fireblocks Transaction ID' + + static description = 'Overrides the required number of confirmations for transaction completion Fireblocks Transaction ID.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: setTransactionConfirmationThreshold\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/setTransactionConfirmationThreshold' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The ID of the transaction', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/transactions/{txId}/set_confirmation_threshold' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetTransactionConfirmationThreshold) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/transactions/{txId}/set_confirmation_threshold') + + const result = await this.makeRequest( + 'POST', + '/v1/transactions/{txId}/set_confirmation_threshold', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/unfreeze-transaction.ts b/src/commands/transactions/unfreeze-transaction.ts new file mode 100644 index 0000000..f118563 --- /dev/null +++ b/src/commands/transactions/unfreeze-transaction.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UnfreezeTransaction extends FireblocksBaseCommand { + static summary = 'Unfreeze a transaction' + + static description = 'Unfreezes a transaction by Fireblocks Transaction ID and makes the transaction available again.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: unfreezeTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/unfreezeTransaction' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The ID of the transaction to unfreeze', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/transactions/{txId}/unfreeze' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UnfreezeTransaction) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/transactions/{txId}/unfreeze') + + const result = await this.makeRequest( + 'POST', + '/v1/transactions/{txId}/unfreeze', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/transactions/validate-address.ts b/src/commands/transactions/validate-address.ts new file mode 100644 index 0000000..125975d --- /dev/null +++ b/src/commands/transactions/validate-address.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ValidateAddress extends FireblocksBaseCommand { + static summary = 'Validate destination address' + + static description = 'Checks if an address is valid and active (for XRP, DOT, XLM, and EOS).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: validateAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Transactions/validateAddress' + + static enableJsonFlag = false + + static flags = { + 'asset-id': Flags.string({ + description: 'The asset of the address', + required: true, + }), + 'address': Flags.string({ + description: 'The address to validate', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/transactions/validate_address/{assetId}/{address}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ValidateAddress) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['assetId'] = String(flags['asset-id']) + pathParams['address'] = String(flags['address']) + + + const result = await this.makeRequest( + 'GET', + '/v1/transactions/validate_address/{assetId}/{address}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/create-trust-proof-of-address.ts b/src/commands/travel-rule/create-trust-proof-of-address.ts new file mode 100644 index 0000000..1977dcb --- /dev/null +++ b/src/commands/travel-rule/create-trust-proof-of-address.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTrustProofOfAddress extends FireblocksBaseCommand { + static summary = 'Create Trust Network Proof of Address' + + static description = 'Creates a cryptographic proof of address ownership for TRUST network.\n\nOperation ID: createTrustProofOfAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/createTrustProofOfAddress' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/travel_rule/providers/trust/proof_of_address' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateTrustProofOfAddress) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/screening/travel_rule/providers/trust/proof_of_address') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/travel_rule/providers/trust/proof_of_address', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/get-trust-proof-of-address.ts b/src/commands/travel-rule/get-trust-proof-of-address.ts new file mode 100644 index 0000000..5a26930 --- /dev/null +++ b/src/commands/travel-rule/get-trust-proof-of-address.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTrustProofOfAddress extends FireblocksBaseCommand { + static summary = 'Retrieve Trust Network Proof of Address Signature' + + static description = 'Retrieves the TRUST-compatible encoded signature for a proof of address transaction. Send this signature directly to TRUST for verification.\n\nOperation ID: getTrustProofOfAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/getTrustProofOfAddress' + + static enableJsonFlag = false + + static flags = { + 'transaction-id': Flags.string({ + description: 'Fireblocks transaction ID (UUID format)', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/travel_rule/providers/trust/proof_of_address/{transactionId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTrustProofOfAddress) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['transactionId'] = String(flags['transaction-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/travel_rule/providers/trust/proof_of_address/{transactionId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/get-vas-ps.ts b/src/commands/travel-rule/get-vas-ps.ts new file mode 100644 index 0000000..a092147 --- /dev/null +++ b/src/commands/travel-rule/get-vas-ps.ts @@ -0,0 +1,82 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVASPs extends FireblocksBaseCommand { + static summary = 'Get All VASPs' + + static description = 'Get All VASPs.\n\nReturns a list of VASPs. VASPs can be searched and sorted.\n\nOperation ID: getVASPs\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/getVASPs' + + static enableJsonFlag = false + + static flags = { + 'order': Flags.string({ + description: 'Field to order by', + options: ['ASC', 'DESC'], + }), + 'page-size': Flags.string({ + description: 'Records per page', + default: '500', + }), + 'fields': Flags.string({ + description: 'CSV of fields to return (all, "blank" or see list of all field names below)', + }), + 'search': Flags.string({ + description: 'Search query', + }), + 'review-value': Flags.string({ + description: 'Filter by the VASP\'s review status. Possible values include: "TRUSTED", "BLOCKED", "MANUAL", or "NULL". When provided, only VASPs that match the specified reviewValue will be returned (i.e., VASPs that have already been reviewed to this status).', + options: ['TRUSTED', 'BLOCKED', 'MANUAL', 'null'], + }), + 'page-cursor': Flags.string({ + description: 'Cursor for pagination. When provided, the response will include the next page of results.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/travel_rule/vasp' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVASPs) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['fields'] !== undefined && flags['fields'] !== null) { + queryParams['fields'] = String(flags['fields']) + } + if (flags['search'] !== undefined && flags['search'] !== null) { + queryParams['search'] = String(flags['search']) + } + if (flags['review-value'] !== undefined && flags['review-value'] !== null) { + queryParams['reviewValue'] = String(flags['review-value']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/screening/travel_rule/vasp', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/get-vasp-by-did.ts b/src/commands/travel-rule/get-vasp-by-did.ts new file mode 100644 index 0000000..76926e0 --- /dev/null +++ b/src/commands/travel-rule/get-vasp-by-did.ts @@ -0,0 +1,51 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVASPByDID extends FireblocksBaseCommand { + static summary = 'Get VASP details' + + static description = 'Get VASP Details.\n\nReturns information about a VASP that has the specified DID.\n\nOperation ID: getVASPByDID\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/getVASPByDID' + + static enableJsonFlag = false + + static flags = { + 'did': Flags.string({ + description: 'The did parameter', + required: true, + }), + 'fields': Flags.string({ + description: 'A CSV of fields to return. Choose from the following options:', + }), + } + + static method = 'GET' + static path = '/v1/screening/travel_rule/vasp/{did}' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(GetVASPByDID) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['did'] = String(flags['did']) + + const queryParams: Record = {} + if (flags['fields'] !== undefined && flags['fields'] !== null) { + queryParams['fields'] = String(flags['fields']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/screening/travel_rule/vasp/{did}', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/get-vasp-for-vault.ts b/src/commands/travel-rule/get-vasp-for-vault.ts new file mode 100644 index 0000000..ef6664f --- /dev/null +++ b/src/commands/travel-rule/get-vasp-for-vault.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaspForVault extends FireblocksBaseCommand { + static summary = 'Get assigned VASP to vault' + + static description = 'Get assigned VASP Did for a specific vault. Returns empty string vaspDid value in response if none assigned.\n\nOperation ID: getVaspForVault\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/getVaspForVault' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/travel_rule/vault/{vaultAccountId}/vasp' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaspForVault) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/travel_rule/vault/{vaultAccountId}/vasp', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/set-vasp-for-vault.ts b/src/commands/travel-rule/set-vasp-for-vault.ts new file mode 100644 index 0000000..dece7f1 --- /dev/null +++ b/src/commands/travel-rule/set-vasp-for-vault.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetVaspForVault extends FireblocksBaseCommand { + static summary = 'Assign VASP to vault' + + static description = 'Sets the VASP Did for a specific vault. Pass empty string to remove existing one.\n\nOperation ID: setVaspForVault\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/setVaspForVault' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/travel_rule/vault/{vaultAccountId}/vasp' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetVaspForVault) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/travel_rule/vault/{vaultAccountId}/vasp') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/travel_rule/vault/{vaultAccountId}/vasp', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/update-vasp.ts b/src/commands/travel-rule/update-vasp.ts new file mode 100644 index 0000000..c79055e --- /dev/null +++ b/src/commands/travel-rule/update-vasp.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateVasp extends FireblocksBaseCommand { + static summary = 'Add jsonDidKey to VASP details' + + static description = 'Update VASP Details.\n\nUpdates a VASP with the provided parameters. Use this endpoint to add your public jsonDIDkey generated by Notabene.\n\nOperation ID: updateVasp\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/updateVasp' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + } + + static method = 'PUT' + static path = '/v1/screening/travel_rule/vasp/update' + static isBeta = false + + async run(): Promise { + const {flags} = await this.parse(UpdateVasp) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('PUT', '/v1/screening/travel_rule/vasp/update') + + const result = await this.makeRequest( + 'PUT', + '/v1/screening/travel_rule/vasp/update', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/validate-full-travel-rule-transaction.ts b/src/commands/travel-rule/validate-full-travel-rule-transaction.ts new file mode 100644 index 0000000..1f24c99 --- /dev/null +++ b/src/commands/travel-rule/validate-full-travel-rule-transaction.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ValidateFullTravelRuleTransaction extends FireblocksBaseCommand { + static summary = 'Validate Full Travel Rule Transaction' + + static description = 'Validate Full Travel Rule transactions.\n\nChecks for all required information on the originator and beneficiary VASPs.\n\nOperation ID: validateFullTravelRuleTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/validateFullTravelRuleTransaction' + + static enableJsonFlag = false + + static flags = { + 'notation': Flags.string({ + description: 'Specifies the notation of the transaction. Possible values are: - \`notabene\`: Uses Notabene notation (default behavior). - \`fireblocks\`: Uses Fireblocks notation, with automatic translation of asset tickers and amounts. - \`\`: Defaults to \`notabene\` for backward compatibility.\n**Note:** The default value for the \`notation\` parameter will change from \`notabene\` to \`fireblocks\` Update your integrations accordingly.', + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/travel_rule/transaction/validate/full' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ValidateFullTravelRuleTransaction) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + const queryParams: Record = {} + if (flags['notation'] !== undefined && flags['notation'] !== null) { + queryParams['notation'] = String(flags['notation']) + } + + await this.confirmOrAbort('POST', '/v1/screening/travel_rule/transaction/validate/full') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/travel_rule/transaction/validate/full', + { + body, + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/travel-rule/validate-travel-rule-transaction.ts b/src/commands/travel-rule/validate-travel-rule-transaction.ts new file mode 100644 index 0000000..2cf4746 --- /dev/null +++ b/src/commands/travel-rule/validate-travel-rule-transaction.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ValidateTravelRuleTransaction extends FireblocksBaseCommand { + static summary = 'Validate Travel Rule Transaction' + + static description = 'Validate Travel Rule transactions.\nChecks what beneficiary VASP details are required by your jurisdiction and the beneficiary\'s jurisdiction.\n**Deprecation Notice** This endpoint will be deprecated soon in favor of the [validate full](https://developers.fireblocks.com/reference/validatefulltravelruletransaction) endpoint. Please update your integrations to use the [validate full](https://developers.fireblocks.com/reference/validatefulltravelruletransaction) endpoint to ensure compatibility with future releases.\nChecks what beneficiary VASP details are required by your jurisdiction and the beneficiary\'s jurisdiction.\nLearn more about Fireblocks Travel Rule management in the following [guide](https://developers.fireblocks.com/docs/define-travel-rule-policies).\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: validateTravelRuleTransaction\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Travel%20Rule/validateTravelRuleTransaction' + + static enableJsonFlag = false + + static flags = { + 'notation': Flags.string({ + description: 'Specifies the notation of the transaction. Possible values are: - \`notabene\`: Uses Notabene notation (default behavior). - \`fireblocks\`: Uses Fireblocks notation, with automatic translation of asset tickers and amounts. - \`\`: Defaults to \`notabene\` for backward compatibility.\n**Note:** The default value for the \`notation\` parameter will change from \`notabene\` to \`fireblocks\` Update your integrations accordingly.', + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/travel_rule/transaction/validate' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ValidateTravelRuleTransaction) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + const queryParams: Record = {} + if (flags['notation'] !== undefined && flags['notation'] !== null) { + queryParams['notation'] = String(flags['notation']) + } + + await this.confirmOrAbort('POST', '/v1/screening/travel_rule/transaction/validate') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/travel_rule/transaction/validate', + { + body, + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/assess-tr-link-travel-rule-requirement.ts b/src/commands/trlink/assess-tr-link-travel-rule-requirement.ts new file mode 100644 index 0000000..828fbd5 --- /dev/null +++ b/src/commands/trlink/assess-tr-link-travel-rule-requirement.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AssessTRLinkTravelRuleRequirement extends FireblocksBaseCommand { + static summary = 'Assess Travel Rule requirement' + + static description = 'Assesses travel rule requirement for a transaction by validating stored credentials and determining whether Travel Rule compliance is required based on amount, jurisdiction, and partner thresholds.\n\nOperation ID: assessTRLinkTravelRuleRequirement\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/assessTRLinkTravelRuleRequirement' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/assess' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AssessTRLinkTravelRuleRequirement) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/assess') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/assess', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/cancel-tr-link-trm.ts b/src/commands/trlink/cancel-tr-link-trm.ts new file mode 100644 index 0000000..0f1aaa4 --- /dev/null +++ b/src/commands/trlink/cancel-tr-link-trm.ts @@ -0,0 +1,75 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CancelTRLinkTrm extends FireblocksBaseCommand { + static summary = 'Cancel Travel Rule Message' + + static description = 'Cancels a travel rule message. The TRM status will be updated to cancelled and the partner will be notified.\n\nOperation ID: cancelTRLinkTrm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/cancelTRLinkTrm' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'trm-id': Flags.string({ + description: 'Travel Rule Message unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/cancel' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CancelTRLinkTrm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + pathParams['trmId'] = String(flags['trm-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/cancel') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/cancel', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/connect-tr-link-integration.ts b/src/commands/trlink/connect-tr-link-integration.ts new file mode 100644 index 0000000..5ebe4af --- /dev/null +++ b/src/commands/trlink/connect-tr-link-integration.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ConnectTRLinkIntegration extends FireblocksBaseCommand { + static summary = 'Connect customer integration' + + static description = 'Connects a customer integration by providing API credentials. Stores encrypted credentials and enables the integration for use.\n\nOperation ID: connectTRLinkIntegration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/connectTRLinkIntegration' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ConnectTRLinkIntegration) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + + await this.confirmOrAbort('PUT', '/v1/screening/trlink/customers/integration/{customerIntegrationId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/create-tr-link-customer.ts b/src/commands/trlink/create-tr-link-customer.ts new file mode 100644 index 0000000..dca7134 --- /dev/null +++ b/src/commands/trlink/create-tr-link-customer.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTRLinkCustomer extends FireblocksBaseCommand { + static summary = 'Create customer' + + static description = 'Creates a new customer (legal entity/VASP) for TRSupport Travel Rule compliance operations. The customer represents your organization in the Travel Rule network and contains IVMS101-compliant identity information.\n\nOperation ID: createTRLinkCustomer\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/createTRLinkCustomer' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/customers' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateTRLinkCustomer) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/customers') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/customers', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/create-tr-link-integration.ts b/src/commands/trlink/create-tr-link-integration.ts new file mode 100644 index 0000000..7861b3f --- /dev/null +++ b/src/commands/trlink/create-tr-link-integration.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTRLinkIntegration extends FireblocksBaseCommand { + static summary = 'Create customer integration' + + static description = 'Creates a new TRSupport integration for a customer. This establishes a connection placeholder between a customer and a Travel Rule partner. Use the connect endpoint to provide credentials after creation. You may optionally supply \`customerIntegrationId\` in the request body when your tenant is enabled for client-provided integration ids.\n\nOperation ID: createTRLinkIntegration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/createTRLinkIntegration' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/customers/integration' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateTRLinkIntegration) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/customers/integration') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/customers/integration', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/create-tr-link-trm.ts b/src/commands/trlink/create-tr-link-trm.ts new file mode 100644 index 0000000..c33a4ce --- /dev/null +++ b/src/commands/trlink/create-tr-link-trm.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateTRLinkTrm extends FireblocksBaseCommand { + static summary = 'Create Travel Rule Message' + + static description = 'Creates a new travel rule message with IVMS101-compliant PII data. Encrypts sensitive originator and beneficiary information before sending to partner.\n\nOperation ID: createTRLinkTrm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/createTRLinkTrm' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateTRLinkTrm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/delete-tr-link-customer.ts b/src/commands/trlink/delete-tr-link-customer.ts new file mode 100644 index 0000000..d9436f7 --- /dev/null +++ b/src/commands/trlink/delete-tr-link-customer.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteTRLinkCustomer extends FireblocksBaseCommand { + static summary = 'Delete customer' + + static description = 'Deletes a customer and all associated integrations. This action cannot be undone.\n\nOperation ID: deleteTRLinkCustomer\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/deleteTRLinkCustomer' + + static enableJsonFlag = false + + static flags = { + 'customer-id': Flags.string({ + description: 'Customer unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/screening/trlink/customers/{customerId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteTRLinkCustomer) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerId'] = String(flags['customer-id']) + + + await this.confirmOrAbort('DELETE', '/v1/screening/trlink/customers/{customerId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/screening/trlink/customers/{customerId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/disconnect-tr-link-integration.ts b/src/commands/trlink/disconnect-tr-link-integration.ts new file mode 100644 index 0000000..0a42ce6 --- /dev/null +++ b/src/commands/trlink/disconnect-tr-link-integration.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DisconnectTRLinkIntegration extends FireblocksBaseCommand { + static summary = 'Disconnect customer integration' + + static description = 'Disconnects the integration for the authenticated workspace (tenant): removes stored credentials and deletes this tenant\'s integration record. The operation is scoped to the caller\'s tenant; it does not remove partner-side state for other workspaces that reuse the same logical customer integration. The record cannot be recovered after delete.\n\nOperation ID: disconnectTRLinkIntegration\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/disconnectTRLinkIntegration' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DisconnectTRLinkIntegration) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + + await this.confirmOrAbort('DELETE', '/v1/screening/trlink/customers/integration/{customerIntegrationId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-customer-by-id.ts b/src/commands/trlink/get-tr-link-customer-by-id.ts new file mode 100644 index 0000000..4b20a7c --- /dev/null +++ b/src/commands/trlink/get-tr-link-customer-by-id.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkCustomerById extends FireblocksBaseCommand { + static summary = 'Get customer by ID' + + static description = 'Retrieves detailed information about a specific customer by their unique identifier.\n\nOperation ID: getTRLinkCustomerById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkCustomerById' + + static enableJsonFlag = false + + static flags = { + 'customer-id': Flags.string({ + description: 'Customer unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/{customerId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkCustomerById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerId'] = String(flags['customer-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/{customerId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-customer-integration-by-id.ts b/src/commands/trlink/get-tr-link-customer-integration-by-id.ts new file mode 100644 index 0000000..87866db --- /dev/null +++ b/src/commands/trlink/get-tr-link-customer-integration-by-id.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkCustomerIntegrationById extends FireblocksBaseCommand { + static summary = 'Get customer integration by ID' + + static description = 'Retrieves detailed information about a specific customer integration.\n\nOperation ID: getTRLinkCustomerIntegrationById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkCustomerIntegrationById' + + static enableJsonFlag = false + + static flags = { + 'customer-id': Flags.string({ + description: 'Customer unique identifier', + required: true, + }), + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/{customerId}/integrations/{customerIntegrationId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkCustomerIntegrationById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerId'] = String(flags['customer-id']) + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/{customerId}/integrations/{customerIntegrationId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-customer-integrations.ts b/src/commands/trlink/get-tr-link-customer-integrations.ts new file mode 100644 index 0000000..db3502e --- /dev/null +++ b/src/commands/trlink/get-tr-link-customer-integrations.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkCustomerIntegrations extends FireblocksBaseCommand { + static summary = 'Get customer integrations' + + static description = 'Retrieves all TRSupport integrations for a specific customer. Returns a list of partner integrations configured for Travel Rule compliance.\n\nOperation ID: getTRLinkCustomerIntegrations\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkCustomerIntegrations' + + static enableJsonFlag = false + + static flags = { + 'customer-id': Flags.string({ + description: 'Customer unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/{customerId}/integrations' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkCustomerIntegrations) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerId'] = String(flags['customer-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/{customerId}/integrations', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-customers.ts b/src/commands/trlink/get-tr-link-customers.ts new file mode 100644 index 0000000..dad6ad5 --- /dev/null +++ b/src/commands/trlink/get-tr-link-customers.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkCustomers extends FireblocksBaseCommand { + static summary = 'Get all customers' + + static description = 'Retrieves all customers associated with the authenticated tenant. Returns a list of legal entities configured for Travel Rule compliance.\n\nOperation ID: getTRLinkCustomers\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkCustomers' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkCustomers) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-integration-public-key.ts b/src/commands/trlink/get-tr-link-integration-public-key.ts new file mode 100644 index 0000000..d67d85e --- /dev/null +++ b/src/commands/trlink/get-tr-link-integration-public-key.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkIntegrationPublicKey extends FireblocksBaseCommand { + static summary = 'Get public key for PII encryption' + + static description = 'Retrieves the partner\'s public key in JWK format for encrypting PII data in Travel Rule Messages. Use this key to encrypt sensitive originator and beneficiary information before sending Travel Rule messages.\n\nOperation ID: getTRLinkIntegrationPublicKey\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkIntegrationPublicKey' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/public_key' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkIntegrationPublicKey) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/public_key', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-partners.ts b/src/commands/trlink/get-tr-link-partners.ts new file mode 100644 index 0000000..507526f --- /dev/null +++ b/src/commands/trlink/get-tr-link-partners.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkPartners extends FireblocksBaseCommand { + static summary = 'List available TRSupport partners' + + static description = 'Retrieves a list of all available Travel Rule Support integration partners. Partners provide Travel Rule compliance services such as VASP discovery, TRM exchange, and PII encryption.\n\nOperation ID: getTRLinkPartners\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkPartners' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/partners' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkPartners) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/partners', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-policy.ts b/src/commands/trlink/get-tr-link-policy.ts new file mode 100644 index 0000000..5046ad5 --- /dev/null +++ b/src/commands/trlink/get-tr-link-policy.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkPolicy extends FireblocksBaseCommand { + static summary = 'Get TRLink policy' + + static description = 'Retrieves the complete TRSupport policy for the authenticated tenant, including pre-screening rules, post-screening rules, and missing TRM rules. Pre-screening rules determine whether transactions should be screened. Post-screening rules determine actions based on screening results. Missing TRM rules handle cases when screening data is unavailable.\n\nOperation ID: getTRLinkPolicy\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkPolicy' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/policy' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkPolicy) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/policy', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-supported-asset.ts b/src/commands/trlink/get-tr-link-supported-asset.ts new file mode 100644 index 0000000..bb34550 --- /dev/null +++ b/src/commands/trlink/get-tr-link-supported-asset.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkSupportedAsset extends FireblocksBaseCommand { + static summary = 'Get supported asset by ID' + + static description = 'Retrieves detailed information about a specific asset by its Fireblocks asset ID. Returns the transformed Fireblocks asset data, raw partner response, and support status.\n\nOperation ID: getTRLinkSupportedAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkSupportedAsset' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'asset-id': Flags.string({ + description: 'Fireblocks asset ID', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/assets/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkSupportedAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/assets/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-trm-by-id.ts b/src/commands/trlink/get-tr-link-trm-by-id.ts new file mode 100644 index 0000000..be6d34a --- /dev/null +++ b/src/commands/trlink/get-tr-link-trm-by-id.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkTrmById extends FireblocksBaseCommand { + static summary = 'Get TRM by ID' + + static description = 'Retrieves a Travel Rule Message by its unique identifier from the partner provider. Returns full TRM details including status, IVMS101 data, and transaction information.\n\nOperation ID: getTRLinkTrmById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkTrmById' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'trm-id': Flags.string({ + description: 'Travel Rule Message unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkTrmById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + pathParams['trmId'] = String(flags['trm-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/get-tr-link-vasp-by-id.ts b/src/commands/trlink/get-tr-link-vasp-by-id.ts new file mode 100644 index 0000000..5b83abc --- /dev/null +++ b/src/commands/trlink/get-tr-link-vasp-by-id.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetTRLinkVaspById extends FireblocksBaseCommand { + static summary = 'Get VASP by ID' + + static description = 'Retrieves detailed information about a specific VASP by its unique identifier. Returns VASP details including public key if available.\n\nOperation ID: getTRLinkVaspById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/getTRLinkVaspById' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'vasp-id': Flags.string({ + description: 'VASP unique identifier (DID format)', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/vasps/{vaspId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetTRLinkVaspById) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + pathParams['vaspId'] = String(flags['vasp-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/vasps/{vaspId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/list-tr-link-supported-assets.ts b/src/commands/trlink/list-tr-link-supported-assets.ts new file mode 100644 index 0000000..2c2af86 --- /dev/null +++ b/src/commands/trlink/list-tr-link-supported-assets.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListTRLinkSupportedAssets extends FireblocksBaseCommand { + static summary = 'List supported assets' + + static description = 'Retrieves a paginated list of assets supported by the partner integration. Includes a flag indicating whether the partner can handle assets not explicitly listed. Supports cursor-based pagination.\n\nOperation ID: listTRLinkSupportedAssets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/listTRLinkSupportedAssets' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'page-size': Flags.integer({ + description: 'Number of results per page (max 100)', + default: 100, + }), + 'page-cursor': Flags.string({ + description: 'Cursor for pagination (from previous response)', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListTRLinkSupportedAssets) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + const queryParams: Record = {} + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/assets', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/list-tr-link-vasps.ts b/src/commands/trlink/list-tr-link-vasps.ts new file mode 100644 index 0000000..919b533 --- /dev/null +++ b/src/commands/trlink/list-tr-link-vasps.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ListTRLinkVasps extends FireblocksBaseCommand { + static summary = 'List VASPs' + + static description = 'Retrieves a paginated list of VASPs (Virtual Asset Service Providers) available through the partner integration. Supports cursor-based pagination.\n\nOperation ID: listTRLinkVasps\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/listTRLinkVasps' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'page-size': Flags.integer({ + description: 'Number of results per page (max 100)', + default: 100, + }), + 'page-cursor': Flags.string({ + description: 'Cursor for pagination (from previous response)', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/vasps' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ListTRLinkVasps) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + const queryParams: Record = {} + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/vasps', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/redirect-tr-link-trm.ts b/src/commands/trlink/redirect-tr-link-trm.ts new file mode 100644 index 0000000..d10c3f9 --- /dev/null +++ b/src/commands/trlink/redirect-tr-link-trm.ts @@ -0,0 +1,75 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class RedirectTRLinkTrm extends FireblocksBaseCommand { + static summary = 'Redirect Travel Rule Message' + + static description = 'Redirects a Travel Rule Message to a subsidiary VASP. This operation requires the partner to support nested VASPs functionality.\n\nOperation ID: redirectTRLinkTrm\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/redirectTRLinkTrm' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'trm-id': Flags.string({ + description: 'Travel Rule Message unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/redirect' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(RedirectTRLinkTrm) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + pathParams['trmId'] = String(flags['trm-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/redirect') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/trm/{trmId}/redirect', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/set-tr-link-destination-travel-rule-message-id.ts b/src/commands/trlink/set-tr-link-destination-travel-rule-message-id.ts new file mode 100644 index 0000000..b52b56f --- /dev/null +++ b/src/commands/trlink/set-tr-link-destination-travel-rule-message-id.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetTRLinkDestinationTravelRuleMessageId extends FireblocksBaseCommand { + static summary = 'Set destination travel rule message ID' + + static description = 'Associates a Travel Rule Message ID with a specific destination in a multi-destination Fireblocks transaction. Matches destinations by amount and peer path.\n\nOperation ID: setTRLinkDestinationTravelRuleMessageId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/setTRLinkDestinationTravelRuleMessageId' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'Fireblocks transaction unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/transaction/{txId}/destination/travel_rule_message_id' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetTRLinkDestinationTravelRuleMessageId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/transaction/{txId}/destination/travel_rule_message_id') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/transaction/{txId}/destination/travel_rule_message_id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/set-tr-link-transaction-travel-rule-message-id.ts b/src/commands/trlink/set-tr-link-transaction-travel-rule-message-id.ts new file mode 100644 index 0000000..fa98a35 --- /dev/null +++ b/src/commands/trlink/set-tr-link-transaction-travel-rule-message-id.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetTRLinkTransactionTravelRuleMessageId extends FireblocksBaseCommand { + static summary = 'Set transaction travel rule message ID' + + static description = 'Associates a Travel Rule Message ID with a Fireblocks transaction. This links the TRM compliance data to the blockchain transaction.\n\nOperation ID: setTRLinkTransactionTravelRuleMessageId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/setTRLinkTransactionTravelRuleMessageId' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'Fireblocks transaction unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/transaction/{txId}/travel_rule_message_id' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetTRLinkTransactionTravelRuleMessageId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/transaction/{txId}/travel_rule_message_id') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/transaction/{txId}/travel_rule_message_id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/test-tr-link-integration-connection.ts b/src/commands/trlink/test-tr-link-integration-connection.ts new file mode 100644 index 0000000..d6da54e --- /dev/null +++ b/src/commands/trlink/test-tr-link-integration-connection.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class TestTRLinkIntegrationConnection extends FireblocksBaseCommand { + static summary = 'Test connection' + + static description = 'Tests the connection to a customer integration by validating stored credentials and attempting communication with the Travel Rule partner. Returns connection status and any error messages.\n\nOperation ID: testTRLinkIntegrationConnection\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/testTRLinkIntegrationConnection' + + static enableJsonFlag = false + + static flags = { + 'customer-integration-id': Flags.string({ + description: 'Customer integration unique identifier', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/screening/trlink/customers/integration/{customerIntegrationId}/test_connection' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(TestTRLinkIntegrationConnection) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['customerIntegrationId'] = String(flags['customer-integration-id']) + + + await this.confirmOrAbort('POST', '/v1/screening/trlink/customers/integration/{customerIntegrationId}/test_connection') + + const result = await this.makeRequest( + 'POST', + '/v1/screening/trlink/customers/integration/{customerIntegrationId}/test_connection', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/trlink/update-tr-link-customer.ts b/src/commands/trlink/update-tr-link-customer.ts new file mode 100644 index 0000000..08c8496 --- /dev/null +++ b/src/commands/trlink/update-tr-link-customer.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateTRLinkCustomer extends FireblocksBaseCommand { + static summary = 'Update customer' + + static description = 'Updates an existing customer\'s information. All fields are optional - only provided fields will be updated.\n\nOperation ID: updateTRLinkCustomer\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/TRLink/updateTRLinkCustomer' + + static enableJsonFlag = false + + static flags = { + 'customer-id': Flags.string({ + description: 'Customer unique identifier', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/screening/trlink/customers/{customerId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateTRLinkCustomer) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['customerId'] = String(flags['customer-id']) + + + await this.confirmOrAbort('PUT', '/v1/screening/trlink/customers/{customerId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/screening/trlink/customers/{customerId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/user-groups/create-user-group.ts b/src/commands/user-groups/create-user-group.ts new file mode 100644 index 0000000..777b950 --- /dev/null +++ b/src/commands/user-groups/create-user-group.ts @@ -0,0 +1,65 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateUserGroup extends FireblocksBaseCommand { + static summary = 'Create user group' + + static description = 'Create a new user group. Users with the Viewer role cannot be added to groups.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: createUserGroup\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/User%20groups/createUserGroup' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/management/user_groups' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateUserGroup) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/management/user_groups') + + const result = await this.makeRequest( + 'POST', + '/v1/management/user_groups', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/user-groups/delete-user-group.ts b/src/commands/user-groups/delete-user-group.ts new file mode 100644 index 0000000..32b0d2a --- /dev/null +++ b/src/commands/user-groups/delete-user-group.ts @@ -0,0 +1,52 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteUserGroup extends FireblocksBaseCommand { + static summary = 'Delete user group' + + static description = 'Delete a user group by ID.\n\n**Note**:\n- This endpoint is now in Beta, disabled for general availability at this time.\n- Please note that this endpoint is available only for API keys with Admin permissions.\n\nOperation ID: deleteUserGroup\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/User%20groups/deleteUserGroup' + + static enableJsonFlag = false + + static flags = { + 'group-id': Flags.string({ + description: 'The ID of the user group', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/management/user_groups/{groupId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteUserGroup) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['groupId'] = String(flags['group-id']) + + + await this.confirmOrAbort('DELETE', '/v1/management/user_groups/{groupId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/management/user_groups/{groupId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/user-groups/get-user-group.ts b/src/commands/user-groups/get-user-group.ts new file mode 100644 index 0000000..9ecf44c --- /dev/null +++ b/src/commands/user-groups/get-user-group.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetUserGroup extends FireblocksBaseCommand { + static summary = 'Get user group' + + static description = 'Get a user group by ID.\n\n**Note**:\n- This endpoint is now in Beta, disabled for general availability at this time.\n- Please note that this endpoint is available only for API keys with Admin permissions.\n\nOperation ID: getUserGroup\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/User%20groups/getUserGroup' + + static enableJsonFlag = false + + static flags = { + 'group-id': Flags.string({ + description: 'The ID of the user group', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/management/user_groups/{groupId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetUserGroup) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['groupId'] = String(flags['group-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/management/user_groups/{groupId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/user-groups/get-user-groups.ts b/src/commands/user-groups/get-user-groups.ts new file mode 100644 index 0000000..f1522d1 --- /dev/null +++ b/src/commands/user-groups/get-user-groups.ts @@ -0,0 +1,43 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetUserGroups extends FireblocksBaseCommand { + static summary = 'List user groups' + + static description = 'Get all user groups in your workspace\n\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getUserGroups\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/User%20groups/getUserGroups' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/management/user_groups' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetUserGroups) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/management/user_groups', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/user-groups/update-user-group.ts b/src/commands/user-groups/update-user-group.ts new file mode 100644 index 0000000..973591b --- /dev/null +++ b/src/commands/user-groups/update-user-group.ts @@ -0,0 +1,72 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateUserGroup extends FireblocksBaseCommand { + static summary = 'Update user group' + + static description = 'Update a user group by ID.\n\n**Note**:\n- This endpoint is now in Beta, disabled for general availability at this time.\n- Please note that this endpoint is available only for API keys with Admin permissions.\n\nOperation ID: updateUserGroup\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/User%20groups/updateUserGroup' + + static enableJsonFlag = false + + static flags = { + 'group-id': Flags.string({ + description: 'The ID of the user group', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/management/user_groups/{groupId}' + static isBeta = true + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateUserGroup) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['groupId'] = String(flags['group-id']) + + + await this.confirmOrAbort('PUT', '/v1/management/user_groups/{groupId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/management/user_groups/{groupId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/users/get-users.ts b/src/commands/users/get-users.ts new file mode 100644 index 0000000..0634631 --- /dev/null +++ b/src/commands/users/get-users.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetUsers extends FireblocksBaseCommand { + static summary = 'List users' + + static description = 'List all users for the workspace.\n\nPlease note that this endpoint is available only for API keys with Admin permissions.\n\nOperation ID: getUsers\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Users/getUsers' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/users' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetUsers) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/users', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/activate-asset-for-vault-account.ts b/src/commands/vaults/activate-asset-for-vault-account.ts new file mode 100644 index 0000000..90b9dfc --- /dev/null +++ b/src/commands/vaults/activate-asset-for-vault-account.ts @@ -0,0 +1,66 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ActivateAssetForVaultAccount extends FireblocksBaseCommand { + static summary = 'Activate a wallet in a vault account' + + static description = 'Initiates activation for a wallet in a vault account. \nActivation is required for tokens that need an on-chain transaction for creation (XLM tokens, SOL tokens etc).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: activateAssetForVaultAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/activateAssetForVaultAccount' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to return, or \'default\' for the default vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'blockchain-wallet-type': Flags.string({ + description: 'Optional immutable blockchain wallet type to store per tenant+vault', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/activate' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ActivateAssetForVaultAccount) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + const queryParams: Record = {} + if (flags['blockchain-wallet-type'] !== undefined && flags['blockchain-wallet-type'] !== null) { + queryParams['blockchainWalletType'] = String(flags['blockchain-wallet-type']) + } + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/{assetId}/activate') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/activate', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/attach-or-detach-tags-from-vault-accounts.ts b/src/commands/vaults/attach-or-detach-tags-from-vault-accounts.ts new file mode 100644 index 0000000..80f9310 --- /dev/null +++ b/src/commands/vaults/attach-or-detach-tags-from-vault-accounts.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class AttachOrDetachTagsFromVaultAccounts extends FireblocksBaseCommand { + static summary = 'Attach or detach tags from vault accounts' + + static description = 'Attach or detach one or more tags from the requested vault accounts.\nEndpoint Permission: For protected tags: Owner, Admin, Non-Signing Admin. For non protected tags: Owner, Admin, Non-Signing Admin, Signer, Editor, Approver.\n\nOperation ID: attachOrDetachTagsFromVaultAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/attachOrDetachTagsFromVaultAccounts' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/attached_tags' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(AttachOrDetachTagsFromVaultAccounts) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/attached_tags') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/attached_tags', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/create-legacy-address.ts b/src/commands/vaults/create-legacy-address.ts new file mode 100644 index 0000000..b37e9fa --- /dev/null +++ b/src/commands/vaults/create-legacy-address.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateLegacyAddress extends FireblocksBaseCommand { + static summary = 'Convert a segwit address to legacy format' + + static description = 'Converts an existing segwit address to the legacy format.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createLegacyAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/createLegacyAddress' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'address-id': Flags.string({ + description: 'The segwit address to translate', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/create_legacy' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateLegacyAddress) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + pathParams['addressId'] = String(flags['address-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/create_legacy') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/create_legacy', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/create-multiple-accounts.ts b/src/commands/vaults/create-multiple-accounts.ts new file mode 100644 index 0000000..6f5aac3 --- /dev/null +++ b/src/commands/vaults/create-multiple-accounts.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateMultipleAccounts extends FireblocksBaseCommand { + static summary = 'Bulk creation of new vault accounts' + + static description = 'Create multiple vault accounts by running an async job. \n- The HBAR, TON, SUI, TERRA, ALGO, and DOT blockchains are not supported.\n- These endpoints are currently in beta and might be subject to changes.\n- Limited to a maximum of 10,000 accounts per operation.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createMultipleAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/createMultipleAccounts' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/bulk' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateMultipleAccounts) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/bulk') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/bulk', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/create-multiple-deposit-addresses.ts b/src/commands/vaults/create-multiple-deposit-addresses.ts new file mode 100644 index 0000000..57cf64f --- /dev/null +++ b/src/commands/vaults/create-multiple-deposit-addresses.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateMultipleDepositAddresses extends FireblocksBaseCommand { + static summary = 'Bulk creation of new deposit addresses' + + static description = '**For UTXO blockchains only.**\n\nCreate multiple deposit addresses by running an async job.\n- The target Vault account should already have a UTXO asset wallet with a permanent address.\n- Limited to a maximum of 10,000 addresses per operation. Use multiple operations for the same Vault account/permanent address if needed.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin.\n\nOperation ID: createMultipleDepositAddresses\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/createMultipleDepositAddresses' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/addresses/bulk' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateMultipleDepositAddresses) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/addresses/bulk') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/addresses/bulk', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/create-vault-account-asset-address.ts b/src/commands/vaults/create-vault-account-asset-address.ts new file mode 100644 index 0000000..7f7fa2b --- /dev/null +++ b/src/commands/vaults/create-vault-account-asset-address.ts @@ -0,0 +1,74 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateVaultAccountAssetAddress extends FireblocksBaseCommand { + static summary = 'Create new asset deposit address' + + static description = 'Creates a new deposit address for an asset of a vault account.\nShould be used for UTXO or Tag/Memo based assets ONLY.\n\nRequests with account based assets will fail.\n\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: createVaultAccountAssetAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/createVaultAccountAssetAddress' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to return', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateVaultAccountAssetAddress) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/create-vault-account-asset.ts b/src/commands/vaults/create-vault-account-asset.ts new file mode 100644 index 0000000..d74fdd8 --- /dev/null +++ b/src/commands/vaults/create-vault-account-asset.ts @@ -0,0 +1,82 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateVaultAccountAsset extends FireblocksBaseCommand { + static summary = 'Create a new vault wallet' + + static description = 'Creates a wallet for a specific asset in a vault account.\nLearn more about Fireblocks Vault Wallets in the following [guide](https://developers.fireblocks.com/reference/create-vault-wallet).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createVaultAccountAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/createVaultAccountAsset' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to return, or \'default\' for the default vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'blockchain-wallet-type': Flags.string({ + description: 'Optional immutable blockchain wallet type to store per tenant+vault', + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateVaultAccountAsset) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + const queryParams: Record = {} + if (flags['blockchain-wallet-type'] !== undefined && flags['blockchain-wallet-type'] !== null) { + queryParams['blockchainWalletType'] = String(flags['blockchain-wallet-type']) + } + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/{assetId}') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/{assetId}', + { + body, + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/create-vault-account.ts b/src/commands/vaults/create-vault-account.ts new file mode 100644 index 0000000..4883dc5 --- /dev/null +++ b/src/commands/vaults/create-vault-account.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateVaultAccount extends FireblocksBaseCommand { + static summary = 'Create a new vault account' + + static description = 'Creates a new vault account with the requested name.\n**Note: ** Vault account names should consist of ASCII characters only.\nLearn more about Fireblocks Vault Accounts in the following [guide](https://developers.fireblocks.com/reference/create-vault-account).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: createVaultAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/createVaultAccount' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateVaultAccount) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/vault/accounts') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-asset-wallets.ts b/src/commands/vaults/get-asset-wallets.ts new file mode 100644 index 0000000..c5d1f2a --- /dev/null +++ b/src/commands/vaults/get-asset-wallets.ts @@ -0,0 +1,82 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetAssetWallets extends FireblocksBaseCommand { + static summary = 'Get vault wallets (Paginated)' + + static description = 'Get all vault wallets of the vault accounts in your workspace. \nA vault wallet is an asset in a vault account. \n\nThis method allows fast traversal of all account balances.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getAssetWallets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getAssetWallets' + + static enableJsonFlag = false + + static flags = { + 'total-amount-larger-than': Flags.string({ + description: 'When specified, only vault wallets with total balance greater than this amount are returned.', + }), + 'asset-id': Flags.string({ + description: 'When specified, only vault wallets with the specified ID are returned.', + }), + 'order-by': Flags.string({ + description: 'The orderBy parameter', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'before': Flags.string({ + description: 'Fetches the next paginated response before this element. \nThis element is a cursor and is returned at the response of the previous page.\n', + }), + 'after': Flags.string({ + description: 'Fetches the next paginated response after this element. This element is a cursor and is returned at the response of the previous page.', + }), + 'limit': Flags.string({ + description: 'The maximum number of vault wallets in a single response. \n\nThe default is 200 and the maximum is 1000.\n', + default: '200', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/asset_wallets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetAssetWallets) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['total-amount-larger-than'] !== undefined && flags['total-amount-larger-than'] !== null) { + queryParams['totalAmountLargerThan'] = String(flags['total-amount-larger-than']) + } + if (flags['asset-id'] !== undefined && flags['asset-id'] !== null) { + queryParams['assetId'] = String(flags['asset-id']) + } + if (flags['order-by'] !== undefined && flags['order-by'] !== null) { + queryParams['orderBy'] = String(flags['order-by']) + } + if (flags['before'] !== undefined && flags['before'] !== null) { + queryParams['before'] = String(flags['before']) + } + if (flags['after'] !== undefined && flags['after'] !== null) { + queryParams['after'] = String(flags['after']) + } + if (flags['limit'] !== undefined && flags['limit'] !== null) { + queryParams['limit'] = String(flags['limit']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/asset_wallets', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-create-multiple-deposit-addresses-job-status.ts b/src/commands/vaults/get-create-multiple-deposit-addresses-job-status.ts new file mode 100644 index 0000000..24fb615 --- /dev/null +++ b/src/commands/vaults/get-create-multiple-deposit-addresses-job-status.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetCreateMultipleDepositAddressesJobStatus extends FireblocksBaseCommand { + static summary = 'Get the job status of the bulk deposit address creation' + + static description = 'Returns the current status of (or an error for) the specified deposit addresss bulk creation job.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, and Viewer.\n\nOperation ID: getCreateMultipleDepositAddressesJobStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getCreateMultipleDepositAddressesJobStatus' + + static enableJsonFlag = false + + static flags = { + 'job-id': Flags.string({ + description: 'The ID of the job to create addresses', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/addresses/bulk/{jobId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetCreateMultipleDepositAddressesJobStatus) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['jobId'] = String(flags['job-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/addresses/bulk/{jobId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-create-multiple-vault-accounts-job-status.ts b/src/commands/vaults/get-create-multiple-vault-accounts-job-status.ts new file mode 100644 index 0000000..1943392 --- /dev/null +++ b/src/commands/vaults/get-create-multiple-vault-accounts-job-status.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetCreateMultipleVaultAccountsJobStatus extends FireblocksBaseCommand { + static summary = 'Get job status of bulk creation of new vault accounts' + + static description = 'Returns the current status of (or error for) the specified vault account bulk creation job.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getCreateMultipleVaultAccountsJobStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getCreateMultipleVaultAccountsJobStatus' + + static enableJsonFlag = false + + static flags = { + 'job-id': Flags.string({ + description: 'The ID of the job to create addresses', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/bulk/{jobId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetCreateMultipleVaultAccountsJobStatus) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['jobId'] = String(flags['job-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/bulk/{jobId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-max-bip-index-used.ts b/src/commands/vaults/get-max-bip-index-used.ts new file mode 100644 index 0000000..ee5f8f3 --- /dev/null +++ b/src/commands/vaults/get-max-bip-index-used.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetMaxBipIndexUsed extends FireblocksBaseCommand { + static summary = 'Get maximum BIP44 index used' + + static description = 'Retrieves the maximum BIP44 address index and change address index used for a specific asset in a vault account (BIP44 standard).\n\nOperation ID: getMaxBipIndexUsed\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getMaxBipIndexUsed' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/max_bip44_index_used' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetMaxBipIndexUsed) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/max_bip44_index_used', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-max-spendable-amount.ts b/src/commands/vaults/get-max-spendable-amount.ts new file mode 100644 index 0000000..27f6a92 --- /dev/null +++ b/src/commands/vaults/get-max-spendable-amount.ts @@ -0,0 +1,61 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetMaxSpendableAmount extends FireblocksBaseCommand { + static summary = 'Get max spendable amount in a transaction' + + static description = '**UTXO assets only.**\n\nRetrieve the maximum amount of the specified asset that can be spent in a single transaction from the specified vault account.\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getMaxSpendableAmount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getMaxSpendableAmount' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account, or \'default\' for the default vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'manual-signging': Flags.boolean({ + description: 'False by default. The maximum number of inputs depends if the transaction will be signed by an automated co-signer server or on a mobile device.', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/max_spendable_amount' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetMaxSpendableAmount) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + const queryParams: Record = {} + if (flags['manual-signging'] !== undefined && flags['manual-signging'] !== null) { + queryParams['manualSignging'] = String(flags['manual-signging']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/max_spendable_amount', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-paged-vault-accounts.ts b/src/commands/vaults/get-paged-vault-accounts.ts new file mode 100644 index 0000000..b5a1d6b --- /dev/null +++ b/src/commands/vaults/get-paged-vault-accounts.ts @@ -0,0 +1,112 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPagedVaultAccounts extends FireblocksBaseCommand { + static summary = 'Get vault accounts (Paginated)' + + static description = 'Gets all vault accounts in your workspace. This endpoint returns a limited amount of results with a quick response time.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getPagedVaultAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getPagedVaultAccounts' + + static enableJsonFlag = false + + static flags = { + 'name-prefix': Flags.string({ + description: 'The namePrefix parameter', + }), + 'name-suffix': Flags.string({ + description: 'The nameSuffix parameter', + }), + 'min-amount-threshold': Flags.string({ + description: 'Specifying minAmountThreshold will filter accounts whose total balance is greater than this value; otherwise, it returns all accounts. The amount set in this parameter represents the native asset amount, not its USD value.', + }), + 'asset-id': Flags.string({ + description: 'The assetId parameter', + }), + 'order-by': Flags.string({ + description: 'The orderBy parameter', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'before': Flags.string({ + description: 'The before parameter', + }), + 'after': Flags.string({ + description: 'The after parameter', + }), + 'limit': Flags.string({ + description: 'The limit parameter', + default: '200', + }), + 'tag-ids': Flags.string({ + description: 'DEPRECATED - use includeTagIds instead', + }), + 'include-tag-ids': Flags.string({ + description: 'List of tag IDs to include. Vault accounts with any of these tags will be included', + }), + 'exclude-tag-ids': Flags.string({ + description: 'List of tag IDs to exclude. Vault accounts with any of these tags will be filtered out', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts_paged' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetPagedVaultAccounts) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['name-prefix'] !== undefined && flags['name-prefix'] !== null) { + queryParams['namePrefix'] = String(flags['name-prefix']) + } + if (flags['name-suffix'] !== undefined && flags['name-suffix'] !== null) { + queryParams['nameSuffix'] = String(flags['name-suffix']) + } + if (flags['min-amount-threshold'] !== undefined && flags['min-amount-threshold'] !== null) { + queryParams['minAmountThreshold'] = String(flags['min-amount-threshold']) + } + if (flags['asset-id'] !== undefined && flags['asset-id'] !== null) { + queryParams['assetId'] = String(flags['asset-id']) + } + if (flags['order-by'] !== undefined && flags['order-by'] !== null) { + queryParams['orderBy'] = String(flags['order-by']) + } + if (flags['before'] !== undefined && flags['before'] !== null) { + queryParams['before'] = String(flags['before']) + } + if (flags['after'] !== undefined && flags['after'] !== null) { + queryParams['after'] = String(flags['after']) + } + if (flags['limit'] !== undefined && flags['limit'] !== null) { + queryParams['limit'] = String(flags['limit']) + } + if (flags['tag-ids'] !== undefined && flags['tag-ids'] !== null) { + queryParams['tagIds'] = String(flags['tag-ids']) + } + if (flags['include-tag-ids'] !== undefined && flags['include-tag-ids'] !== null) { + queryParams['includeTagIds'] = String(flags['include-tag-ids']) + } + if (flags['exclude-tag-ids'] !== undefined && flags['exclude-tag-ids'] !== null) { + queryParams['excludeTagIds'] = String(flags['exclude-tag-ids']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts_paged', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-public-key-info-for-address.ts b/src/commands/vaults/get-public-key-info-for-address.ts new file mode 100644 index 0000000..8b6a659 --- /dev/null +++ b/src/commands/vaults/get-public-key-info-for-address.ts @@ -0,0 +1,71 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPublicKeyInfoForAddress extends FireblocksBaseCommand { + static summary = 'Get an asset\'s public key' + + static description = 'Get the public key information for a specific asset in a vault account.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getPublicKeyInfoForAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getPublicKeyInfoForAddress' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The vaultAccountId parameter', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The assetId parameter', + required: true, + }), + 'change': Flags.string({ + description: 'The change parameter', + required: true, + }), + 'address-index': Flags.string({ + description: 'The addressIndex parameter', + required: true, + }), + 'compressed': Flags.boolean({ + description: 'The compressed parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/{change}/{addressIndex}/public_key_info' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetPublicKeyInfoForAddress) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + pathParams['change'] = String(flags['change']) + pathParams['addressIndex'] = String(flags['address-index']) + + const queryParams: Record = {} + if (flags['compressed'] !== undefined && flags['compressed'] !== null) { + queryParams['compressed'] = String(flags['compressed']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/{change}/{addressIndex}/public_key_info', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-public-key-info.ts b/src/commands/vaults/get-public-key-info.ts new file mode 100644 index 0000000..f4bd98d --- /dev/null +++ b/src/commands/vaults/get-public-key-info.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetPublicKeyInfo extends FireblocksBaseCommand { + static summary = 'Get the public key for a derivation path' + + static description = 'Gets the public key information based on derivation path and signing algorithm.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getPublicKeyInfo\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getPublicKeyInfo' + + static enableJsonFlag = false + + static flags = { + 'derivation-path': Flags.string({ + description: 'The derivationPath parameter', + required: true, + }), + 'algorithm': Flags.string({ + description: 'The algorithm parameter', + required: true, + }), + 'compressed': Flags.boolean({ + description: 'The compressed parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/public_key_info' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetPublicKeyInfo) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['derivation-path'] !== undefined && flags['derivation-path'] !== null) { + queryParams['derivationPath'] = String(flags['derivation-path']) + } + if (flags['algorithm'] !== undefined && flags['algorithm'] !== null) { + queryParams['algorithm'] = String(flags['algorithm']) + } + if (flags['compressed'] !== undefined && flags['compressed'] !== null) { + queryParams['compressed'] = String(flags['compressed']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/public_key_info', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-unspent-inputs.ts b/src/commands/vaults/get-unspent-inputs.ts new file mode 100644 index 0000000..6f161f1 --- /dev/null +++ b/src/commands/vaults/get-unspent-inputs.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetUnspentInputs extends FireblocksBaseCommand { + static summary = 'Get UTXO unspent inputs information' + + static description = 'Returns unspent inputs information of an UTXO asset in a vault account.\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getUnspentInputs\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getUnspentInputs' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/unspent_inputs' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetUnspentInputs) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/unspent_inputs', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-vault-account-asset-addresses-paginated.ts b/src/commands/vaults/get-vault-account-asset-addresses-paginated.ts new file mode 100644 index 0000000..27e61ea --- /dev/null +++ b/src/commands/vaults/get-vault-account-asset-addresses-paginated.ts @@ -0,0 +1,73 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaultAccountAssetAddressesPaginated extends FireblocksBaseCommand { + static summary = 'Get addresses (Paginated)' + + static description = 'Returns a paginated response of the addresses for a given vault account and asset.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getVaultAccountAssetAddressesPaginated\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getVaultAccountAssetAddressesPaginated' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to return', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'limit': Flags.string({ + description: 'The limit parameter', + }), + 'before': Flags.string({ + description: 'The before parameter', + }), + 'after': Flags.string({ + description: 'The after parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses_paginated' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaultAccountAssetAddressesPaginated) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + const queryParams: Record = {} + if (flags['limit'] !== undefined && flags['limit'] !== null) { + queryParams['limit'] = String(flags['limit']) + } + if (flags['before'] !== undefined && flags['before'] !== null) { + queryParams['before'] = String(flags['before']) + } + if (flags['after'] !== undefined && flags['after'] !== null) { + queryParams['after'] = String(flags['after']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses_paginated', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-vault-account-asset-addresses.ts b/src/commands/vaults/get-vault-account-asset-addresses.ts new file mode 100644 index 0000000..3a4e80c --- /dev/null +++ b/src/commands/vaults/get-vault-account-asset-addresses.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaultAccountAssetAddresses extends FireblocksBaseCommand { + static summary = 'Get asset addresses' + + static description = 'DEPRECATED!\n\n- If your application logic or scripts rely on the deprecated endpoint, you should update to account for GET/V1/vault/accounts/{vaultAccountId}/{assetId}/addresses_paginated before Mar 31,2024.\n- All workspaces created after Mar 31,2024. will have it disabled. If it is disabled for your workspace and you attempt to use it, you will receive the following error message: "This endpoint is unavailable.\n- Please use the GET /v1/vault/accounts/{vaultAccountId}/{assetId}/addresses_paginated endpoint to return all the wallet addresses associated with the specified vault account and asset in a paginated list.\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getVaultAccountAssetAddresses\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getVaultAccountAssetAddresses' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to return', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaultAccountAssetAddresses) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-vault-account-asset.ts b/src/commands/vaults/get-vault-account-asset.ts new file mode 100644 index 0000000..7750401 --- /dev/null +++ b/src/commands/vaults/get-vault-account-asset.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaultAccountAsset extends FireblocksBaseCommand { + static summary = 'Get the asset balance for a vault account' + + static description = 'Returns a specific vault wallet balance information for a specific asset.\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor,\n Viewer.\n\nOperation ID: getVaultAccountAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getVaultAccountAsset' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to return', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaultAccountAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-vault-account.ts b/src/commands/vaults/get-vault-account.ts new file mode 100644 index 0000000..5059fb5 --- /dev/null +++ b/src/commands/vaults/get-vault-account.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaultAccount extends FireblocksBaseCommand { + static summary = 'Get a vault account by ID' + + static description = 'Get a vault account by its unique ID.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getVaultAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getVaultAccount' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts/{vaultAccountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaultAccount) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts/{vaultAccountId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-vault-accounts.ts b/src/commands/vaults/get-vault-accounts.ts new file mode 100644 index 0000000..bf0dde9 --- /dev/null +++ b/src/commands/vaults/get-vault-accounts.ts @@ -0,0 +1,67 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaultAccounts extends FireblocksBaseCommand { + static summary = 'Get vault accounts' + + static description = 'DEPRECATED - Please use \`/vault/accounts_paged\` endpoint instead.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getVaultAccounts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getVaultAccounts' + + static enableJsonFlag = false + + static flags = { + 'name-prefix': Flags.string({ + description: 'The namePrefix parameter', + }), + 'name-suffix': Flags.string({ + description: 'The nameSuffix parameter', + }), + 'min-amount-threshold': Flags.string({ + description: 'The minAmountThreshold parameter', + }), + 'asset-id': Flags.string({ + description: 'The assetId parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/accounts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaultAccounts) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['name-prefix'] !== undefined && flags['name-prefix'] !== null) { + queryParams['namePrefix'] = String(flags['name-prefix']) + } + if (flags['name-suffix'] !== undefined && flags['name-suffix'] !== null) { + queryParams['nameSuffix'] = String(flags['name-suffix']) + } + if (flags['min-amount-threshold'] !== undefined && flags['min-amount-threshold'] !== null) { + queryParams['minAmountThreshold'] = String(flags['min-amount-threshold']) + } + if (flags['asset-id'] !== undefined && flags['asset-id'] !== null) { + queryParams['assetId'] = String(flags['asset-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/accounts', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-vault-assets.ts b/src/commands/vaults/get-vault-assets.ts new file mode 100644 index 0000000..ed743bd --- /dev/null +++ b/src/commands/vaults/get-vault-assets.ts @@ -0,0 +1,55 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaultAssets extends FireblocksBaseCommand { + static summary = 'Get asset balance for chosen assets' + + static description = 'Gets the assets amount summary for all accounts or filtered accounts.\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getVaultAssets\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getVaultAssets' + + static enableJsonFlag = false + + static flags = { + 'account-name-prefix': Flags.string({ + description: 'The accountNamePrefix parameter', + }), + 'account-name-suffix': Flags.string({ + description: 'The accountNameSuffix parameter', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/assets' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaultAssets) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['account-name-prefix'] !== undefined && flags['account-name-prefix'] !== null) { + queryParams['accountNamePrefix'] = String(flags['account-name-prefix']) + } + if (flags['account-name-suffix'] !== undefined && flags['account-name-suffix'] !== null) { + queryParams['accountNameSuffix'] = String(flags['account-name-suffix']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/vault/assets', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/get-vault-balance-by-asset.ts b/src/commands/vaults/get-vault-balance-by-asset.ts new file mode 100644 index 0000000..dc9294f --- /dev/null +++ b/src/commands/vaults/get-vault-balance-by-asset.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetVaultBalanceByAsset extends FireblocksBaseCommand { + static summary = 'Get vault balance by an asset' + + static description = 'Get the total balance of an asset across all the vault accounts.\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor, Viewer.\n\nOperation ID: getVaultBalanceByAsset\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/getVaultBalanceByAsset' + + static enableJsonFlag = false + + static flags = { + 'asset-id': Flags.string({ + description: 'The assetId parameter', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/vault/assets/{assetId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetVaultBalanceByAsset) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['assetId'] = String(flags['asset-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/vault/assets/{assetId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/hide-vault-account.ts b/src/commands/vaults/hide-vault-account.ts new file mode 100644 index 0000000..c7ae5b0 --- /dev/null +++ b/src/commands/vaults/hide-vault-account.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class HideVaultAccount extends FireblocksBaseCommand { + static summary = 'Hide a vault account in the console' + + static description = 'Hides the requested vault account from the web console view.\nThis operation is required when creating thousands of vault accounts to serve your end-users.\nUsed for preventing the web console to be swamped with too much vault accounts.\nLearn more in the following [guide](https://developers.fireblocks.com/docs/create-direct-custody-wallets#hiding-vault-accounts).\nNOTE: Hiding the vault account from the web console will also hide all the related transactions to/from this vault.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: hideVaultAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/hideVaultAccount' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The vault account to hide', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/hide' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(HideVaultAccount) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/hide') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/hide', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/set-customer-ref-id-for-address.ts b/src/commands/vaults/set-customer-ref-id-for-address.ts new file mode 100644 index 0000000..50baf3a --- /dev/null +++ b/src/commands/vaults/set-customer-ref-id-for-address.ts @@ -0,0 +1,80 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetCustomerRefIdForAddress extends FireblocksBaseCommand { + static summary = 'Assign AML customer reference ID' + + static description = 'Sets an AML/KYT customer reference ID for a specific address.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: setCustomerRefIdForAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/setCustomerRefIdForAddress' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'address-id': Flags.string({ + description: 'The address for which to add a description. For XRP, use
:, for all other assets, use only the address', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/set_customer_ref_id' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetCustomerRefIdForAddress) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + pathParams['addressId'] = String(flags['address-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/set_customer_ref_id') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}/set_customer_ref_id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/set-vault-account-auto-fuel.ts b/src/commands/vaults/set-vault-account-auto-fuel.ts new file mode 100644 index 0000000..f9665a8 --- /dev/null +++ b/src/commands/vaults/set-vault-account-auto-fuel.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetVaultAccountAutoFuel extends FireblocksBaseCommand { + static summary = 'Set auto fueling to on or off' + + static description = 'Toggles the auto fueling property of the vault account to enabled or disabled.\nVault Accounts with \'autoFuel=true\' are monitored and auto fueled by the Fireblocks Gas Station.\nLearn more about the Fireblocks Gas Station in the following [guide](https://developers.fireblocks.com/docs/work-with-gas-station).\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: setVaultAccountAutoFuel\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/setVaultAccountAutoFuel' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The vault account ID', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/set_auto_fuel' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetVaultAccountAutoFuel) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/set_auto_fuel') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/set_auto_fuel', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/set-vault-account-customer-ref-id.ts b/src/commands/vaults/set-vault-account-customer-ref-id.ts new file mode 100644 index 0000000..fe72d7c --- /dev/null +++ b/src/commands/vaults/set-vault-account-customer-ref-id.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class SetVaultAccountCustomerRefId extends FireblocksBaseCommand { + static summary = 'Set an AML/KYT ID for a vault account' + + static description = 'Assigns an AML/KYT customer reference ID for the vault account. Learn more about Fireblocks AML management in the following [guide](https://developers.fireblocks.com/docs/define-aml-policies). Endpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: setVaultAccountCustomerRefId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/setVaultAccountCustomerRefId' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The vault account ID', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/set_customer_ref_id' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(SetVaultAccountCustomerRefId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/set_customer_ref_id') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/set_customer_ref_id', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/unhide-vault-account.ts b/src/commands/vaults/unhide-vault-account.ts new file mode 100644 index 0000000..da5886b --- /dev/null +++ b/src/commands/vaults/unhide-vault-account.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UnhideVaultAccount extends FireblocksBaseCommand { + static summary = 'Unhide a vault account in the console' + + static description = 'Makes a hidden vault account visible in web console view.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: unhideVaultAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/unhideVaultAccount' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The vault account to unhide', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/unhide' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UnhideVaultAccount) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/unhide') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/unhide', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/update-vault-account-asset-address.ts b/src/commands/vaults/update-vault-account-asset-address.ts new file mode 100644 index 0000000..0dfa4a7 --- /dev/null +++ b/src/commands/vaults/update-vault-account-asset-address.ts @@ -0,0 +1,79 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateVaultAccountAssetAddress extends FireblocksBaseCommand { + static summary = 'Update address description' + + static description = 'Updates the description of an existing address of an asset in a vault account.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: updateVaultAccountAssetAddress\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/updateVaultAccountAssetAddress' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'address-id': Flags.string({ + description: 'The address for which to add a description. For XRP, use
:, for all other assets, use only the address', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateVaultAccountAssetAddress) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + pathParams['addressId'] = String(flags['address-id']) + + + await this.confirmOrAbort('PUT', '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/addresses/{addressId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/update-vault-account-asset-balance.ts b/src/commands/vaults/update-vault-account-asset-balance.ts new file mode 100644 index 0000000..96ba361 --- /dev/null +++ b/src/commands/vaults/update-vault-account-asset-balance.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateVaultAccountAssetBalance extends FireblocksBaseCommand { + static summary = 'Refresh asset balance data' + + static description = 'Updates the balance of a specific asset in a vault account.\n\nThis API endpoint is subject to a strict rate limit.\nShould be used by clients in very specific scenarios.\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: updateVaultAccountAssetBalance\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/updateVaultAccountAssetBalance' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to return', + required: true, + }), + 'asset-id': Flags.string({ + description: 'The ID of the asset', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/vault/accounts/{vaultAccountId}/{assetId}/balance' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateVaultAccountAssetBalance) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + pathParams['assetId'] = String(flags['asset-id']) + + + await this.confirmOrAbort('POST', '/v1/vault/accounts/{vaultAccountId}/{assetId}/balance') + + const result = await this.makeRequest( + 'POST', + '/v1/vault/accounts/{vaultAccountId}/{assetId}/balance', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/vaults/update-vault-account.ts b/src/commands/vaults/update-vault-account.ts new file mode 100644 index 0000000..3e4c225 --- /dev/null +++ b/src/commands/vaults/update-vault-account.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateVaultAccount extends FireblocksBaseCommand { + static summary = 'Rename a vault account' + + static description = 'Renames the requested vault account.\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver.\n\nOperation ID: updateVaultAccount\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Vaults/updateVaultAccount' + + static enableJsonFlag = false + + static flags = { + 'vault-account-id': Flags.string({ + description: 'The ID of the vault account to edit', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/vault/accounts/{vaultAccountId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateVaultAccount) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['vaultAccountId'] = String(flags['vault-account-id']) + + + await this.confirmOrAbort('PUT', '/v1/vault/accounts/{vaultAccountId}') + + const result = await this.makeRequest( + 'PUT', + '/v1/vault/accounts/{vaultAccountId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/web3-connections/create.ts b/src/commands/web3-connections/create.ts new file mode 100644 index 0000000..d62c5b0 --- /dev/null +++ b/src/commands/web3-connections/create.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Create extends FireblocksBaseCommand { + static summary = 'Create a new Web3 connection.' + + static description = 'Initiate a new Web3 connection.\n\n* Note: After this succeeds, make a request to \`PUT /v1/connections/wc/{id}\` (below) to approve or reject the new Web3 connection.\n\nOperation ID: create\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Web3%20connections/create' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/connections/wc' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Create) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/connections/wc') + + const result = await this.makeRequest( + 'POST', + '/v1/connections/wc', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/web3-connections/get.ts b/src/commands/web3-connections/get.ts new file mode 100644 index 0000000..0420b9d --- /dev/null +++ b/src/commands/web3-connections/get.ts @@ -0,0 +1,78 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Get extends FireblocksBaseCommand { + static summary = 'List all open Web3 connections.' + + static description = 'Get open Web3 connections.\n\nOperation ID: get\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Web3%20connections/get' + + static enableJsonFlag = false + + static flags = { + 'order': Flags.string({ + description: 'List order; ascending or descending.', + default: 'ASC', + options: ['ASC', 'DESC'], + }), + 'filter': Flags.string({ + description: 'Parsed filter object', + }), + 'sort': Flags.string({ + description: 'Property to sort Web3 connections by.', + default: 'createdAt', + options: ['id', 'userId', 'vaultAccountId', 'createdAt', 'feeLevel', 'appUrl', 'appName'], + }), + 'page-size': Flags.string({ + description: 'Amount of results to return in the next page.', + default: '10', + }), + 'next': Flags.string({ + description: 'Cursor to the next page', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/connections' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Get) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['filter'] !== undefined && flags['filter'] !== null) { + queryParams['filter'] = String(flags['filter']) + } + if (flags['sort'] !== undefined && flags['sort'] !== null) { + queryParams['sort'] = String(flags['sort']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['next'] !== undefined && flags['next'] !== null) { + queryParams['next'] = String(flags['next']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/connections', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/web3-connections/remove.ts b/src/commands/web3-connections/remove.ts new file mode 100644 index 0000000..fe8bfd7 --- /dev/null +++ b/src/commands/web3-connections/remove.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Remove extends FireblocksBaseCommand { + static summary = 'Remove an existing Web3 connection.' + + static description = 'Remove a Web3 connection\n\nOperation ID: remove\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Web3%20connections/remove' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The ID of the existing Web3 connection to remove.', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/connections/wc/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Remove) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('DELETE', '/v1/connections/wc/{id}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/connections/wc/{id}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/web3-connections/submit.ts b/src/commands/web3-connections/submit.ts new file mode 100644 index 0000000..14c7c5f --- /dev/null +++ b/src/commands/web3-connections/submit.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class Submit extends FireblocksBaseCommand { + static summary = 'Respond to a pending Web3 connection request.' + + static description = 'Submit a response to *approve* or *reject* an initiated Web3 connection.\n* Note: This call is used to complete your \`POST /v1/connections/wc/\` request.\n\nAfter this succeeds, your new Web3 connection is created and functioning.\n\nOperation ID: submit\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Web3%20connections/submit' + + static enableJsonFlag = false + + static flags = { + 'id': Flags.string({ + description: 'The ID of the initiated Web3 connection to approve.', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PUT' + static path = '/v1/connections/wc/{id}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(Submit) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['id'] = String(flags['id']) + + + await this.confirmOrAbort('PUT', '/v1/connections/wc/{id}') + + const result = await this.makeRequest( + 'PUT', + '/v1/connections/wc/{id}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/create-webhook.ts b/src/commands/webhooks-v2/create-webhook.ts new file mode 100644 index 0000000..25d774c --- /dev/null +++ b/src/commands/webhooks-v2/create-webhook.ts @@ -0,0 +1,63 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class CreateWebhook extends FireblocksBaseCommand { + static summary = 'Create a new webhook' + + static description = 'Creates a new webhook, which will be triggered on the specified events\n\n**Endpoint Permissions:** Owner, Admin, Non-Signing Admin.\n\nOperation ID: createWebhook\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/createWebhook' + + static enableJsonFlag = false + + static flags = { + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/webhooks' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(CreateWebhook) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/webhooks') + + const result = await this.makeRequest( + 'POST', + '/v1/webhooks', + { + body, + headers, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/delete-webhook.ts b/src/commands/webhooks-v2/delete-webhook.ts new file mode 100644 index 0000000..4f1435b --- /dev/null +++ b/src/commands/webhooks-v2/delete-webhook.ts @@ -0,0 +1,50 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class DeleteWebhook extends FireblocksBaseCommand { + static summary = 'Delete webhook' + + static description = 'Delete a webhook by its id\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin.\n\nOperation ID: deleteWebhook\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/deleteWebhook' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The unique identifier of the webhook', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'DELETE' + static path = '/v1/webhooks/{webhookId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(DeleteWebhook) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + + + await this.confirmOrAbort('DELETE', '/v1/webhooks/{webhookId}') + + const result = await this.makeRequest( + 'DELETE', + '/v1/webhooks/{webhookId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/get-metrics.ts b/src/commands/webhooks-v2/get-metrics.ts new file mode 100644 index 0000000..d9840bd --- /dev/null +++ b/src/commands/webhooks-v2/get-metrics.ts @@ -0,0 +1,54 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetMetrics extends FireblocksBaseCommand { + static summary = 'Get webhook metrics' + + static description = 'Get webhook metrics by webhook id and metric name\n\nOperation ID: getMetrics\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/getMetrics' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The webhookId parameter', + required: true, + }), + 'metric-name': Flags.string({ + description: 'Name of the metric to retrieve', + required: true, + options: ['LAST_ACTIVE_HOUR_ERROR_RATE'], + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/webhooks/{webhookId}/metrics/{metricName}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetMetrics) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + pathParams['metricName'] = String(flags['metric-name']) + + + const result = await this.makeRequest( + 'GET', + '/v1/webhooks/{webhookId}/metrics/{metricName}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/get-notification-attempts.ts b/src/commands/webhooks-v2/get-notification-attempts.ts new file mode 100644 index 0000000..227fdef --- /dev/null +++ b/src/commands/webhooks-v2/get-notification-attempts.ts @@ -0,0 +1,68 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNotificationAttempts extends FireblocksBaseCommand { + static summary = 'Get notification attempts' + + static description = 'Get notification attempts by notification id\n\nOperation ID: getNotificationAttempts\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/getNotificationAttempts' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The ID of the webhook to fetch', + required: true, + }), + 'notification-id': Flags.string({ + description: 'The ID of the notification to fetch', + required: true, + }), + 'page-cursor': Flags.string({ + description: 'Cursor of the required page', + }), + 'page-size': Flags.string({ + description: 'Maximum number of items in the page', + default: '10', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/webhooks/{webhookId}/notifications/{notificationId}/attempts' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNotificationAttempts) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + pathParams['notificationId'] = String(flags['notification-id']) + + const queryParams: Record = {} + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/webhooks/{webhookId}/notifications/{notificationId}/attempts', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/get-notification.ts b/src/commands/webhooks-v2/get-notification.ts new file mode 100644 index 0000000..01c0abd --- /dev/null +++ b/src/commands/webhooks-v2/get-notification.ts @@ -0,0 +1,61 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNotification extends FireblocksBaseCommand { + static summary = 'Get notification by id' + + static description = 'Get notification by id\n\nOperation ID: getNotification\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/getNotification' + + static enableJsonFlag = false + + static flags = { + 'include-data': Flags.boolean({ + description: 'Include the data of the notification', + }), + 'webhook-id': Flags.string({ + description: 'The ID of the webhook to fetch', + required: true, + }), + 'notification-id': Flags.string({ + description: 'The ID of the notification to fetch', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/webhooks/{webhookId}/notifications/{notificationId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNotification) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + pathParams['notificationId'] = String(flags['notification-id']) + + const queryParams: Record = {} + if (flags['include-data'] !== undefined && flags['include-data'] !== null) { + queryParams['includeData'] = String(flags['include-data']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/webhooks/{webhookId}/notifications/{notificationId}', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/get-notifications.ts b/src/commands/webhooks-v2/get-notifications.ts new file mode 100644 index 0000000..6a208f6 --- /dev/null +++ b/src/commands/webhooks-v2/get-notifications.ts @@ -0,0 +1,109 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetNotifications extends FireblocksBaseCommand { + static summary = 'Get all notifications by webhook id' + + static description = 'Get all notifications by webhook id (paginated)\n\nOperation ID: getNotifications\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/getNotifications' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The webhookId parameter', + required: true, + }), + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'sort-by': Flags.string({ + description: 'Sort by field', + default: 'updatedAt', + options: ['id', 'createdAt', 'updatedAt', 'status', 'eventType', 'resourceId'], + }), + 'page-cursor': Flags.string({ + description: 'Cursor of the required page', + }), + 'page-size': Flags.string({ + description: 'Maximum number of items in the page', + default: '100', + }), + 'start-time': Flags.string({ + description: 'Start time in milliseconds since epoch to filter by notifications created after this time (default 31 days ago)', + }), + 'end-time': Flags.string({ + description: 'End time in milliseconds since epoch to filter by notifications created before this time (default current time)', + }), + 'statuses': Flags.string({ + description: 'List of notification statuses to filter by', + }), + 'events': Flags.string({ + description: 'List of webhook event types to filter by', + }), + 'resource-id': Flags.string({ + description: 'Resource ID to filter by', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/webhooks/{webhookId}/notifications' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetNotifications) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + + const queryParams: Record = {} + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['sort-by'] !== undefined && flags['sort-by'] !== null) { + queryParams['sortBy'] = String(flags['sort-by']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + if (flags['start-time'] !== undefined && flags['start-time'] !== null) { + queryParams['startTime'] = String(flags['start-time']) + } + if (flags['end-time'] !== undefined && flags['end-time'] !== null) { + queryParams['endTime'] = String(flags['end-time']) + } + if (flags['statuses'] !== undefined && flags['statuses'] !== null) { + queryParams['statuses'] = String(flags['statuses']) + } + if (flags['events'] !== undefined && flags['events'] !== null) { + queryParams['events'] = String(flags['events']) + } + if (flags['resource-id'] !== undefined && flags['resource-id'] !== null) { + queryParams['resourceId'] = String(flags['resource-id']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/webhooks/{webhookId}/notifications', + { + headers, + pathParams, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/get-resend-job-status.ts b/src/commands/webhooks-v2/get-resend-job-status.ts new file mode 100644 index 0000000..7d06876 --- /dev/null +++ b/src/commands/webhooks-v2/get-resend-job-status.ts @@ -0,0 +1,53 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetResendJobStatus extends FireblocksBaseCommand { + static summary = 'Get resend job status' + + static description = 'Get the status of a resend job\n\nOperation ID: getResendJobStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/getResendJobStatus' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The ID of the webhook', + required: true, + }), + 'job-id': Flags.string({ + description: 'The ID of the resend job', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/webhooks/{webhookId}/notifications/resend_failed/jobs/{jobId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetResendJobStatus) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + pathParams['jobId'] = String(flags['job-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/webhooks/{webhookId}/notifications/resend_failed/jobs/{jobId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/get-webhook.ts b/src/commands/webhooks-v2/get-webhook.ts new file mode 100644 index 0000000..7cbd30f --- /dev/null +++ b/src/commands/webhooks-v2/get-webhook.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetWebhook extends FireblocksBaseCommand { + static summary = 'Get webhook by id' + + static description = 'Retrieve a webhook by its id\n\nOperation ID: getWebhook\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/getWebhook' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The unique identifier of the webhook', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/webhooks/{webhookId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetWebhook) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/webhooks/{webhookId}', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/get-webhooks.ts b/src/commands/webhooks-v2/get-webhooks.ts new file mode 100644 index 0000000..ebd29a8 --- /dev/null +++ b/src/commands/webhooks-v2/get-webhooks.ts @@ -0,0 +1,64 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetWebhooks extends FireblocksBaseCommand { + static summary = 'Get all webhooks' + + static description = 'Get all webhooks (paginated).\n\nOperation ID: getWebhooks\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/getWebhooks' + + static enableJsonFlag = false + + static flags = { + 'order': Flags.string({ + description: 'ASC / DESC ordering (default DESC)', + default: 'DESC', + options: ['ASC', 'DESC'], + }), + 'page-cursor': Flags.string({ + description: 'Cursor of the required page', + }), + 'page-size': Flags.string({ + description: 'Maximum number of items in the page', + default: '10', + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/webhooks' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetWebhooks) + + + const headers: Record = {} + + + const queryParams: Record = {} + if (flags['order'] !== undefined && flags['order'] !== null) { + queryParams['order'] = String(flags['order']) + } + if (flags['page-cursor'] !== undefined && flags['page-cursor'] !== null) { + queryParams['pageCursor'] = String(flags['page-cursor']) + } + if (flags['page-size'] !== undefined && flags['page-size'] !== null) { + queryParams['pageSize'] = String(flags['page-size']) + } + + const result = await this.makeRequest( + 'GET', + '/v1/webhooks', + { + headers, + queryParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/resend-failed-notifications.ts b/src/commands/webhooks-v2/resend-failed-notifications.ts new file mode 100644 index 0000000..39c2ce8 --- /dev/null +++ b/src/commands/webhooks-v2/resend-failed-notifications.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ResendFailedNotifications extends FireblocksBaseCommand { + static summary = 'Resend failed notifications' + + static description = 'Resend all failed notifications for a webhook in the last 24 hours\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Editor, Signer.\n\nOperation ID: resendFailedNotifications\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/resendFailedNotifications' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The ID of the webhook', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/webhooks/{webhookId}/notifications/resend_failed' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID","Location"] + + async run(): Promise { + const {flags} = await this.parse(ResendFailedNotifications) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + + + await this.confirmOrAbort('POST', '/v1/webhooks/{webhookId}/notifications/resend_failed') + + const result = await this.makeRequest( + 'POST', + '/v1/webhooks/{webhookId}/notifications/resend_failed', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/resend-notification-by-id.ts b/src/commands/webhooks-v2/resend-notification-by-id.ts new file mode 100644 index 0000000..58f9f88 --- /dev/null +++ b/src/commands/webhooks-v2/resend-notification-by-id.ts @@ -0,0 +1,58 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ResendNotificationById extends FireblocksBaseCommand { + static summary = 'Resend notification by id' + + static description = 'Resend notification by ID\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Editor, Signer.\n\nOperation ID: resendNotificationById\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/resendNotificationById' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The ID of the webhook', + required: true, + }), + 'notification-id': Flags.string({ + description: 'The ID of the notification', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/webhooks/{webhookId}/notifications/{notificationId}/resend' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ResendNotificationById) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + pathParams['notificationId'] = String(flags['notification-id']) + + + await this.confirmOrAbort('POST', '/v1/webhooks/{webhookId}/notifications/{notificationId}/resend') + + const result = await this.makeRequest( + 'POST', + '/v1/webhooks/{webhookId}/notifications/{notificationId}/resend', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/resend-notifications-by-resource-id.ts b/src/commands/webhooks-v2/resend-notifications-by-resource-id.ts new file mode 100644 index 0000000..f5eeb1e --- /dev/null +++ b/src/commands/webhooks-v2/resend-notifications-by-resource-id.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ResendNotificationsByResourceId extends FireblocksBaseCommand { + static summary = 'Resend notifications by resource Id' + + static description = 'Resend notifications by resource Id\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin, Editor, Signer.\n\nOperation ID: resendNotificationsByResourceId\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/resendNotificationsByResourceId' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The ID of the webhook', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/webhooks/{webhookId}/notifications/resend_by_resource' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ResendNotificationsByResourceId) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + + + await this.confirmOrAbort('POST', '/v1/webhooks/{webhookId}/notifications/resend_by_resource') + + const result = await this.makeRequest( + 'POST', + '/v1/webhooks/{webhookId}/notifications/resend_by_resource', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks-v2/update-webhook.ts b/src/commands/webhooks-v2/update-webhook.ts new file mode 100644 index 0000000..f47fb08 --- /dev/null +++ b/src/commands/webhooks-v2/update-webhook.ts @@ -0,0 +1,67 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class UpdateWebhook extends FireblocksBaseCommand { + static summary = 'Update webhook' + + static description = 'Update a webhook by its id\n\nEndpoint Permission: Owner, Admin, Non-Signing Admin.\n\nOperation ID: updateWebhook\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks%20V2/updateWebhook' + + static enableJsonFlag = false + + static flags = { + 'webhook-id': Flags.string({ + description: 'The unique identifier of the webhook', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'PATCH' + static path = '/v1/webhooks/{webhookId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(UpdateWebhook) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['webhookId'] = String(flags['webhook-id']) + + + await this.confirmOrAbort('PATCH', '/v1/webhooks/{webhookId}') + + const result = await this.makeRequest( + 'PATCH', + '/v1/webhooks/{webhookId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks/resend-transaction-webhooks.ts b/src/commands/webhooks/resend-transaction-webhooks.ts new file mode 100644 index 0000000..cfb8507 --- /dev/null +++ b/src/commands/webhooks/resend-transaction-webhooks.ts @@ -0,0 +1,70 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ResendTransactionWebhooks extends FireblocksBaseCommand { + static summary = 'Resend webhooks for a transaction by ID' + + static description = 'Resends webhook notifications for a transaction by its unique identifier.\n\nLearn more about Fireblocks Webhooks in the following [guide](https://developers.fireblocks.com/docs/configure-webhooks).\n\n**Endpoint Permissions:** Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: resendTransactionWebhooks\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks/resendTransactionWebhooks' + + static enableJsonFlag = false + + static flags = { + 'tx-id': Flags.string({ + description: 'The ID of the transaction for webhooks', + required: true, + }), + data: Flags.string({ + description: 'JSON request body', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/webhooks/resend/{txId}' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ResendTransactionWebhooks) + + let body: Record | undefined + if (flags.data) { + try { + const parsed = JSON.parse(flags.data) + if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) { + this.error('--data must be a JSON object (e.g., \'{"key": "value"}\')') + } + body = parsed as Record + } catch { + this.error('Invalid JSON in --data flag. Ensure the value is valid JSON.') + } + } + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + const pathParams: Record = {} + pathParams['txId'] = String(flags['tx-id']) + + + await this.confirmOrAbort('POST', '/v1/webhooks/resend/{txId}') + + const result = await this.makeRequest( + 'POST', + '/v1/webhooks/resend/{txId}', + { + body, + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/webhooks/resend-webhooks.ts b/src/commands/webhooks/resend-webhooks.ts new file mode 100644 index 0000000..08bdd93 --- /dev/null +++ b/src/commands/webhooks/resend-webhooks.ts @@ -0,0 +1,46 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class ResendWebhooks extends FireblocksBaseCommand { + static summary = 'Resend failed webhooks' + + static description = 'Resends all failed webhook notifications.\n\nLearn more about Fireblocks Webhooks in the following [guide](https://developers.fireblocks.com/docs/configure-webhooks).\n\nEndpoint Permission: Admin, Non-Signing Admin, Signer, Approver, Editor.\n\nOperation ID: resendWebhooks\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Webhooks/resendWebhooks' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/webhooks/resend' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(ResendWebhooks) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/webhooks/resend') + + const result = await this.makeRequest( + 'POST', + '/v1/webhooks/resend', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/whitelist-ip-addresses/get-whitelist-ip-addresses.ts b/src/commands/whitelist-ip-addresses/get-whitelist-ip-addresses.ts new file mode 100644 index 0000000..cc6ebea --- /dev/null +++ b/src/commands/whitelist-ip-addresses/get-whitelist-ip-addresses.ts @@ -0,0 +1,48 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetWhitelistIpAddresses extends FireblocksBaseCommand { + static summary = 'Get whitelisted ip addresses for an API Key' + + static description = 'Get a list of the whitelisted IP addresses for a specific API Key\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getWhitelistIpAddresses\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/whitelist%20ip%20addresses/getWhitelistIpAddresses' + + static enableJsonFlag = false + + static flags = { + 'user-id': Flags.string({ + description: 'The ID of the api user', + required: true, + }), + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/management/api_users/{userId}/whitelist_ip_addresses' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetWhitelistIpAddresses) + + + const headers: Record = {} + + const pathParams: Record = {} + pathParams['userId'] = String(flags['user-id']) + + + const result = await this.makeRequest( + 'GET', + '/v1/management/api_users/{userId}/whitelist_ip_addresses', + { + headers, + pathParams, + }, + ) + + return result + } +} diff --git a/src/commands/whoami.ts b/src/commands/whoami.ts new file mode 100644 index 0000000..7d6e381 --- /dev/null +++ b/src/commands/whoami.ts @@ -0,0 +1,49 @@ +import {FireblocksBaseCommand} from '../lib/base-command.js' + +function maskApiKey(key: string): string { + if (key.length <= 8) return '****' + return key.slice(0, 4) + '...' + key.slice(-4) +} + +export default class Whoami extends FireblocksBaseCommand { + static override description = 'Show current auth context and verify credentials' + + static override examples = [ + '$ fireblocks whoami', + '$ fireblocks whoami --dry-run', + '$ fireblocks whoami --profile staging', + ] + + static override flags = { + ...FireblocksBaseCommand.baseFlags, + } + + static override enableJsonFlag = true + + async run(): Promise> { + const {flags} = await this.parse(Whoami) + const auth = await this.resolveAuth() + + const info: Record = { + apiKey: maskApiKey(auth.apiKey), + baseUrl: auth.baseUrl, + } + + if (flags.profile) { + info.profile = flags.profile + } + + if (flags['dry-run']) { + this.log('Resolved auth context (dry-run, no API call):') + this.log(JSON.stringify(info, null, 2)) + return info + } + + // Verify credentials by calling the users/me endpoint + const result = await this.makeRequest('GET', '/v1/users/me') + info.verified = true + info.user = result + + return info + } +} diff --git a/src/commands/workspace-status/get-workspace-status.ts b/src/commands/workspace-status/get-workspace-status.ts new file mode 100644 index 0000000..73daf21 --- /dev/null +++ b/src/commands/workspace-status/get-workspace-status.ts @@ -0,0 +1,38 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetWorkspaceStatus extends FireblocksBaseCommand { + static summary = 'Returns current workspace status' + + static description = 'Returns current workspace status (Beta).\n**Note**:\n- This endpoint is now in Beta, disabled for general availability at this time.\n- Please note that this endpoint is available only for API keys with Admin/Non Signing Admin permissions.\n\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: getWorkspaceStatus\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Workspace%20Status/getWorkspaceStatus' + + static enableJsonFlag = false + + static flags = { + } + + static method = 'GET' + static path = '/v1/management/workspace_status' + static isBeta = true + + async run(): Promise { + const {flags} = await this.parse(GetWorkspaceStatus) + + this.logToStderr('Warning: This command is in beta and may change in future releases.') + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/management/workspace_status', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/workspace/freeze-workspace.ts b/src/commands/workspace/freeze-workspace.ts new file mode 100644 index 0000000..e7d5e4f --- /dev/null +++ b/src/commands/workspace/freeze-workspace.ts @@ -0,0 +1,46 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class FreezeWorkspace extends FireblocksBaseCommand { + static summary = 'Freeze' + + static description = 'Freezes a Workspace so that ALL operations by ANY user are blocked.\nYou should only perform this action when the workspace faces imminent risk, such as when you have a security breach.\nTo unfreeze a workspace, the workspace Owner must submit a request to Fireblocks Support.\n**NOTE:** \n- This operation can only be performed by the workspace Admins - Your workspace continues to receive incoming transfers during this time.\nEndpoint Permission: Admin, Non-Signing Admin.\n\nOperation ID: freezeWorkspace\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Workspace/freezeWorkspace' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'POST' + static path = '/v1/workspace/freeze' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(FreezeWorkspace) + + + const headers: Record = {} + if (flags['idempotency-key']) { + headers['Idempotency-Key'] = flags['idempotency-key'] + } + + + + await this.confirmOrAbort('POST', '/v1/workspace/freeze') + + const result = await this.makeRequest( + 'POST', + '/v1/workspace/freeze', + { + headers, + }, + ) + + return result + } +} diff --git a/src/commands/workspace/get-workspace.ts b/src/commands/workspace/get-workspace.ts new file mode 100644 index 0000000..24f661a --- /dev/null +++ b/src/commands/workspace/get-workspace.ts @@ -0,0 +1,41 @@ +import {Flags} from '@oclif/core' +import {FireblocksBaseCommand} from '../../lib/base-command.js' + +export default class GetWorkspace extends FireblocksBaseCommand { + static summary = 'Get workspace' + + static description = 'Returns the workspace ID and name for the authenticated user.\n\nOperation ID: getWorkspace\nDocs: https://docs.fireblocks.com/api/swagger-ui/#/Workspace/getWorkspace' + + static enableJsonFlag = false + + static flags = { + 'include-headers': Flags.boolean({ + description: 'Include spec-defined response headers in output', + default: false, + }), + } + + static method = 'GET' + static path = '/v1/workspace' + static isBeta = false + static responseHeaders: string[] = ["X-Request-ID"] + + async run(): Promise { + const {flags} = await this.parse(GetWorkspace) + + + const headers: Record = {} + + + + const result = await this.makeRequest( + 'GET', + '/v1/workspace', + { + headers, + }, + ) + + return result + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..e32b0b2 --- /dev/null +++ b/src/index.ts @@ -0,0 +1 @@ +export {run} from '@oclif/core' diff --git a/src/lib/auth/config.test.ts b/src/lib/auth/config.test.ts new file mode 100644 index 0000000..6d3388e --- /dev/null +++ b/src/lib/auth/config.test.ts @@ -0,0 +1,235 @@ +import {generateKeyPairSync} from 'node:crypto' +import {resolve} from 'node:path' + +import {resolveAuth} from './config.js' + +// Mock the fs/promises module used by config.ts +jest.mock('node:fs/promises', () => ({ + readFile: jest.fn(), + mkdir: jest.fn(), + writeFile: jest.fn(), +})) + +import {readFile} from 'node:fs/promises' + +const mockReadFile = readFile as jest.Mock + +function enoent(): NodeJS.ErrnoException { + const err: NodeJS.ErrnoException = new Error('ENOENT: no such file or directory') + err.code = 'ENOENT' + return err +} + +const KEY_PATH = resolve('/path/to/key.pem') +const STAGING_KEY_PATH = resolve('/path/to/staging-key.pem') + +let FAKE_PEM: string +let FAKE_CONFIG: string + +beforeEach(() => { + FAKE_PEM = generateKeyPairSync('rsa', { + modulusLength: 1024, + privateKeyEncoding: {type: 'pkcs8', format: 'pem'}, + publicKeyEncoding: {type: 'spki', format: 'pem'}, + }).privateKey + + FAKE_CONFIG = JSON.stringify({ + profiles: { + default: { + apiKey: 'config-api-key', + privateKeyPath: KEY_PATH, + baseUrl: 'https://config-base.example.com', + }, + staging: { + apiKey: 'staging-api-key', + privateKeyPath: STAGING_KEY_PATH, + }, + }, + defaultProfile: 'default', + }) + + jest.resetAllMocks() + delete process.env.FIREBLOCKS_API_KEY + delete process.env.FIREBLOCKS_SECRET_KEY + delete process.env.FIREBLOCKS_SECRET_KEY_PATH + delete process.env.FIREBLOCKS_BASE_URL +}) + +afterEach(() => { + delete process.env.FIREBLOCKS_API_KEY + delete process.env.FIREBLOCKS_SECRET_KEY + delete process.env.FIREBLOCKS_SECRET_KEY_PATH + delete process.env.FIREBLOCKS_BASE_URL +}) + +describe('resolveAuth', () => { + describe('precedence: CLI flags > env vars > config file', () => { + it('uses CLI flags when all sources are available', async () => { + process.env.FIREBLOCKS_API_KEY = 'env-api-key' + process.env.FIREBLOCKS_SECRET_KEY = FAKE_PEM + + const result = await resolveAuth({ + apiKey: 'flag-api-key', + secretKey: FAKE_PEM, + baseUrl: 'https://flag-base.example.com', + }) + + expect(result.apiKey).toBe('flag-api-key') + expect(result.baseUrl).toBe('https://flag-base.example.com') + expect(result.privateKey).toBe(FAKE_PEM) + }) + + it('falls back to env vars when flags are not provided', async () => { + process.env.FIREBLOCKS_API_KEY = 'env-api-key' + process.env.FIREBLOCKS_SECRET_KEY = FAKE_PEM + process.env.FIREBLOCKS_BASE_URL = 'https://env-base.example.com' + + const result = await resolveAuth({}) + + expect(result.apiKey).toBe('env-api-key') + expect(result.privateKey).toBe(FAKE_PEM) + expect(result.baseUrl).toBe('https://env-base.example.com') + }) + + it('falls back to FIREBLOCKS_SECRET_KEY_PATH env var', async () => { + process.env.FIREBLOCKS_API_KEY = 'env-api-key' + process.env.FIREBLOCKS_SECRET_KEY_PATH = '/env/path/to/key.pem' + + mockReadFile.mockImplementation(async (path: any) => { + if (String(path) === resolve('/env/path/to/key.pem')) return FAKE_PEM + throw enoent() + }) + + const result = await resolveAuth({}) + + expect(result.apiKey).toBe('env-api-key') + expect(result.privateKey).toBe(FAKE_PEM) + }) + + it('falls back to config file when flags and env vars are not provided', async () => { + mockReadFile.mockImplementation(async (path: any) => { + const pathStr = String(path) + if (pathStr.endsWith('config.json')) return FAKE_CONFIG + if (pathStr === KEY_PATH) return FAKE_PEM + throw new Error(`Unexpected readFile call: ${pathStr}`) + }) + + const result = await resolveAuth({}) + + expect(result.apiKey).toBe('config-api-key') + expect(result.privateKey).toBe(FAKE_PEM) + expect(result.baseUrl).toBe('https://config-base.example.com') + }) + + it('uses a named profile from config file', async () => { + mockReadFile.mockImplementation(async (path: any) => { + const pathStr = String(path) + if (pathStr.endsWith('config.json')) return FAKE_CONFIG + if (pathStr === STAGING_KEY_PATH) return FAKE_PEM + throw new Error(`Unexpected readFile call: ${pathStr}`) + }) + + const result = await resolveAuth({profile: 'staging'}) + + expect(result.apiKey).toBe('staging-api-key') + expect(result.privateKey).toBe(FAKE_PEM) + // staging profile has no baseUrl, so default should be used + expect(result.baseUrl).toBe('https://api.fireblocks.io') + }) + }) + + describe('error handling', () => { + it('throws when no credentials are available', async () => { + mockReadFile.mockRejectedValue(enoent()) + + await expect(resolveAuth({})).rejects.toThrow('Missing Fireblocks credentials') + }) + + it('throws when only api key is provided without secret key', async () => { + mockReadFile.mockRejectedValue(enoent()) + + await expect(resolveAuth({apiKey: 'some-key'})).rejects.toThrow( + 'Missing Fireblocks credentials', + ) + }) + + it('throws when only secret key is provided without api key', async () => { + mockReadFile.mockRejectedValue(enoent()) + + await expect(resolveAuth({secretKey: FAKE_PEM})).rejects.toThrow( + 'Missing Fireblocks credentials', + ) + }) + }) + + describe('private key reading', () => { + it('uses inline PEM directly when it contains BEGIN marker', async () => { + const result = await resolveAuth({ + apiKey: 'test-key', + secretKey: FAKE_PEM, + }) + + expect(result.privateKey).toBe(FAKE_PEM) + // readFile should not be called for the private key (only potentially for config) + }) + + it('reads private key from file path when no BEGIN marker present', async () => { + mockReadFile.mockImplementation(async (path: any) => { + if (String(path) === resolve('/my/key.pem')) return FAKE_PEM + throw enoent() + }) + + const result = await resolveAuth({ + apiKey: 'test-key', + secretKey: '/my/key.pem', + }) + + expect(result.privateKey).toBe(FAKE_PEM) + }) + }) + + describe('default base URL', () => { + it('uses default base URL when none is specified', async () => { + const result = await resolveAuth({ + apiKey: 'test-key', + secretKey: FAKE_PEM, + }) + + expect(result.baseUrl).toBe('https://api.fireblocks.io') + }) + }) + + describe('base URL validation', () => { + it('rejects HTTP base URL by default', async () => { + await expect( + resolveAuth({apiKey: 'test-key', secretKey: FAKE_PEM, baseUrl: 'http://localhost:3000'}), + ).rejects.toThrow('HTTP base URLs are not allowed') + }) + + it('allows HTTP base URL when FIREBLOCKS_ALLOW_HTTP is set', async () => { + process.env.FIREBLOCKS_ALLOW_HTTP = '1' + const result = await resolveAuth({ + apiKey: 'test-key', + secretKey: FAKE_PEM, + baseUrl: 'http://localhost:3000', + }) + expect(result.baseUrl).toBe('http://localhost:3000') + delete process.env.FIREBLOCKS_ALLOW_HTTP + }) + + it('accepts HTTPS base URL', async () => { + const result = await resolveAuth({ + apiKey: 'test-key', + secretKey: FAKE_PEM, + baseUrl: 'https://sandbox.fireblocks.io', + }) + expect(result.baseUrl).toBe('https://sandbox.fireblocks.io') + }) + + it('rejects invalid URL', async () => { + await expect( + resolveAuth({apiKey: 'test-key', secretKey: FAKE_PEM, baseUrl: 'not-a-url'}), + ).rejects.toThrow('Invalid base URL') + }) + }) +}) diff --git a/src/lib/auth/config.ts b/src/lib/auth/config.ts new file mode 100644 index 0000000..d427627 --- /dev/null +++ b/src/lib/auth/config.ts @@ -0,0 +1,132 @@ +import {readFile, mkdir, writeFile} from 'node:fs/promises' +import {homedir} from 'node:os' +import {join, resolve} from 'node:path' + +export interface AuthContext { + apiKey: string + privateKey: string + baseUrl: string +} + +export interface ProfileConfig { + apiKey: string + privateKeyPath: string + baseUrl?: string +} + +export interface CliConfig { + profiles: Record + defaultProfile: string +} + +const CONFIG_DIR = join(homedir(), '.config', 'fireblocks') +const CONFIG_PATH = join(CONFIG_DIR, 'config.json') +export const DEFAULT_BASE_URL = 'https://api.fireblocks.io' + +export function getConfigPath(): string { + return CONFIG_PATH +} + +export async function readConfig(): Promise { + try { + const raw = await readFile(CONFIG_PATH, 'utf-8') + return JSON.parse(raw) as CliConfig + } catch (error) { + const code = (error as NodeJS.ErrnoException).code + if (code === 'ENOENT') return null + if (code === 'EACCES') { + throw new Error(`Permission denied reading config at ${CONFIG_PATH}. Check file permissions (should be 0600).`, {cause: error}) + } + + throw new Error(`Failed to read config at ${CONFIG_PATH}: ${(error as Error).message}`, {cause: error}) + } +} + +export async function writeConfig(config: CliConfig): Promise { + await mkdir(CONFIG_DIR, {recursive: true, mode: 0o700}) + await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', {encoding: 'utf-8', mode: 0o600}) +} + +async function readPrivateKey(pathOrInline: string): Promise { + if (pathOrInline.trimStart().startsWith('-----BEGIN')) { + return pathOrInline + } + + const resolved = resolve(pathOrInline) + const content = await readFile(resolved, 'utf-8') + if (!content.trimStart().startsWith('-----BEGIN')) { + throw new Error(`File at ${resolved} does not appear to contain a PEM-encoded key`) + } + + return content +} + +export async function resolveAuth(options: { + apiKey?: string + secretKey?: string + profile?: string + baseUrl?: string +}): Promise { + // 1. CLI flags (highest priority) + let apiKey = options.apiKey + let secretKeyRaw = options.secretKey + let baseUrl = options.baseUrl + + // 2. Environment variables + if (!apiKey) apiKey = process.env.FIREBLOCKS_API_KEY + if (!secretKeyRaw) { + secretKeyRaw = process.env.FIREBLOCKS_SECRET_KEY ?? process.env.FIREBLOCKS_SECRET_KEY_PATH + } + + if (!baseUrl) baseUrl = process.env.FIREBLOCKS_BASE_URL + + // 3. Config file profile + if (!apiKey || !secretKeyRaw) { + const config = await readConfig() + if (config) { + const profileName = options.profile ?? config.defaultProfile ?? 'default' + const profile = config.profiles[profileName] + if (profile) { + if (!apiKey) apiKey = profile.apiKey + if (!secretKeyRaw) secretKeyRaw = profile.privateKeyPath + if (!baseUrl) baseUrl = profile.baseUrl + } + } + } + + if (!apiKey || !secretKeyRaw) { + throw new Error( + 'Missing Fireblocks credentials. Provide --api-key and --secret-key flags, ' + + 'set FIREBLOCKS_API_KEY and FIREBLOCKS_SECRET_KEY environment variables, ' + + 'or run `fireblocks configure` to set up a profile.', + ) + } + + const privateKey = await readPrivateKey(secretKeyRaw) + + const resolvedBaseUrl = baseUrl ?? DEFAULT_BASE_URL + + let parsed: URL + try { + parsed = new URL(resolvedBaseUrl) + } catch { + throw new Error(`Invalid base URL: "${resolvedBaseUrl}"`) + } + + if (parsed.protocol === 'http:' && !['1', 'true'].includes(process.env.FIREBLOCKS_ALLOW_HTTP ?? '')) { + throw new Error( + 'HTTP base URLs are not allowed — credentials would be sent in cleartext. ' + + 'Use HTTPS or set FIREBLOCKS_ALLOW_HTTP=1 for local development.', + ) + } + + if (!['https:', 'http:'].includes(parsed.protocol)) { + throw new Error(`Invalid base URL protocol: ${parsed.protocol} — only https: is allowed`) + } + + return { + apiKey, + privateKey, + baseUrl: resolvedBaseUrl, + } +} diff --git a/src/lib/auth/index.ts b/src/lib/auth/index.ts new file mode 100644 index 0000000..805b839 --- /dev/null +++ b/src/lib/auth/index.ts @@ -0,0 +1,3 @@ +export {signRequest} from './signer.js' +export {resolveAuth} from './config.js' +export type {AuthContext, CliConfig, ProfileConfig} from './config.js' diff --git a/src/lib/auth/signer.test.ts b/src/lib/auth/signer.test.ts new file mode 100644 index 0000000..6d9bbfa --- /dev/null +++ b/src/lib/auth/signer.test.ts @@ -0,0 +1,174 @@ +import {generateKeyPairSync, createHash, createVerify, createSign, createPrivateKey} from 'node:crypto' + +// Mock jose (ESM-only) with native Node.js crypto equivalents so signer.ts can load +jest.mock('jose', () => { + const {createSign: _createSign, createPrivateKey: _createPrivateKey} = require('node:crypto') + + class SignJWT { + private _payload: Record + private _header: Record = {} + private _iat?: number + private _exp?: number + + constructor(payload: Record) { + this._payload = {...payload} + } + + setProtectedHeader(header: Record) { + this._header = header + return this + } + + setIssuedAt(time: number) { + this._iat = time + return this + } + + setExpirationTime(time: number) { + this._exp = time + return this + } + + async sign(key: {pem: string}) { + const payload = {...this._payload} + if (this._iat !== undefined) payload.iat = this._iat + if (this._exp !== undefined) payload.exp = this._exp + + const headerB64 = Buffer.from(JSON.stringify(this._header)).toString('base64url') + const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url') + const data = `${headerB64}.${payloadB64}` + + const signer = _createSign('RSA-SHA256') + signer.update(data) + const signature = signer.sign(key.pem, 'base64url') + return `${data}.${signature}` + } + } + + async function importPKCS8(pem: string, _alg: string) { + return {pem} + } + + return {SignJWT, importPKCS8} +}) + +import {signRequest} from './signer.js' + +// Generate a test RSA key pair in PEM format +const {publicKey, privateKey} = generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: {type: 'spki', format: 'pem'}, + privateKeyEncoding: {type: 'pkcs8', format: 'pem'}, +}) + +const TEST_API_KEY = 'test-api-key-12345' +const TEST_PATH = '/v1/vault/accounts' + +// Native JWT decoding helpers (avoids ESM-only jose dependency in tests) +function decodeJwtHeader(token: string): Record { + const [headerB64] = token.split('.') + return JSON.parse(Buffer.from(headerB64, 'base64url').toString()) +} + +function decodeJwtPayload(token: string): Record { + const [, payloadB64] = token.split('.') + return JSON.parse(Buffer.from(payloadB64, 'base64url').toString()) +} + +function verifyJwtSignature(token: string, pubKey: string): boolean { + const [headerB64, payloadB64, signatureB64] = token.split('.') + const data = `${headerB64}.${payloadB64}` + const signature = Buffer.from(signatureB64, 'base64url') + const verifier = createVerify('RSA-SHA256') + verifier.update(data) + return verifier.verify(pubKey, signature) +} + +describe('signRequest', () => { + it('produces a valid JWT with RS256 algorithm', async () => { + const token = await signRequest(TEST_API_KEY, privateKey, TEST_PATH) + + const header = decodeJwtHeader(token) + expect(header.alg).toBe('RS256') + expect(header.typ).toBe('JWT') + }) + + it('can be verified with the corresponding public key', async () => { + const token = await signRequest(TEST_API_KEY, privateKey, TEST_PATH) + + expect(verifyJwtSignature(token, publicKey)).toBe(true) + + const payload = decodeJwtPayload(token) + expect(payload.sub).toBe(TEST_API_KEY) + expect(payload.uri).toBe(TEST_PATH) + }) + + it('includes correct payload fields without body', async () => { + const token = await signRequest(TEST_API_KEY, privateKey, TEST_PATH) + + const payload = decodeJwtPayload(token) + + expect(payload.sub).toBe(TEST_API_KEY) + expect(payload.uri).toBe(TEST_PATH) + expect(payload.nonce).toBeDefined() + expect(typeof payload.nonce).toBe('string') + // nonce should be a UUID v4 pattern + expect(payload.nonce).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, + ) + expect(payload.iat).toBeDefined() + expect(typeof payload.iat).toBe('number') + expect(payload.exp).toBeDefined() + expect(typeof payload.exp).toBe('number') + // exp should be iat + 55 + expect((payload.exp as number) - (payload.iat as number)).toBe(55) + + // bodyHash is SHA-256 of empty string when no body provided + const expectedHash = createHash('sha256').update('').digest('hex') + expect(payload.bodyHash).toBe(expectedHash) + }) + + it('includes correct bodyHash when body is provided', async () => { + const body = '{"amount": "1.5", "assetId": "BTC"}' + const token = await signRequest(TEST_API_KEY, privateKey, TEST_PATH, body) + + const payload = decodeJwtPayload(token) + + const expectedHash = createHash('sha256').update(body).digest('hex') + expect(payload.bodyHash).toBe(expectedHash) + }) + + it('generates unique nonces for each call', async () => { + const token1 = await signRequest(TEST_API_KEY, privateKey, TEST_PATH) + const token2 = await signRequest(TEST_API_KEY, privateKey, TEST_PATH) + + const payload1 = decodeJwtPayload(token1) + const payload2 = decodeJwtPayload(token2) + + expect(payload1.nonce).not.toBe(payload2.nonce) + }) + + it('uses the api key as the subject claim', async () => { + const customKey = 'my-custom-api-key-67890' + const token = await signRequest(customKey, privateKey, TEST_PATH) + + const payload = decodeJwtPayload(token) + expect(payload.sub).toBe(customKey) + }) + + it('uses the path as the uri claim', async () => { + const customPath = '/v1/transactions' + const token = await signRequest(TEST_API_KEY, privateKey, customPath) + + const payload = decodeJwtPayload(token) + expect(payload.uri).toBe(customPath) + }) + + it('includes query string in the uri claim when present', async () => { + const pathWithQuery = '/v1/vault/accounts_paged?orderBy=DESC&limit=200' + const token = await signRequest(TEST_API_KEY, privateKey, pathWithQuery) + + const payload = decodeJwtPayload(token) + expect(payload.uri).toBe(pathWithQuery) + }) +}) diff --git a/src/lib/auth/signer.ts b/src/lib/auth/signer.ts new file mode 100644 index 0000000..6b4d4da --- /dev/null +++ b/src/lib/auth/signer.ts @@ -0,0 +1,40 @@ +import {SignJWT, importPKCS8} from 'jose' +import {createHash, randomUUID} from 'node:crypto' + +let cachedKey: {pemHash: string; key: CryptoKey} | null = null + +async function getKey(privateKey: string): Promise { + const pemHash = createHash('sha256').update(privateKey).digest('hex') + if (cachedKey?.pemHash === pemHash) return cachedKey.key + const key = await importPKCS8(privateKey, 'RS256') + cachedKey = {pemHash, key} + return key +} + +const JWT_EXPIRY_SECONDS = 55 + +// Matches the signing approach from fireblocks/ts-sdk bearerTokenProvider.ts +export async function signRequest( + apiKey: string, + privateKey: string, + path: string, + body?: string, +): Promise { + const now = Math.floor(Date.now() / 1000) + const bodyHash = createHash('sha256') + .update(body || '') + .digest('hex') + + const key = await getKey(privateKey) + + return new SignJWT({ + uri: path, + nonce: randomUUID(), + sub: apiKey, + bodyHash, + }) + .setProtectedHeader({alg: 'RS256', typ: 'JWT'}) + .setIssuedAt(now) + .setExpirationTime(now + JWT_EXPIRY_SECONDS) + .sign(key) +} diff --git a/src/lib/base-command.ts b/src/lib/base-command.ts new file mode 100644 index 0000000..c0fcee8 --- /dev/null +++ b/src/lib/base-command.ts @@ -0,0 +1,190 @@ +import {Command, Flags, Interfaces} from '@oclif/core' +import {createInterface} from 'node:readline' +import {resolveAuth} from './auth/index.js' +import type {AuthContext} from './auth/index.js' +import {fireblocksFetch, type RequestOptions, type ApiResponse} from './http/client.js' +import {mapHttpError, EXIT_CODE} from './errors/mapper.js' +import {formatOutput} from './output/formatter.js' +import {formatHeaders} from './output/headers.js' + +export type BaseFlags = Interfaces.InferredFlags + +export abstract class FireblocksBaseCommand extends Command { + static baseFlags = { + 'api-key': Flags.string({ + description: 'Fireblocks API key', + env: 'FIREBLOCKS_API_KEY', + }), + 'secret-key': Flags.string({ + description: 'RSA private key (inline PEM or file path)', + }), + 'base-url': Flags.string({ + description: 'API base URL override', + env: 'FIREBLOCKS_BASE_URL', + }), + profile: Flags.string({ + description: 'Named credential profile', + }), + output: Flags.string({ + char: 'o', + description: 'Output format', + options: ['json', 'yaml'], + default: 'json', + }), + 'dry-run': Flags.boolean({ + description: 'Preview request without executing', + default: false, + }), + 'no-confirm': Flags.boolean({ + description: 'Skip confirmation prompts', + default: false, + }), + debug: Flags.boolean({ + description: 'Enable debug logging to stderr', + default: false, + }), + 'idempotency-key': Flags.string({ + description: 'Unique identifier for idempotent requests', + }), + } + + static enableJsonFlag = false + + protected parsedFlags?: BaseFlags + private cachedAuth?: AuthContext + + private async getFlags(): Promise { + if (!this.parsedFlags) { + const {flags} = await this.parse(this.constructor as typeof FireblocksBaseCommand) + this.parsedFlags = flags + } + return this.parsedFlags + } + + protected async resolveAuth(): Promise { + if (this.cachedAuth) return this.cachedAuth + const flags = await this.getFlags() + const auth = await resolveAuth({ + apiKey: flags['api-key'], + secretKey: flags['secret-key'], + profile: flags.profile, + baseUrl: flags['base-url'], + }) + this.cachedAuth = auth + return auth + } + + protected async confirmOrAbort(method: string, path: string): Promise { + const flags = await this.getFlags() + if (flags['no-confirm']) return + if (!process.stdin.isTTY) return + + const answer = await new Promise((resolve) => { + const rl = createInterface({input: process.stdin, output: process.stderr}) + rl.question(`About to execute ${method} ${path}. Continue? (y/N) `, (ans) => { + rl.close() + resolve(ans) + }) + }) + + if (answer.toLowerCase() !== 'y') { + this.log('Aborted.') + return this.exit(0) + } + } + + protected async makeRequest( + method: string, + path: string, + options?: RequestOptions & {pathParams?: Record}, + ): Promise { + const flags = await this.getFlags() + + // Substitute path parameters + let resolvedPath = path + if (options?.pathParams) { + for (const [key, value] of Object.entries(options.pathParams)) { + resolvedPath = resolvedPath.replaceAll(`{${key}}`, encodeURIComponent(value)) + } + } + + const auth = await this.resolveAuth() + + // Dry-run: print request preview and exit + if (flags['dry-run']) { + const url = auth.baseUrl + resolvedPath + const preview = { + method, + url, + queryParams: options?.queryParams, + body: options?.body, + headers: options?.headers, + } + + this.log(formatOutput(preview, flags.output)) + return preview + } + + if (flags.debug) { + this.logToStderr(`[DEBUG] ${method} ${auth.baseUrl}${resolvedPath}`) + if (options?.body) { + const safeBody = {...options.body as Record} + for (const key of ['privateKey', 'secretKey', 'password', 'seed', 'mnemonic', 'secret']) { + if (key in safeBody) safeBody[key] = '[REDACTED]' + } + this.logToStderr(`[DEBUG] Body: ${JSON.stringify(safeBody)}`) + } + } + + let response: ApiResponse + try { + response = await fireblocksFetch(auth, method, resolvedPath, options) + } catch (error) { + const isTimeout = + (error instanceof DOMException && error.name === 'TimeoutError') || + (error instanceof Error && (error.message.includes('ETIMEDOUT') || error.name === 'AbortError')) + if (isTimeout) { + this.logToStderr(JSON.stringify({code: EXIT_CODE.TIMEOUT, message: 'Request timed out'})) + return this.exit(EXIT_CODE.TIMEOUT) + } + + const message = error instanceof Error ? error.message : String(error) + this.logToStderr(JSON.stringify({code: EXIT_CODE.GENERAL, message})) + return this.exit(EXIT_CODE.GENERAL) + } + + if (flags.debug) { + this.logToStderr(`[DEBUG] Response: ${response.status}`) + this.logToStderr(`[DEBUG] Request-ID: ${response.requestId}`) + } + + // Output response headers if --include-headers is set and the command declares spec-defined headers. + // Headers are metadata and always go to stderr to keep stdout clean for JSON consumers and pipes. + const responseHeaderNames = (this.constructor as {responseHeaders?: string[]}).responseHeaders ?? [] + if (responseHeaderNames.length > 0 && (flags as Record)['include-headers']) { + const headerLines = formatHeaders(response.headers, responseHeaderNames) + if (headerLines) { + this.logToStderr(headerLines) + this.logToStderr('') + } + } + + // Handle HTTP errors + if (response.status >= 400) { + const retryAfter = response.headers.get('retry-after') + const {exitCode, structured} = mapHttpError( + response.status, + response.body, + response.requestId, + retryAfter, + ) + + this.logToStderr(JSON.stringify(structured)) + return this.exit(exitCode) + } + + // Output result + this.log(formatOutput(response.body, flags.output)) + return response.body + } +} diff --git a/src/lib/errors/mapper.test.ts b/src/lib/errors/mapper.test.ts new file mode 100644 index 0000000..3ef58ec --- /dev/null +++ b/src/lib/errors/mapper.test.ts @@ -0,0 +1,151 @@ +import {mapHttpError, EXIT_CODE} from './mapper.js' + +describe('mapHttpError', () => { + describe('401/403 -> AUTH exit code', () => { + it('maps 401 to AUTH exit code', () => { + const result = mapHttpError(401, null) + expect(result.exitCode).toBe(EXIT_CODE.AUTH) + expect(result.structured.code).toBe(EXIT_CODE.AUTH) + expect(result.structured.status).toBe(401) + expect(result.message).toBe('Authentication error (401)') + }) + + it('maps 403 to AUTH exit code', () => { + const result = mapHttpError(403, null) + expect(result.exitCode).toBe(EXIT_CODE.AUTH) + expect(result.structured.code).toBe(EXIT_CODE.AUTH) + expect(result.structured.status).toBe(403) + expect(result.message).toBe('Authentication error (403)') + }) + + it('uses body message for 401 when available', () => { + const result = mapHttpError(401, {message: 'Invalid API key'}) + expect(result.exitCode).toBe(EXIT_CODE.AUTH) + expect(result.message).toBe('Invalid API key') + }) + }) + + describe('404 -> NOT_FOUND exit code', () => { + it('maps 404 to NOT_FOUND exit code', () => { + const result = mapHttpError(404, null) + expect(result.exitCode).toBe(EXIT_CODE.NOT_FOUND) + expect(result.structured.code).toBe(EXIT_CODE.NOT_FOUND) + expect(result.structured.status).toBe(404) + expect(result.message).toBe('Resource not found') + }) + + it('uses body message for 404 when available', () => { + const result = mapHttpError(404, {message: 'Vault account not found'}) + expect(result.exitCode).toBe(EXIT_CODE.NOT_FOUND) + expect(result.message).toBe('Vault account not found') + }) + }) + + describe('429 -> RATE_LIMIT exit code with retry_after', () => { + it('maps 429 to RATE_LIMIT exit code', () => { + const result = mapHttpError(429, null) + expect(result.exitCode).toBe(EXIT_CODE.RATE_LIMIT) + expect(result.structured.code).toBe(EXIT_CODE.RATE_LIMIT) + expect(result.structured.status).toBe(429) + expect(result.message).toBe('Rate limit exceeded') + }) + + it('includes retry_after when valid numeric string', () => { + const result = mapHttpError(429, null, 'req-123', '30') + expect(result.exitCode).toBe(EXIT_CODE.RATE_LIMIT) + expect(result.structured.retry_after).toBe(30) + }) + + it('does not include retry_after when header is missing', () => { + const result = mapHttpError(429, null, undefined, null) + expect(result.structured.retry_after).toBeUndefined() + }) + + it('ignores NaN retry_after values like date strings', () => { + const result = mapHttpError(429, null, 'req-123', 'Wed, 21 Oct 2015') + expect(result.structured.retry_after).toBeUndefined() + }) + + it('ignores negative retry_after values', () => { + const result = mapHttpError(429, null, 'req-123', '-1') + expect(result.structured.retry_after).toBeUndefined() + }) + }) + + describe('500+ -> SERVER exit code', () => { + it('maps 500 to SERVER exit code', () => { + const result = mapHttpError(500, null) + expect(result.exitCode).toBe(EXIT_CODE.SERVER) + expect(result.structured.code).toBe(EXIT_CODE.SERVER) + expect(result.structured.status).toBe(500) + expect(result.message).toBe('Server error (500)') + }) + + it('maps 502 to SERVER exit code', () => { + const result = mapHttpError(502, null) + expect(result.exitCode).toBe(EXIT_CODE.SERVER) + expect(result.message).toBe('Server error (502)') + }) + + it('maps 503 to SERVER exit code', () => { + const result = mapHttpError(503, null) + expect(result.exitCode).toBe(EXIT_CODE.SERVER) + expect(result.message).toBe('Server error (503)') + }) + }) + + describe('other status codes -> GENERAL exit code', () => { + it('maps 400 to GENERAL exit code', () => { + const result = mapHttpError(400, null) + expect(result.exitCode).toBe(EXIT_CODE.GENERAL) + expect(result.structured.code).toBe(EXIT_CODE.GENERAL) + expect(result.message).toBe('HTTP error 400') + }) + + it('maps 422 to GENERAL exit code', () => { + const result = mapHttpError(422, {message: 'Validation error'}) + expect(result.exitCode).toBe(EXIT_CODE.GENERAL) + expect(result.message).toBe('Validation error') + }) + + it('maps 409 to GENERAL exit code', () => { + const result = mapHttpError(409, null) + expect(result.exitCode).toBe(EXIT_CODE.GENERAL) + expect(result.message).toBe('HTTP error 409') + }) + }) + + describe('request_id handling', () => { + it('includes request_id in structured error when provided', () => { + const result = mapHttpError(500, null, 'req-abc-123') + expect(result.structured.request_id).toBe('req-abc-123') + }) + + it('does not include request_id when not provided', () => { + const result = mapHttpError(500, null) + expect(result.structured.request_id).toBeUndefined() + }) + }) + + describe('body message extraction', () => { + it('extracts message from body object', () => { + const result = mapHttpError(400, {message: 'Bad request body'}) + expect(result.message).toBe('Bad request body') + }) + + it('uses default message when body has no message field', () => { + const result = mapHttpError(400, {error: 'something'}) + expect(result.message).toBe('HTTP error 400') + }) + + it('uses default message when body is null', () => { + const result = mapHttpError(500, null) + expect(result.message).toBe('Server error (500)') + }) + + it('uses default message when body is a string', () => { + const result = mapHttpError(500, 'plain string') + expect(result.message).toBe('Server error (500)') + }) + }) +}) diff --git a/src/lib/errors/mapper.ts b/src/lib/errors/mapper.ts new file mode 100644 index 0000000..6761f60 --- /dev/null +++ b/src/lib/errors/mapper.ts @@ -0,0 +1,69 @@ +export interface StructuredError { + code: number + status: number + message: string + request_id?: string + retry_after?: number +} + +export const EXIT_CODE = { + GENERAL: 1, + AUTH: 3, + NOT_FOUND: 4, + RATE_LIMIT: 5, + SERVER: 6, + TIMEOUT: 7, +} as const + +export function mapHttpError( + status: number, + body: unknown, + requestId?: string, + retryAfter?: string | null, +): {exitCode: number; message: string; structured: StructuredError} { + let exitCode: number + let message: string + + const bodyMessage = + typeof body === 'object' && body !== null && 'message' in body + ? String((body as {message: unknown}).message) + : undefined + + switch (true) { + case status === 401 || status === 403: + exitCode = EXIT_CODE.AUTH + message = bodyMessage ?? `Authentication error (${status})` + break + case status === 404: + exitCode = EXIT_CODE.NOT_FOUND + message = bodyMessage ?? 'Resource not found' + break + case status === 429: + exitCode = EXIT_CODE.RATE_LIMIT + message = bodyMessage ?? 'Rate limit exceeded' + break + case status >= 500: + exitCode = EXIT_CODE.SERVER + message = bodyMessage ?? `Server error (${status})` + break + default: + exitCode = EXIT_CODE.GENERAL + message = bodyMessage ?? `HTTP error ${status}` + } + + const structured: StructuredError = { + code: exitCode, + status, + message, + } + + if (requestId) structured.request_id = requestId + if (retryAfter) { + const parsed = Number.parseInt(retryAfter, 10) + if (!Number.isNaN(parsed) && parsed > 0) { + structured.retry_after = parsed + } + } + + return {exitCode, message, structured} +} diff --git a/src/lib/http/client.test.ts b/src/lib/http/client.test.ts new file mode 100644 index 0000000..e6f770a --- /dev/null +++ b/src/lib/http/client.test.ts @@ -0,0 +1,277 @@ +import {generateKeyPairSync} from 'node:crypto' +import type {AuthContext} from '../auth/config.js' +import type {RequestOptions} from './client.js' + +// Mock the signer +jest.mock('../auth/signer.js', () => ({ + signRequest: jest.fn().mockResolvedValue('mock-jwt-token'), +})) + +// Mock version module to avoid import.meta.url in Jest CJS mode +jest.mock('../version.js', () => ({ + getCliVersion: () => '1.0.0-test', +})) + +import {fireblocksFetch} from './client.js' +import {signRequest} from '../auth/signer.js' + +const mockSignRequest = signRequest as jest.Mock + +const {privateKey: TEST_PRIVATE_KEY} = generateKeyPairSync('rsa', { + modulusLength: 2048, + privateKeyEncoding: {type: 'pkcs8', format: 'pem'}, + publicKeyEncoding: {type: 'spki', format: 'pem'}, +}) + +const testAuth: AuthContext = { + apiKey: 'test-api-key', + privateKey: TEST_PRIVATE_KEY, + baseUrl: 'https://api.test.fireblocks.io', +} + +function mockResponse(body: unknown, status = 200, headers: Record = {}): Response { + const defaultHeaders = {'content-type': 'application/json', ...headers} + return { + status, + ok: status < 400, + headers: new Headers(defaultHeaders), + json: () => Promise.resolve(body), + text: () => Promise.resolve(typeof body === 'string' ? body : JSON.stringify(body)), + } as unknown as Response +} + +let originalFetch: typeof globalThis.fetch +const mockFetch = jest.fn, [RequestInfo | URL, RequestInit?]>() + +beforeEach(() => { + jest.clearAllMocks() + originalFetch = globalThis.fetch + globalThis.fetch = mockFetch as unknown as typeof globalThis.fetch +}) + +afterEach(() => { + globalThis.fetch = originalFetch +}) + +describe('fireblocksFetch', () => { + describe('basic GET request', () => { + it('constructs the correct URL, sets auth headers, and uses the right method', async () => { + mockFetch.mockResolvedValueOnce(mockResponse({data: 'ok'})) + + const result = await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts') + + expect(mockFetch).toHaveBeenCalledTimes(1) + const [url, init] = mockFetch.mock.calls[0] + expect(url).toBe('https://api.test.fireblocks.io/v1/vault/accounts') + expect(init?.method).toBe('GET') + expect(init?.headers).toMatchObject({ + Authorization: 'Bearer mock-jwt-token', + 'X-API-Key': 'test-api-key', + 'User-Agent': expect.stringMatching(/^fireblocks-cli\//), + }) + expect(init?.body).toBeUndefined() + + expect(mockSignRequest).toHaveBeenCalledWith( + 'test-api-key', + testAuth.privateKey, + '/v1/vault/accounts', + undefined, + ) + + expect(result.status).toBe(200) + expect(result.body).toEqual({data: 'ok'}) + }) + }) + + describe('POST with body', () => { + it('stringifies the body and sets Content-Type header', async () => { + mockFetch.mockResolvedValueOnce(mockResponse({id: '123'})) + + const options: RequestOptions = { + body: {name: 'My Vault', autoFuel: true}, + } + + await fireblocksFetch(testAuth, 'POST', '/v1/vault/accounts', options) + + const [, init] = mockFetch.mock.calls[0] + expect(init?.body).toBe(JSON.stringify({name: 'My Vault', autoFuel: true})) + expect(init?.headers).toMatchObject({ + 'Content-Type': 'application/json', + }) + + expect(mockSignRequest).toHaveBeenCalledWith( + 'test-api-key', + testAuth.privateKey, + '/v1/vault/accounts', + JSON.stringify({name: 'My Vault', autoFuel: true}), + ) + }) + }) + + describe('query parameters', () => { + it('appends query string to URL and includes it in signed path', async () => { + mockFetch.mockResolvedValueOnce(mockResponse([])) + + const options: RequestOptions = { + queryParams: {limit: 10, offset: 0, namePrefix: 'test'}, + } + + await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts', options) + + const [url] = mockFetch.mock.calls[0] + const parsed = new URL(url as string) + expect(parsed.searchParams.get('limit')).toBe('10') + expect(parsed.searchParams.get('offset')).toBe('0') + expect(parsed.searchParams.get('namePrefix')).toBe('test') + + // JWT must be signed with path + query string (matches TS-SDK behavior) + const signedPath = mockSignRequest.mock.calls[0][2] as string + expect(signedPath).toContain('?') + expect(signedPath).toMatch(/^\/v1\/vault\/accounts\?/) + const signedParams = new URLSearchParams(signedPath.split('?')[1]) + expect(signedParams.get('limit')).toBe('10') + expect(signedParams.get('offset')).toBe('0') + expect(signedParams.get('namePrefix')).toBe('test') + }) + + it('skips undefined, null, and empty string values', async () => { + mockFetch.mockResolvedValueOnce(mockResponse([])) + + const options: RequestOptions = { + queryParams: { + limit: 10, + offset: undefined, + filter: null, + namePrefix: '', + active: true, + }, + } + + await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts', options) + + const [url] = mockFetch.mock.calls[0] + const parsed = new URL(url as string) + expect(parsed.searchParams.get('limit')).toBe('10') + expect(parsed.searchParams.get('active')).toBe('true') + expect(parsed.searchParams.has('offset')).toBe(false) + expect(parsed.searchParams.has('filter')).toBe(false) + expect(parsed.searchParams.has('namePrefix')).toBe(false) + + // Signed path should only contain the non-empty params + const signedPath = mockSignRequest.mock.calls[0][2] as string + const signedParams = new URLSearchParams(signedPath.split('?')[1]) + expect(signedParams.get('limit')).toBe('10') + expect(signedParams.get('active')).toBe('true') + expect(signedParams.has('offset')).toBe(false) + }) + + it('signs with bare path when all query params are empty', async () => { + mockFetch.mockResolvedValueOnce(mockResponse([])) + + const options: RequestOptions = { + queryParams: {offset: undefined, filter: null, namePrefix: ''}, + } + + await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts', options) + + expect(mockSignRequest).toHaveBeenCalledWith( + 'test-api-key', + testAuth.privateKey, + '/v1/vault/accounts', + undefined, + ) + }) + }) + + describe('JSON response parsing', () => { + it('parses JSON response body correctly', async () => { + const responseData = {id: '1', name: 'Test Account', assets: [{id: 'BTC'}]} + mockFetch.mockResolvedValueOnce(mockResponse(responseData)) + + const result = await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts/1') + + expect(result.body).toEqual(responseData) + expect(result.status).toBe(200) + }) + }) + + describe('non-JSON response', () => { + it('returns null body for non-JSON content types', async () => { + mockFetch.mockResolvedValueOnce( + mockResponse('OK', 200, {'content-type': 'text/plain'}), + ) + + const result = await fireblocksFetch(testAuth, 'GET', '/v1/health') + + expect(result.body).toBeNull() + }) + }) + + describe('invalid JSON response', () => { + it('returns _parseError and _rawBody fields for malformed JSON', async () => { + const malformedResponse = { + status: 200, + ok: true, + headers: new Headers({'content-type': 'application/json'}), + json: () => Promise.reject(new Error('Unexpected token')), + text: () => Promise.resolve('this is not json {{{'), + } as unknown as Response + mockFetch.mockResolvedValueOnce(malformedResponse) + + const result = await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts') + + expect(result.body).toEqual({ + _parseError: 'Response body was not valid JSON', + _rawBody: 'this is not json {{{', + }) + }) + }) + + describe('request ID extraction', () => { + it('captures x-request-id header from response', async () => { + mockFetch.mockResolvedValueOnce( + mockResponse({ok: true}, 200, {'x-request-id': 'req-abc-123'}), + ) + + const result = await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts') + + expect(result.requestId).toBe('req-abc-123') + }) + + it('returns undefined requestId when header is absent', async () => { + const response = { + status: 200, + ok: true, + headers: new Headers({'content-type': 'application/json'}), + json: () => Promise.resolve({}), + text: () => Promise.resolve('{}'), + } as unknown as Response + mockFetch.mockResolvedValueOnce(response) + + const result = await fireblocksFetch(testAuth, 'GET', '/v1/vault/accounts') + + expect(result.requestId).toBeUndefined() + }) + }) + + describe('204 No Content', () => { + it('does not attempt body parsing for 204 responses', async () => { + const textSpy = jest.fn() + const response = { + status: 204, + ok: true, + headers: new Headers({'content-type': 'application/json'}), + json: jest.fn(), + text: textSpy, + } as unknown as Response + mockFetch.mockResolvedValueOnce(response) + + const result = await fireblocksFetch(testAuth, 'DELETE', '/v1/vault/accounts/1') + + expect(result.status).toBe(204) + expect(result.body).toBeNull() + expect(textSpy).not.toHaveBeenCalled() + expect(response.json).not.toHaveBeenCalled() + }) + }) +}) diff --git a/src/lib/http/client.ts b/src/lib/http/client.ts new file mode 100644 index 0000000..853f1c7 --- /dev/null +++ b/src/lib/http/client.ts @@ -0,0 +1,87 @@ +import {signRequest} from '../auth/signer.js' +import type {AuthContext} from '../auth/config.js' +import {getCliVersion} from '../version.js' +const REQUEST_TIMEOUT_MS = 30_000 + +export interface RequestOptions { + body?: Record + queryParams?: Record + headers?: Record +} + +export interface ApiResponse { + status: number + body: unknown + headers: Headers + requestId?: string +} + +export async function fireblocksFetch( + auth: AuthContext, + method: string, + path: string, + options?: RequestOptions, +): Promise { + // Build query string and include it in the signed path. + // The Fireblocks server validates the JWT uri claim against the full + // request path including query params (matching the TS-SDK approach). + let queryString = '' + if (options?.queryParams) { + const params = new URLSearchParams() + for (const [key, value] of Object.entries(options.queryParams)) { + if (value === undefined || value === null || value === '') continue + params.set(key, String(value)) + } + + const qs = params.toString() + if (qs) queryString = '?' + qs + } + + const signedPath = path + queryString + const url = auth.baseUrl + signedPath + + // Serialize body + const bodyString = options?.body ? JSON.stringify(options.body) : undefined + + // Sign the request + const jwt = await signRequest(auth.apiKey, auth.privateKey, signedPath, bodyString) + + // Build headers + const headers: Record = { + ...options?.headers, + Authorization: `Bearer ${jwt}`, + 'X-API-Key': auth.apiKey, + 'User-Agent': `fireblocks-cli/${getCliVersion()}`, + } + + if (bodyString) { + headers['Content-Type'] = 'application/json' + } + + // Execute fetch + const response = await fetch(url, { + method, + headers, + body: bodyString, + signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS), + }) + + const contentType = response.headers.get('content-type') ?? '' + let responseBody: unknown = null + if (contentType.includes('application/json') && response.status !== 204) { + const text = await response.text() + try { + responseBody = JSON.parse(text) + } catch { + responseBody = {_parseError: 'Response body was not valid JSON', _rawBody: text.slice(0, 1000)} + } + } + const requestId = response.headers.get('x-request-id') ?? undefined + + return { + status: response.status, + body: responseBody, + headers: response.headers, + requestId, + } +} diff --git a/src/lib/output/formatter.ts b/src/lib/output/formatter.ts new file mode 100644 index 0000000..c00bb8d --- /dev/null +++ b/src/lib/output/formatter.ts @@ -0,0 +1,8 @@ +import {dump} from 'js-yaml' + +export function formatOutput(data: unknown, format: string = 'json'): string { + if (format === 'yaml') { + return dump(data, {indent: 2, lineWidth: -1}) + } + return JSON.stringify(data, null, 2) +} diff --git a/src/lib/output/headers.test.ts b/src/lib/output/headers.test.ts new file mode 100644 index 0000000..d72defb --- /dev/null +++ b/src/lib/output/headers.test.ts @@ -0,0 +1,79 @@ +import {formatHeaders} from './headers.js' + +describe('formatHeaders', () => { + it('returns matching headers in spec-defined order', () => { + const headers = new Headers({ + 'x-request-id': 'abc-123', + 'next-page': 'https://api.fireblocks.io/v1/transactions?next=xyz', + 'prev-page': 'https://api.fireblocks.io/v1/transactions?prev=abc', + }) + + const result = formatHeaders(headers, ['X-Request-ID', 'next-page', 'prev-page']) + + expect(result).toBe( + 'X-Request-ID: abc-123\n' + + 'next-page: https://api.fireblocks.io/v1/transactions?next=xyz\n' + + 'prev-page: https://api.fireblocks.io/v1/transactions?prev=abc', + ) + }) + + it('returns null when no headers match', () => { + const headers = new Headers({}) + const result = formatHeaders(headers, ['X-Request-ID']) + expect(result).toBeNull() + }) + + it('skips headers not in the allowlist', () => { + const headers = new Headers({ + 'x-request-id': 'abc-123', + 'content-type': 'application/json', + 'x-extra-header': 'should-not-appear', + }) + + const result = formatHeaders(headers, ['X-Request-ID']) + + expect(result).toBe('X-Request-ID: abc-123') + expect(result).not.toContain('content-type') + expect(result).not.toContain('x-extra-header') + }) + + it('skips allowed headers not present in the response', () => { + const headers = new Headers({ + 'x-request-id': 'abc-123', + }) + + const result = formatHeaders(headers, ['X-Request-ID', 'next-page', 'prev-page']) + + expect(result).toBe('X-Request-ID: abc-123') + }) + + it('handles partial presence — only includes present headers', () => { + const headers = new Headers({ + 'next-page': 'https://api.fireblocks.io/v1/transactions?next=xyz', + }) + + const result = formatHeaders(headers, ['X-Request-ID', 'next-page', 'prev-page']) + + expect(result).toBe('next-page: https://api.fireblocks.io/v1/transactions?next=xyz') + }) + + it('preserves allowedHeaders casing in output even if server sends lowercase', () => { + const headers = new Headers({ + 'x-request-id': 'abc-123', + }) + + const result = formatHeaders(headers, ['X-Request-ID']) + + expect(result).toBe('X-Request-ID: abc-123') + }) + + it('returns null for empty allowedHeaders array', () => { + const headers = new Headers({ + 'x-request-id': 'abc-123', + }) + + const result = formatHeaders(headers, []) + + expect(result).toBeNull() + }) +}) diff --git a/src/lib/output/headers.ts b/src/lib/output/headers.ts new file mode 100644 index 0000000..ca21a79 --- /dev/null +++ b/src/lib/output/headers.ts @@ -0,0 +1,19 @@ +/** + * Format response headers for display. Only includes headers that are both + * in the allowed list (from the OpenAPI spec) and present in the actual response. + * Returns null if no matching headers are found. + */ +export function formatHeaders( + responseHeaders: Headers, + allowedHeaders: string[], +): string | null { + const lines: string[] = [] + for (const name of allowedHeaders) { + const value = responseHeaders.get(name) + if (value !== null) { + lines.push(`${name}: ${value}`) + } + } + + return lines.length > 0 ? lines.join('\n') : null +} diff --git a/src/lib/version.ts b/src/lib/version.ts new file mode 100644 index 0000000..a0c1b99 --- /dev/null +++ b/src/lib/version.ts @@ -0,0 +1,17 @@ +import {readFileSync} from 'node:fs' +import {fileURLToPath} from 'node:url' +import {join, dirname} from 'node:path' + +let _cliVersion: string | undefined + +export function getCliVersion(): string { + if (_cliVersion !== undefined) return _cliVersion + try { + const here = dirname(fileURLToPath(import.meta.url)) + const pkg = JSON.parse(readFileSync(join(here, '..', '..', 'package.json'), 'utf-8')) as {version: string} + _cliVersion = pkg.version + } catch { + _cliVersion = 'unknown' + } + return _cliVersion +} diff --git a/test/contract.test.ts b/test/contract.test.ts new file mode 100644 index 0000000..f51e1f5 --- /dev/null +++ b/test/contract.test.ts @@ -0,0 +1,74 @@ +import {existsSync, readdirSync, readFileSync} from 'node:fs' +import {join} from 'node:path' + +const COMMANDS_DIR = join(__dirname, '..', 'src', 'commands') + +describe('contract: generated CLI structure', () => { + it('has generated command directories (namespaces)', () => { + const entries = readdirSync(COMMANDS_DIR, {withFileTypes: true}) + const dirs = entries.filter((e) => e.isDirectory()) + expect(dirs.length).toBeGreaterThan(10) + }) + + it('has hand-written commands', () => { + expect(existsSync(join(COMMANDS_DIR, 'configure.ts'))).toBe(true) + expect(existsSync(join(COMMANDS_DIR, 'whoami.ts'))).toBe(true) + expect(existsSync(join(COMMANDS_DIR, 'help-index.ts'))).toBe(true) + }) + + it('generated commands extend FireblocksBaseCommand', () => { + const namespaces = readdirSync(COMMANDS_DIR, {withFileTypes: true}) + .filter((e) => e.isDirectory()) + + let checked = 0 + for (const ns of namespaces) { + const files = readdirSync(join(COMMANDS_DIR, ns.name)).filter((f) => f.endsWith('.ts')) + for (const file of files.slice(0, 3)) { + const content = readFileSync(join(COMMANDS_DIR, ns.name, file), 'utf-8') + expect(content).toContain('FireblocksBaseCommand') + expect(content).toContain("from '../../lib/base-command.js'") + checked++ + } + } + + expect(checked).toBeGreaterThan(10) + }) + + it('getTransactions has responseHeaders and include-headers flag', () => { + const txFile = join(COMMANDS_DIR, 'transactions', 'get-transactions.ts') + expect(existsSync(txFile)).toBe(true) + + const content = readFileSync(txFile, 'utf-8') + expect(content).toContain('static responseHeaders: string[]') + expect(content).toContain('next-page') + expect(content).toContain('prev-page') + expect(content).toContain("'include-headers': Flags.boolean(") + }) + + it('commands without response headers do not have include-headers flag', () => { + // whoami is a hand-written command without responseHeaders + const whoamiContent = readFileSync(join(COMMANDS_DIR, 'whoami.ts'), 'utf-8') + expect(whoamiContent).not.toContain('include-headers') + expect(whoamiContent).not.toContain('responseHeaders') + }) + + it('write commands have --data flag', () => { + const namespaces = readdirSync(COMMANDS_DIR, {withFileTypes: true}) + .filter((e) => e.isDirectory()) + + let writeCommands = 0 + for (const ns of namespaces) { + const files = readdirSync(join(COMMANDS_DIR, ns.name)).filter((f) => f.endsWith('.ts')) + for (const file of files) { + const content = readFileSync(join(COMMANDS_DIR, ns.name, file), 'utf-8') + if (content.includes("static method = 'POST'") || content.includes("static method = 'PUT'")) { + if (content.includes("flags.data")) { + writeCommands++ + } + } + } + } + + expect(writeCommands).toBeGreaterThan(10) + }) +}) diff --git a/test/e2e.test.ts b/test/e2e.test.ts new file mode 100644 index 0000000..58b6018 --- /dev/null +++ b/test/e2e.test.ts @@ -0,0 +1,501 @@ +import {generateKeyPairSync} from 'node:crypto' + +// Generate a real RSA key pair for signing +const {privateKey: TEST_PRIVATE_KEY} = generateKeyPairSync('rsa', { + modulusLength: 2048, + publicKeyEncoding: {type: 'spki', format: 'pem'}, + privateKeyEncoding: {type: 'pkcs8', format: 'pem'}, +}) + +const TEST_API_KEY = 'e2e-test-api-key' +const TEST_BASE_URL = 'https://api.fireblocks.io' + +// Mock resolveAuth so commands don't need real credentials or config files +jest.mock('../src/lib/auth/config.js', () => ({ + resolveAuth: jest.fn().mockResolvedValue({ + apiKey: TEST_API_KEY, + privateKey: TEST_PRIVATE_KEY, + baseUrl: TEST_BASE_URL, + }), +})) + +jest.mock('../src/lib/auth/index.js', () => ({ + resolveAuth: jest.fn().mockResolvedValue({ + apiKey: TEST_API_KEY, + privateKey: TEST_PRIVATE_KEY, + baseUrl: TEST_BASE_URL, + }), +})) + +// Mock the HTTP client to intercept all API calls +const mockFireblocksFetch = jest.fn() +jest.mock('../src/lib/http/client.js', () => ({ + fireblocksFetch: mockFireblocksFetch, +})) + +// Suppress oclif's command discovery warnings — oclif emits CLIError objects +// via process.emitWarning(), which Node 22+ rejects (expects string or Error). +const originalEmitWarning = process.emitWarning +beforeAll(() => { + process.emitWarning = (() => {}) as typeof process.emitWarning +}) + +afterAll(() => { + process.emitWarning = originalEmitWarning +}) + +beforeEach(() => { + mockFireblocksFetch.mockReset() +}) + +afterEach(() => { + jest.restoreAllMocks() +}) + +/** + * Helper: create a mock ApiResponse compatible with what fireblocksFetch returns. + */ +function createMockApiResponse( + status: number, + body: unknown, + headers?: Record, + requestId?: string, +) { + return { + status, + body, + headers: new Headers(headers), + requestId, + } +} + +describe('e2e: full command execution flow', () => { + describe('successful GET request', () => { + it('executes a GET command and outputs the response', async () => { + const mockBody = { + id: 'vault-1', + name: 'My Vault', + assets: [], + } + + mockFireblocksFetch.mockResolvedValueOnce(createMockApiResponse(200, mockBody)) + + // Import and run the command + const {default: GetVaultAccount} = require( + '../src/commands/vaults/get-vault-account.js' + ) + + // Use oclif's run method with argv + try { + await GetVaultAccount.run([ + '--vault-account-id', '123', + '--no-confirm', + ]) + } catch (error: any) { + // oclif wraps exits in errors; successful exits are expected + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) { + throw error + } + } + + // Verify fireblocksFetch was called + expect(mockFireblocksFetch).toHaveBeenCalledTimes(1) + + const [auth, method, path] = mockFireblocksFetch.mock.calls[0] + expect(path).toContain('/v1/vault/accounts/123') + expect(method).toBe('GET') + + // Verify auth context was passed + expect(auth.apiKey).toBe(TEST_API_KEY) + expect(auth.baseUrl).toBe(TEST_BASE_URL) + }) + }) + + describe('successful POST request with --data', () => { + it('executes a POST command with JSON body', async () => { + const mockResponseBody = { + id: 'tx-1', + status: 'SUBMITTED', + } + + mockFireblocksFetch.mockResolvedValueOnce(createMockApiResponse(200, mockResponseBody)) + + const {default: CreateTransaction} = require( + '../src/commands/transactions/create-transaction.js' + ) + + try { + await CreateTransaction.run([ + '--data', '{"assetId":"BTC","amount":"1.0","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"VAULT_ACCOUNT","id":"1"}}', + '--no-confirm', + ]) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) { + throw error + } + } + + expect(mockFireblocksFetch).toHaveBeenCalledTimes(1) + + const [auth, method, path, options] = mockFireblocksFetch.mock.calls[0] + expect(path).toContain('/v1/transactions') + expect(method).toBe('POST') + expect(options?.body).toBeDefined() + expect(options.body.assetId).toBe('BTC') + expect(options.body.amount).toBe('1.0') + }) + }) + + describe('--dry-run mode', () => { + it('outputs request preview without making an HTTP call', async () => { + const {default: GetVaultAccount} = require( + '../src/commands/vaults/get-vault-account.js' + ) + + try { + await GetVaultAccount.run([ + '--vault-account-id', '456', + '--dry-run', + '--no-confirm', + ]) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) { + throw error + } + } + + // fireblocksFetch should NOT have been called in dry-run mode + expect(mockFireblocksFetch).not.toHaveBeenCalled() + }) + }) + + describe('--output flag', () => { + it('outputs JSON by default', async () => { + const mockBody = {id: 'vault-1', name: 'My Vault', assets: []} + + mockFireblocksFetch.mockResolvedValueOnce(createMockApiResponse(200, mockBody)) + + const {default: GetVaultAccount} = require('../src/commands/vaults/get-vault-account.js') + const logSpy = jest.spyOn(GetVaultAccount.prototype, 'log').mockImplementation(() => {}) + + try { + await GetVaultAccount.run(['--vault-account-id', '123', '--no-confirm']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) throw error + } + + const output = logSpy.mock.calls[0][0] as string + expect(() => JSON.parse(output)).not.toThrow() + expect(output).toContain('"vault-1"') + logSpy.mockRestore() + }) + + it('outputs YAML when --output yaml is set', async () => { + const mockBody = {id: 'vault-1', name: 'My Vault', assets: []} + + mockFireblocksFetch.mockResolvedValueOnce(createMockApiResponse(200, mockBody)) + + const {default: GetVaultAccount} = require('../src/commands/vaults/get-vault-account.js') + const logSpy = jest.spyOn(GetVaultAccount.prototype, 'log').mockImplementation(() => {}) + + try { + await GetVaultAccount.run(['--vault-account-id', '123', '--no-confirm', '--output', 'yaml']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) throw error + } + + const output = logSpy.mock.calls[0][0] as string + expect(output).toContain('id: vault-1') + expect(output).toContain('name: My Vault') + expect(output).not.toContain('"vault-1"') + logSpy.mockRestore() + }) + + it('outputs YAML when -o yaml short flag is set', async () => { + const mockBody = [{id: 'tx-1', status: 'COMPLETED'}] + + mockFireblocksFetch.mockResolvedValueOnce(createMockApiResponse(200, mockBody)) + + const {default: GetTransactions} = require('../src/commands/transactions/get-transactions.js') + const logSpy = jest.spyOn(GetTransactions.prototype, 'log').mockImplementation(() => {}) + + try { + await GetTransactions.run(['--no-confirm', '-o', 'yaml']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) throw error + } + + const output = logSpy.mock.calls[0][0] as string + expect(output).toContain('id: tx-1') + expect(output).toContain('status: COMPLETED') + expect(output).not.toContain('"tx-1"') + logSpy.mockRestore() + }) + + it('outputs YAML for dry-run preview when --output yaml is set', async () => { + const {default: GetVaultAccount} = require('../src/commands/vaults/get-vault-account.js') + const logSpy = jest.spyOn(GetVaultAccount.prototype, 'log').mockImplementation(() => {}) + + try { + await GetVaultAccount.run(['--vault-account-id', '456', '--dry-run', '--no-confirm', '--output', 'yaml']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) throw error + } + + expect(mockFireblocksFetch).not.toHaveBeenCalled() + const output = logSpy.mock.calls[0][0] as string + expect(output).toContain('method: GET') + expect(output).toContain('/v1/vault/accounts/456') + logSpy.mockRestore() + }) + }) + + describe('--include-headers flag', () => { + it('prints response headers to stderr when flag is set', async () => { + const mockBody = [{id: 'tx-1', status: 'COMPLETED'}] + + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse(200, mockBody, { + 'x-request-id': 'req-abc-123', + 'next-page': 'https://api.fireblocks.io/v1/transactions?next=cursor123', + 'prev-page': 'https://api.fireblocks.io/v1/transactions?prev=cursor456', + }), + ) + + const {default: GetTransactions} = require( + '../src/commands/transactions/get-transactions.js' + ) + + const logSpy = jest.spyOn(GetTransactions.prototype, 'log').mockImplementation(() => {}) + const stderrSpy = jest.spyOn(GetTransactions.prototype, 'logToStderr').mockImplementation(() => {}) + + try { + await GetTransactions.run(['--include-headers', '--no-confirm']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) { + throw error + } + } + + // Headers go to stderr (keeps stdout clean for pipes/JSON) + const stderrCalls = stderrSpy.mock.calls.map((c) => c[0]) + expect(stderrCalls[0]).toContain('X-Request-ID: req-abc-123') + expect(stderrCalls[0]).toContain('next-page: https://api.fireblocks.io/v1/transactions?next=cursor123') + expect(stderrCalls[0]).toContain('prev-page: https://api.fireblocks.io/v1/transactions?prev=cursor456') + + // Blank separator on stderr + expect(stderrCalls[1]).toBe('') + + // Body goes to stdout only + const logCalls = logSpy.mock.calls.map((c) => c[0]) + expect(logCalls).toHaveLength(1) + expect(logCalls[0]).toContain('"tx-1"') + + logSpy.mockRestore() + stderrSpy.mockRestore() + }) + + it('does not print headers when flag is not set', async () => { + const mockBody = [{id: 'tx-1', status: 'COMPLETED'}] + + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse(200, mockBody, { + 'x-request-id': 'req-abc-123', + 'next-page': 'https://api.fireblocks.io/v1/transactions?next=cursor123', + }), + ) + + const {default: GetTransactions} = require( + '../src/commands/transactions/get-transactions.js' + ) + + const logSpy = jest.spyOn(GetTransactions.prototype, 'log').mockImplementation(() => {}) + + try { + await GetTransactions.run(['--no-confirm']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) { + throw error + } + } + + const logCalls = logSpy.mock.calls.map((c) => c[0]) + + // Only the body should be logged, no headers + expect(logCalls).toHaveLength(1) + expect(logCalls[0]).toContain('"tx-1"') + + logSpy.mockRestore() + }) + + it('only prints spec-defined headers, not extra response headers', async () => { + const mockBody = [{id: 'tx-1'}] + + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse(200, mockBody, { + 'x-request-id': 'req-abc-123', + 'next-page': 'https://api.fireblocks.io/v1/transactions?next=cursor123', + 'content-type': 'application/json', + 'x-custom-header': 'should-not-appear', + }), + ) + + const {default: GetTransactions} = require( + '../src/commands/transactions/get-transactions.js' + ) + + const stderrSpy = jest.spyOn(GetTransactions.prototype, 'logToStderr').mockImplementation(() => {}) + + try { + await GetTransactions.run(['--include-headers', '--no-confirm']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) { + throw error + } + } + + const stderrCalls = stderrSpy.mock.calls.map((c) => c[0]) + const headerOutput = stderrCalls[0] + + expect(headerOutput).toContain('X-Request-ID:') + expect(headerOutput).toContain('next-page:') + expect(headerOutput).not.toContain('content-type') + expect(headerOutput).not.toContain('x-custom-header') + + stderrSpy.mockRestore() + }) + + it('routes headers to stderr on error responses', async () => { + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse(401, {message: 'Unauthorized'}, { + 'x-request-id': 'req-err-456', + 'next-page': 'https://api.fireblocks.io/v1/transactions?next=cursor123', + }), + ) + + const {default: GetTransactions} = require( + '../src/commands/transactions/get-transactions.js' + ) + + const stderrSpy = jest.spyOn(GetTransactions.prototype, 'logToStderr').mockImplementation(() => {}) + + try { + await GetTransactions.run(['--include-headers', '--no-confirm']) + } catch (error: any) { + // expected — 401 exits with code 3 + } + + const stderrCalls = stderrSpy.mock.calls.map((c) => c[0]) + + // Headers should appear on stderr + expect(stderrCalls[0]).toContain('X-Request-ID: req-err-456') + expect(stderrCalls[0]).toContain('next-page:') + + stderrSpy.mockRestore() + }) + + it('does not print headers when response has none of the spec-defined headers', async () => { + const mockBody = [{id: 'tx-1'}] + + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse(200, mockBody, {}), + ) + + const {default: GetTransactions} = require( + '../src/commands/transactions/get-transactions.js' + ) + + const logSpy = jest.spyOn(GetTransactions.prototype, 'log').mockImplementation(() => {}) + const stderrSpy = jest.spyOn(GetTransactions.prototype, 'logToStderr').mockImplementation(() => {}) + + try { + await GetTransactions.run(['--include-headers', '--no-confirm']) + } catch (error: any) { + if (error?.oclif?.exit !== undefined && error.oclif.exit !== 0) { + throw error + } + } + + const logCalls = logSpy.mock.calls.map((c) => c[0]) + + // Only the body should be logged — no header output at all + expect(logCalls).toHaveLength(1) + expect(logCalls[0]).toContain('"tx-1"') + + // No header output on stderr either + const stderrCalls = stderrSpy.mock.calls.map((c) => c[0] as string) + expect(stderrCalls.every((c) => !c.includes('X-Request-ID'))).toBe(true) + + logSpy.mockRestore() + stderrSpy.mockRestore() + }) + }) + + describe('error scenarios', () => { + it('handles 401 authentication error with exit code 3', async () => { + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse(401, {message: 'Unauthorized'}), + ) + + const {default: GetVaultAccount} = require( + '../src/commands/vaults/get-vault-account.js' + ) + + try { + await GetVaultAccount.run([ + '--vault-account-id', '123', + '--no-confirm', + ]) + // If we get here without an error, the command didn't exit properly + throw new Error('Expected command to exit with code 3') + } catch (error: any) { + // oclif wraps process.exit in an error with code property + expect(error?.oclif?.exit).toBe(3) + } + }) + + it('handles 429 rate limit error with exit code 5', async () => { + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse( + 429, + {message: 'Rate limit exceeded'}, + {'retry-after': '30'}, + ), + ) + + const {default: GetVaultAccount} = require( + '../src/commands/vaults/get-vault-account.js' + ) + + try { + await GetVaultAccount.run([ + '--vault-account-id', '123', + '--no-confirm', + ]) + throw new Error('Expected command to exit with code 5') + } catch (error: any) { + expect(error?.oclif?.exit).toBe(5) + } + }) + + it('handles 500 server error with exit code 6', async () => { + mockFireblocksFetch.mockResolvedValueOnce( + createMockApiResponse(500, {message: 'Internal server error'}), + ) + + const {default: GetVaultAccount} = require( + '../src/commands/vaults/get-vault-account.js' + ) + + try { + await GetVaultAccount.run([ + '--vault-account-id', '123', + '--no-confirm', + ]) + throw new Error('Expected command to exit with code 6') + } catch (error: any) { + expect(error?.oclif?.exit).toBe(6) + } + }) + }) +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..298702a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "nodenext", + "target": "ES2023", + "declaration": true, + "outDir": "dist", + "rootDir": "src", + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true + }, + "include": ["./src/**/*"], + "exclude": ["./src/**/*.test.ts"], + "ts-node": { + "esm": true + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..3b31635 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4739 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aws-crypto/crc32@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz#cfcc22570949c98c6689cfcbd2d693d36cdae2e1" + integrity sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/crc32c@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz#4e34aab7f419307821509a98b9b08e84e0c1917e" + integrity sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/sha1-browser@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz#b0ee2d2821d3861f017e965ef3b4cb38e3b6a0f4" + integrity sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg== + dependencies: + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-browser@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz#153895ef1dba6f9fce38af550e0ef58988eb649e" + integrity sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw== + dependencies: + "@aws-crypto/sha256-js" "^5.2.0" + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-js@5.2.0", "@aws-crypto/sha256-js@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz#c4fdb773fdbed9a664fc1a95724e206cf3860042" + integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/supports-web-crypto@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz#a1e399af29269be08e695109aa15da0a07b5b5fb" + integrity sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg== + dependencies: + tslib "^2.6.2" + +"@aws-crypto/util@5.2.0", "@aws-crypto/util@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz#71284c9cffe7927ddadac793c14f14886d3876da" + integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-sdk/client-cloudfront@3.1009.0": + version "3.1009.0" + resolved "https://registry.npmjs.org/@aws-sdk/client-cloudfront/-/client-cloudfront-3.1009.0.tgz#378ce05603c38d31856a60fbc57032a6ecee07e4" + integrity sha512-KRac+gkuj3u49IyWkrudHRlP/q/faTto+1xRS7Aj6cDGewMIzgdQArrdZEJoVntbaVZHLM5s/NVmWORzBWNcSw== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "^3.973.20" + "@aws-sdk/credential-provider-node" "^3.972.21" + "@aws-sdk/middleware-host-header" "^3.972.8" + "@aws-sdk/middleware-logger" "^3.972.8" + "@aws-sdk/middleware-recursion-detection" "^3.972.8" + "@aws-sdk/middleware-user-agent" "^3.972.21" + "@aws-sdk/region-config-resolver" "^3.972.8" + "@aws-sdk/types" "^3.973.6" + "@aws-sdk/util-endpoints" "^3.996.5" + "@aws-sdk/util-user-agent-browser" "^3.972.8" + "@aws-sdk/util-user-agent-node" "^3.973.7" + "@smithy/config-resolver" "^4.4.11" + "@smithy/core" "^3.23.11" + "@smithy/fetch-http-handler" "^5.3.15" + "@smithy/hash-node" "^4.2.12" + "@smithy/invalid-dependency" "^4.2.12" + "@smithy/middleware-content-length" "^4.2.12" + "@smithy/middleware-endpoint" "^4.4.25" + "@smithy/middleware-retry" "^4.4.42" + "@smithy/middleware-serde" "^4.2.14" + "@smithy/middleware-stack" "^4.2.12" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/node-http-handler" "^4.4.16" + "@smithy/protocol-http" "^5.3.12" + "@smithy/smithy-client" "^4.12.5" + "@smithy/types" "^4.13.1" + "@smithy/url-parser" "^4.2.12" + "@smithy/util-base64" "^4.3.2" + "@smithy/util-body-length-browser" "^4.2.2" + "@smithy/util-body-length-node" "^4.2.3" + "@smithy/util-defaults-mode-browser" "^4.3.41" + "@smithy/util-defaults-mode-node" "^4.2.44" + "@smithy/util-endpoints" "^3.3.3" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-retry" "^4.2.12" + "@smithy/util-stream" "^4.5.19" + "@smithy/util-utf8" "^4.2.2" + "@smithy/util-waiter" "^4.2.13" + tslib "^2.6.2" + +"@aws-sdk/client-s3@3.1014.0": + version "3.1014.0" + resolved "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1014.0.tgz#46684750c3b95b46841000ba04115c010dc0b521" + integrity sha512-0XLrOT4Cm3NEhhiME7l/8LbTXS4KdsbR4dSrY207KNKTcHLLTZ9EXt4ZpgnTfLvWQF3pGP2us4Zi1fYLo0N+Ow== + dependencies: + "@aws-crypto/sha1-browser" "5.2.0" + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "^3.973.23" + "@aws-sdk/credential-provider-node" "^3.972.24" + "@aws-sdk/middleware-bucket-endpoint" "^3.972.8" + "@aws-sdk/middleware-expect-continue" "^3.972.8" + "@aws-sdk/middleware-flexible-checksums" "^3.974.3" + "@aws-sdk/middleware-host-header" "^3.972.8" + "@aws-sdk/middleware-location-constraint" "^3.972.8" + "@aws-sdk/middleware-logger" "^3.972.8" + "@aws-sdk/middleware-recursion-detection" "^3.972.8" + "@aws-sdk/middleware-sdk-s3" "^3.972.23" + "@aws-sdk/middleware-ssec" "^3.972.8" + "@aws-sdk/middleware-user-agent" "^3.972.24" + "@aws-sdk/region-config-resolver" "^3.972.9" + "@aws-sdk/signature-v4-multi-region" "^3.996.11" + "@aws-sdk/types" "^3.973.6" + "@aws-sdk/util-endpoints" "^3.996.5" + "@aws-sdk/util-user-agent-browser" "^3.972.8" + "@aws-sdk/util-user-agent-node" "^3.973.10" + "@smithy/config-resolver" "^4.4.13" + "@smithy/core" "^3.23.12" + "@smithy/eventstream-serde-browser" "^4.2.12" + "@smithy/eventstream-serde-config-resolver" "^4.3.12" + "@smithy/eventstream-serde-node" "^4.2.12" + "@smithy/fetch-http-handler" "^5.3.15" + "@smithy/hash-blob-browser" "^4.2.13" + "@smithy/hash-node" "^4.2.12" + "@smithy/hash-stream-node" "^4.2.12" + "@smithy/invalid-dependency" "^4.2.12" + "@smithy/md5-js" "^4.2.12" + "@smithy/middleware-content-length" "^4.2.12" + "@smithy/middleware-endpoint" "^4.4.27" + "@smithy/middleware-retry" "^4.4.44" + "@smithy/middleware-serde" "^4.2.15" + "@smithy/middleware-stack" "^4.2.12" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/node-http-handler" "^4.5.0" + "@smithy/protocol-http" "^5.3.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + "@smithy/url-parser" "^4.2.12" + "@smithy/util-base64" "^4.3.2" + "@smithy/util-body-length-browser" "^4.2.2" + "@smithy/util-body-length-node" "^4.2.3" + "@smithy/util-defaults-mode-browser" "^4.3.43" + "@smithy/util-defaults-mode-node" "^4.2.47" + "@smithy/util-endpoints" "^3.3.3" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-retry" "^4.2.12" + "@smithy/util-stream" "^4.5.20" + "@smithy/util-utf8" "^4.2.2" + "@smithy/util-waiter" "^4.2.13" + tslib "^2.6.2" + +"@aws-sdk/core@^3.973.20", "@aws-sdk/core@^3.973.23", "@aws-sdk/core@^3.973.25": + version "3.973.25" + resolved "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.25.tgz#7fbfa463458c4b9e0d5d7b2f77d21e7a8a55fcf6" + integrity sha512-TNrx7eq6nKNOO62HWPqoBqPLXEkW6nLZQGwjL6lq1jZtigWYbK1NbCnT7mKDzbLMHZfuOECUt3n6CzxjUW9HWQ== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@aws-sdk/xml-builder" "^3.972.16" + "@smithy/core" "^3.23.12" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/property-provider" "^4.2.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/signature-v4" "^5.3.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + "@smithy/util-base64" "^4.3.2" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@aws-sdk/crc64-nvme@^3.972.5": + version "3.972.5" + resolved "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.5.tgz#8b6213341e86759568dbf2d7631c6820580d2969" + integrity sha512-2VbTstbjKdT+yKi8m7b3a9CiVac+pL/IY2PHJwsaGkkHmuuqkJZIErPck1h6P3T9ghQMLSdMPyW6Qp7Di5swFg== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-env@^3.972.23": + version "3.972.23" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.23.tgz#567c0c227610707ef2c3a56bf79752cf696a0327" + integrity sha512-EamaclJcCEaPHp6wiVknNMM2RlsPMjAHSsYSFLNENBM8Wz92QPc6cOn3dif6vPDQt0Oo4IEghDy3NMDCzY/IvA== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/types" "^3.973.6" + "@smithy/property-provider" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-http@^3.972.25": + version "3.972.25" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.25.tgz#f5f08c6e3e68c5a0b750f6a7a10a005354af4d01" + integrity sha512-qPymamdPcLp6ugoVocG1y5r69ScNiRzb0hogX25/ij+Wz7c7WnsgjLTaz7+eB5BfRxeyUwuw5hgULMuwOGOpcw== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/types" "^3.973.6" + "@smithy/fetch-http-handler" "^5.3.15" + "@smithy/node-http-handler" "^4.5.0" + "@smithy/property-provider" "^4.2.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + "@smithy/util-stream" "^4.5.20" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-ini@^3.972.26": + version "3.972.26" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.26.tgz#d86842af5d218f32b757e304e82c31052ae3b6a8" + integrity sha512-xKxEAMuP6GYx2y5GET+d3aGEroax3AgGfwBE65EQAUe090lzyJ/RzxPX9s8v7Z6qAk0XwfQl+LrmH05X7YvTeg== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/credential-provider-env" "^3.972.23" + "@aws-sdk/credential-provider-http" "^3.972.25" + "@aws-sdk/credential-provider-login" "^3.972.26" + "@aws-sdk/credential-provider-process" "^3.972.23" + "@aws-sdk/credential-provider-sso" "^3.972.26" + "@aws-sdk/credential-provider-web-identity" "^3.972.26" + "@aws-sdk/nested-clients" "^3.996.16" + "@aws-sdk/types" "^3.973.6" + "@smithy/credential-provider-imds" "^4.2.12" + "@smithy/property-provider" "^4.2.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-login@^3.972.26": + version "3.972.26" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.26.tgz#2861846beb05dba5955ffc0067fec82d0c29b025" + integrity sha512-EFcM8RM3TUxnZOfMJo++3PnyxFu1fL/huzmn3Vh+8IWRgqZawUD3cRwwOr+/4bE9DpyHaLOWFAjY0lfK5X9ZkQ== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/nested-clients" "^3.996.16" + "@aws-sdk/types" "^3.973.6" + "@smithy/property-provider" "^4.2.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-node@^3.972.21", "@aws-sdk/credential-provider-node@^3.972.24": + version "3.972.27" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.27.tgz#083a99a817f5d3b430e174057b590075f48d46ba" + integrity sha512-jXpxSolfFnPVj6GCTtx3xIdWNoDR7hYC/0SbetGZxOC9UnNmipHeX1k6spVstf7eWJrMhXNQEgXC0pD1r5tXIg== + dependencies: + "@aws-sdk/credential-provider-env" "^3.972.23" + "@aws-sdk/credential-provider-http" "^3.972.25" + "@aws-sdk/credential-provider-ini" "^3.972.26" + "@aws-sdk/credential-provider-process" "^3.972.23" + "@aws-sdk/credential-provider-sso" "^3.972.26" + "@aws-sdk/credential-provider-web-identity" "^3.972.26" + "@aws-sdk/types" "^3.973.6" + "@smithy/credential-provider-imds" "^4.2.12" + "@smithy/property-provider" "^4.2.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-process@^3.972.23": + version "3.972.23" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.23.tgz#78436ebbc1b2970cf78834c61eea44a1c7b7bd62" + integrity sha512-IL/TFW59++b7MpHserjUblGrdP5UXy5Ekqqx1XQkERXBFJcZr74I7VaSrQT5dxdRMU16xGK4L0RQ5fQG1pMgnA== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/types" "^3.973.6" + "@smithy/property-provider" "^4.2.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-sso@^3.972.26": + version "3.972.26" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.26.tgz#d0aef5cd6bf958e42caf63c449f7d17a99b8be5f" + integrity sha512-c6ghvRb6gTlMznWhGxn/bpVCcp0HRaz4DobGVD9kI4vwHq186nU2xN/S7QGkm0lo0H2jQU8+dgpUFLxfTcwCOg== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/nested-clients" "^3.996.16" + "@aws-sdk/token-providers" "3.1019.0" + "@aws-sdk/types" "^3.973.6" + "@smithy/property-provider" "^4.2.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-web-identity@^3.972.26": + version "3.972.26" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.26.tgz#10fcf1a514db7763d00e16224f78e641ee0ce402" + integrity sha512-cXcS3+XD3iwhoXkM44AmxjmbcKueoLCINr1e+IceMmCySda5ysNIfiGBGe9qn5EMiQ9Jd7pP0AGFtcd6OV3Lvg== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/nested-clients" "^3.996.16" + "@aws-sdk/types" "^3.973.6" + "@smithy/property-provider" "^4.2.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-bucket-endpoint@^3.972.8": + version "3.972.8" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.8.tgz#cbb5eccad6e699991027dbd35e88153f92ea5082" + integrity sha512-WR525Rr2QJSETa9a050isktyWi/4yIGcmY3BQ1kpHqb0LqUglQHCS8R27dTJxxWNZvQ0RVGtEZjTCbZJpyF3Aw== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@aws-sdk/util-arn-parser" "^3.972.3" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + "@smithy/util-config-provider" "^4.2.2" + tslib "^2.6.2" + +"@aws-sdk/middleware-expect-continue@^3.972.8": + version "3.972.8" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.8.tgz#47857e3f8d792c702a0212dc565d32eefa4fac67" + integrity sha512-5DTBTiotEES1e2jOHAq//zyzCjeMB78lEHd35u15qnrid4Nxm7diqIf9fQQ3Ov0ChH1V3Vvt13thOnrACmfGVQ== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-flexible-checksums@^3.974.3": + version "3.974.5" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.5.tgz#5abff7dc7d0f4eee00c229b006caf5ee94c1e485" + integrity sha512-SPSvF0G1t8m8CcB0L+ClNFszzQOvXaxmRj25oRWDf6aU+TuN2PXPFAJ9A6lt1IvX4oGAqqbTdMPTYs/SSHUYYQ== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@aws-crypto/crc32c" "5.2.0" + "@aws-crypto/util" "5.2.0" + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/crc64-nvme" "^3.972.5" + "@aws-sdk/types" "^3.973.6" + "@smithy/is-array-buffer" "^4.2.2" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-stream" "^4.5.20" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@aws-sdk/middleware-host-header@^3.972.8": + version "3.972.8" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.8.tgz#72186e96500b49b38fb5482d6b7bf95e5b985281" + integrity sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-location-constraint@^3.972.8": + version "3.972.8" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.8.tgz#67e15d3ca55e825596fcc36da9aaf9f482da6fc9" + integrity sha512-KaUoFuoFPziIa98DSQsTPeke1gvGXlc5ZGMhy+b+nLxZ4A7jmJgLzjEF95l8aOQN2T/qlPP3MrAyELm8ExXucw== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-logger@^3.972.8": + version "3.972.8" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.8.tgz#7fee4223afcb6f7828dbdf4ea745ce15027cf384" + integrity sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-recursion-detection@^3.972.8", "@aws-sdk/middleware-recursion-detection@^3.972.9": + version "3.972.9" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.9.tgz#53a2cc0cf827863163b2351209212f642015c2e2" + integrity sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@aws/lambda-invoke-store" "^0.2.2" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-sdk-s3@^3.972.23", "@aws-sdk/middleware-sdk-s3@^3.972.26": + version "3.972.26" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.26.tgz#eac2558614babef07a22a363b2b2a0f4dd689124" + integrity sha512-5q7UGSTtt7/KF0Os8wj2VZtlLxeWJVb0e2eDrDJlWot2EIxUNKDDMPFq/FowUqrwZ40rO2bu6BypxaKNvQhI+g== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/types" "^3.973.6" + "@aws-sdk/util-arn-parser" "^3.972.3" + "@smithy/core" "^3.23.12" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/signature-v4" "^5.3.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + "@smithy/util-config-provider" "^4.2.2" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-stream" "^4.5.20" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@aws-sdk/middleware-ssec@^3.972.8": + version "3.972.8" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.8.tgz#4f71982bad76a907e4f5771796d18372e063c511" + integrity sha512-wqlK0yO/TxEC2UsY9wIlqeeutF6jjLe0f96Pbm40XscTo57nImUk9lBcw0dPgsm0sppFtAkSlDrfpK+pC30Wqw== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/middleware-user-agent@^3.972.21", "@aws-sdk/middleware-user-agent@^3.972.24", "@aws-sdk/middleware-user-agent@^3.972.26": + version "3.972.26" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.26.tgz#b37d7913e527a655e6aa6f22dfc3ce6abb04d010" + integrity sha512-AilFIh4rI/2hKyyGN6XrB0yN96W2o7e7wyrPWCM6QjZM1mcC/pVkW3IWWRvuBWMpVP8Fg+rMpbzeLQ6dTM4gig== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/types" "^3.973.6" + "@aws-sdk/util-endpoints" "^3.996.5" + "@smithy/core" "^3.23.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + "@smithy/util-retry" "^4.2.12" + tslib "^2.6.2" + +"@aws-sdk/nested-clients@^3.996.16": + version "3.996.16" + resolved "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.16.tgz#a77ed4542e190a9eff70fd2738a1756e29eddce1" + integrity sha512-L7Qzoj/qQU1cL5GnYLQP5LbI+wlLCLoINvcykR3htKcQ4tzrPf2DOs72x933BM7oArYj1SKrkb2lGlsJHIic3g== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/middleware-host-header" "^3.972.8" + "@aws-sdk/middleware-logger" "^3.972.8" + "@aws-sdk/middleware-recursion-detection" "^3.972.9" + "@aws-sdk/middleware-user-agent" "^3.972.26" + "@aws-sdk/region-config-resolver" "^3.972.10" + "@aws-sdk/types" "^3.973.6" + "@aws-sdk/util-endpoints" "^3.996.5" + "@aws-sdk/util-user-agent-browser" "^3.972.8" + "@aws-sdk/util-user-agent-node" "^3.973.12" + "@smithy/config-resolver" "^4.4.13" + "@smithy/core" "^3.23.12" + "@smithy/fetch-http-handler" "^5.3.15" + "@smithy/hash-node" "^4.2.12" + "@smithy/invalid-dependency" "^4.2.12" + "@smithy/middleware-content-length" "^4.2.12" + "@smithy/middleware-endpoint" "^4.4.27" + "@smithy/middleware-retry" "^4.4.44" + "@smithy/middleware-serde" "^4.2.15" + "@smithy/middleware-stack" "^4.2.12" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/node-http-handler" "^4.5.0" + "@smithy/protocol-http" "^5.3.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + "@smithy/url-parser" "^4.2.12" + "@smithy/util-base64" "^4.3.2" + "@smithy/util-body-length-browser" "^4.2.2" + "@smithy/util-body-length-node" "^4.2.3" + "@smithy/util-defaults-mode-browser" "^4.3.43" + "@smithy/util-defaults-mode-node" "^4.2.47" + "@smithy/util-endpoints" "^3.3.3" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-retry" "^4.2.12" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@aws-sdk/region-config-resolver@^3.972.10", "@aws-sdk/region-config-resolver@^3.972.8", "@aws-sdk/region-config-resolver@^3.972.9": + version "3.972.10" + resolved "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.10.tgz#cbabd969a2d4fedb652273403e64d98b79d0144c" + integrity sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/config-resolver" "^4.4.13" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/signature-v4-multi-region@^3.996.11": + version "3.996.14" + resolved "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.14.tgz#5ac1f558adc64a5b5569f34547a686505d9e8808" + integrity sha512-4nZSrBr1NO+48HCM/6BRU8mnRjuHZjcpziCvLXZk5QVftwWz5Mxqbhwdz4xf7WW88buaTB8uRO2MHklSX1m0vg== + dependencies: + "@aws-sdk/middleware-sdk-s3" "^3.972.26" + "@aws-sdk/types" "^3.973.6" + "@smithy/protocol-http" "^5.3.12" + "@smithy/signature-v4" "^5.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/token-providers@3.1019.0": + version "3.1019.0" + resolved "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1019.0.tgz#e19522b0f4ccd831a41e33e1065fd1f910d77edd" + integrity sha512-OF+2RfRmUKyjzrRWlDcyju3RBsuqcrYDQ8TwrJg8efcOotMzuZN4U9mpVTIdATpmEc4lWNZBMSjPzrGm6JPnAQ== + dependencies: + "@aws-sdk/core" "^3.973.25" + "@aws-sdk/nested-clients" "^3.996.16" + "@aws-sdk/types" "^3.973.6" + "@smithy/property-provider" "^4.2.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/types@^3.222.0", "@aws-sdk/types@^3.973.6": + version "3.973.6" + resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.6.tgz#1964a7c01b5cb18befa445998ad1d02f86c5432d" + integrity sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@aws-sdk/util-arn-parser@^3.972.3": + version "3.972.3" + resolved "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.972.3.tgz#ed989862bbb172ce16d9e1cd5790e5fe367219c2" + integrity sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-endpoints@^3.996.5": + version "3.996.5" + resolved "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.5.tgz#6b12e80869ae6e84075bc24c2a4e6273ea87dfc2" + integrity sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/types" "^4.13.1" + "@smithy/url-parser" "^4.2.12" + "@smithy/util-endpoints" "^3.3.3" + tslib "^2.6.2" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.965.5" + resolved "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz#e30e6ff2aff6436209ed42c765dec2d2a48df7c0" + integrity sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-browser@^3.972.8": + version "3.972.8" + resolved "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.8.tgz#1044845c97c898cd68fc3f9c773494a6a98cdf80" + integrity sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA== + dependencies: + "@aws-sdk/types" "^3.973.6" + "@smithy/types" "^4.13.1" + bowser "^2.11.0" + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-node@^3.973.10", "@aws-sdk/util-user-agent-node@^3.973.12", "@aws-sdk/util-user-agent-node@^3.973.7": + version "3.973.12" + resolved "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.12.tgz#63442fd7d6d2bcec825755874522c3c2b1535d17" + integrity sha512-8phW0TS8ntENJgDcFewYT/Q8dOmarpvSxEjATu2GUBAutiHr++oEGCiBUwxslCMNvwW2cAPZNT53S/ym8zm/gg== + dependencies: + "@aws-sdk/middleware-user-agent" "^3.972.26" + "@aws-sdk/types" "^3.973.6" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/types" "^4.13.1" + "@smithy/util-config-provider" "^4.2.2" + tslib "^2.6.2" + +"@aws-sdk/xml-builder@^3.972.16": + version "3.972.16" + resolved "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.16.tgz#ea22fe022cf12d12b07f6faf75c4fa214dea00bc" + integrity sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A== + dependencies: + "@smithy/types" "^4.13.1" + fast-xml-parser "5.5.8" + tslib "^2.6.2" + +"@aws/lambda-invoke-store@^0.2.2": + version "0.2.4" + resolved "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz#802f6a50f6b6589063ef63ba8acdee86fcb9f395" + integrity sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ== + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": + version "7.29.0" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" + integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== + dependencies: + "@babel/helper-validator-identifier" "^7.28.5" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.28.6": + version "7.29.0" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d" + integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.29.0" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" + integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.29.0", "@babel/generator@^7.7.2": + version "7.29.1" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" + integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== + dependencies: + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== + dependencies: + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.6": + version "7.29.2" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz#9cfbccb02b8e229892c0b07038052cc1a8709c49" + integrity sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw== + dependencies: + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": + version "7.29.2" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz#58bd50b9a7951d134988a1ae177a35ef9a703ba1" + integrity sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA== + dependencies: + "@babel/types" "^7.29.0" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/template@^7.28.6", "@babel/template@^7.3.3": + version "7.28.6" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0": + version "7.29.0" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" + integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.29.0", "@babel/types@^7.3.3": + version "7.29.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@esbuild/aix-ppc64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz#4c585002f7ad694d38fe0e8cbf5cfd939ccff327" + integrity sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q== + +"@esbuild/android-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz#7625d0952c3b402d3ede203a16c9f2b78f8a4827" + integrity sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw== + +"@esbuild/android-arm@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz#9a0cf1d12997ec46dddfb32ce67e9bca842381ac" + integrity sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ== + +"@esbuild/android-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz#06e1fdc6283fccd6bc6aadd6754afce6cf96f42e" + integrity sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw== + +"@esbuild/darwin-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz#6c550ee6c0273bcb0fac244478ff727c26755d80" + integrity sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ== + +"@esbuild/darwin-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz#ed7a125e9f25ce0091b9aff783ee943f6ba6cb86" + integrity sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw== + +"@esbuild/freebsd-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz#597dc8e7161dba71db4c1656131c1f1e9d7660c6" + integrity sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw== + +"@esbuild/freebsd-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz#ea171f9f4f00efaa8e9d3fe8baa1b75d757d1b36" + integrity sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ== + +"@esbuild/linux-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz#e52d57f202369386e6dbcb3370a17a0491ab1464" + integrity sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA== + +"@esbuild/linux-arm@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz#5e0c0b634908adbce0a02cebeba8b3acac263fb6" + integrity sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg== + +"@esbuild/linux-ia32@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz#5f90f01f131652473ec06b038a14c49683e14ec7" + integrity sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA== + +"@esbuild/linux-loong64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz#63bacffdb99574c9318f9afbd0dd4fff76a837e3" + integrity sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA== + +"@esbuild/linux-mips64el@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz#c4b6952eca6a8efff67fee3671a3536c8e67b7eb" + integrity sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw== + +"@esbuild/linux-ppc64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz#6dea67d3d98c6986f1b7769e4f1848e5ae47ad58" + integrity sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA== + +"@esbuild/linux-riscv64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz#9ad2b4c3c0502c6bada9c81997bb56c597853489" + integrity sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw== + +"@esbuild/linux-s390x@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz#c43d3cfd073042ca6f5c52bb9bc313ed2066ce28" + integrity sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA== + +"@esbuild/linux-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz#45fa173e0591ac74d80d3cf76704713e14e2a4a6" + integrity sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA== + +"@esbuild/netbsd-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz#366b0ef40cdb986fc751cbdad16e8c25fe1ba879" + integrity sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q== + +"@esbuild/netbsd-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz#e985d49a3668fd2044343071d52e1ae815112b3e" + integrity sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg== + +"@esbuild/openbsd-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz#6fb4ab7b73f7e5572ce5ec9cf91c13ff6dd44842" + integrity sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow== + +"@esbuild/openbsd-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz#641f052040a0d79843d68898f5791638a026d983" + integrity sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ== + +"@esbuild/openharmony-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz#fc1d33eac9d81ae0a433b3ed1dd6171a20d4e317" + integrity sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg== + +"@esbuild/sunos-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz#af2cd5ca842d6d057121f66a192d4f797de28f53" + integrity sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g== + +"@esbuild/win32-arm64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz#78ec7e59bb06404583d4c9511e621db31c760de3" + integrity sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg== + +"@esbuild/win32-ia32@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz#0e616aa488b7ee5d2592ab070ff9ec06a9fddf11" + integrity sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw== + +"@esbuild/win32-x64@0.27.4": + version "0.27.4" + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz#1f7ba71a3d6155d44a6faa8dbe249c62ab3e408c" + integrity sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg== + +"@inquirer/ansi@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz#674a4c4d81ad460695cb2a1fc69d78cd187f337e" + integrity sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ== + +"@inquirer/checkbox@^4.3.2": + version "4.3.2" + resolved "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz#e1483e6519d6ffef97281a54d2a5baa0d81b3f3b" + integrity sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/core" "^10.3.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/confirm@^3.1.22": + version "3.2.0" + resolved "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.2.0.tgz#6af1284670ea7c7d95e3f1253684cfbd7228ad6a" + integrity sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw== + dependencies: + "@inquirer/core" "^9.1.0" + "@inquirer/type" "^1.5.3" + +"@inquirer/confirm@^5.1.21": + version "5.1.21" + resolved "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz#610c4acd7797d94890a6e2dde2c98eb1e891dd12" + integrity sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/core@^10.3.2": + version "10.3.2" + resolved "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz#535979ff3ff4fe1e7cc4f83e2320504c743b7e20" + integrity sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + cli-width "^4.1.0" + mute-stream "^2.0.0" + signal-exit "^4.1.0" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.3" + +"@inquirer/core@^9.1.0": + version "9.2.1" + resolved "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz#677c49dee399c9063f31e0c93f0f37bddc67add1" + integrity sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg== + dependencies: + "@inquirer/figures" "^1.0.6" + "@inquirer/type" "^2.0.0" + "@types/mute-stream" "^0.0.4" + "@types/node" "^22.5.5" + "@types/wrap-ansi" "^3.0.0" + ansi-escapes "^4.3.2" + cli-width "^4.1.0" + mute-stream "^1.0.0" + signal-exit "^4.1.0" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/editor@^4.2.23": + version "4.2.23" + resolved "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz#fe046a3bfdae931262de98c1052437d794322e0b" + integrity sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/external-editor" "^1.0.3" + "@inquirer/type" "^3.0.10" + +"@inquirer/expand@^4.0.23": + version "4.0.23" + resolved "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz#a38b5f32226d75717c370bdfed792313b92bdc05" + integrity sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/external-editor@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz#c23988291ee676290fdab3fd306e64010a6d13b8" + integrity sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA== + dependencies: + chardet "^2.1.1" + iconv-lite "^0.7.0" + +"@inquirer/figures@^1.0.15", "@inquirer/figures@^1.0.5", "@inquirer/figures@^1.0.6": + version "1.0.15" + resolved "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz#dbb49ed80df11df74268023b496ac5d9acd22b3a" + integrity sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g== + +"@inquirer/input@^2.2.4": + version "2.3.0" + resolved "https://registry.npmjs.org/@inquirer/input/-/input-2.3.0.tgz#9b99022f53780fecc842908f3f319b52a5a16865" + integrity sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw== + dependencies: + "@inquirer/core" "^9.1.0" + "@inquirer/type" "^1.5.3" + +"@inquirer/input@^4.3.1": + version "4.3.1" + resolved "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz#778683b4c4c4d95d05d4b05c4a854964b73565b4" + integrity sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/number@^3.0.23": + version "3.0.23" + resolved "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz#3fdec2540d642093fd7526818fd8d4bdc7335094" + integrity sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/password@^4.0.23": + version "4.0.23" + resolved "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz#b9f5187c8c92fd7aa9eceb9d8f2ead0d7e7b000d" + integrity sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + +"@inquirer/prompts@^7.10.1": + version "7.10.1" + resolved "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz#e1436c0484cf04c22548c74e2cd239e989d5f847" + integrity sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg== + dependencies: + "@inquirer/checkbox" "^4.3.2" + "@inquirer/confirm" "^5.1.21" + "@inquirer/editor" "^4.2.23" + "@inquirer/expand" "^4.0.23" + "@inquirer/input" "^4.3.1" + "@inquirer/number" "^3.0.23" + "@inquirer/password" "^4.0.23" + "@inquirer/rawlist" "^4.1.11" + "@inquirer/search" "^3.2.2" + "@inquirer/select" "^4.4.2" + +"@inquirer/rawlist@^4.1.11": + version "4.1.11" + resolved "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz#313c8c3ffccb7d41e990c606465726b4a898a033" + integrity sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/search@^3.2.2": + version "3.2.2" + resolved "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz#4cc6fd574dcd434e4399badc37c742c3fd534ac8" + integrity sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA== + dependencies: + "@inquirer/core" "^10.3.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/select@^2.5.0": + version "2.5.0" + resolved "https://registry.npmjs.org/@inquirer/select/-/select-2.5.0.tgz#345c6908ecfaeef3d84ddd2f9feb2f487c558efb" + integrity sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA== + dependencies: + "@inquirer/core" "^9.1.0" + "@inquirer/figures" "^1.0.5" + "@inquirer/type" "^1.5.3" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/select@^4.4.2": + version "4.4.2" + resolved "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz#2ac8fca960913f18f1d1b35323ed8fcd27d89323" + integrity sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w== + dependencies: + "@inquirer/ansi" "^1.0.2" + "@inquirer/core" "^10.3.2" + "@inquirer/figures" "^1.0.15" + "@inquirer/type" "^3.0.10" + yoctocolors-cjs "^2.1.3" + +"@inquirer/type@^1.5.3": + version "1.5.5" + resolved "https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz#303ea04ce7ad2e585b921b662b3be36ef7b4f09b" + integrity sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA== + dependencies: + mute-stream "^1.0.0" + +"@inquirer/type@^2.0.0": + version "2.0.0" + resolved "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz#08fa513dca2cb6264fe1b0a2fabade051444e3f6" + integrity sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag== + dependencies: + mute-stream "^1.0.0" + +"@inquirer/type@^3.0.10": + version "3.0.10" + resolved "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz#11ed564ec78432a200ea2601a212d24af8150d50" + integrity sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@mswjs/interceptors@^0.41.0": + version "0.41.3" + resolved "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.3.tgz#d766dc1a168aa315a6a0b2d0f2e0cf1b74f23c82" + integrity sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA== + dependencies: + "@open-draft/deferred-promise" "^2.2.0" + "@open-draft/logger" "^0.3.0" + "@open-draft/until" "^2.0.0" + is-node-process "^1.2.0" + outvariant "^1.4.3" + strict-event-emitter "^0.5.1" + +"@oclif/core@4.9.0": + version "4.9.0" + resolved "https://registry.npmjs.org/@oclif/core/-/core-4.9.0.tgz#aa9fbfc47ed4b0c7fdb9ae50b39a5b047fbca83c" + integrity sha512-k/ntRgDcUprTT+aaNoF+whk3cY3f9fRD2lkF6ul7JeCUg2MaMXVXZXfbRhJCfsiX51X8/5Pqo0LGdO9SLYXNHg== + dependencies: + ansi-escapes "^4.3.2" + ansis "^3.17.0" + clean-stack "^3.0.1" + cli-spinners "^2.9.2" + debug "^4.4.3" + ejs "^3.1.10" + get-package-type "^0.1.0" + indent-string "^4.0.0" + is-wsl "^2.2.0" + lilconfig "^3.1.3" + minimatch "^10.2.4" + semver "^7.7.3" + string-width "^4.2.3" + supports-color "^8" + tinyglobby "^0.2.14" + widest-line "^3.1.0" + wordwrap "^1.0.0" + wrap-ansi "^7.0.0" + +"@oclif/core@^4", "@oclif/core@^4.10.3": + version "4.10.3" + resolved "https://registry.npmjs.org/@oclif/core/-/core-4.10.3.tgz#8b817320a593a003698ed928c17f99a9ff6963fb" + integrity sha512-0mD8vcrrX5uRsxzvI8tbWmSVGngvZA/Qo6O0ZGvLPAWEauSf5GFniwgirhY0SkszuHwu0S1J1ivj/jHmqtIDuA== + dependencies: + ansi-escapes "^4.3.2" + ansis "^3.17.0" + clean-stack "^3.0.1" + cli-spinners "^2.9.2" + debug "^4.4.3" + ejs "^3.1.10" + get-package-type "^0.1.0" + indent-string "^4.0.0" + is-wsl "^2.2.0" + lilconfig "^3.1.3" + minimatch "^10.2.4" + semver "^7.7.3" + string-width "^4.2.3" + supports-color "^8" + tinyglobby "^0.2.14" + widest-line "^3.1.0" + wordwrap "^1.0.0" + wrap-ansi "^7.0.0" + +"@oclif/plugin-autocomplete@^3.2.42": + version "3.2.43" + resolved "https://registry.npmjs.org/@oclif/plugin-autocomplete/-/plugin-autocomplete-3.2.43.tgz#936dc36f8d51c31a6173617ea4902c25bc4b480b" + integrity sha512-Gz+z85f6PbnG9aphBe2IDD/IhYWRN9aOPIpiKG1bhJV3lKLiFHo26ZEWmB9+7Or+JCqcMMoi/4hEX/HaidMpSg== + dependencies: + "@oclif/core" "^4" + ansis "^3.16.0" + debug "^4.4.1" + ejs "^3.1.10" + +"@oclif/plugin-help@^6", "@oclif/plugin-help@^6.2.38": + version "6.2.41" + resolved "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.41.tgz#587f73a9dae1dfdf8c8f89c748ea9f1db3a1007a" + integrity sha512-oHqpm9a8NnLY9J5yIA+znchB2QCBqDUu5n7XINdZwfbhO6WOUZ2ANww6QN7crhvAKgpN5HK/ELN8Hy96kgLUuA== + dependencies: + "@oclif/core" "^4" + +"@oclif/plugin-not-found@^3.2.76": + version "3.2.78" + resolved "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-3.2.78.tgz#acdc8bd53005c8d23dfea948184de7968238b27e" + integrity sha512-wFg7rUYUxYsBMl0fEBHOJ+GAO0/3Nwpn4scmkqV3IQdch7+N1ke8qFOzLZal0kpa0wt+Tr/aJvaT8iYccPGZDQ== + dependencies: + "@inquirer/prompts" "^7.10.1" + "@oclif/core" "^4.10.3" + ansis "^3.17.0" + fast-levenshtein "^3.0.0" + +"@oclif/plugin-warn-if-update-available@^3.1.57": + version "3.1.58" + resolved "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.1.58.tgz#721dc1441770eff022a3de2bca779c5e4dfcad03" + integrity sha512-iZWcwqTW9ylpuU/kaUJY6gRQE+VzK3p1oFSa6/fDu7snx4knQlH8TBtaUR6ugTz2yzdDULF7MtuAyr3LXZg9/w== + dependencies: + "@oclif/core" "^4" + ansis "^3.17.0" + debug "^4.4.3" + http-call "^5.2.2" + lodash "^4.17.23" + registry-auth-token "^5.1.1" + +"@oclif/test@^4": + version "4.1.17" + resolved "https://registry.npmjs.org/@oclif/test/-/test-4.1.17.tgz#5c759e24f79d4e71113805d0bbcbfa4dcddcd3c7" + integrity sha512-OaD6/2vW9MqL58ZtaTGO1wc2vnPxZ/LLN0qp/+HVdMsBt/UDubxZreC3cxGR9rT8SMfyBvGIU8MzmZEBuiikAQ== + dependencies: + ansis "^3.17.0" + debug "^4.4.3" + +"@open-draft/deferred-promise@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz#4a822d10f6f0e316be4d67b4d4f8c9a124b073bd" + integrity sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA== + +"@open-draft/logger@^0.3.0": + version "0.3.0" + resolved "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz#2b3ab1242b360aa0adb28b85f5d7da1c133a0954" + integrity sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ== + dependencies: + is-node-process "^1.2.0" + outvariant "^1.4.0" + +"@open-draft/until@^2.0.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz#0acf32f470af2ceaf47f095cdecd40d68666efda" + integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== + +"@pnpm/config.env-replace@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c" + integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w== + +"@pnpm/network.ca-file@^1.0.1": + version "1.0.2" + resolved "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983" + integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA== + dependencies: + graceful-fs "4.2.10" + +"@pnpm/npm-conf@^3.0.2": + version "3.0.2" + resolved "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-3.0.2.tgz#857622421aa9bbf254e557b8a022c216a7928f47" + integrity sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA== + dependencies: + "@pnpm/config.env-replace" "^1.1.0" + "@pnpm/network.ca-file" "^1.0.1" + config-chain "^1.1.11" + +"@sinclair/typebox@^0.27.8": + version "0.27.10" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz#beefe675f1853f73676aecc915b2bd2ac98c4fc6" + integrity sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA== + +"@sindresorhus/is@^5.2.0": + version "5.6.0" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@smithy/abort-controller@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.12.tgz#80c86416f232b0b4e79cef530877ef87d626ac42" + integrity sha512-xolrFw6b+2iYGl6EcOL7IJY71vvyZ0DJ3mcKtpykqPe2uscwtzDZJa1uVQXyP7w9Dd+kGwYnPbMsJrGISKiY/Q== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader-native@^4.2.3": + version "4.2.3" + resolved "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.3.tgz#9e79a80d8d44798e7ce7a8f968cbbbaf5a40d950" + integrity sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw== + dependencies: + "@smithy/util-base64" "^4.3.2" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader@^5.2.2": + version "5.2.2" + resolved "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.2.tgz#3af48e37b10e5afed478bb31d2b7bc03c81d196c" + integrity sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw== + dependencies: + tslib "^2.6.2" + +"@smithy/config-resolver@^4.4.11", "@smithy/config-resolver@^4.4.13": + version "4.4.13" + resolved "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.13.tgz#8bffd41de647ec349b4a74bf02bdd1b32452bacd" + integrity sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg== + dependencies: + "@smithy/node-config-provider" "^4.3.12" + "@smithy/types" "^4.13.1" + "@smithy/util-config-provider" "^4.2.2" + "@smithy/util-endpoints" "^3.3.3" + "@smithy/util-middleware" "^4.2.12" + tslib "^2.6.2" + +"@smithy/core@^3.23.11", "@smithy/core@^3.23.12": + version "3.23.12" + resolved "https://registry.npmjs.org/@smithy/core/-/core-3.23.12.tgz#a16537bb03260337ac5adda31aedb325fcf9bb06" + integrity sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w== + dependencies: + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + "@smithy/url-parser" "^4.2.12" + "@smithy/util-base64" "^4.3.2" + "@smithy/util-body-length-browser" "^4.2.2" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-stream" "^4.5.20" + "@smithy/util-utf8" "^4.2.2" + "@smithy/uuid" "^1.1.2" + tslib "^2.6.2" + +"@smithy/credential-provider-imds@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.12.tgz#fa2e52116cac7eaf5625e0bfd399a4927b598f66" + integrity sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg== + dependencies: + "@smithy/node-config-provider" "^4.3.12" + "@smithy/property-provider" "^4.2.12" + "@smithy/types" "^4.13.1" + "@smithy/url-parser" "^4.2.12" + tslib "^2.6.2" + +"@smithy/eventstream-codec@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.12.tgz#8cd62d08709344fb8b35fd17870fdf1435de61a3" + integrity sha512-FE3bZdEl62ojmy8x4FHqxq2+BuOHlcxiH5vaZ6aqHJr3AIZzwF5jfx8dEiU/X0a8RboyNDjmXjlbr8AdEyLgiA== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@smithy/types" "^4.13.1" + "@smithy/util-hex-encoding" "^4.2.2" + tslib "^2.6.2" + +"@smithy/eventstream-serde-browser@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.12.tgz#3ceb8743750edaf5d6e42cd1a2327e048f85ba4e" + integrity sha512-XUSuMxlTxV5pp4VpqZf6Sa3vT/Q75FVkLSpSSE3KkWBvAQWeuWt1msTv8fJfgA4/jcJhrbrbMzN1AC/hvPmm5A== + dependencies: + "@smithy/eventstream-serde-universal" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/eventstream-serde-config-resolver@^4.3.12": + version "4.3.12" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.12.tgz#a29164bc5480d935ece9dbdca0f79924259e519a" + integrity sha512-7epsAZ3QvfHkngz6RXQYseyZYHlmWXSTPOfPmXkiS+zA6TBNo1awUaMFL9vxyXlGdoELmCZyZe1nQE+imbmV+Q== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/eventstream-serde-node@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.12.tgz#2cc06a1ea1108f679d376aab81e95a6f69877b4a" + integrity sha512-D1pFuExo31854eAvg89KMn9Oab/wEeJR6Buy32B49A9Ogdtx5fwZPqBHUlDzaCDpycTFk2+fSQgX689Qsk7UGA== + dependencies: + "@smithy/eventstream-serde-universal" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/eventstream-serde-universal@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.12.tgz#a3640d1e7c3e348168360035661db8d21b51e078" + integrity sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ== + dependencies: + "@smithy/eventstream-codec" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/fetch-http-handler@^5.3.15": + version "5.3.15" + resolved "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.15.tgz#acf69a8b3bab0396d2782fc901bad0b957c8c6a2" + integrity sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A== + dependencies: + "@smithy/protocol-http" "^5.3.12" + "@smithy/querystring-builder" "^4.2.12" + "@smithy/types" "^4.13.1" + "@smithy/util-base64" "^4.3.2" + tslib "^2.6.2" + +"@smithy/hash-blob-browser@^4.2.13": + version "4.2.13" + resolved "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.13.tgz#464a7fb6b8355f6a56ddd0de194857760543248f" + integrity sha512-YrF4zWKh+ghLuquldj6e/RzE3xZYL8wIPfkt0MqCRphVICjyyjH8OwKD7LLlKpVEbk4FLizFfC1+gwK6XQdR3g== + dependencies: + "@smithy/chunked-blob-reader" "^5.2.2" + "@smithy/chunked-blob-reader-native" "^4.2.3" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/hash-node@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.12.tgz#0ee7f6a1d2958c313ee24b07159dcb9547792441" + integrity sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w== + dependencies: + "@smithy/types" "^4.13.1" + "@smithy/util-buffer-from" "^4.2.2" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@smithy/hash-stream-node@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.12.tgz#cff200a551bd3f246f8d0aed4309d05873039437" + integrity sha512-O3YbmGExeafuM/kP7Y8r6+1y0hIh3/zn6GROx0uNlB54K9oihAL75Qtc+jFfLNliTi6pxOAYZrRKD9A7iA6UFw== + dependencies: + "@smithy/types" "^4.13.1" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@smithy/invalid-dependency@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.12.tgz#1a28c13fb33684b91848d4d6ec5104a1c1413e7f" + integrity sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/is-array-buffer@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz#f84f0d9f9a36601a9ca9381688bd1b726fd39111" + integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA== + dependencies: + tslib "^2.6.2" + +"@smithy/is-array-buffer@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz#c401ce54b12a16529eb1c938a0b6c2247cb763b8" + integrity sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow== + dependencies: + tslib "^2.6.2" + +"@smithy/md5-js@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.12.tgz#8f4f0bd4d57eee488bb4dec712f3c4d25ea6f5d7" + integrity sha512-W/oIpHCpWU2+iAkfZYyGWE+qkpuf3vEXHLxQQDx9FPNZTTdnul0dZ2d/gUFrtQ5je1G2kp4cjG0/24YueG2LbQ== + dependencies: + "@smithy/types" "^4.13.1" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@smithy/middleware-content-length@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.12.tgz#dec97ea1444b12e734156b764e9953b2b37c70fd" + integrity sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA== + dependencies: + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/middleware-endpoint@^4.4.25", "@smithy/middleware-endpoint@^4.4.27": + version "4.4.27" + resolved "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.27.tgz#cf2b334f7fc302e7ebf3fe00c1a1279ee9214afd" + integrity sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA== + dependencies: + "@smithy/core" "^3.23.12" + "@smithy/middleware-serde" "^4.2.15" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + "@smithy/url-parser" "^4.2.12" + "@smithy/util-middleware" "^4.2.12" + tslib "^2.6.2" + +"@smithy/middleware-retry@^4.4.42", "@smithy/middleware-retry@^4.4.44": + version "4.4.44" + resolved "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.44.tgz#5c678ea74bde3a480cb28d013156a24009063c5e" + integrity sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA== + dependencies: + "@smithy/node-config-provider" "^4.3.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/service-error-classification" "^4.2.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-retry" "^4.2.12" + "@smithy/uuid" "^1.1.2" + tslib "^2.6.2" + +"@smithy/middleware-serde@^4.2.14", "@smithy/middleware-serde@^4.2.15": + version "4.2.15" + resolved "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.15.tgz#18c6ed60339389b62e7955e822abe88e6f53ea55" + integrity sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg== + dependencies: + "@smithy/core" "^3.23.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/middleware-stack@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.12.tgz#96b43b2fab0d4a6723f813f76b72418b0fdb6ba0" + integrity sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/node-config-provider@^4.3.12": + version "4.3.12" + resolved "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.12.tgz#bb722da6e2a130ae585754fa7bc8d909f9f5d702" + integrity sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw== + dependencies: + "@smithy/property-provider" "^4.2.12" + "@smithy/shared-ini-file-loader" "^4.4.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/node-http-handler@^4.4.16", "@smithy/node-http-handler@^4.5.0": + version "4.5.0" + resolved "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.0.tgz#6a506a0da462c79e725fdbcfa55b0eed5b929727" + integrity sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A== + dependencies: + "@smithy/abort-controller" "^4.2.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/querystring-builder" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/property-provider@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.12.tgz#e9f8e5ce125413973b16e39c87cf4acd41324e21" + integrity sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/protocol-http@^5.3.12": + version "5.3.12" + resolved "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.12.tgz#c913053e7dfbac6cdd7f374f0b4f5aa7c518d0e1" + integrity sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/querystring-builder@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.12.tgz#20a0266b151a4b58409f901e1463257a72835c16" + integrity sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg== + dependencies: + "@smithy/types" "^4.13.1" + "@smithy/util-uri-escape" "^4.2.2" + tslib "^2.6.2" + +"@smithy/querystring-parser@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.12.tgz#918cb609b2d606ab81f2727bfde0265d2ebb2758" + integrity sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/service-error-classification@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.12.tgz#795e9484207acf63817a9e9cf67e90b42e720840" + integrity sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ== + dependencies: + "@smithy/types" "^4.13.1" + +"@smithy/shared-ini-file-loader@^4.4.7": + version "4.4.7" + resolved "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.7.tgz#18cc5a21f871509fafbe535a7bf44bde5a500727" + integrity sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/signature-v4@^5.3.12": + version "5.3.12" + resolved "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.12.tgz#b61ce40a94bdd91dfdd8f5f2136631c8eb67f253" + integrity sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw== + dependencies: + "@smithy/is-array-buffer" "^4.2.2" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + "@smithy/util-hex-encoding" "^4.2.2" + "@smithy/util-middleware" "^4.2.12" + "@smithy/util-uri-escape" "^4.2.2" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@smithy/smithy-client@^4.12.5", "@smithy/smithy-client@^4.12.7": + version "4.12.7" + resolved "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.7.tgz#3867272c062e39d3d4b719bf83ba491c76e1ee93" + integrity sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ== + dependencies: + "@smithy/core" "^3.23.12" + "@smithy/middleware-endpoint" "^4.4.27" + "@smithy/middleware-stack" "^4.2.12" + "@smithy/protocol-http" "^5.3.12" + "@smithy/types" "^4.13.1" + "@smithy/util-stream" "^4.5.20" + tslib "^2.6.2" + +"@smithy/types@^4.13.1": + version "4.13.1" + resolved "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz#8aaf15bb0f42b4e7c93c87018a3678a06d74691d" + integrity sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g== + dependencies: + tslib "^2.6.2" + +"@smithy/url-parser@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.12.tgz#e940557bf0b8e9a25538a421970f64bd827f456f" + integrity sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA== + dependencies: + "@smithy/querystring-parser" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/util-base64@^4.3.2": + version "4.3.2" + resolved "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.2.tgz#be02bcb29a87be744356467ea25ffa413e695cea" + integrity sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ== + dependencies: + "@smithy/util-buffer-from" "^4.2.2" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@smithy/util-body-length-browser@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.2.tgz#c4404277d22039872abdb80e7800f9a63f263862" + integrity sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ== + dependencies: + tslib "^2.6.2" + +"@smithy/util-body-length-node@^4.2.3": + version "4.2.3" + resolved "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.3.tgz#f923ca530defb86a9ac3ca2d3066bcca7b304fbc" + integrity sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g== + dependencies: + tslib "^2.6.2" + +"@smithy/util-buffer-from@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz#6fc88585165ec73f8681d426d96de5d402021e4b" + integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA== + dependencies: + "@smithy/is-array-buffer" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-buffer-from@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz#2c6b7857757dfd88f6cd2d36016179a40ccc913b" + integrity sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q== + dependencies: + "@smithy/is-array-buffer" "^4.2.2" + tslib "^2.6.2" + +"@smithy/util-config-provider@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.2.tgz#52ebf9d8942838d18bc5fb1520de1e8699d7aad6" + integrity sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ== + dependencies: + tslib "^2.6.2" + +"@smithy/util-defaults-mode-browser@^4.3.41", "@smithy/util-defaults-mode-browser@^4.3.43": + version "4.3.43" + resolved "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.43.tgz#8e2667c31cacdc0d59d414863f9a475daef79b28" + integrity sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ== + dependencies: + "@smithy/property-provider" "^4.2.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/util-defaults-mode-node@^4.2.44", "@smithy/util-defaults-mode-node@^4.2.47": + version "4.2.47" + resolved "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.47.tgz#95ab7663f21513dff5c13b5ab7fa2957418254c5" + integrity sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ== + dependencies: + "@smithy/config-resolver" "^4.4.13" + "@smithy/credential-provider-imds" "^4.2.12" + "@smithy/node-config-provider" "^4.3.12" + "@smithy/property-provider" "^4.2.12" + "@smithy/smithy-client" "^4.12.7" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/util-endpoints@^3.3.3": + version "3.3.3" + resolved "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.3.tgz#0119f15bcac30b3b9af1d3cc0a8477e7199d0185" + integrity sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig== + dependencies: + "@smithy/node-config-provider" "^4.3.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/util-hex-encoding@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.2.tgz#4abf3335dd1eb884041d8589ca7628d81a6fd1d3" + integrity sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg== + dependencies: + tslib "^2.6.2" + +"@smithy/util-middleware@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.12.tgz#d6cb837c2390375e2b6957e7f917350ca4bd8757" + integrity sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ== + dependencies: + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/util-retry@^4.2.12": + version "4.2.12" + resolved "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.12.tgz#be4805afee530f95b00a6ba771e18cb4c324f822" + integrity sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ== + dependencies: + "@smithy/service-error-classification" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/util-stream@^4.5.19", "@smithy/util-stream@^4.5.20": + version "4.5.20" + resolved "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.20.tgz#2d312ac8b9ea1780561a77048b027e7db1c6a3d4" + integrity sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw== + dependencies: + "@smithy/fetch-http-handler" "^5.3.15" + "@smithy/node-http-handler" "^4.5.0" + "@smithy/types" "^4.13.1" + "@smithy/util-base64" "^4.3.2" + "@smithy/util-buffer-from" "^4.2.2" + "@smithy/util-hex-encoding" "^4.2.2" + "@smithy/util-utf8" "^4.2.2" + tslib "^2.6.2" + +"@smithy/util-uri-escape@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.2.tgz#48e40206e7fe9daefc8d44bb43a1ab17e76abf4a" + integrity sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw== + dependencies: + tslib "^2.6.2" + +"@smithy/util-utf8@^2.0.0": + version "2.3.0" + resolved "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz#dd96d7640363259924a214313c3cf16e7dd329c5" + integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A== + dependencies: + "@smithy/util-buffer-from" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-utf8@^4.2.2": + version "4.2.2" + resolved "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.2.tgz#21db686982e6f3393ac262e49143b42370130f13" + integrity sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw== + dependencies: + "@smithy/util-buffer-from" "^4.2.2" + tslib "^2.6.2" + +"@smithy/util-waiter@^4.2.13": + version "4.2.13" + resolved "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.13.tgz#fea123340d650825a0ae3cc6c4525337806811ca" + integrity sha512-2zdZ9DTHngRtcYxJK1GUDxruNr53kv5W2Lupe0LMU+Imr6ohQg8M2T14MNkj1Y0wS3FFwpgpGQyvuaMF7CiTmQ== + dependencies: + "@smithy/abort-controller" "^4.2.12" + "@smithy/types" "^4.13.1" + tslib "^2.6.2" + +"@smithy/uuid@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz#b6e97c7158615e4a3c775e809c00d8c269b5a12e" + integrity sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g== + dependencies: + tslib "^2.6.2" + +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== + dependencies: + defer-to-connect "^2.0.1" + +"@tsconfig/node10@^1.0.7": + version "1.0.12" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz#be57ceac1e4692b41be9de6be8c32a106636dba4" + integrity sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.28.0" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/http-cache-semantics@^4.0.2": + version "4.2.0" + resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#f6a7788f438cbfde15f29acad46512b4c01913b3" + integrity sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29": + version "29.5.14" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/js-yaml@^4": + version "4.0.9" + resolved "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz#cd82382c4f902fed9691a2ed79ec68c5898af4c2" + integrity sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg== + +"@types/mute-stream@^0.0.4": + version "0.0.4" + resolved "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" + integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "25.5.0" + resolved "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz#5c99f37c443d9ccc4985866913f1ed364217da31" + integrity sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw== + dependencies: + undici-types "~7.18.0" + +"@types/node@^22", "@types/node@^22.5.5": + version "22.19.15" + resolved "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz#6091d99fdf7c08cb57dc8b1345d407ba9a1df576" + integrity sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg== + dependencies: + undici-types "~6.21.0" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/wrap-ansi@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" + integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.35" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== + dependencies: + "@types/yargs-parser" "*" + +acorn-walk@^8.1.1: + version "8.3.5" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz#8a6b8ca8fc5b34685af15dabb44118663c296496" + integrity sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.4.1: + version "8.16.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" + integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.2: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansis@^3.16.0, ansis@^3.17.0: + version "3.17.0" + resolved "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz#fa8d9c2a93fe7d1177e0c17f9eeb562a58a832d7" + integrity sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + +async@^3.2.6: + version "3.2.6" + resolved "https://registry.npmjs.org/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.2.0" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +balanced-match@^4.0.2: + version "4.0.4" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" + integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== + +baseline-browser-mapping@^2.9.0: + version "2.10.12" + resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz#60f9e2172e962839ac313d4e0c8e182090fb6621" + integrity sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ== + +bowser@^2.11.0: + version "2.14.1" + resolved "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz#4ea39bf31e305184522d7ad7bfd91389e4f0cb79" + integrity sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg== + +brace-expansion@^1.1.7: + version "1.1.13" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz#d37875c01dc9eff988dd49d112a57cb67b54efe6" + integrity sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.3" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz#0493338bdd58e319b1039c67cf7ee439892c01d9" + integrity sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA== + dependencies: + balanced-match "^1.0.0" + +brace-expansion@^5.0.2: + version "5.0.5" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz#dcc3a37116b79f3e1b46db994ced5d570e930fdb" + integrity sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ== + dependencies: + balanced-match "^4.0.2" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.28.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== + dependencies: + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" + +bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001759: + version "1.0.30001782" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz#f2b8617f998bc134701c54ce9748af44f646e062" + integrity sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw== + +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + +chalk@5: + version "5.6.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea" + integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +change-case@^4: + version "4.1.2" + resolved "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" + integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== + dependencies: + camel-case "^4.1.2" + capital-case "^1.0.4" + constant-case "^3.0.4" + dot-case "^3.0.4" + header-case "^2.0.4" + no-case "^3.0.4" + param-case "^3.0.4" + pascal-case "^3.1.2" + path-case "^3.0.4" + sentence-case "^3.0.4" + snake-case "^3.0.4" + tslib "^2.0.3" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chardet@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz#5c75593704a642f71ee53717df234031e65373c8" + integrity sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.4.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + +clean-stack@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz#155bf0b2221bf5f4fba89528d24c5953f17fe3a8" + integrity sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg== + dependencies: + escape-string-regexp "4.0.0" + +cli-spinners@^2.9.2: + version "2.9.2" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== + +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +constant-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" + integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case "^2.0.2" + +content-type@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.3: + version "7.0.6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.4.0, debug@^4.4.1, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +dedent@^1.0.0: + version "1.7.2" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz#34e2264ab538301e27cf7b07bf2369c19baa8dd9" + integrity sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +defer-to-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +detect-indent@^7.0.1: + version "7.0.2" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz#16c516bf75d4b2f759f68214554996d467c8d648" + integrity sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-newline@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz#fcefdb5713e1fb8cb2839b8b6ee22e6716ab8f23" + integrity sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.4" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz#7a6dbfda325f25f07517e9b518f897c08332e07d" + integrity sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ== + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + +electron-to-chromium@^1.5.263: + version "1.5.328" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.328.tgz#d24ce55f1aa5e4a3b877c1b315a0ab40e9498cc8" + integrity sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.4" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414" + integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ== + dependencies: + is-arrayish "^0.2.1" + +esbuild@~0.27.0: + version "0.27.4" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz#b9591dd7e0ab803a11c9c3b602850403bef22f00" + integrity sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ== + optionalDependencies: + "@esbuild/aix-ppc64" "0.27.4" + "@esbuild/android-arm" "0.27.4" + "@esbuild/android-arm64" "0.27.4" + "@esbuild/android-x64" "0.27.4" + "@esbuild/darwin-arm64" "0.27.4" + "@esbuild/darwin-x64" "0.27.4" + "@esbuild/freebsd-arm64" "0.27.4" + "@esbuild/freebsd-x64" "0.27.4" + "@esbuild/linux-arm" "0.27.4" + "@esbuild/linux-arm64" "0.27.4" + "@esbuild/linux-ia32" "0.27.4" + "@esbuild/linux-loong64" "0.27.4" + "@esbuild/linux-mips64el" "0.27.4" + "@esbuild/linux-ppc64" "0.27.4" + "@esbuild/linux-riscv64" "0.27.4" + "@esbuild/linux-s390x" "0.27.4" + "@esbuild/linux-x64" "0.27.4" + "@esbuild/netbsd-arm64" "0.27.4" + "@esbuild/netbsd-x64" "0.27.4" + "@esbuild/openbsd-arm64" "0.27.4" + "@esbuild/openbsd-x64" "0.27.4" + "@esbuild/openharmony-arm64" "0.27.4" + "@esbuild/sunos-x64" "0.27.4" + "@esbuild/win32-arm64" "0.27.4" + "@esbuild/win32-ia32" "0.27.4" + "@esbuild/win32-x64" "0.27.4" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz#37b899ae47e1090e40e3fd2318e4d5f0142ca912" + integrity sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ== + dependencies: + fastest-levenshtein "^1.0.7" + +fast-xml-builder@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz#0c407a1d9d5996336c0cd76f7ff785cac6413017" + integrity sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg== + dependencies: + path-expression-matcher "^1.1.3" + +fast-xml-parser@5.5.8: + version "5.5.8" + resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz#929571ed8c5eb96e6d9bd572ba14fc4b84875716" + integrity sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ== + dependencies: + fast-xml-builder "^1.1.4" + path-expression-matcher "^1.2.0" + strnum "^2.2.0" + +fastest-levenshtein@^1.0.7: + version "1.0.16" + resolved "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +filelist@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz#1e8870942a7c636c862f7c49b9394937b6a995a3" + integrity sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== + +fs-extra@^8.1: + version "8.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stdin@^9.0.0: + version "9.0.0" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" + integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== + +get-stream@^6.0.0, get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-tsconfig@^4.7.5: + version "4.13.7" + resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz#b9d8b199b06033ceeea1a93df7ea5765415089bc" + integrity sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q== + dependencies: + resolve-pkg-maps "^1.0.0" + +git-hooks-list@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-3.2.0.tgz#ffe5d5895e29d24f930f9a98dd604b7e407d2f5f" + integrity sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ== + +github-slugger@^2: + version "2.0.0" + resolved "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" + integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== + +glob@^7.0.0, glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +got@^13: + version "13.0.0" + resolved "https://registry.npmjs.org/got/-/got-13.0.0.tgz#a2402862cef27a5d0d1b07c0fb25d12b58175422" + integrity sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + +graceful-fs@4.2.10: + version "4.2.10" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handlebars@^4.7.8: + version "4.7.9" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz#6f139082ab58dc4e5a0e51efe7db5ae890d56a0f" + integrity sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +header-case@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" + integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== + dependencies: + capital-case "^1.0.4" + tslib "^2.0.3" + +hosted-git-info@^7.0.0: + version "7.0.2" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" + integrity sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w== + dependencies: + lru-cache "^10.0.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-cache-semantics@^4.1.1: + version "4.2.0" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" + integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== + +http-call@^5.2.2: + version "5.3.0" + resolved "https://registry.npmjs.org/http-call/-/http-call-5.3.0.tgz#4ded815b13f423de176eb0942d69c43b25b148db" + integrity sha512-ahwimsC23ICE4kPl9xTBjKB4inbRaeLyZeRunC/1Jy/Z6X8tv22MEAjK+KBOMSVLaqXPTTmd8638waVIKLGx2w== + dependencies: + content-type "^1.0.4" + debug "^4.1.1" + is-retry-allowed "^1.1.0" + is-stream "^2.0.0" + parse-json "^4.0.0" + tunnel-agent "^0.6.0" + +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@^0.7.0: + version "0.7.2" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" + integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.4: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.16.1: + version "2.16.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-node-process@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" + integrity sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + +is-retry-allowed@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jake@^10.8.5: + version "10.9.4" + resolved "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz#d626da108c63d5cfb00ab5c25fadc7e0084af8e6" + integrity sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA== + dependencies: + async "^3.2.6" + filelist "^1.0.4" + picocolors "^1.1.1" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29: + version "29.7.0" + resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +jose@^6.2.1: + version "6.2.2" + resolved "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz#d6b5279b89b3e88d531c202e3fbe351f39a44aac" + integrity sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.2" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4: + version "4.1.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +lilconfig@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash@^4.17.23: + version "4.18.0" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.18.0.tgz#dfd726f07ab2e39dd763de28fcf66e395c03e440" + integrity sha512-l1mfj2atMqndAHI3ls7XqPxEjV2J9ZkcNyHpoZA3r2T1LLwDB69jgkMWh71YKwhBbK0G2f4WSn05ahmQXVxupA== + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + +lru-cache@^10.0.1: + version "10.4.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1, make-error@^1.3.6: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== + +minimatch@^10.2.4: + version "10.2.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz#465b3accbd0218b8281f5301e27cedc697f96fde" + integrity sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg== + dependencies: + brace-expansion "^5.0.2" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.9" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz#1293ef15db0098b394540e8f9f744f9fda8dee4b" + integrity sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.3, minimist@^1.2.5: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mute-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + +mute-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz#a5446fc0c512b71c83c44d908d5c7b7b4c493b2b" + integrity sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +nock@^14: + version "14.0.11" + resolved "https://registry.npmjs.org/nock/-/nock-14.0.11.tgz#4ed20d50433b0479ddabd9f03c5886054608aeae" + integrity sha512-u5xUnYE+UOOBA6SpELJheMCtj2Laqx15Vl70QxKo43Wz/6nMHXS7PrEioXLjXAwhmawdEMNImwKCcPhBJWbKVw== + dependencies: + "@mswjs/interceptors" "^0.41.0" + json-stringify-safe "^5.0.1" + propagate "^2.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.27: + version "2.0.36" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz#99fd6552aaeda9e17c4713b57a63964a2e325e9d" + integrity sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA== + +normalize-package-data@^6: + version "6.0.2" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz#a7bc22167fe24025412bcff0a9651eb768b03506" + integrity sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g== + dependencies: + hosted-git-info "^7.0.0" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz#751a20c8520e5725404c06015fea21d7567f25ef" + integrity sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +oclif@^4: + version "4.22.96" + resolved "https://registry.npmjs.org/oclif/-/oclif-4.22.96.tgz#a5adc7d64947c65df17b31c5f05463d187707efa" + integrity sha512-aWM9cMb7Q3KW09qi5Mkw0Hq9sIM7DjVlyMAUl8Q2FP3+e5afBlUU9vmL3EJazVPhqcbg5u18E3z+6kCMk72KYw== + dependencies: + "@aws-sdk/client-cloudfront" "3.1009.0" + "@aws-sdk/client-s3" "3.1014.0" + "@inquirer/confirm" "^3.1.22" + "@inquirer/input" "^2.2.4" + "@inquirer/select" "^2.5.0" + "@oclif/core" "4.9.0" + "@oclif/plugin-help" "^6.2.38" + "@oclif/plugin-not-found" "^3.2.76" + "@oclif/plugin-warn-if-update-available" "^3.1.57" + ansis "^3.16.0" + async-retry "^1.3.3" + change-case "^4" + debug "^4.4.0" + ejs "^3.1.10" + find-yarn-workspace-root "^2.0.0" + fs-extra "^8.1" + github-slugger "^2" + got "^13" + lodash "^4.17.23" + normalize-package-data "^6" + semver "^7.7.4" + sort-package-json "^2.15.1" + tiny-jsonc "^1.0.2" + validate-npm-package-name "^5.0.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +outvariant@^1.4.0, outvariant@^1.4.3: + version "1.4.3" + resolved "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz#221c1bfc093e8fec7075497e7799fdbf43d14873" + integrity sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA== + +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +path-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" + integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-expression-matcher@^1.1.3, path-expression-matcher@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz#9bdae3787f43b0857b0269e9caaa586c12c8abee" + integrity sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.2" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz#5a942915e26b372dc0f0e6753149a16e6b1c5601" + integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA== + +picomatch@^4.0.3: + version "4.0.4" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589" + integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A== + +pirates@^4.0.4: + version "4.0.7" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +propagate@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" + integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== + +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + +registry-auth-token@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.1.tgz#f1ff69c8e492e7edee07110b4752dd0a8aa82853" + integrity sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q== + dependencies: + "@pnpm/npm-conf" "^3.0.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-alpn@^1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve.exports@^2.0.0: + version "2.0.3" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== + +resolve@^1.1.6, resolve@^1.20.0: + version "1.22.11" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== + dependencies: + lowercase-keys "^3.0.0" + +retry@0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.7.3, semver@^7.7.4: + version "7.7.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + +sentence-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" + integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shelljs@^0.8.5: + version "0.8.5" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +shx@^0.3.3: + version "0.3.4" + resolved "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz#74289230b4b663979167f94e1935901406e40f02" + integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g== + dependencies: + minimist "^1.2.3" + shelljs "^0.8.5" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +sort-object-keys@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45" + integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg== + +sort-package-json@^2.15.1: + version "2.15.1" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-2.15.1.tgz#e5a035fad7da277b1947b9eecc93ea09c1c2526e" + integrity sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA== + dependencies: + detect-indent "^7.0.1" + detect-newline "^4.0.0" + get-stdin "^9.0.0" + git-hooks-list "^3.0.0" + is-plain-obj "^4.1.0" + semver "^7.6.0" + sort-object-keys "^1.1.3" + tinyglobby "^0.2.9" + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.23" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz#b069e687b1291a32f126893ed76a27a745ee2133" + integrity sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +strict-event-emitter@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz#1602ece81c51574ca39c6815e09f1a3e8550bd93" + integrity sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strnum@^2.2.0: + version "2.2.2" + resolved "https://registry.npmjs.org/strnum/-/strnum-2.2.2.tgz#f11fd94ab62b536ba2ecc615858f3747c2881b3f" + integrity sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8, supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +tiny-jsonc@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/tiny-jsonc/-/tiny-jsonc-1.0.2.tgz#208df4c437684199cc724f31c2b91ee39c349678" + integrity sha512-f5QDAfLq6zIVSyCZQZhhyl0QS6MvAyTxgz4X4x3+EoCktNWEYJ6PeoEA97fyb98njpBNNi88ybpD7m+BDFXaCw== + +tinyglobby@^0.2.14, tinyglobby@^0.2.9: + version "0.2.15" + resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-jest@^29: + version "29.4.6" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz#51cb7c133f227396818b71297ad7409bb77106e9" + integrity sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA== + dependencies: + bs-logger "^0.2.6" + fast-json-stable-stringify "^2.1.0" + handlebars "^4.7.8" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.7.3" + type-fest "^4.41.0" + yargs-parser "^21.1.1" + +ts-node@^10: + version "10.9.2" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^2.0.3, tslib@^2.6.2: + version "2.8.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tsx@^4: + version "4.21.0" + resolved "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz#32aa6cf17481e336f756195e6fe04dae3e6308b1" + integrity sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw== + dependencies: + esbuild "~0.27.0" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^4.41.0: + version "4.41.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + +typescript@^5: + version "5.9.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +undici-types@~7.18.0: + version "7.18.2" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz#29357a89e7b7ca4aef3bf0fd3fd0cd73884229e9" + integrity sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" + +upper-case@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" + integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== + dependencies: + tslib "^2.0.3" + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validate-npm-package-name@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" + integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yoctocolors-cjs@^2.1.2, yoctocolors-cjs@^2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa" + integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==