Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
9bd9942
feat(docs): add basic generator
heyllog May 7, 2026
bd9637e
feat(docs): move everything related to docs to docs folder
heyllog May 7, 2026
a3d4671
docs: use templates in jsdoc
heyllog May 7, 2026
ca70be3
docs: rework returns
heyllog May 7, 2026
e3aab1e
feat(docs): add type links
heyllog May 7, 2026
dd4eea6
feat(docs): start appkit balances docs
heyllog May 7, 2026
a895724
feat(docs): delete unused Balance type and add links from types to fu…
heyllog May 8, 2026
5eb6996
feat(docs): simplify generator
heyllog May 8, 2026
a544c9c
feat(docs): delete useless .toString() from examples
heyllog May 8, 2026
87d0769
feat(docs): rework links
heyllog May 8, 2026
e10afe7
feat(docs): all descriptions are now oneliners
heyllog May 8, 2026
1e55fc5
feat(docs): add skill for jsdoc
heyllog May 8, 2026
99d9754
feat(docs): all constants as separate category
heyllog May 8, 2026
902ed44
feat(docs): add @extract property to extract type from another lib
heyllog May 8, 2026
74080d0
feat(docs): rework @extract
heyllog May 8, 2026
cb0bf2b
feat(docs): DefiError docs
heyllog May 8, 2026
ffa099e
feat(docs): start reexports
heyllog May 8, 2026
ae78034
feat(docs): complete reexports
heyllog May 8, 2026
410b4f9
feat(docs): update balance actions
heyllog May 8, 2026
650dfec
feat(docs): update connector actions
heyllog May 8, 2026
5353dbf
feat(docs): update crypto onramp actions
heyllog May 8, 2026
14af74d
feat(docs): separate connector and wallet sections
heyllog May 8, 2026
671b14e
docs: add jetton actions
heyllog May 8, 2026
c049c48
docs: show generic types with default value
heyllog May 8, 2026
f68f483
docs: add network actions
heyllog May 8, 2026
5c28678
docs: add client section
heyllog May 8, 2026
11955cc
docs: add wallets actions
heyllog May 8, 2026
45a5f09
docs: add signing actions
heyllog May 8, 2026
fce1fb1
docs: add provider actions
heyllog May 8, 2026
eccb84f
docs: add swap actions
heyllog May 8, 2026
29c6c30
docs: add staking actions
heyllog May 8, 2026
6d852f0
docs: add connector docs
heyllog May 8, 2026
46653a8
docs: add providers docs
heyllog May 8, 2026
e9eb3b4
docs: update rest docs
heyllog May 8, 2026
d29afc3
docs: add descriptions for all elements
heyllog May 8, 2026
31145d6
docs: start appkit-react reference
heyllog May 8, 2026
d54b87f
docs: polishing
heyllog May 10, 2026
a0380bc
fix(appkit): rework connectors events
heyllog May 10, 2026
3fd6c5e
docs(appkit): polishing
heyllog May 10, 2026
4ade6f5
docs(appkit): update staking docs
heyllog May 10, 2026
1734202
docs(appkit): polishing
heyllog May 10, 2026
cdeb047
docs(appkit): polishing
heyllog May 11, 2026
db6b9f0
docs(appkit-react): add all docs
heyllog May 11, 2026
fc07134
docs(appkit-react): delete no props
heyllog May 11, 2026
bf4efac
docs(appkit-react): rework cross-lib links
heyllog May 11, 2026
90af551
docs(appkit-react): improve links with text blocks
heyllog May 11, 2026
80d241c
docs(appkit-react): add docs for factories
heyllog May 11, 2026
75387bc
docs(appkit): add missing docs
heyllog May 11, 2026
b0422a7
docs(appkit): improve wording
heyllog May 11, 2026
79af081
docs: wording
heyllog May 11, 2026
4680aac
docs(appkit): formatting
heyllog May 11, 2026
551ce7b
docs: polishing
heyllog May 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
34 changes: 23 additions & 11 deletions .claude/skills/add-action-and-hook/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export {
} from './<category>/get-xxx';
```

### 1.4 Document the action

Add `@public` JSDoc to the action and to `GetXxxOptions` so they show up in the auto-generated reference. Follow the [`document-public-api`](../document-public-api/SKILL.md) skill for the exact tag set, allowed `@category` values, and style rules (one-sentence summaries, `{@link X}` syntax for type cells, `@expand` for options-bag flattening, `@sample` for code examples).

---

## Step 2: Create the Query or Mutation in `appkit` (for get actions only)
Expand Down Expand Up @@ -219,12 +223,16 @@ Add to `packages/appkit-react/src/features/<category>/index.ts`:
export { useXxx, type UseXxxParameters, type UseXxxReturnType } from './hooks/use-xxx';
```

### Document the hook

Tag the hook (and `UseXxxParameters` / `UseXxxReturnType` if useful) with `@public` JSDoc. Use `@category Hook` and `@section <Domain>`. The full ruleset (required tags, allowed values, `{@link}` linking, `@sample` placeholders) is in the [`document-public-api`](../document-public-api/SKILL.md) skill.

---

## Step 4: Add Examples and Tests

### 4.1 Action example
Create `demo/examples/src/appkit/actions/<category>/get-xxx.ts`:
Create `docs/examples/src/appkit/actions/<category>/get-xxx.ts`:
```ts
import type { AppKit } from '@ton/appkit';
import { getXxx } from '@ton/appkit';
Expand All @@ -237,10 +245,12 @@ export const getXxxExample = async (appKit: AppKit) => {
};
```

Export it in `demo/examples/src/appkit/actions/<category>/index.ts`.
Export it in `docs/examples/src/appkit/actions/<category>/index.ts`.

The `// SAMPLE_START: GET_XXX … // SAMPLE_END: GET_XXX` block is what `@sample docs/examples/src/appkit/actions/<category>#GET_XXX` in the action's JSDoc will pull into the reference (see [`document-public-api`](../document-public-api/SKILL.md)).

### 4.2 Hook example
Create `demo/examples/src/appkit/hooks/<category>/use-xxx.tsx`:
Create `docs/examples/src/appkit/hooks/<category>/use-xxx.tsx`:
```tsx
import { useXxx } from '@ton/appkit-react';

Expand All @@ -252,7 +262,7 @@ export const UseXxxExample = () => {
};
```

Export it in `demo/examples/src/appkit/hooks/<category>/index.ts`.
Export it in `docs/examples/src/appkit/hooks/<category>/index.ts`.

### 4.3 Write tests
**Important:** Do NOT create a new test file per example. Add tests to the existing `<category>.test.ts` / `<category>.test.tsx` file in the same directory.
Expand Down Expand Up @@ -280,24 +290,26 @@ If the mock `appKit` in `beforeEach` doesn't have the required mocks (e.g., `get

## Step 5: Update Templates and Docs

### 5.1 Update action template
Edit `template/appkit-actions.md`, add after the nearest related action:
The reference at `packages/<pkg>/docs/reference.md` is fully generated from `@public` JSDoc, so once Step 1.4 / Step 3.1 are done your action and hook are already in the reference. The two steps below update the older hand-curated `actions.md` / `hooks.md` listings.

### 5.1 Update action listing
Edit `docs/templates/packages/appkit/docs/actions.md`, add after the nearest related action:
```md
### `getXxx`

Description of what the action does.

%%demo/examples/src/appkit/actions/<category>#GET_XXX%%
%%docs/examples/src/appkit/actions/<category>#GET_XXX%%
```

### 5.2 Update hooks template
Edit `template/appkit-hooks.md`, add after the nearest related hook:
### 5.2 Update hooks listing
Edit `docs/templates/packages/appkit-react/docs/hooks.md`, add after the nearest related hook:
```md
### `useXxx`

Hook to ...

%%demo/examples/src/appkit/hooks/<category>#USE_XXX%%
%%docs/examples/src/appkit/hooks/<category>#USE_XXX%%
```

### 5.3 Run quality check
Expand All @@ -310,4 +322,4 @@ All tests and type checks must pass before continuing.
```bash
pnpm docs:update
```
Verify the relevant `.md` files in `packages/appkit/docs/` and `packages/appkit-react/docs/` were updated.
Runs `docs:reference` (regenerates `reference.md` from `@public` JSDoc) followed by `docs:template` (resolves `%%path#SAMPLE%%` placeholders into real code blocks). Verify the resulting `.md` files in `packages/appkit/docs/` and `packages/appkit-react/docs/` were updated.
10 changes: 10 additions & 0 deletions .claude/skills/add-ui-component/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,13 @@ Use `packages/appkit-react/src/components/block` as the canonical reference for:
- `block.tsx`
- `block.module.css`
- `block.stories.tsx`

---

## 5. Documentation

If the component is meant to be part of the public API, tag it with `@public` JSDoc so it shows up in the auto-generated reference (`packages/appkit-react/docs/reference.md`). Use `@category Component` and `@section <Domain>`. The full ruleset (required tags, allowed values, `{@link X}` for type-cell links, single-sentence description style, `@sample` for usage examples) lives in the [`document-public-api`](../document-public-api/SKILL.md) skill.

For compound components (`const Foo = { Container: …, Item: … }`), the same `@public` block on the namespace object is enough — the generator walks each member and renders them as `#### Foo.Container`, `#### Foo.Item`, etc.

After editing JSDoc run `pnpm docs:update` to regenerate `packages/appkit-react/docs/reference.md`.
227 changes: 227 additions & 0 deletions .claude/skills/document-public-api/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
---
name: document-public-api
description: How to write JSDoc for public symbols so they appear in the auto-generated reference (`packages/<pkg>/docs/reference.md`). Use whenever adding `@public` to an export or editing the surrounding doc-comment.
---

# Documenting public API for the reference generator

The generator at `docs/reference-generator/` walks every export of `packages/appkit` and `packages/appkit-react`, picks the ones tagged `@public`, and renders them into `packages/<pkg>/docs/reference.md`. The output goes through `docs/template-resolver/` which resolves `%%path#NAME%%` placeholders into real code from `docs/examples/`.

This skill describes exactly which JSDoc tags the generator understands, in what shape, and what the rendered output looks like.

---

## Required tags

Every `@public` symbol **must** also declare:

- `@public` — opt-in marker. Without it the symbol is invisible to the generator.
- `@category <Class | Action | Hook | Component | Type | Constants>` — top-level group (`## Class`, `## Action`, …). The generator validates the value; anything else is an error.
- `@section <Domain>` — second-level group (`### Balances`, `### Connectors and wallets`, …). Free-form string; symbols sharing the same value end up under one heading.

If any of the three is missing, `pnpm docs:reference` aborts with a list of offending symbols.

### Which declaration shape fits each `@category`

| `@category` | Allowed declaration |
| --- | --- |
| `Class` | `export class X { }` |
| `Action` / `Hook` | `export function name(...)` or `export const name = (...) => ...` |
| `Component` | Function returning JSX **or** a `const X = { Sub: …, Sub2: … }` object of FCs (rendered as a compound component) |
| `Type` | `export interface X { }` or `export type X = ...` |
| `Constants` | `export const X = { ... } as const` (or any `export const X = literal`) |

Putting `@category Class` on an interface raises `[X] @category Class requires the symbol to be a class declaration.` at generate time. `Type` and `Constants` are deliberately split so a `const X = {}` cannot accidentally land under "Type" — pick `Constants` for runtime values, `Type` for compile-time-only declarations.

---

## Optional tags

- `@param <name> - <description>` — column row in the parameters table. Description should be a single self-contained sentence with a trailing period.
- `@returns <description>` — appears as `Returns: \`Type\` — <description>.`
- `@example` — inline TS/TSX code block printed under the entry.
- `@sample <dir/path>#<SAMPLE_NAME>` — placeholder that `pnpm docs:template` replaces with the body of a `// SAMPLE_START: NAME … // SAMPLE_END: NAME` block under `docs/examples/`. Multiple `@sample` tags are allowed.
- `@expand <paramName>` — for actions that take an options-bag (`getBalanceByAddress(appKit, options)`), expands the named parameter's fields into extra rows like `options.address`, `options.network`. Without `@expand`, the parameter is shown as one row.
- `@extract` — for type aliases that re-export a type from another package (typically walletkit). The renderer follows the alias to the original `interface` / `type` and uses **its** structure (field table or code block). `@public`/`@category`/`@section` still live on the alias; the source's JSDoc supplies field-level descriptions. See "Re-exporting from walletkit" below.
- `@title <Override>` — override the top-level heading for this single symbol. Rarely needed; usually omit.

`@param` accepts a `{@link X}`-as-type-override at the very start of its description (see below); `@returns` does **not** — see the warning in that section.

---

## Cross-reference syntax: `{@link X}`

`{@link X}` becomes a markdown link to the `#x` anchor in the same reference. It works in two places:

1. **Anywhere in a description** (summary, field doc, `@param` description, `@returns` description). The text reads `... see {@link getBalance} ...` and renders `... see [\`getBalance\`](#getbalance) ...`.

2. **At the very start of `@param` description** — the link is extracted and used as the **Type column** for that row. The text after the link goes into the Description column.

