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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ coverage/
Thumbs.db

# Include spec files
!src/openapi3.yaml
!src/contracts/*.arc56.json

# Fetched by `pnpm fetch:openapi` from the private nfd-backend repo, so it is
# not reproducible from this repo alone and is not committed.
packages/sdk/openapi3.yaml
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ build
# Generated files
pnpm-lock.yaml
**/openapi3.yaml
# The whole directory: openapi-ts emits its own fetch runtime into
# src/api/client and src/api/core, and not every file there ends in .gen.ts.
packages/sdk/src/api/
**/*.gen.ts
**/*.arc56.json
**/contracts/*Client.ts
Expand Down
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,19 @@ pnpm --filter @txnlab/nfd-sdk exec vitest run tests/utils/nfd.test.ts

The SDK has auto-generated code from two sources:

1. **OpenAPI client** (`src/api/*.gen.ts`) — generated from `src/api/openapi3.yaml` via `@hey-api/client-fetch`
1. **OpenAPI client** (all of `src/api/`) — generated by `@hey-api/openapi-ts` from `packages/sdk/openapi3.yaml`
2. **Algorand contract clients** (`src/contracts/NFD*Client.ts`) — generated from ARC-56 JSON specs in `src/contracts/minimal/`

Regenerate all: `pnpm --filter @txnlab/nfd-sdk generate`

**Do not hand-edit generated files.** The contract client files (`NFDInstanceClient.ts`, `NFDRegistryClient.ts`) are excluded from tsconfig compilation and are very large (~150KB each).

Three things about the OpenAPI half are easy to get wrong:

- **The whole of `src/api/` is generated, not just `*.gen.ts`.** openapi-ts vendors its own fetch runtime into `src/api/client/` and `src/api/core/`, so the SDK has no `@hey-api/client-fetch` dependency any more. `eslint.config.js` and the root `.prettierignore` exclude the directory; a glob that only matches `src/api/*.gen.ts` misses two thirds of the output.
- **`openapi3.yaml` lives beside `openapi-ts.config.ts`, not inside `src/api/`.** openapi-ts cleans its output directory before every run, so a spec kept in there is deleted by the generator that reads it. It is fetched by `pnpm fetch:openapi` from the private `TxnLab/nfd-backend` repo (needs `GITHUB_TOKEN`), and is gitignored — regenerating is not reproducible from this repo alone.
- **Operation names track the spec's `operationId`s verbatim** (`nfd_getLookup`, not `nfdGetLookup`). Only `src/api-client.ts` imports them; nothing generated is re-exported from `src/index.ts`, so renames there are internal.

## Architecture

### Client & Module Pattern
Expand Down
8 changes: 6 additions & 2 deletions packages/sdk/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ CHANGELOG.md
# directory, so `pnpm format` (which runs in this package) never sees the root
# .prettierignore — without these it rewrites the generated contract clients
# that `pnpm format:check` correctly skips.
src/api/openapi3.yaml
src/api/*.gen.ts
openapi3.yaml
src/contracts/**/*.arc56.json
src/contracts/*Client.ts

# src/api/**.gen.ts is deliberately NOT listed. openapi-ts formats its own
# output by running prettier from this directory, so an ignore entry here
# silences that step and the client lands unformatted. The root
# .prettierignore still excludes it from `pnpm format:check`.
7 changes: 6 additions & 1 deletion packages/sdk/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import baseConfig from '../../eslint.config.js'

export default tseslint.config(
...baseConfig,
{
// Generated OpenAPI client. openapi-ts >= 0.7x emits its own fetch runtime
// into src/api/client and src/api/core, so the old src/api/*.gen.ts glob no
// longer covers the output.
ignores: ['src/api/**'],
},
{
// Source files
files: ['src/**/*.ts'],
ignores: ['src/api/*.gen.ts'],
languageOptions: {
parserOptions: {
project: './tsconfig.json',
Expand Down
7 changes: 4 additions & 3 deletions packages/sdk/openapi-ts.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { defineConfig } from '@hey-api/openapi-ts'

export default defineConfig({
input: './src/api/openapi3.yaml',
input: './openapi3.yaml',
output: {
format: 'prettier',
lint: 'eslint',
path: './src/api',
// eslint is not in the list: the generated client is excluded from linting
// (see eslint.config.js), so running it here only fails the generate step.
postProcess: ['prettier'],
},
plugins: ['@hey-api/client-fetch'],
})
3 changes: 1 addition & 2 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@
"generate": "pnpm fetch:specs && pnpm generate:clients && pnpm generate:openapi"
},
"dependencies": {
"@algorandfoundation/algokit-utils": "^8.2.2",
"@hey-api/client-fetch": "^0.8.4"
"@algorandfoundation/algokit-utils": "^8.2.2"
},
"peerDependencies": {
"algosdk": "^3.6.0"
Expand Down
4 changes: 3 additions & 1 deletion packages/sdk/scripts/fetch-openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ config({ path: packageEnv })
const GITHUB_TOKEN = process.env.GITHUB_TOKEN
const SPEC_URL =
'https://raw.githubusercontent.com/TxnLab/nfd-backend/main/goasvcs/pubapi/gen/http/openapi3.yaml'
const OUTPUT_PATH = resolve(__dirname, '../src/api/openapi3.yaml')
// Deliberately outside src/api: openapi-ts cleans its output directory before
// every run, so a spec kept in there is deleted by the generator it feeds.
const OUTPUT_PATH = resolve(__dirname, '../openapi3.yaml')

async function fetchOpenApiSpec() {
if (!GITHUB_TOKEN) {
Expand Down
24 changes: 12 additions & 12 deletions packages/sdk/src/api-client.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { client } from './api/client.gen'
import {
nfdGetLookup,
nfdGetNfd,
nfdSearchV2,
nfdSuggest,
nfdVerifyConfirm,
nfdVerifyRequest,
nfd_getLookup,
nfd_getNfd,
nfd_searchV2,
nfd_suggest,
nfd_verifyConfirm,
nfd_verifyRequest,
} from './api/sdk.gen'
import { NfdApiBaseUrl, NfdRegistryId } from './constants'
import { chunkArray } from './utils/internal/array'
Expand Down Expand Up @@ -93,7 +93,7 @@ export class NfdApiClient {
// Add cache parameter if needed
const params = this._getCacheParam(options.nocache)

const response = await nfdGetNfd({
const response = await nfd_getNfd({
client: this._client,
query: {
view: options.view,
Expand Down Expand Up @@ -138,7 +138,7 @@ export class NfdApiClient {
// Make parallel requests for each chunk
const responses = await Promise.all(
addressChunks.map((chunk) =>
nfdGetLookup({
nfd_getLookup({
client: this._client,
query: {
address: chunk,
Expand Down Expand Up @@ -184,7 +184,7 @@ export class NfdApiClient {
// Add cache parameter if needed
const params = this._getCacheParam(options.nocache)

const response = await nfdSearchV2({
const response = await nfd_searchV2({
client: this._client,
query: {
name: options.name,
Expand Down Expand Up @@ -231,7 +231,7 @@ export class NfdApiClient {
* @returns Array of suggested NFD records
*/
public async suggest(name: string, options: SuggestOptions): Promise<Nfd[]> {
const response = await nfdSuggest({
const response = await nfd_suggest({
client: this._client,
path: { name },
query: {
Expand All @@ -257,7 +257,7 @@ export class NfdApiClient {
sender: string,
field: VerifyField,
): Promise<VerifyRequestResult> {
const response = await nfdVerifyRequest({
const response = await nfd_verifyRequest({
client: this._client,
body: {
name,
Expand All @@ -280,7 +280,7 @@ export class NfdApiClient {
id: string,
challenge?: string,
): Promise<VerifyConfirmResult> {
const response = await nfdVerifyConfirm({
const response = await nfd_verifyConfirm({
client: this._client,
path: { id },
body: {
Expand Down
21 changes: 9 additions & 12 deletions packages/sdk/src/api/client.gen.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// This file is auto-generated by @hey-api/openapi-ts

import {
type Client,
type ClientOptions,
type Config,
type ClientOptions as DefaultClientOptions,
createClient,
createConfig,
} from '@hey-api/client-fetch'

import type { ClientOptions } from './types.gen'
} from './client'
import type { ClientOptions as ClientOptions2 } from './types.gen'

/**
* The `createClientConfig()` function will be called on client initialization
Expand All @@ -17,13 +17,10 @@ import type { ClientOptions } from './types.gen'
* `setConfig()`. This is useful for example if you're using Next.js
* to ensure your client always has the correct values.
*/
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> =
(
override?: Config<DefaultClientOptions & T>,
) => Config<Required<DefaultClientOptions> & T>
export type CreateClientConfig<T extends ClientOptions = ClientOptions2> = (
override?: Config<ClientOptions & T>,
) => Config<Required<ClientOptions> & T>

export const client = createClient(
createConfig<ClientOptions>({
baseUrl: 'https://api.nf.domains',
}),
export const client: Client = createClient(
createConfig<ClientOptions2>({ baseUrl: 'https://api.nf.domains' }),
)
Loading