Skip to content

[RFC] @alchemy/data-apis MVP — Data SDK vertical slice#2539

Closed
blakecduncan wants to merge 6 commits into
mainfrom
blake/data-sdk-mvp
Closed

[RFC] @alchemy/data-apis MVP — Data SDK vertical slice#2539
blakecduncan wants to merge 6 commits into
mainfrom
blake/data-sdk-mvp

Conversation

@blakecduncan

@blakecduncan blakecduncan commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

What

A vertical-slice prototype of the Data SDK (@alchemy/data-apis) to prove the architecture discussed in #tx-eng before scaling to the full v1 surface (Portfolio, Prices, NFT, Token, Transfers). Not intended to merge as-is — this is the concrete artifact for the direction discussion.

One action per architectural seam:

Method Channel Proves
portfolio.getTokensByAddress REST → global api.g.alchemy.com/data/v1 Multi-network request bodies via AlchemyRestClient; networks are payload, client chain uninvolved
nft.getNftsForOwner REST → {network}.g.alchemy.com/nft/v3 Network-scoped URL resolution; per-request network override with client default fallback
transfers.getAssetTransfers JSON-RPC → AlchemyTransport Plain viem action; override derives a transport instance from client.transport.config

Two equivalent entry points (tested):

// data-only devs — no viem knowledge needed
const data = createDataClient({ apiKey, network: "eth-mainnet" });

// devs already holding a viem client with an Alchemy transport
const client = createClient({ chain: mainnet, transport: alchemyTransport({ apiKey }) })
  .extend(dataActions);

Network identity (the thread's three-format proposal, working)

resolveNetwork() in @alchemy/common accepts a viem Chain, an Alchemy slug ("eth-mainnet"), or CAIP-2 ("eip155:1", "solana:mainnet"). The slug ↔ chain-ID maps are derived from the existing daikon-generated ALCHEMY_RPC_MAPPING — no second registry, no new exported chain objects. The proper version is a ws-tools generator change emitting { slug, chainId, caip2 } entries + a generated KnownAlchemyNetwork union.

Codegen: type internals generated from the docs specs

@alchemy/api-codegen (private workspace package) implements a two-stage pipeline:

  1. snapshot (network, run rarely): bundles specs from a local alchemyplatform/docs checkout using the docs repo's own tooling (redocly for OpenAPI, its generate:rpc for OpenRPC), commits the bundled JSON under specs/ with a lockfile pinning the docs commit SHA + sha256 checksums.
  2. generate (offline, deterministic, pnpm generate): emits committed TypeScript into packages/data-apis/src/generated — openapi-typescript output + RestRequestSchema entries for REST; json-schema-to-typescript params/results + viem RpcSchema entries for OpenRPC.

The hand-maintained codegen.manifest.ts maps spec operations → SDK surface; a renamed/removed spec operation hard-fails generation (drift alarm), uncovered spec operations are reported (new-endpoint visibility). Public types in types.ts are hand-reviewed aliases over generated internals — generated names never leak into the semver surface. pnpm generate && git diff --exit-code is CI-gate-ready (not wired into workflows in this PR).

Deliberate public-type deltas from generating (spec-accurate): transfers/ownedNfts/totalCount/category became optional (specs declare no required lists); portfolio tokens gained spec fields (e.g. error); the spec's "Not Found (null)" string result branch on transfers is collapsed away.

@alchemy/common changes

  • networks/networkRegistry.tsresolveNetwork + network input types
  • AlchemyRestClient exported (built for signer v5, previously unexported)

Deliberately out of scope (tracked in the data SDK scope plan)

  • Rest client hardening (retries, timeouts, request-id, first-class query params)
  • Pagination iterators, error normalization, remaining methods
  • CI drift-gate workflow step + spec-bump automation (pipeline supports both)

Open questions for reviewers

  • REST auth here is header-based off the transport config; docs specs put the key in the URL path. (Update: verified — 14/14 live smoke tests pass; the codegen emitter strips {apiKey} path segments accordingly.)
  • Escape-hatch semantics: registry-unknown slugs work for data (slug is complete routing info) but wallet-apis needs the chain id — per-client escape hatches as discussed in the thread.
  • Whether createDataClient lives here long-term or gets re-exported from a future top-level alchemy package.
  • Long-term spec artifact: should docs publish @alchemy/api-specs to npm (mirrors @alchemy/wallet-api-types)? The snapshot stage swaps sources cleanly if so.

Test plan

  • packages/api-codegen: 15 unit tests (fixture-driven: path normalization, REST/RPC emitters, manifest drift hard-errors)
  • packages/data-apis: 4 unit tests (stubbed fetch) covering all three actions through both entry points
  • packages/common: 6 resolveNetwork tests; full common suite passes
  • pnpm generate idempotent (run twice → no diff); snapshot deterministic; build + typecheck clean
  • Live smoke test (scripts/smoke-test.ts): 14/14 pass against the real API on the generated internals — all three methods, all three network input formats, per-request overrides, raw decorator path

🤖 Generated with Claude Code


PR-Codex overview

This PR introduces significant updates to the @alchemy/api-codegen and @alchemy/data-apis packages, enhancing TypeScript configuration, adding autogenerated files, and refining the API client structure for better functionality and maintainability.

Detailed summary

  • Updated tsconfig.json files for TypeScript configuration.
  • Added VERSION export in src/version.ts.
  • Introduced CodegenError class for error handling.
  • Implemented normalizePath function for path normalization.
  • Enhanced API client with new methods and decorators.
  • Added tests for various functionalities and schemas.
  • Improved documentation in README.md files.

The following files were skipped due to too many changes: packages/data-apis/src/dataClient.test.ts, packages/common/src/networks/networkRegistry.ts, packages/api-codegen/src/manifest.ts, packages/api-codegen/src/rest/schemaEmitter.ts, packages/api-codegen/src/snapshot.ts, packages/data-apis/scripts/smoke-test.ts, packages/api-codegen/specs/transfers.json, pnpm-lock.yaml, packages/data-apis/src/generated/rest/portfolio.types.ts, packages/api-codegen/specs/portfolio.json, packages/data-apis/src/generated/rest/nft.types.ts, packages/api-codegen/specs/nft.json

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

blakecduncan and others added 2 commits June 9, 2026 16:24
…nnels

Vertical-slice prototype of the Data SDK architecture:
- 3 actions, one per seam: portfolio.getTokensByAddress (REST, multi-network
  body via AlchemyRestClient), nft.getNftsForOwner (REST, network-scoped URL
  with per-request override), transfers.getAssetTransfers (JSON-RPC over
  AlchemyTransport, override via derived transport instance)
- dataActions decorator + createAlchemyDataClient convenience wrapper
- common: resolveNetwork accepting viem Chain | slug | CAIP-2, derived from
  the existing daikon-generated ALCHEMY_RPC_MAPPING; AlchemyRestClient exported

See packages/data/README.md for scope and deliberate omissions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matches the wallet-apis package naming standard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@blakecduncan blakecduncan changed the title [RFC] @alchemy/data MVP — Data SDK vertical slice [RFC] @alchemy/data-apis MVP — Data SDK vertical slice Jun 9, 2026
blakecduncan and others added 4 commits June 9, 2026 16:51
14-test script covering all three methods (portfolio, nft, transfers),
all three network input formats (viem Chain, slug, CAIP-2), per-request
network overrides, and the raw decorator path — all verified green.

Run with: ALCHEMY_API_KEY=<key> pnpm --filter @alchemy/data-apis smoke-test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Package is already namespaced to Alchemy; the prefix is redundant.
Mirrors the wallet-apis pattern of dropping the brand prefix from
the factory function name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds @alchemy/api-codegen (private workspace package) implementing the
two-stage pipeline from the data SDK codegen plan:

- snapshot (network): bundles specs from a local docs checkout using the
  docs repo's own tooling (redocly / generate:rpc), commits them under
  specs/ with a lockfile pinning the docs commit SHA + sha256 checksums
- generate (offline, deterministic): emits committed TypeScript into
  packages/data-apis/src/generated — openapi-typescript output +
  RestRequestSchema entries for REST, json-schema-to-typescript params/
  result types + viem RpcSchema entries for OpenRPC

The hand-maintained codegen.manifest.ts maps spec operations to the
generated surface; a renamed/removed spec operation hard-fails generate
(drift alarm), uncovered operations are reported for visibility.

data-apis schema/rest.ts, schema/rpc.ts, and types.ts are now thin
hand-reviewed aliases over generated internals. Runtime action code is
untouched; public types adopt spec-accurate optionality (transfers/
ownedNfts/totalCount/category optional) and richer fields. The spec's
"Not Found (null)" string result branch is deliberately collapsed.

Repo wiring: turbo generate task (was referenced by root scripts but
undefined), nx generate outputs, prettier/eslint handling (generated
files carry a file-level eslint-disable and are self-formatted with the
repo prettier config; spec snapshots are ignored).

Verified: 15 generator unit tests, 4 data-apis unit tests, build +
typecheck clean, pnpm generate idempotent, 14/14 live smoke tests pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@blakecduncan

Copy link
Copy Markdown
Collaborator Author

Superseded by #2541. This RFC did its job: it proved the actions architecture and the codegen pipeline, and the coupling analysis it enabled is what made the standalone-core pivot (decision doc) a bounded refactor instead of a rewrite. The viem decorator pattern explored here lives on as the parked /viem adapter.

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