Skip to content

feat(digitalocean): new provider package — droplets, sshKeys, firewalls, reservedIps, tags - #448

Open
rickyeescobar wants to merge 4 commits into
alchemy-run:mainfrom
rickyeescobar:digitalocean
Open

feat(digitalocean): new provider package — droplets, sshKeys, firewalls, reservedIps, tags#448
rickyeescobar wants to merge 4 commits into
alchemy-run:mainfrom
rickyeescobar:digitalocean

Conversation

@rickyeescobar

@rickyeescobar rickyeescobar commented Aug 12, 2026

Copy link
Copy Markdown

New @distilled.cloud/digitalocean provider package — droplets, sshKeys, firewalls, reservedIps, and tags — generated from DigitalOcean's bundled public OpenAPI spec (vendored via scripts/fetch-spec.ts; upstream maintains a multi-file $ref tree, so we vendor the single-file bundle CI publishes). Bearer-auth REST on the fly-io template.

202 Accepted becomes a per-provider success status

DigitalOcean's async-accept endpoints (droplet create, droplet actions) answer 202 with the created resource in the body; the converter only consulted 200/201/204, so those outputs collapsed to empty structs and the created droplet id was unreachable. Success statuses are now a converter option so no other provider's generated output moves:

// packages/digitalocean/scripts/convert.ts
options: {
  // Async-accept endpoints answer 202 with the resource in the body.
  successStatuses: ["200", "201", "202", "204"],
}

Patches

  • droplet_create's oneOf(Single, Multiple) response collapses to one object with optional droplet / droplets members (the converter has no discriminated-response support)
  • droplet/action/firewall/sshKey response envelopes and server-assigned members (id, status, fingerprint, created_at, …) marked required — every response carries them, and the converter already strips readOnly members from request bodies, so this only removes phantom-undefined handling in consumers
  • sshKeys_create declares the duplicate-key 422 it documents in prose, so it fails typed (UnprocessableEntity) instead of the untyped catch-all

Tags service

tags (create/delete/list/assign/unassign) backs alchemy's droplet tag sync and ownership branding.

Also carried

  • Cherry-pick of claude/floci-cloudwatch-patch (0d2c579, unmerged): alchemy main's DynamoDB Table (floci, alchemy#1154) catches UnsupportedOperation on describeInsightRules, so alchemy main doesn't type-check against distilled main without it. Merging that branch first makes this a no-op.

Smoke-tested live: sshKeysList with a bad token surfaces typed Unauthorized, and alchemy's Droplet/Firewall/SshKey live suites run green against this SDK.

🤖 Generated with Claude Code

@rickyeescobar

Copy link
Copy Markdown
Author

The consumer for this SDK is ready on the alchemy side: rickyeescobar/alchemy#1 — a DigitalOcean provider (Droplet, SshKey, Firewall) with live-tested lifecycles and website docs. It's held on my fork because its distilled submodule pointer needs a commit that exists upstream; once this merges I'll bump the pointer to the merged SHA and open it against alchemy-run/alchemy.

rickyeescobar and others added 4 commits August 14, 2026 14:56
…ls, reservedIps

Generated from DigitalOcean's bundled public OpenAPI spec (vendored via
scripts/fetch-spec.ts; upstream maintains a multi-file $ref tree, so we
vendor the single-file bundle spec CI publishes). Bearer-auth REST protocol
following the fly-io template; oneOf/anyOf unions emit as opaque schemas.
Smoke-tested live: sshKeysList with a bad token surfaces typed Unauthorized.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DigitalOcean's droplet create (and several actions) answer 202; the
converter only consulted 200/201/204, so those outputs collapsed to empty
structs. Also patch DigitalOcean's droplet_create oneOf response into one
object with optional droplet/droplets members — the converter has no
discriminated-response support and the created droplet id was unreachable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
readOnly server-assigned fields the API always returns; marking them
required removes phantom-undefined casts in consumers. Request bodies are
unaffected (the converter already strips readOnly members).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nse members

- successStatuses becomes a per-provider converter option (default
  200/201/204) so DigitalOcean's async-accept 202s stop changing every
  other OpenAPI provider's generated output on regeneration
- new tags service (create/delete/list/assign/unassign) for droplet tag
  sync and ownership branding
- patches: droplet/action/firewall/sshKey response envelopes and
  server-assigned members marked required; sshKeys_create declares its
  422 so duplicate key material fails typed (UnprocessableEntity)
- generate.ts no longer claims the patch chain is unwired; convert.ts
  keepPaths rename

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant