Skip to content

Commit e6acb5b

Browse files
authored
feat: use x-turso-organization header instead of path (#23)
* feat: use x-turso-organization header instead of path * docs: update readme * chore: prelease tags * chore: update workflow * chore: cleanup
1 parent 9be4a82 commit e6acb5b

13 files changed

Lines changed: 116 additions & 136 deletions

File tree

.github/workflows/release.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ name: Release
22

33
on:
44
push:
5-
branches:
6-
- main
5+
branches:
6+
- main
7+
- next
78

89
permissions:
910
contents: write
1011
issues: write
1112
pull-requests: write
12-
13+
1314
jobs:
1415
release:
1516
runs-on: ubuntu-latest

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
node_modules
2-
dist
2+
dist

README.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@
77
```ts
88
import { createClient } from "@tursodatabase/api";
99

10+
// Personal account client
1011
const turso = createClient({
11-
org: "", // Your personal account or organization slug
12+
token: "...",
13+
});
14+
15+
// Organization account client
16+
const turso = createClient({
17+
org: "...", // Your organization slug
1218
token: "...",
1319
});
1420
```
@@ -51,9 +57,9 @@ const token = await turso.groups.createToken("default", {
5157
const token = await turso.groups.createToken("default", {
5258
permissions: {
5359
read_attach: {
54-
databases: ["db1", "db2"]
55-
}
56-
}
60+
databases: ["db1", "db2"],
61+
},
62+
},
5763
});
5864
const token = await turso.groups.rotateTokens("default");
5965
```
@@ -112,9 +118,9 @@ const token = await turso.databases.createToken("my-db", {
112118
const token = await turso.databases.createToken("my-db", {
113119
permissions: {
114120
read_attach: {
115-
databases: ["db1", "db2"]
116-
}
117-
}
121+
databases: ["db1", "db2"],
122+
},
123+
},
118124
});
119125
const token = await turso.databases.rotateTokens("my-db");
120126

release.config.cjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module.exports = {
2-
branches: ["main"],
3-
};
2+
branches: ["main", { name: "next", prerelease: true }],
3+
};

src/api-token.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { TursoConfig } from "./config";
2-
import { TursoClient } from "./client";
1+
import { TursoClient, type TursoConfig } from "./client";
32

43
export interface ApiToken {
54
id: string;
@@ -24,7 +23,7 @@ export class ApiTokenClient {
2423

2524
async list(): Promise<ApiToken[]> {
2625
const response = await TursoClient.request<{ tokens: ApiToken[] }>(
27-
"auth/api-tokens",
26+
`auth/api-tokens`,
2827
this.config
2928
);
3029

@@ -60,7 +59,7 @@ export class ApiTokenClient {
6059

6160
async validate(token: string): Promise<ApiTokenValidation> {
6261
const response = await TursoClient.request<{ exp: number }>(
63-
"auth/api-tokens/validate",
62+
`auth/api-tokens/validate`,
6463
this.config,
6564
{
6665
headers: {

src/client.test.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,20 @@ import { TursoClient, TursoClientError, createClient } from "./client";
33

44
describe("TursoClient", () => {
55
it("should throw an error if no API token is provided", () => {
6-
const config = { org: "turso" };
7-
86
// @ts-expect-error
9-
expect(() => new TursoClient(config)).toThrow(
7+
expect(() => new TursoClient({ org: "turso" })).toThrow(
108
"You must provide an API token"
119
);
1210
});
1311

1412
it("should create an instance of TursoClient", () => {
15-
const config = { org: "turso", token: "abc" };
16-
const client = new TursoClient(config);
13+
const client = new TursoClient({ org: "turso", token: "abc" });
1714

1815
expect(client).toBeInstanceOf(TursoClient);
1916
});
2017

2118
it("should throw an error message that will match with API's error message", async () => {
22-
const config = { org: "turso", token: "abc" };
23-
const client = new TursoClient(config);
19+
const client = new TursoClient({ org: "turso", token: "abc" });
2420

2521
const error = await client.databases
2622
.get("databaseName")

src/client.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { TursoConfig } from "./config";
21
import { ApiTokenClient } from "./api-token";
32
import { OrganizationClient } from "./organization";
43
import { LocationClient } from "./location";
54
import { GroupClient } from "./group";
65
import { DatabaseClient } from "./database";
76

7+
export const TURSO_API_URL = "https://api.turso.tech/v1/";
8+
89
interface ApiErrorResponse {
910
error: string;
1011
}
@@ -22,6 +23,26 @@ export class TursoClientError extends Error {
2223
}
2324
}
2425

26+
/**
27+
* Configuration interface for Turso API client.
28+
*/
29+
export interface TursoConfig {
30+
/**
31+
* Organization identifier.
32+
*/
33+
org?: string;
34+
35+
/**
36+
* API token for authentication.
37+
*/
38+
token: string;
39+
40+
/**
41+
* Base URL for the API. Optional and defaults to "https://api.turso.tech/v1/".
42+
*/
43+
baseUrl?: string;
44+
}
45+
2546
export class TursoClient {
2647
private config: TursoConfig;
2748
public apiTokens: ApiTokenClient;
@@ -36,7 +57,7 @@ export class TursoClient {
3657
}
3758

3859
this.config = {
39-
baseUrl: "https://api.turso.tech/v1/",
60+
baseUrl: TURSO_API_URL,
4061
...config,
4162
};
4263

@@ -47,6 +68,14 @@ export class TursoClient {
4768
this.databases = new DatabaseClient(this.config);
4869
}
4970

71+
/**
72+
* Makes an API request.
73+
* @param url - The endpoint URL.
74+
* @param config - The Turso configuration.
75+
* @param options - The request options.
76+
* @returns The API response.
77+
* @throws TursoClientError if the request fails.
78+
*/
5079
static async request<T>(
5180
url: string,
5281
config: TursoConfig,
@@ -58,6 +87,7 @@ export class TursoClient {
5887
...options.headers,
5988
Authorization: `Bearer ${config.token}`,
6089
"User-Agent": "@tursodatabase/api",
90+
...(config.org && { "x-turso-organization": config.org }),
6191
},
6292
});
6393

@@ -75,6 +105,11 @@ export class TursoClient {
75105
}
76106
}
77107

108+
/**
109+
* Creates a new TursoClient instance.
110+
* @param config - The Turso configuration.
111+
* @returns The TursoClient instance.
112+
*/
78113
export function createClient(config: TursoConfig): TursoClient {
79114
return new TursoClient(config);
80115
}

src/config.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/database.ts

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
import { TursoClient, type TursoConfig } from "./client";
12
import { LocationKeys } from "./location";
2-
import { TursoConfig } from "./config";
3-
import { TursoClient } from "./client";
43

54
export interface Database {
65
name: string;
@@ -101,15 +100,15 @@ export class DatabaseClient {
101100
async list(): Promise<Database[]> {
102101
const response = await TursoClient.request<{
103102
databases: ApiDatabaseResponse[];
104-
}>(`organizations/${this.config.org}/databases`, this.config);
103+
}>(`databases`, this.config);
105104

106105
return (response.databases ?? []).map((db) => this.formatResponse(db));
107106
}
108107

109108
async get(dbName: string): Promise<Database> {
110109
const response = await TursoClient.request<{
111110
database: ApiDatabaseResponse;
112-
}>(`organizations/${this.config.org}/databases/${dbName}`, this.config);
111+
}>(`databases/${dbName}`, this.config);
113112

114113
return this.formatResponse(response.database);
115114
}
@@ -146,7 +145,7 @@ export class DatabaseClient {
146145

147146
const response = await TursoClient.request<{
148147
database: ApiCreateDatabaseResponse;
149-
}>(`organizations/${this.config.org}/databases`, this.config, {
148+
}>(`databases`, this.config, {
150149
method: "POST",
151150
headers: {
152151
"content-type": "application/json",
@@ -162,7 +161,7 @@ export class DatabaseClient {
162161

163162
async updateVersion(dbName: string): Promise<void> {
164163
return await TursoClient.request(
165-
`organizations/${this.config.org}/databases/${dbName}/update`,
164+
`databases/${dbName}/update`,
166165
this.config,
167166
{
168167
method: "POST",
@@ -172,7 +171,7 @@ export class DatabaseClient {
172171

173172
async delete(dbName: string) {
174173
const response = await TursoClient.request<DeletedDatabase>(
175-
`organizations/${this.config.org}/databases/${dbName}`,
174+
`databases/${dbName}`,
176175
this.config,
177176
{
178177
method: "DELETE",
@@ -185,10 +184,7 @@ export class DatabaseClient {
185184
async listInstances(dbName: string): Promise<DatabaseInstance[]> {
186185
const response = await TursoClient.request<{
187186
instances: DatabaseInstance[];
188-
}>(
189-
`organizations/${this.config.org}/databases/${dbName}/instances`,
190-
this.config
191-
);
187+
}>(`databases/${dbName}/instances`, this.config);
192188

193189
return response.instances ?? [];
194190
}
@@ -199,10 +195,7 @@ export class DatabaseClient {
199195
): Promise<DatabaseInstance> {
200196
const response = await TursoClient.request<{
201197
instance: DatabaseInstance;
202-
}>(
203-
`organizations/${this.config.org}/databases/${dbName}/instances/${instanceName}`,
204-
this.config
205-
);
198+
}>(`databases/${dbName}/instances/${instanceName}`, this.config);
206199

207200
return response.instance ?? null;
208201
}
@@ -228,7 +221,7 @@ export class DatabaseClient {
228221
}
229222

230223
const response = await TursoClient.request<DatabaseToken>(
231-
`organizations/${this.config.org}/databases/${dbName}/auth/tokens?${queryParams}`,
224+
`databases/${dbName}/auth/tokens?${queryParams}`,
232225
this.config,
233226
{
234227
method: "POST",
@@ -247,7 +240,7 @@ export class DatabaseClient {
247240

248241
async rotateTokens(dbName: string): Promise<void> {
249242
return await TursoClient.request<void>(
250-
`organizations/${this.config.org}/databases/${dbName}/auth/rotate`,
243+
`databases/${dbName}/auth/rotate`,
251244
this.config,
252245
{
253246
method: "POST",
@@ -273,10 +266,7 @@ export class DatabaseClient {
273266
database: DatabaseUsage;
274267
instances: InstanceUsages;
275268
total: TotalUsage;
276-
}>(
277-
`organizations/${this.config.org}/databases/${dbName}/usage?${queryParams}`,
278-
this.config
279-
);
269+
}>(`databases/${dbName}/usage?${queryParams}`, this.config);
280270

281271
return response.database;
282272
}

0 commit comments

Comments
 (0)