Skip to content
Open
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
617 changes: 526 additions & 91 deletions patches/vocs@2.12.0.patch

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions src/lib/markdown-output.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,22 @@ No validator P2P or RPC port should be directly accessible from the internet.
expect(unchanged).not.toContain('currency=')
})

test('uses embed path and body presets in Markdown samples', async () => {
const balances = await render(
'<OpenApi.Playground operationId="getAddressBalances" params="address=0xabc" query="currency=usd" />',
)
expect(balances).toContain('https://api.tempo.xyz/v1/addresses/0xabc/balances?currency=usd')
expect(balances).not.toContain('0x123')
expect(balances).not.toContain('chainId=')

const transfer = await render(
`<OpenApi.Playground operationId="createRoutesTransfer" body='{"amount": "1000000", "mode": "exactSource"}' />`,
)
expect(transfer).toContain('"amount": "1000000"')
expect(transfer).toContain("amount: '1000000'")
expect(transfer).not.toContain('quote_example')
})

test('matches hidden query parameters in the API tool', async () => {
const output = await render(
'<OpenApi.Playground operationId="getAddressBalances" hideQueryParams />',
Expand Down Expand Up @@ -414,6 +430,27 @@ No validator P2P or RPC port should be directly accessible from the internet.
'<OpenApi.Playground operationId="getAddressBalances" query={dynamic} />',
'static query attribute',
],
[
'<OpenApi.Playground operationId="getAddressBalances" body={dynamic} />',
'static body attribute',
],
[
'<OpenApi.Playground operationId="getAddressBalances" params={dynamic} />',
'static params attribute',
],
[
'<OpenApi.Playground operationId="getAddressBalances" params="adress=0xabc" />',
'no path parameter `adress`',
],
[
'<OpenApi.Playground operationId="getAddressBalances" query="curency=usd" />',
'no query parameter `curency`',
],
[
`<OpenApi.Playground operationId="getAddressBalances" body='{"amount": "1"}' />`,
'has no request body',
],
[`<OpenApi.Playground operationId="createRoutesTransfer" body='{"amount": ' />`, 'JSON'],
])('fails instead of silently losing API content: %s', async (source, message) => {
await expect(render(source)).rejects.toThrow(message)
})
Expand Down
9 changes: 7 additions & 2 deletions src/lib/markdown-output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
type IrOperation,
parse,
} from '../../node_modules/vocs/dist/internal/openapi/parser.js'
import { operationWithQuery } from '../../node_modules/vocs/dist/internal/openapi/query-presets.js'
import { operationWithPreset } from '../../node_modules/vocs/dist/internal/openapi/query-presets.js'
import { groupPath } from '../../node_modules/vocs/dist/internal/openapi/route.js'
import { codeSamples } from '../../node_modules/vocs/dist/internal/openapi/sample.js'
import { tempoAgentSetupCommands } from './ai-install-commands'
Expand Down Expand Up @@ -625,8 +625,13 @@ function renderOpenApi(
throw new TypeError(`Unknown OpenAPI operation for Markdown output: ${operationId}`)
const href = `${mount}/${groupPath(group)}#${operation.id}`
const query = optionalStaticStringAttribute(node, 'query')
const preset = {
body: optionalStaticStringAttribute(node, 'body'),
params: optionalStaticStringAttribute(node, 'params'),
query,
}
const { sampleOperation, authentication } = apiAuthentication(
initialRequest(operationWithQuery(operation, query), query),
initialRequest(operationWithPreset(operation, preset), query),
Comment thread
claude[bot] marked this conversation as resolved.
Resolved
ir,
)
const samples = codeSamples(sampleOperation, ir.servers[0]?.url, {
Expand Down
48 changes: 48 additions & 0 deletions src/lib/openapi-query-presets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest'
import type { IrOperation } from '../../node_modules/vocs/dist/internal/openapi/parser.js'
import {
documentWithQuery,
operationWithPreset,
operationWithQuery,
} from '../../node_modules/vocs/dist/internal/openapi/query-presets.js'
import { codeSamples } from '../../node_modules/vocs/dist/internal/openapi/sample.js'
Expand Down Expand Up @@ -55,6 +56,53 @@ describe('inline API query presets', () => {
expect(document).toEqual(before)
})

test('fills path values and the JSON body, and drops unnamed optional query rows', () => {
const create: IrOperation = {
id: 'createtransfer',
method: 'POST',
path: '/v1/transfers/{id}',
parameters: [
{ in: 'path', name: 'id', required: true, schema: { example: 'rtr_1' } },
{ in: 'query', name: 'chainId', schema: { examples: [4217] } },
{ in: 'query', name: 'tokens', required: true, schema: { examples: ['0x1'] } },
],
requestBody: {
content: [{ mediaType: 'application/json', schema: { type: 'object' } }],
},
responses: [],
}
const preset = operationWithPreset(create, {
body: '{"amount":"1000000"}',
params: 'id=rtr_2',
query: 'tokens=0xa,0xb',
})
const sample = codeSamples(preset, 'https://api.tempo.xyz', { expand: true })[0]
expect(sample.code).toContain('/v1/transfers/rtr_2?tokens=0xa,0xb')
expect(sample.code).not.toContain('chainId')
expect(sample.code).toContain('"amount": "1000000"')
expect(sample.collapsed).toBeUndefined()

const document = {
paths: {
'/v1/transfers/{id}': {
post: {
parameters: structuredClone(create.parameters),
requestBody: { content: { 'application/json': { examples: { a: { value: {} } } } } },
},
},
},
}
const scalar = documentWithQuery(document, {
body: '{"amount":"1000000"}',
method: 'POST',
params: 'id=rtr_2',
path: '/v1/transfers/{id}',
}) as typeof document
const post = scalar.paths['/v1/transfers/{id}'].post
expect(post.parameters[0]).toMatchObject({ examples: { default: { value: 'rtr_2' } } })
expect(post.requestBody.content['application/json']).toEqual({ example: { amount: '1000000' } })
})

test('leaves normal API reference instances unchanged', () => {
const document = { paths: {} }
expect(documentWithQuery(document)).toBe(document)
Expand Down
58 changes: 29 additions & 29 deletions src/pages/docs/routes/fx.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ Every step also runs from a terminal with curl and jq, as the [FX swap example](

### Check the account

Name the pair by its two token addresses, in either order.
Send your pool address and listed account in place of the example's `0xbe05…039e` and `0x2222…2222`. Name the pair by its two token addresses, in either order.

```bash
curl --get \
'https://api.tempo.xyz/v1/prop-amms/<POOL_ADDRESS>/accounts/<ACCOUNT_ADDRESS>/access' \
--header "tempo-api-key: $TEMPO_API_KEY" \
--data-urlencode 'tokens=<SOURCE_TOKEN_ADDRESS>,<DESTINATION_TOKEN_ADDRESS>'
```
<OpenApi.Playground
operationId="getPropAmmTokensAccountAccess"
params="account=0x2222222222222222222222222222222222222222"
query="tokens=0x20c0000000000000000000006a37da5c996874be,0x20c0000000000000000000001621e21f71cf12fb"
anchors={false}
/>

The API checks the account against your organization's saved list. A listed account returns `"member": true`, `"allowed": true`, and `"reason": "allowed"`. Routes runs the same check when it quotes. Otherwise `reason` and `explanation` name what's missing, such as `notListed`.

Expand All @@ -82,23 +82,20 @@ Show the source amount, the destination amount, and `destinationAmountMin`. Crea

Send the same inputs with an [idempotency key](/docs/routes/api-setup#set-idempotency-keys).

```bash [Terminal]
curl 'https://api.tempo.xyz/v1/routes/transfers' \
--request POST \
--header "tempo-api-key: $TEMPO_API_KEY" \
--header 'idempotency-key: <IDEMPOTENCY_KEY>' \
--header 'Content-Type: application/json' \
--data '{
<OpenApi.Playground
operationId="createRoutesTransfer"
body='{
"sourceChain": "tempo",
"sourceToken": "0x20c0000000000000000000006a37da5c996874be",
"destinationChain": "tempo",
"destinationToken": "0x20c0000000000000000000001621e21f71cf12fb",
"sender": "<ACCOUNT_ADDRESS>",
"recipient": "<ACCOUNT_ADDRESS>",
"sender": "0x2222222222222222222222222222222222222222",
"recipient": "0x2222222222222222222222222222222222222222",
"amount": "1000000",
"mode": "exactSource"
}'
```
anchors={false}
/>

This request swaps 1 OUSD for EURC.e from one account to itself.

Expand Down Expand Up @@ -132,23 +129,21 @@ A list has one admin account. The admin adds or removes up to 50 accounts in one

### Prepare the change

Send the list's admin account as `sender`. Name the pair by its two token addresses, in either order.
Send the list's admin account as `sender`, in place of the example's `0x1111…1111`. Name the pair by its two token addresses, in either order.

```bash [Terminal]
curl 'https://api.tempo.xyz/v1/prop-amms/<POOL_ADDRESS>/access/prepare' \
--request POST \
--header "tempo-api-key: $TEMPO_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"sender": "<LIST_ADMIN_ADDRESS>",
<OpenApi.Playground
operationId="preparePropAmmAccess"
body='{
"sender": "0x1111111111111111111111111111111111111111",
"action": {
"type": "setMembers",
"tokens": ["<SOURCE_TOKEN_ADDRESS>", "<DESTINATION_TOKEN_ADDRESS>"],
"accounts": ["<ACCOUNT_ADDRESS>"],
"tokens": ["0x20c0000000000000000000006a37da5c996874be", "0x20c0000000000000000000001621e21f71cf12fb"],
"accounts": ["0x2222222222222222222222222222222222222222"],
"allowed": true
}
}'
```
anchors={false}
/>

The API applies the change to your organization's saved list. It simulates the change and returns an unsigned `transaction`. `effect` names the resolved pair index and sponsor ID, such as `List 1 account(s) on pair 0 under sponsor 5.`

Expand All @@ -171,7 +166,12 @@ Requests that omit `sponsorId` use your organization's saved list. Requests with
- **Sponsor ID.** Pass `sponsorId` as a decimal string to name a list, such as `"0"` for the pool's default list. The account check takes it as a query parameter. The access change takes it in `action`.
- **Pair index.** Pass `pairIndex` in place of `tokens` in the access change. Send exactly one of the two. The account check takes the pair index in its path.

<OpenApi.Playground operationId="getPropAmmAccountAccess" anchors={false} />
<OpenApi.Playground
operationId="getPropAmmAccountAccess"
params="account=0x2222222222222222222222222222222222222222&pairIndex=0"
query="sponsorId=0"
anchors={false}
/>

## Account list errors

Expand Down
Loading