Skip to content

feat: @maple-dev/alchemy — Alchemy provider for Maple resources#240

Merged
Makisuo merged 2 commits into
mainfrom
feat/alchemy-maple-provider
Jul 21, 2026
Merged

feat: @maple-dev/alchemy — Alchemy provider for Maple resources#240
Makisuo merged 2 commits into
mainfrom
feat/alchemy-maple-provider

Conversation

@Makisuo

@Makisuo Makisuo commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

A new publishable package, @maple-dev/alchemy (lib/alchemy-maple), an Alchemy provider that lets Maple customers declare Maple resources in their own alchemy.run.ts, authenticated with a maple_ak_… key against the public v2 API:

Resource Semantics
Maple.Dashboard Full CRUD; wire-shape props pass through verbatim; drift-checked PATCH
Maple.AlertDestination Full CRUD; discriminated on type; write-only secrets accept Redacted; type change ⇒ replace
Maple.AlertRule Full CRUD; destination_ids takes Output refs from destinations; lost state re-adopts by org-unique name
Maple.ApiKey Create/roll/revoke; one-time secret captured as Redacted into Alchemy state; rotate prop bump rolls in place; other prop changes replace
Maple.IngestKeys Read-only per-org singleton (nuke: { singleton: true }) surfacing keys as Redacted outputs

Usage: providers: Layer.mergeAll(Cloudflare.providers(), Maple.providers()), credentials from MAPLE_API_KEY / MAPLE_API_URL.

Why

Maple-side resources previously had to be clicked together in the UI or scripted by hand. This makes them declarable IaC next to the infrastructure they observe, dogfooding the v2 public API.

Design notes for review

  • Zero runtime deps: alchemy (>=2.0.0-beta.61 <3) and effect are peers so customers get a single Effect/alchemy instance. @maple/domain is a dev-only dependency — the package ships small hand-written wire schemas instead, kept honest by contract tests that decode the provider's request bodies against the real V2*CreateParams schemas.
  • Client: thin JSON client on effect/unstable/http with typed errors (404/409/401·403 tags for adopt/recreate flows) and bounded 429/5xx retry (v2 allows 600 req/60s).
  • No Idempotency-Key on the v2 API yet, so reconcile is observe-then-create; alert rules are safe against double-create via org-unique-name adoption (dashboards/destinations are documented as best-effort).
  • ApiKey.secret can never be re-read from the API — it lives only in Alchemy state; list() returns secretless placeholders (enumeration/nuke only).

Testing

  • 13 unit + contract tests in the package (provider lifecycles vs a stub API; wire-schema contract vs @maple/domain).
  • apps/api/src/routes/v2/alchemy-provider.integration.test.ts: drives the real provider code through the real v2 handlers over PGlite (custom fetch into the in-process web handler) — create → noop → drift-patch → adopt-by-name → roll → revoke/delete cycles for dashboards, destinations+rules, and API keys.
  • tsdown build emits a clean 24 kB ESM dist with only effect/alchemy externals; npm pack --dry-run = 4 files, no workspace specifiers; root bun typecheck green.

Not included (follow-ups): npm publish, manual smoke deploy of examples/alchemy-maple against a dev deployment.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Open in Devin Review

Publishable Alchemy (v2, Effect-based) provider package so customers can
declare Maple resources in their own alchemy.run.ts against the public v2
API: dashboards, alert destinations, alert rules, API keys (one-time secret
kept as Redacted in Alchemy state, rotate-prop rolls in place), and the
ingest-keys singleton.

- lib/alchemy-maple: zero runtime deps (alchemy + effect as peers); thin
  HTTP client with typed errors and bounded 429/5xx retry; hand-written
  minimal wire schemas guarded by contract tests against @maple/domain
  (dev-only dep, never shipped)
- integration test drives the real provider lifecycles through the real
  v2 handlers over PGlite via a custom fetch
- examples/alchemy-maple: customer-facing usage example

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pullfrog

pullfrog Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Your Pullfrog Router balance is exhausted.

You have a card on file but auto-reload is disabled, so runs paused once your balance went past the overdraft buffer.

Top up balance → · Enable auto-reload →

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Rerun failed job ➔View workflow run | via Pullfrog | Using Claude Opus𝕏

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

The package tests import plain vitest; @effect/vitest was never used.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Makisuo
Makisuo merged commit 47ce445 into main Jul 21, 2026
6 of 7 checks passed
@Makisuo
Makisuo deleted the feat/alchemy-maple-provider branch July 21, 2026 11:01
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