Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.5.0"
".": "0.6.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 183
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zavu/zavudev-5d75bbdcac3a0b0a8b798c0b4ef0dacfbc64ad4a20605489dc46dda7c8d1d8d8.yml
openapi_spec_hash: bb242cfd8cc43354412164c2dceae89c
config_hash: 261e1b852ca7f8364e4a283a3edd350a
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/zavu/zavudev-5257b1c4e3b9259ae2df6cd9ac2d2a31a39ddb336f50baf0dadbcc865c1913f3.yml
openapi_spec_hash: 4103decc37e4053c1cba58ba9527a5e7
config_hash: f6a05e2edf2cd1af3f762b8ac759b9a7
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 0.6.0 (2026-09-15)

Full Changelog: [v0.5.0...v0.6.0](https://github.com/zavudev/cli/compare/v0.5.0...v0.6.0)

### Features

* **api:** api update ([78967ce](https://github.com/zavudev/cli/commit/78967ce99892dfa4438b0d89af1e93a1f73df408))
* **api:** api update ([c090781](https://github.com/zavudev/cli/commit/c0907819c7645e321e49192c00653604b1d34f43))
* **api:** api update ([5e87793](https://github.com/zavudev/cli/commit/5e87793117d3d0c4545b583a2d8d9744dee18645))

## 0.5.0 (2026-09-08)

Full Changelog: [v0.4.0...v0.5.0](https://github.com/zavudev/cli/compare/v0.4.0...v0.5.0)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/tidwall/pretty v1.2.1
github.com/urfave/cli-docs/v3 v3.0.0-alpha6
github.com/urfave/cli/v3 v3.3.2
github.com/zavudev/sdk-go v0.4.0
github.com/zavudev/sdk-go v0.5.0
golang.org/x/sys v0.38.0
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ github.com/urfave/cli/v3 v3.3.2 h1:BYFVnhhZ8RqT38DxEYVFPPmGFTEf7tJwySTXsVRrS/o=
github.com/urfave/cli/v3 v3.3.2/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/zavudev/sdk-go v0.4.0 h1:OpPmvyDZVLF8y7Gc6tHB3JHhqRPy8aZMzVB6cOaeSPE=
github.com/zavudev/sdk-go v0.4.0/go.mod h1:ncdVbaf7JHHiUcpJu2JE3c1xion5lkWSAUCn5CnX3bo=
github.com/zavudev/sdk-go v0.5.0 h1:PfXs1NDhnMPI5t8TemrOIjrcavxJLpnLDugxOXCpp2s=
github.com/zavudev/sdk-go v0.5.0/go.mod h1:ncdVbaf7JHHiUcpJu2JE3c1xion5lkWSAUCn5CnX3bo=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
Expand Down
25 changes: 15 additions & 10 deletions pkg/cmd/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,26 @@ import (

var addressesCreate = cli.Command{
Name: "create",
Usage: "Create a regulatory address for phone number purchases. Some countries require a\nverified address before phone numbers can be activated.",
Usage: "Create a regulatory address, to use as the value of an `address` requirement\nwhen buying a phone number. It is registered for review when it is created, with\nstatus `pending`.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "country-code",
Required: true,
BodyPath: "countryCode",
},
&requestflag.Flag[string]{
Name: "first-name",
Usage: "First name of the person the address is registered to.",
Required: true,
BodyPath: "firstName",
},
&requestflag.Flag[string]{
Name: "last-name",
Usage: "Last name of the person the address is registered to.",
Required: true,
BodyPath: "lastName",
},
&requestflag.Flag[string]{
Name: "locality",
Required: true,
Expand All @@ -45,20 +57,13 @@ var addressesCreate = cli.Command{
},
&requestflag.Flag[string]{
Name: "business-name",
Usage: "Business name, when the address belongs to a business. Defaults to the person's full name.",
BodyPath: "businessName",
},
&requestflag.Flag[string]{
Name: "extended-address",
BodyPath: "extendedAddress",
},
&requestflag.Flag[string]{
Name: "first-name",
BodyPath: "firstName",
},
&requestflag.Flag[string]{
Name: "last-name",
BodyPath: "lastName",
},
},
Action: handleAddressesCreate,
HideHelpCommand: true,
Expand Down Expand Up @@ -104,7 +109,7 @@ var addressesList = cli.Command{

var addressesDelete = cli.Command{
Name: "delete",
Usage: "Delete a regulatory address. Cannot delete addresses that are in use.",
Usage: "Delete a regulatory address from this project. Any address can be deleted,\nwhatever its status. Phone numbers already purchased with it are not affected,\nand neither is information already submitted for later purchases in its country.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Expand Down
10 changes: 5 additions & 5 deletions pkg/cmd/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,29 @@ func TestAddressesCreate(t *testing.T) {
"--api-key", "string",
"addresses", "create",
"--country-code", "DE",
"--first-name", "John",
"--last-name", "Doe",
"--locality", "Berlin",
"--postal-code", "10115",
"--street-address", "123 Main St",
"--administrative-area", "administrativeArea",
"--business-name", "businessName",
"--extended-address", "extendedAddress",
"--first-name", "John",
"--last-name", "Doe",
)
})

t.Run("piping data", func(t *testing.T) {
// Test piping YAML data over stdin
pipeData := []byte("" +
"countryCode: DE\n" +
"firstName: John\n" +
"lastName: Doe\n" +
"locality: Berlin\n" +
"postalCode: '10115'\n" +
"streetAddress: 123 Main St\n" +
"administrativeArea: administrativeArea\n" +
"businessName: businessName\n" +
"extendedAddress: extendedAddress\n" +
"firstName: John\n" +
"lastName: Doe\n")
"extendedAddress: extendedAddress\n")
mocktest.TestRunMockTestWithPipeAndFlags(
t, pipeData,
"--api-key", "string",
Expand Down
43 changes: 35 additions & 8 deletions pkg/cmd/phonenumber.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var phoneNumbersUpdate = cli.Command{
},
&requestflag.Flag[*string]{
Name: "sender-id",
Usage: "Sender ID to assign the phone number to. Set to null to unassign.",
Usage: "Sender ID to assign the phone number to. Set to null to unassign. A number under regulatory review is recorded now and connected to the sender when approved; a rejected number is refused.",
BodyPath: "senderId",
},
},
Expand All @@ -71,7 +71,7 @@ var phoneNumbersList = cli.Command{
},
&requestflag.Flag[string]{
Name: "status",
Usage: `Allowed values: "active", "suspended", "pending".`,
Usage: "Billing state of an owned number, separate from `regulatoryStatus`. `pending` is legacy and is not written to numbers today. The SDKs carry `active`, `suspended` and `pending` only; `releasing` and `released` are returned by the REST API until their next release.",
QueryPath: "status",
},
&requestflag.Flag[int64]{
Expand All @@ -83,9 +83,9 @@ var phoneNumbersList = cli.Command{
HideHelpCommand: true,
}

var phoneNumbersPurchase = cli.Command{
var phoneNumbersPurchase = requestflag.WithInnerFlags(cli.Command{
Name: "purchase",
Usage: "Purchase an available phone number. Requires a paid plan: the Free plan cannot\npurchase phone numbers and receives `402` with code `paid_plan_required`. Paid\nplans include one US number at no charge. The included number is one per account\nand is granted once: claiming it spends the benefit for good, so releasing that\nnumber does not make another one free, and numbers the account already bought do\nnot consume it.",
Usage: "Purchase an available phone number. Requires a paid plan: the Free plan cannot\npurchase phone numbers and receives `402` with code `paid_plan_required`.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Expand All @@ -99,10 +99,33 @@ var phoneNumbersPurchase = cli.Command{
Usage: "Optional custom name for the phone number.",
BodyPath: "name",
},
&requestflag.Flag[[]map[string]any]{
Name: "regulatory-requirement",
Usage: "Regulatory information, for numbers whose requirements list is not empty. Get the list with `GET /v1/phone-numbers/requirements?phoneNumber=...` and send one entry per requirement id, except `action` requirements, which take no value. Every required id must be present, once, and no unknown id may be sent; otherwise the purchase is refused with `400 invalid_request` before anything is charged.\n\nThe information is kept for your project under the number's country and `type`. A later purchase there may omit this field if what is kept still covers that number's requirements. Omit it for numbers without requirements.",
BodyPath: "regulatoryRequirements",
},
&requestflag.Flag[string]{
Name: "type",
Usage: "Type of phone number. `mobile` is stocked in countries where no geographic (`local`) or non-geographic (`national`) inventory exists, and in several markets it is the only type that can receive SMS.",
BodyPath: "type",
},
},
Action: handlePhoneNumbersPurchase,
HideHelpCommand: true,
}
}, map[string][]requestflag.HasOuterFlag{
"regulatory-requirement": {
&requestflag.InnerFlag[string]{
Name: "regulatory-requirement.field-value",
Usage: "Depends on the requirement's `type`: the text itself for `textual`; for `address`, the `id` of an address created in this project with `POST /v1/addresses`; for `document`, the `id` of a document created with `POST /v1/documents`. An address or document from another project, or one rejected in review, is refused.",
InnerField: "fieldValue",
},
&requestflag.InnerFlag[string]{
Name: "regulatory-requirement.requirement-type",
Usage: "A `requirementTypes[].id` from `GET /v1/phone-numbers/requirements`. Each id may appear only once.",
InnerField: "requirementType",
},
},
})

var phoneNumbersRelease = cli.Command{
Name: "release",
Expand All @@ -121,15 +144,19 @@ var phoneNumbersRelease = cli.Command{

var phoneNumbersRequirements = cli.Command{
Name: "requirements",
Usage: "Get regulatory requirements for purchasing phone numbers in a specific country.\nSome countries require additional documentation (addresses, identity documents)\nbefore phone numbers can be activated.",
Usage: "Get the regulatory information needed to buy a phone number, for one specific\nnumber or for a country and number type. Prefer `phoneNumber`: the response is\nthen exactly the list the purchase of that number validates against. Pass each\n`requirementTypes[].id` back as `requirementType` in `regulatoryRequirements` on\n`POST /v1/phone-numbers`.",
Suggest: true,
Flags: []cli.Flag{
&requestflag.Flag[string]{
Name: "country-code",
Usage: "Two-letter ISO country code.",
Required: true,
Usage: "Two-letter ISO country code. Required unless `phoneNumber` is given.",
QueryPath: "countryCode",
},
&requestflag.Flag[string]{
Name: "phone-number",
Usage: "E.164 number from `GET /v1/phone-numbers/available`, with `+` encoded as `%2B`. Returns the requirements the purchase of that number checks. Takes precedence over `countryCode`.",
QueryPath: "phoneNumber",
},
&requestflag.Flag[string]{
Name: "type",
Usage: "Type of phone number. `mobile` is stocked in countries where no geographic (`local`) or non-geographic (`national`) inventory exists, and in several markets it is the only type that can receive SMS.",
Expand Down
27 changes: 26 additions & 1 deletion pkg/cmd/phonenumber_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"github.com/zavudev/cli/internal/mocktest"
"github.com/zavudev/cli/internal/requestflag"
)

func TestPhoneNumbersRetrieve(t *testing.T) {
Expand Down Expand Up @@ -71,14 +72,37 @@ func TestPhoneNumbersPurchase(t *testing.T) {
"phone-numbers", "purchase",
"--phone-number", "+15551234567",
"--name", "Primary Line",
"--regulatory-requirement", "{fieldValue: jd7x2k3m4n5p6q7r8s9t0abc, requirementType: 8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10}",
"--type", "local",
)
})

t.Run("inner flags", func(t *testing.T) {
// Check that inner flags have been set up correctly
requestflag.CheckInnerFlags(phoneNumbersPurchase)

// Alternative argument passing style using inner flags
mocktest.TestRunMockTestWithFlags(
t,
"--api-key", "string",
"phone-numbers", "purchase",
"--phone-number", "+15551234567",
"--name", "Primary Line",
"--regulatory-requirement.field-value", "jd7x2k3m4n5p6q7r8s9t0abc",
"--regulatory-requirement.requirement-type", "8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10",
"--type", "local",
)
})

t.Run("piping data", func(t *testing.T) {
// Test piping YAML data over stdin
pipeData := []byte("" +
"phoneNumber: '+15551234567'\n" +
"name: Primary Line\n")
"name: Primary Line\n" +
"regulatoryRequirements:\n" +
" - fieldValue: jd7x2k3m4n5p6q7r8s9t0abc\n" +
" requirementType: 8c5b1a2e-0f3d-4f5b-9a61-2c7e4d9b1f10\n" +
"type: local\n")
mocktest.TestRunMockTestWithPipeAndFlags(
t, pipeData,
"--api-key", "string",
Expand Down Expand Up @@ -107,6 +131,7 @@ func TestPhoneNumbersRequirements(t *testing.T) {
"--api-key", "string",
"phone-numbers", "requirements",
"--country-code", "xx",
"--phone-number", "phoneNumber",
"--type", "local",
)
})
Expand Down
6 changes: 3 additions & 3 deletions pkg/cmd/sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var sendersCreate = cli.Command{
},
&requestflag.Flag[bool]{
Name: "email-receiving-enabled",
Usage: "Enable inbound email receiving on this sender. Requires a verified MX record on the domain; ignored otherwise.",
Usage: "Enable inbound email receiving on this sender. Requires a verified inbound MX record on the domain; the request is ignored otherwise. Read `emailReceivingEnabled` back off the response to see whether it was applied — it comes back `false` when the MX has not verified.",
BodyPath: "emailReceivingEnabled",
},
&requestflag.Flag[bool]{
Expand All @@ -58,7 +58,7 @@ var sendersCreate = cli.Command{
},
&requestflag.Flag[string]{
Name: "phone-number",
Usage: "Phone number in E.164 format, and it must be a number your project already owns (see `GET /v1/phone-numbers`). The number is routed to the sender as part of this call, which is what turns the SMS channel on. Passing a number the project does not own, or one already attached to another sender, returns 400 rather than creating a sender that cannot send. Omit for an email-only sender.",
Usage: "Phone number in E.164 format, and it must be a number your project already owns (see `GET /v1/phone-numbers`). The number is routed to the sender as part of this call, which is what turns the SMS channel on. Passing a number the project does not own, one already attached to another sender, or one rejected in regulatory review returns 400 rather than creating a sender that cannot send. A number still under review is attached and starts carrying messages when it is approved. Omit for an email-only sender.",
BodyPath: "phoneNumber",
},
&requestflag.Flag[bool]{
Expand Down Expand Up @@ -133,7 +133,7 @@ var sendersUpdate = cli.Command{
},
&requestflag.Flag[bool]{
Name: "email-receiving-enabled",
Usage: "Enable or disable inbound email receiving for this sender.",
Usage: "Enable or disable inbound email receiving for this sender. Enabling requires a verified inbound MX record on the domain; the request is ignored otherwise, and `emailReceivingEnabled` comes back `false` on the response. Disabling always applies.",
BodyPath: "emailReceivingEnabled",
},
&requestflag.Flag[bool]{
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

package cmd

const Version = "0.5.0" // x-release-please-version
const Version = "0.6.0" // x-release-please-version
Loading