Skip to content
Merged
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
134 changes: 134 additions & 0 deletions docs/openapi/monitoring-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -16343,6 +16343,127 @@
}
}
},
"/api/v1/status-pages/{id}/domains/{domainId}/primary": {
"post": {
"tags": [
"Status Pages"
],
"summary": "Mark a verified custom domain as the page's primary host",
"operationId": "setPrimaryDomain",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
},
{
"name": "domainId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/SingleValueResponseStatusPageCustomDomainDto"
}
}
}
},
"400": {
"description": "Bad request — the payload failed validation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"401": {
"description": "Unauthorized — missing or invalid credentials",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"403": {
"description": "Forbidden — the actor lacks permission for this resource",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"404": {
"description": "Not found — the requested resource does not exist",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"409": {
"description": "Conflict — the request collides with current resource state",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"500": {
"description": "Internal server error — see the message field for details",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"502": {
"description": "Bad gateway — an upstream provider returned an error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"503": {
"description": "Service unavailable — try again shortly",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/api/v1/status-pages/{id}/domains/{domainId}/verify": {
"post": {
"tags": [
Expand Down Expand Up @@ -29801,6 +29922,19 @@
"type": "string",
"nullable": true
},
"cfCustomHostnameId": {
"type": "string",
"nullable": true
},
"cfSslStatus": {
"type": "string",
"nullable": true
},
"sslActiveAt": {
"type": "string",
"format": "date-time",
"nullable": true
},
"createdAt": {
"type": "string",
"format": "date-time"
Expand Down
29 changes: 26 additions & 3 deletions src/commands/status-pages/domains/add.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import {Command, Flags} from '@oclif/core'
import type {components} from '../../../lib/api.generated.js'
import {globalFlags, buildClient, display} from '../../../lib/base-command.js'
import {apiPost, unwrapData} from '../../../lib/api-client.js'
import {uuidArg} from '../../../lib/validators.js'

type StatusPageCustomDomain = components['schemas']['StatusPageCustomDomainDto']

export default class StatusPagesDomainsAdd extends Command {
static description = 'Add a custom domain to a status page'
static examples = ['<%= config.bin %> status-pages domains add <page-id> --hostname status.example.com']
static description = 'Add a custom domain to a status page and print its verification record'
static examples = [
'<%= config.bin %> status-pages domains add <page-id> --hostname status.example.com',
'<%= config.bin %> status-pages domains add <page-id> --hostname status.example.com --output json',
]

static args = {id: uuidArg({description: 'Status page ID', required: true})}
static flags = {
...globalFlags,
Expand All @@ -16,6 +23,22 @@ export default class StatusPagesDomainsAdd extends Command {
const {args, flags} = await this.parse(StatusPagesDomainsAdd)
const client = buildClient(flags)
const resp = await apiPost(client, `/api/v1/status-pages/${args.id}/domains`, {hostname: flags.hostname})
display(this, unwrapData(resp), flags.output)
const domain = unwrapData(resp) as StatusPageCustomDomain

if (flags.output === 'json' || flags.output === 'yaml') {
display(this, domain, flags.output)
return
}

this.log(`Added '${domain.hostname}' (id ${domain.id}).`)
this.log('')
this.log('Verification record (create at your DNS provider):')
if (domain.verificationMethod === 'TXT') {
this.log(` TXT ${domain.hostname} → "${domain.verificationToken}"`)
} else {
this.log(` CNAME ${domain.hostname} → ${domain.verificationCnameTarget}`)
}
this.log('')
this.log(`Run 'devhelm status-pages domains verify ${args.id} ${domain.id}' once DNS has propagated.`)
}
}
7 changes: 5 additions & 2 deletions src/commands/status-pages/domains/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {uuidArg} from '../../../lib/validators.js'
type StatusPageCustomDomain = components['schemas']['StatusPageCustomDomainDto']

export default class StatusPagesDomainsList extends Command {
static description = 'List custom domains on a status page'
static description = 'List custom domains on a status page (incl. verification CNAME target)'
static examples = ['<%= config.bin %> status-pages domains list <page-id>']
static args = {id: uuidArg({description: 'Status page ID', required: true})}
static flags = {...globalFlags}
Expand All @@ -19,8 +19,11 @@ export default class StatusPagesDomainsList extends Command {
display(this, items, flags.output, [
{header: 'ID', get: (r: StatusPageCustomDomain) => r.id ?? ''},
{header: 'HOSTNAME', get: (r: StatusPageCustomDomain) => r.hostname ?? ''},
{header: 'VERIFIED', get: (r: StatusPageCustomDomain) => r.verifiedAt ?? ''},
{header: 'PRIMARY', get: (r: StatusPageCustomDomain) => (r.primary ? 'yes' : '')},
{header: 'STATUS', get: (r: StatusPageCustomDomain) => r.status ?? ''},
{header: 'SSL', get: (r: StatusPageCustomDomain) => r.cfSslStatus ?? ''},
{header: 'CNAME TARGET', get: (r: StatusPageCustomDomain) => r.verificationCnameTarget ?? ''},
{header: 'VERIFIED AT', get: (r: StatusPageCustomDomain) => r.verifiedAt ?? ''},
])
}
}
22 changes: 22 additions & 0 deletions src/commands/status-pages/domains/set-primary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {Command} from '@oclif/core'
import {globalFlags, buildClient, display} from '../../../lib/base-command.js'
import {apiPost, unwrapData} from '../../../lib/api-client.js'
import {uuidArg} from '../../../lib/validators.js'

export default class StatusPagesDomainsSetPrimary extends Command {
static description = 'Mark a verified custom domain as the primary host for a status page'
static examples = ['<%= config.bin %> status-pages domains set-primary <page-id> <domain-id>']
static args = {
id: uuidArg({description: 'Status page ID', required: true}),
'domain-id': uuidArg({description: 'Domain ID', required: true}),
}

static flags = {...globalFlags}

async run() {
const {args, flags} = await this.parse(StatusPagesDomainsSetPrimary)
const client = buildClient(flags)
const resp = await apiPost(client, `/api/v1/status-pages/${args.id}/domains/${args['domain-id']}/primary`, {})
display(this, unwrapData(resp), flags.output)
}
}
25 changes: 23 additions & 2 deletions src/commands/status-pages/domains/verify.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
import {Command} from '@oclif/core'
import type {components} from '../../../lib/api.generated.js'
import {globalFlags, buildClient, display} from '../../../lib/base-command.js'
import {apiPost, unwrapData} from '../../../lib/api-client.js'
import {uuidArg} from '../../../lib/validators.js'

type StatusPageCustomDomain = components['schemas']['StatusPageCustomDomainDto']

export default class StatusPagesDomainsVerify extends Command {
static description = 'Verify a custom domain on a status page'
static description = 'Re-check verification + SSL status for a custom domain'
static examples = ['<%= config.bin %> status-pages domains verify <page-id> <domain-id>']
static args = {
id: uuidArg({description: 'Status page ID', required: true}),
'domain-id': uuidArg({description: 'Domain ID', required: true}),
}

static flags = {...globalFlags}

async run() {
const {args, flags} = await this.parse(StatusPagesDomainsVerify)
const client = buildClient(flags)
const resp = await apiPost(client, `/api/v1/status-pages/${args.id}/domains/${args['domain-id']}/verify`, {})
display(this, unwrapData(resp), flags.output)
const domain = unwrapData(resp) as StatusPageCustomDomain

if (flags.output === 'json' || flags.output === 'yaml') {
display(this, domain, flags.output)
return
}

this.log(`Hostname: ${domain.hostname}`)
this.log(`Status: ${domain.status}`)
if (domain.cfSslStatus) this.log(`SSL: ${domain.cfSslStatus}`)
if (domain.verificationError) {
this.log('')
this.log(`Error: ${domain.verificationError}`)
this.log(`Expected CNAME → ${domain.verificationCnameTarget}`)
} else if (domain.status !== 'ACTIVE') {
this.log('')
this.log(`Expected CNAME → ${domain.verificationCnameTarget}`)
}
}
}
3 changes: 3 additions & 0 deletions src/lib/api-zod.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2693,6 +2693,9 @@ const StatusPageCustomDomainDto = z
verificationCnameTarget: z.string(),
verifiedAt: z.string().datetime({ offset: true }).nullish(),
verificationError: z.string().nullish(),
cfCustomHostnameId: z.string().nullish(),
cfSslStatus: z.string().nullish(),
sslActiveAt: z.string().datetime({ offset: true }).nullish(),
createdAt: z.string().datetime({ offset: true }),
updatedAt: z.string().datetime({ offset: true }),
primary: z.boolean(),
Expand Down
Loading
Loading