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
44 changes: 42 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,42 @@
# api
Library for accessing the tscircuit API
# @tscircuit/api

Library for accessing the tscircuit API.

## Usage

```ts
import { TscircuitApiClient } from "@tscircuit/api"

const client = new TscircuitApiClient({ apiKey: "your-api-key" })
```

### Create a datasheet

```ts
const datasheet = await client.datasheets.create({ chip_name: "RP2040" })
```

### Get a datasheet

You can retrieve a datasheet by `datasheet_id` or by `chip_name`.

```ts
// by id
const dsById = await client.datasheets.get({ datasheet_id: datasheet.datasheet_id })

// by chip name
const dsByName = await client.datasheets.get({ chip_name: "RP2040" })
```

### Find, create and wait for processing

`findCreateWait` is a convenience method that attempts to fetch a datasheet by
`chip_name`. If it does not exist the datasheet is created. The method then
polls `datasheets/get` until the datasheet's `pin_information` field is
populated.

```ts
const processed = await client.datasheets.findCreateWait({ chip_name: "RP2040" })
```

The promise resolves once processing is complete or throws after a timeout.
47 changes: 44 additions & 3 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,59 @@ export class TscircuitApiClient {
}

public datasheets = {
create: async ({ chip_name }: { chip_name: string }): Promise<Datasheet> => {
create: async ({
chip_name,
}: {
chip_name: string
}): Promise<Datasheet> => {
const res = await this.ky
.post("datasheets/create", { json: { chip_name } })
.json<{ datasheet: Datasheet }>()
return res.datasheet
},
get: async ({ datasheet_id }: { datasheet_id: string }): Promise<Datasheet> => {
get: async ({
datasheet_id,
chip_name,
}: {
datasheet_id?: string
chip_name?: string
}): Promise<Datasheet> => {
const searchParams: Record<string, string> = {}
if (datasheet_id) searchParams.datasheet_id = datasheet_id
if (chip_name) searchParams.chip_name = chip_name
const res = await this.ky
.get("datasheets/get", { searchParams: { datasheet_id } })
.get("datasheets/get", { searchParams })
.json<{ datasheet: Datasheet }>()
return res.datasheet
},
findCreateWait: async ({
chip_name,
}: {
chip_name: string
}): Promise<Datasheet> => {
try {
const existing = await this.datasheets.get({ chip_name })
if (existing.pin_information) return existing
} catch (err: any) {
if (!(err instanceof Error) || (err as any)?.response?.status !== 404) {
throw err
}
}

await this.datasheets.create({ chip_name })

for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 1000))
try {
const ds = await this.datasheets.get({ chip_name })
if (ds.pin_information) return ds
} catch (err: any) {
if ((err as any)?.response?.status !== 404) throw err
}
}

throw new Error("Timed out waiting for datasheet to be processed")
},
}
}

Expand Down
19 changes: 19 additions & 0 deletions tests/datasheets/findCreateWait.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { test, expect } from "bun:test"
import { getTestFixture } from "tests/fixtures/getTestFixture"

const delay = (ms: number) => new Promise((r) => setTimeout(r, ms))

test("datasheets.findCreateWait", async () => {
const { client, ky } = await getTestFixture()

const waitPromise = client.datasheets.findCreateWait({
chip_name: "WaitChip",
})

await delay(100)
await ky.get("_fake/run_async_tasks").json()

const result = await waitPromise
expect(result.chip_name).toBe("WaitChip")
expect(result.pin_information).not.toBeNull()
})
14 changes: 13 additions & 1 deletion tests/datasheets/get.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,19 @@ test("/datasheets/get", async () => {

const created = await client.datasheets.create({ chip_name: "Chip" })

const gotten = await client.datasheets.get({ datasheet_id: created.datasheet_id })
const gotten = await client.datasheets.get({
datasheet_id: created.datasheet_id,
})

expect(gotten.datasheet_id).toBe(created.datasheet_id)
})

test("/datasheets/get by chip_name", async () => {
const { client } = await getTestFixture()

await client.datasheets.create({ chip_name: "ChipName" })

const gotten = await client.datasheets.get({ chip_name: "ChipName" })

expect(gotten.chip_name).toBe("ChipName")
})
25 changes: 25 additions & 0 deletions tests/fixtures/startServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,31 @@ export const startServer = async ({

const server = Bun.serve({
fetch: (bunReq) => {
const url = new URL(bunReq.url)
if (
url.pathname === "/api/datasheets/get" &&
url.searchParams.has("chip_name")
) {
const chipName = url.searchParams.get("chip_name")!
const datasheet = (db as any).datasheets.find(
(d: any) => d.chip_name === chipName,
)
if (!datasheet) {
return new Response(
JSON.stringify({
error: {
error_code: "datasheet_not_found",
message: "Datasheet not found",
},
}),
{ status: 404, headers: { "content-type": "application/json" } },
)
}
return new Response(JSON.stringify({ datasheet }), {
headers: { "content-type": "application/json" },
})
}

const req = new EdgeRuntimeRequest(bunReq.url, {
headers: bunReq.headers,
method: bunReq.method,
Expand Down
Loading