```ts
@param config - {@link AppKitConfig} Networks, connectors, providers and runtime flags.
```

renders as:

| Parameter | Type | Description |
| --- | --- | --- |
| `config`* | [`AppKitConfig`](#appkitconfig) | Networks, connectors, providers and runtime flags. |

The TS-inferred type is replaced by the link. Use this when the inferred type is verbose or you want a cleaner cell.

⚠ **Don't put `{@link X}` at the start of `@returns`.** ts-morph's JSDoc parser interprets a leading `{…}` as a legacy type annotation (`@returns {Type} desc`) and silently drops it from the comment text — both the type-override and the description disappear. Write the description as plain prose; the inferred return type is auto-linked anyway. If you really want to mention a type, put `{@link X}` mid-sentence: `@returns The wallet response carrying …`.

`X` must name another `@public` symbol in the same reference — the generator does not validate this, so a typo or an undocumented target produces a dead link.

---

## Style rules

- **One sentence per description.** Summary, `@param` description, field doc, `@returns` description — all collapse onto one line in the rendered table. Multi-paragraph JSDoc reads as a long ugly run-on. If you need a second clause, join with `;` or `—`.
- **Self-contained sentences after `{@link X}`.** Capitalize the first word, end with a period. Don't write `{@link X} with foo` (renders as Description = `with foo` — fragment); write `{@link X} Foo and bar.`.
- **No bullet lists, no fenced code, no tables in JSDoc descriptions.** They survive the markdown but break table rendering.
- **No outright fabrication.** Don't claim methods or behavior that don't exist in the code; the reference is pulled directly from the JSDoc and any error there ships to readers.

---

## Worked example

```ts
/**
* Read the Toncoin balance of an arbitrary address — useful for wallets that aren't selected in AppKit (use {@link getBalance} for the selected wallet).
*
* @param appKit - {@link AppKit} Runtime instance.
* @param options - {@link GetBalanceByAddressOptions} Target address and optional network.
* @returns Balance in TON as a human-readable decimal string.
*
* @sample docs/examples/src/appkit/actions/balances#GET_BALANCE_BY_ADDRESS
* @expand options
*
* @public
* @category Action
* @section Balances
*/
export const getBalanceByAddress = async (
appKit: AppKit,
options: GetBalanceByAddressOptions,
): Promise<GetBalanceByAddressReturnType> => { /* ... */ };
```

```ts
/**
* Constructor options for {@link AppKit} — networks, connectors, providers and runtime flags.
*
* @public
* @category Type
* @section Core
*/
export interface AppKitConfig {
/** Map of chain id to api-client config; if omitted, AppKit defaults to mainnet only. */
networks?: NetworkAdapters;

/** Wallet connectors registered at startup. */
connectors?: ConnectorInput[];

/** Default network connectors enforce on new connections; `undefined` to allow any. */
defaultNetwork?: Network;

/** Defi/onramp providers registered at startup. */
providers?: ProviderInput[];

/** Set to `true` to enable server-side rendering support. */
ssr?: boolean;
}
```

---

## Re-exporting from walletkit (`@extract`)

Some types live in `@ton/walletkit` but are part of the `@ton/appkit` public API (e.g. `Network`, `NetworkAdapters`, `NetworkConfig`, `ApiClientConfig`). A bare `export { Network } from '@ton/walletkit'` will **not** appear in the appkit reference — `collect.ts` filters out symbols whose declaration lives outside the package. Use a local type alias plus `@extract` to surface them:

```ts
// packages/appkit/src/types/network.ts
import type { NetworkAdapters as WalletkitNetworkAdapters } from '@ton/walletkit';

/**
* @extract
* @public
* @category Type
* @section Networks
*/
export type NetworkAdapters = WalletkitNetworkAdapters;
```

What happens at generate time:

1. The alias declaration sits in `appkit/src/`, so the package-boundary filter passes it.
2. `@extract` tells `extractType` to follow the alias to the underlying walletkit `interface`/`type` and reuse its shape — fields show up in the reference table, JSDoc on each field is pulled from walletkit.
3. `@public`/`@category`/`@section` are read from the alias (you control where it appears in the appkit reference, not walletkit).
4. If the alias has its own summary on the JSDoc block, that takes precedence over walletkit's.

For declaration-merged symbols (a value + same-named interface, like `Network`), keep the value side as a separate `export const`:

```ts
import type { Network as WalletkitNetwork } from '@ton/walletkit';
import { Network as WalletkitNetworkValue } from '@ton/walletkit';

/**
* @extract
* @public
* @category Type
* @section Networks
*/
export type Network = WalletkitNetwork;

// Value side — `Network.mainnet()` etc.
export const Network = WalletkitNetworkValue;
```

The cleanest form is a JSDoc-tagged ExportDeclaration — one block tags every symbol inside the same `export { … }`:

```ts
/**
* @extract
* @public
* @category Class
* @section Swap
*/
export { SwapError, SwapProvider, SwapManager } from '@ton/walletkit';

/**
* @extract
* @public
* @category Type
* @section Swap
*/
export type { SwapToken, TokenAmount, SwapParams } from '@ton/walletkit';
```

Group symbols by `(category, section)` — one ExportDeclaration per group keeps the JSDoc shared.

**Rebuild walletkit after editing its JSDoc.** ts-morph resolves cross-package symbols through `dist/.../*.d.ts`, not the source `*.ts`, so JSDoc edits in `packages/walletkit/src/...` only land in the reference after `pnpm --filter @ton/walletkit build`. For appkit-only edits (no walletkit changes), `pnpm docs:update` alone is enough.

**Important**: `@extract` does NOT make a wildcard `export * from '@ton/appkit'` (used in appkit-react) leak appkit symbols into appkit-react. Wildcard re-exports cannot carry JSDoc, so they cannot carry `@extract`, so the boundary filter still drops them. The opt-in is local and explicit.

---

## After editing JSDoc

Run `pnpm docs:update` (alias for `pnpm docs:reference && pnpm docs:template`). The first step regenerates `docs/templates/packages/<pkg>/docs/reference.md`; the second resolves `@sample` placeholders into real code blocks and writes the final `packages/<pkg>/docs/reference.md`.

If validation fails, the script prints every problem in one go — fix them all before re-running.

---

## Quick checklist

- [ ] `@public` present
- [ ] `@category` set to one of `Class`, `Action`, `Hook`, `Component`, `Type`, `Constants`
- [ ] `@section` set to a domain string (matches existing entries where appropriate)
- [ ] Summary is one sentence with a trailing period
- [ ] Each `@param` description is one self-contained sentence
- [ ] `{@link X}` only used for symbols that are themselves `@public`
- [ ] `@expand` used for any options-bag parameter you want flattened
- [ ] `@extract` used for type aliases that re-export a walletkit type
- [ ] `@sample` points to a real `// SAMPLE_START: NAME` block in `docs/examples/`
- [ ] `pnpm docs:update` runs cleanly
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,8 @@ describe('Balance Actions Examples (Integration)', () => {

appKit.walletsManager.setWallets([mockWallet]);

// Setup balance response
// Using a simple object that mimics TokenAmount to avoid constructor issues if any,
// or we could use `new TokenAmount(1000000000n, 9)` if available.
// Since we test the example which calls .toString(), this is sufficient.
const balanceValue = { toString: () => '1000000000' } as TokenAmount;
// Setup balance response. TokenAmount is a string alias.
const balanceValue: TokenAmount = '1000000000';
mockGetBalance.mockResolvedValue(balanceValue);

await getBalanceExample(appKit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { getBalanceByAddress } from '@ton/appkit';
export const getBalanceByAddressExample = async (appKit: AppKit) => {
// SAMPLE_START: GET_BALANCE_BY_ADDRESS
const balanceByAddress = await getBalanceByAddress(appKit, {
address: 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c', // Zero Address
address: 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c',
});
console.log('Balance by address:', balanceByAddress.toString());
console.log('Balance by address:', balanceByAddress);
// SAMPLE_END: GET_BALANCE_BY_ADDRESS
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const getBalanceExample = async (appKit: AppKit) => {
// SAMPLE_START: GET_BALANCE
const balance = await getBalance(appKit);
if (balance) {
console.log('Balance:', balance.toString());
console.log('Balance:', balance);
}
// SAMPLE_END: GET_BALANCE
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { createTonConnectConnector } from '@ton/appkit';

export const addConnectorExample = (appKit: AppKit) => {
// SAMPLE_START: ADD_CONNECTOR
const stopWatching = addConnector(
const unregister = addConnector(
appKit,
createTonConnectConnector({
tonConnectOptions: {
Expand All @@ -21,7 +21,7 @@ export const addConnectorExample = (appKit: AppKit) => {
}),
);

// Later: stopWatching();
// Later: unregister();
// SAMPLE_END: ADD_CONNECTOR
return stopWatching;
return unregister;
};
Loading
Loading