get-db9 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,14 +29,15 @@ const db = await instantDatabase({
29
29
  });
30
30
  ```
31
31
 
32
- ## Customer API
32
+ ## Db9 Client
33
33
 
34
- Full typed client for the Customer API (register, databases, SQL, migrations).
34
+ Full typed client for the API (register, databases, SQL, migrations).
35
35
 
36
36
  ```typescript
37
- import { createCustomerClient } from 'get-db9/customer';
37
+ import { createDb9Client } from 'get-db9/client';
38
38
 
39
- const client = createCustomerClient({ token: 'your-token' });
39
+ // No token needed. Automatically anonymous-registers and saves credentials.
40
+ const client = createDb9Client();
40
41
 
41
42
  // Create a database
42
43
  const db = await client.databases.create({ name: 'myapp' });
@@ -56,26 +57,6 @@ await client.databases.applyMigration(db.id, {
56
57
  });
57
58
  ```
58
59
 
59
- ## Admin API
60
-
61
- Full typed client for the Admin API (tenant management, batch operations, audit).
62
-
63
- ```typescript
64
- import { createAdminClient } from 'get-db9/admin';
65
-
66
- const admin = createAdminClient({ apiKey: 'your-api-key' });
67
-
68
- // List tenants
69
- const { items } = await admin.tenants.list({ state: 'ACTIVE' });
70
-
71
- // Create tenant
72
- const tenant = await admin.tenants.create();
73
- console.log(tenant.connection_string);
74
-
75
- // Batch operations
76
- const batch = await admin.tenants.batchCreate({ count: 5 });
77
- ```
78
-
79
60
  ## Configuration
80
61
 
81
62
  ### instantDatabase options
@@ -89,22 +70,24 @@ const batch = await admin.tenants.batchCreate({ count: 5 });
89
70
  | `seed` | `string` | — | SQL to run after creation |
90
71
  | `seedFile` | `string` | — | SQL file content to run |
91
72
 
92
- ### Customer client options
73
+ ### Db9 client options
93
74
 
94
75
  | Option | Type | Default | Description |
95
76
  |--------|------|---------|-------------|
96
77
  | `baseUrl` | `string` | Production URL | API endpoint |
97
- | `token` | `string` | — | Bearer token |
78
+ | `token` | `string` | — | Bearer token (optional) |
98
79
  | `fetch` | `FetchFn` | `globalThis.fetch` | Custom fetch |
99
- | `credentialStore` | `CredentialStore` | | Auto-load token |
80
+ | `credentialStore` | `CredentialStore` | `FileCredentialStore` | Load/save token |
100
81
 
101
- ### Admin client options
82
+ ## Zero-config client
102
83
 
103
- | Option | Type | Default | Description |
104
- |--------|------|---------|-------------|
105
- | `baseUrl` | `string` | Production URL | API endpoint |
106
- | `apiKey` | `string` | — | X-API-Key header |
107
- | `fetch` | `FetchFn` | `globalThis.fetch` | Custom fetch |
84
+ ```typescript
85
+ import { createDb9Client } from 'get-db9';
86
+
87
+ // No token needed! Auto-registers anonymously
88
+ const client = createDb9Client();
89
+ const db = await client.databases.create({ name: 'myapp' });
90
+ ```
108
91
 
109
92
  ## Error Handling
110
93
 
@@ -11,6 +11,41 @@ interface HttpClient {
11
11
  del<T>(path: string): Promise<T>;
12
12
  }
13
13
 
14
+ /** Credential fields stored in `~/.db9/credentials` (TOML). */
15
+ interface Credentials {
16
+ token: string;
17
+ is_anonymous?: boolean;
18
+ anonymous_id?: string;
19
+ anonymous_secret?: string;
20
+ }
21
+ /** Async credential persistence abstraction. */
22
+ interface CredentialStore {
23
+ load(): Promise<Credentials | null>;
24
+ save(credentials: Credentials): Promise<void>;
25
+ clear(): Promise<void>;
26
+ }
27
+ declare class FileCredentialStore implements CredentialStore {
28
+ private readonly customPath;
29
+ /**
30
+ * @param path — Override the credential file location.
31
+ * Defaults to `~/.db9/credentials` (resolved lazily).
32
+ */
33
+ constructor(path?: string);
34
+ /** Resolve the credential file path (lazy to avoid top-level `os` import). */
35
+ private resolvePath;
36
+ load(): Promise<Credentials | null>;
37
+ save(credentials: Credentials): Promise<void>;
38
+ clear(): Promise<void>;
39
+ }
40
+ declare class MemoryCredentialStore implements CredentialStore {
41
+ private credentials;
42
+ load(): Promise<Credentials | null>;
43
+ save(credentials: Credentials): Promise<void>;
44
+ clear(): Promise<void>;
45
+ }
46
+ /** Returns a FileCredentialStore with the default path (`~/.db9/credentials`). */
47
+ declare function defaultCredentialStore(): CredentialStore;
48
+
14
49
  interface Endpoint {
15
50
  host: string;
16
51
  port: number;
@@ -318,4 +353,47 @@ interface MigrationMetadata {
318
353
  }
319
354
  type TenantState = 'CREATING' | 'ACTIVE' | 'DISABLING' | 'DISABLED' | 'CREATE_FAILED';
320
355
 
321
- export type { TenantObservabilityResponse as $, AdminCreateUserRequest as A, BatchCreateRequest as B, ClaimRequest as C, DatabaseResponse as D, Endpoint as E, FetchFn as F, LoginRequest as G, HealthResponse as H, LoginResponse as I, MigrationApplyRequest as J, MigrationApplyResponse as K, ListTenantsParams as L, MessageResponse as M, MigrationMetadata as N, ObservabilitySummary as O, PasswordResetResponse as P, QuerySample as Q, RegisterRequest as R, SchemaResponse as S, SqlExecuteRequest as T, SqlQueryRequest as U, SqlQueryResponse as V, SqlResult as W, TableMetadata as X, TenantConnectRequest as Y, TenantConnectResponse as Z, TenantListResponse as _, AnonymousRefreshRequest as a, TenantResponse as a0, TenantState as a1, TenantUpdateRequest as a2, TokenResponse as a3, UserCreateResponse as a4, UserResponse as a5, ViewMetadata as a6, AnonymousRefreshResponse as b, AnonymousRegisterResponse as c, AnonymousSecretResponse as d, AuditLogParams as e, AuditLogResponse as f, BatchCreateResponse as g, BatchDeleteRequest as h, BatchDeleteResponse as i, BatchItemError as j, BatchUpdateRequest as k, BatchUpdateResponse as l, BranchRequest as m, ClaimResponse as n, ColumnInfo as o, ColumnMetadata as p, CreateDatabaseRequest as q, CreateTenantRequest as r, CreateTenantResponse as s, CreateUserRequest as t, CustomerPasswordResetResponse as u, CustomerResponse as v, DumpRequest as w, DumpResponse as x, HttpClient as y, HttpClientOptions as z };
356
+ interface Db9ClientOptions {
357
+ baseUrl?: string;
358
+ token?: string;
359
+ fetch?: FetchFn;
360
+ credentialStore?: CredentialStore;
361
+ }
362
+ declare function createDb9Client(options?: Db9ClientOptions): {
363
+ auth: {
364
+ register: (req: RegisterRequest) => Promise<CustomerResponse>;
365
+ login: (req: LoginRequest) => Promise<LoginResponse>;
366
+ anonymousRegister: () => Promise<AnonymousRegisterResponse>;
367
+ anonymousRefresh: (req: AnonymousRefreshRequest) => Promise<AnonymousRefreshResponse>;
368
+ me: () => Promise<CustomerResponse>;
369
+ getAnonymousSecret: () => Promise<AnonymousSecretResponse>;
370
+ claim: (req: ClaimRequest) => Promise<ClaimResponse>;
371
+ };
372
+ tokens: {
373
+ list: () => Promise<TokenResponse[]>;
374
+ revoke: (tokenId: string) => Promise<MessageResponse>;
375
+ };
376
+ databases: {
377
+ create: (req: CreateDatabaseRequest) => Promise<DatabaseResponse>;
378
+ list: () => Promise<DatabaseResponse[]>;
379
+ get: (databaseId: string) => Promise<DatabaseResponse>;
380
+ delete: (databaseId: string) => Promise<MessageResponse>;
381
+ resetPassword: (databaseId: string) => Promise<CustomerPasswordResetResponse>;
382
+ observability: (databaseId: string) => Promise<TenantObservabilityResponse>;
383
+ sql: (databaseId: string, query: string) => Promise<SqlResult>;
384
+ sqlFile: (databaseId: string, fileContent: string) => Promise<SqlResult>;
385
+ schema: (databaseId: string) => Promise<SchemaResponse>;
386
+ dump: (databaseId: string, req?: DumpRequest) => Promise<DumpResponse>;
387
+ applyMigration: (databaseId: string, req: MigrationApplyRequest) => Promise<MigrationApplyResponse>;
388
+ listMigrations: (databaseId: string) => Promise<MigrationMetadata[]>;
389
+ branch: (databaseId: string, req: BranchRequest) => Promise<DatabaseResponse>;
390
+ users: {
391
+ list: (databaseId: string) => Promise<UserResponse[]>;
392
+ create: (databaseId: string, req: CreateUserRequest) => Promise<MessageResponse>;
393
+ delete: (databaseId: string, username: string) => Promise<MessageResponse>;
394
+ };
395
+ };
396
+ };
397
+ type Db9Client = ReturnType<typeof createDb9Client>;
398
+
399
+ export { type SqlQueryResponse as $, type AdminCreateUserRequest as A, type BatchCreateRequest as B, type CredentialStore as C, type DatabaseResponse as D, type DumpRequest as E, type FetchFn as F, type DumpResponse as G, type Endpoint as H, FileCredentialStore as I, type HealthResponse as J, type HttpClient as K, type HttpClientOptions as L, type ListTenantsParams as M, type LoginRequest as N, type LoginResponse as O, MemoryCredentialStore as P, type MessageResponse as Q, type MigrationApplyRequest as R, type MigrationApplyResponse as S, type MigrationMetadata as T, type ObservabilitySummary as U, type PasswordResetResponse as V, type QuerySample as W, type RegisterRequest as X, type SchemaResponse as Y, type SqlExecuteRequest as Z, type SqlQueryRequest as _, type AnonymousRefreshRequest as a, type SqlResult as a0, type TableMetadata as a1, type TenantConnectRequest as a2, type TenantConnectResponse as a3, type TenantListResponse as a4, type TenantObservabilityResponse as a5, type TenantResponse as a6, type TenantState as a7, type TenantUpdateRequest as a8, type TokenResponse as a9, type UserCreateResponse as aa, type UserResponse as ab, type ViewMetadata as ac, createDb9Client as ad, defaultCredentialStore as ae, type AnonymousRefreshResponse as b, type AnonymousRegisterResponse as c, type AnonymousSecretResponse as d, type AuditLogParams as e, type AuditLogResponse as f, type BatchCreateResponse as g, type BatchDeleteRequest as h, type BatchDeleteResponse as i, type BatchItemError as j, type BatchUpdateRequest as k, type BatchUpdateResponse as l, type BranchRequest as m, type ClaimRequest as n, type ClaimResponse as o, type ColumnInfo as p, type ColumnMetadata as q, type CreateDatabaseRequest as r, type CreateTenantRequest as s, type CreateTenantResponse as t, type CreateUserRequest as u, type Credentials as v, type CustomerPasswordResetResponse as w, type CustomerResponse as x, type Db9Client as y, type Db9ClientOptions as z };
@@ -11,6 +11,41 @@ interface HttpClient {
11
11
  del<T>(path: string): Promise<T>;
12
12
  }
13
13
 
14
+ /** Credential fields stored in `~/.db9/credentials` (TOML). */
15
+ interface Credentials {
16
+ token: string;
17
+ is_anonymous?: boolean;
18
+ anonymous_id?: string;
19
+ anonymous_secret?: string;
20
+ }
21
+ /** Async credential persistence abstraction. */
22
+ interface CredentialStore {
23
+ load(): Promise<Credentials | null>;
24
+ save(credentials: Credentials): Promise<void>;
25
+ clear(): Promise<void>;
26
+ }
27
+ declare class FileCredentialStore implements CredentialStore {
28
+ private readonly customPath;
29
+ /**
30
+ * @param path — Override the credential file location.
31
+ * Defaults to `~/.db9/credentials` (resolved lazily).
32
+ */
33
+ constructor(path?: string);
34
+ /** Resolve the credential file path (lazy to avoid top-level `os` import). */
35
+ private resolvePath;
36
+ load(): Promise<Credentials | null>;
37
+ save(credentials: Credentials): Promise<void>;
38
+ clear(): Promise<void>;
39
+ }
40
+ declare class MemoryCredentialStore implements CredentialStore {
41
+ private credentials;
42
+ load(): Promise<Credentials | null>;
43
+ save(credentials: Credentials): Promise<void>;
44
+ clear(): Promise<void>;
45
+ }
46
+ /** Returns a FileCredentialStore with the default path (`~/.db9/credentials`). */
47
+ declare function defaultCredentialStore(): CredentialStore;
48
+
14
49
  interface Endpoint {
15
50
  host: string;
16
51
  port: number;
@@ -318,4 +353,47 @@ interface MigrationMetadata {
318
353
  }
319
354
  type TenantState = 'CREATING' | 'ACTIVE' | 'DISABLING' | 'DISABLED' | 'CREATE_FAILED';
320
355
 
321
- export type { TenantObservabilityResponse as $, AdminCreateUserRequest as A, BatchCreateRequest as B, ClaimRequest as C, DatabaseResponse as D, Endpoint as E, FetchFn as F, LoginRequest as G, HealthResponse as H, LoginResponse as I, MigrationApplyRequest as J, MigrationApplyResponse as K, ListTenantsParams as L, MessageResponse as M, MigrationMetadata as N, ObservabilitySummary as O, PasswordResetResponse as P, QuerySample as Q, RegisterRequest as R, SchemaResponse as S, SqlExecuteRequest as T, SqlQueryRequest as U, SqlQueryResponse as V, SqlResult as W, TableMetadata as X, TenantConnectRequest as Y, TenantConnectResponse as Z, TenantListResponse as _, AnonymousRefreshRequest as a, TenantResponse as a0, TenantState as a1, TenantUpdateRequest as a2, TokenResponse as a3, UserCreateResponse as a4, UserResponse as a5, ViewMetadata as a6, AnonymousRefreshResponse as b, AnonymousRegisterResponse as c, AnonymousSecretResponse as d, AuditLogParams as e, AuditLogResponse as f, BatchCreateResponse as g, BatchDeleteRequest as h, BatchDeleteResponse as i, BatchItemError as j, BatchUpdateRequest as k, BatchUpdateResponse as l, BranchRequest as m, ClaimResponse as n, ColumnInfo as o, ColumnMetadata as p, CreateDatabaseRequest as q, CreateTenantRequest as r, CreateTenantResponse as s, CreateUserRequest as t, CustomerPasswordResetResponse as u, CustomerResponse as v, DumpRequest as w, DumpResponse as x, HttpClient as y, HttpClientOptions as z };
356
+ interface Db9ClientOptions {
357
+ baseUrl?: string;
358
+ token?: string;
359
+ fetch?: FetchFn;
360
+ credentialStore?: CredentialStore;
361
+ }
362
+ declare function createDb9Client(options?: Db9ClientOptions): {
363
+ auth: {
364
+ register: (req: RegisterRequest) => Promise<CustomerResponse>;
365
+ login: (req: LoginRequest) => Promise<LoginResponse>;
366
+ anonymousRegister: () => Promise<AnonymousRegisterResponse>;
367
+ anonymousRefresh: (req: AnonymousRefreshRequest) => Promise<AnonymousRefreshResponse>;
368
+ me: () => Promise<CustomerResponse>;
369
+ getAnonymousSecret: () => Promise<AnonymousSecretResponse>;
370
+ claim: (req: ClaimRequest) => Promise<ClaimResponse>;
371
+ };
372
+ tokens: {
373
+ list: () => Promise<TokenResponse[]>;
374
+ revoke: (tokenId: string) => Promise<MessageResponse>;
375
+ };
376
+ databases: {
377
+ create: (req: CreateDatabaseRequest) => Promise<DatabaseResponse>;
378
+ list: () => Promise<DatabaseResponse[]>;
379
+ get: (databaseId: string) => Promise<DatabaseResponse>;
380
+ delete: (databaseId: string) => Promise<MessageResponse>;
381
+ resetPassword: (databaseId: string) => Promise<CustomerPasswordResetResponse>;
382
+ observability: (databaseId: string) => Promise<TenantObservabilityResponse>;
383
+ sql: (databaseId: string, query: string) => Promise<SqlResult>;
384
+ sqlFile: (databaseId: string, fileContent: string) => Promise<SqlResult>;
385
+ schema: (databaseId: string) => Promise<SchemaResponse>;
386
+ dump: (databaseId: string, req?: DumpRequest) => Promise<DumpResponse>;
387
+ applyMigration: (databaseId: string, req: MigrationApplyRequest) => Promise<MigrationApplyResponse>;
388
+ listMigrations: (databaseId: string) => Promise<MigrationMetadata[]>;
389
+ branch: (databaseId: string, req: BranchRequest) => Promise<DatabaseResponse>;
390
+ users: {
391
+ list: (databaseId: string) => Promise<UserResponse[]>;
392
+ create: (databaseId: string, req: CreateUserRequest) => Promise<MessageResponse>;
393
+ delete: (databaseId: string, username: string) => Promise<MessageResponse>;
394
+ };
395
+ };
396
+ };
397
+ type Db9Client = ReturnType<typeof createDb9Client>;
398
+
399
+ export { type SqlQueryResponse as $, type AdminCreateUserRequest as A, type BatchCreateRequest as B, type CredentialStore as C, type DatabaseResponse as D, type DumpRequest as E, type FetchFn as F, type DumpResponse as G, type Endpoint as H, FileCredentialStore as I, type HealthResponse as J, type HttpClient as K, type HttpClientOptions as L, type ListTenantsParams as M, type LoginRequest as N, type LoginResponse as O, MemoryCredentialStore as P, type MessageResponse as Q, type MigrationApplyRequest as R, type MigrationApplyResponse as S, type MigrationMetadata as T, type ObservabilitySummary as U, type PasswordResetResponse as V, type QuerySample as W, type RegisterRequest as X, type SchemaResponse as Y, type SqlExecuteRequest as Z, type SqlQueryRequest as _, type AnonymousRefreshRequest as a, type SqlResult as a0, type TableMetadata as a1, type TenantConnectRequest as a2, type TenantConnectResponse as a3, type TenantListResponse as a4, type TenantObservabilityResponse as a5, type TenantResponse as a6, type TenantState as a7, type TenantUpdateRequest as a8, type TokenResponse as a9, type UserCreateResponse as aa, type UserResponse as ab, type ViewMetadata as ac, createDb9Client as ad, defaultCredentialStore as ae, type AnonymousRefreshResponse as b, type AnonymousRegisterResponse as c, type AnonymousSecretResponse as d, type AuditLogParams as e, type AuditLogResponse as f, type BatchCreateResponse as g, type BatchDeleteRequest as h, type BatchDeleteResponse as i, type BatchItemError as j, type BatchUpdateRequest as k, type BatchUpdateResponse as l, type BranchRequest as m, type ClaimRequest as n, type ClaimResponse as o, type ColumnInfo as p, type ColumnMetadata as q, type CreateDatabaseRequest as r, type CreateTenantRequest as s, type CreateTenantResponse as t, type CreateUserRequest as u, type Credentials as v, type CustomerPasswordResetResponse as w, type CustomerResponse as x, type Db9Client as y, type Db9ClientOptions as z };
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,14 +17,22 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
- // src/customer.ts
21
- var customer_exports = {};
22
- __export(customer_exports, {
23
- createCustomerClient: () => createCustomerClient
30
+ // src/client.ts
31
+ var client_exports = {};
32
+ __export(client_exports, {
33
+ createDb9Client: () => createDb9Client
24
34
  });
25
- module.exports = __toCommonJS(customer_exports);
35
+ module.exports = __toCommonJS(client_exports);
26
36
 
27
37
  // src/errors.ts
28
38
  var Db9Error = class _Db9Error extends Error {
@@ -114,22 +124,124 @@ function createHttpClient(options) {
114
124
  };
115
125
  }
116
126
 
117
- // src/customer.ts
118
- function createCustomerClient(options = {}) {
127
+ // src/credentials.ts
128
+ var import_toml = require("@iarna/toml");
129
+ var FileCredentialStore = class {
130
+ customPath;
131
+ /**
132
+ * @param path — Override the credential file location.
133
+ * Defaults to `~/.db9/credentials` (resolved lazily).
134
+ */
135
+ constructor(path) {
136
+ this.customPath = path;
137
+ }
138
+ /** Resolve the credential file path (lazy to avoid top-level `os` import). */
139
+ async resolvePath() {
140
+ if (this.customPath) return this.customPath;
141
+ const os = await import("os");
142
+ const nodePath = await import("path");
143
+ return nodePath.join(os.homedir(), ".db9", "credentials");
144
+ }
145
+ async load() {
146
+ const fs = await import("fs/promises");
147
+ const filePath = await this.resolvePath();
148
+ let content;
149
+ try {
150
+ content = await fs.readFile(filePath, "utf-8");
151
+ } catch (err) {
152
+ if (err.code === "ENOENT") return null;
153
+ throw err;
154
+ }
155
+ const parsed = (0, import_toml.parse)(content);
156
+ const token = parsed["token"];
157
+ if (typeof token !== "string") return null;
158
+ const creds = { token };
159
+ if (typeof parsed["is_anonymous"] === "boolean") {
160
+ creds.is_anonymous = parsed["is_anonymous"];
161
+ }
162
+ if (typeof parsed["anonymous_id"] === "string") {
163
+ creds.anonymous_id = parsed["anonymous_id"];
164
+ }
165
+ if (typeof parsed["anonymous_secret"] === "string") {
166
+ creds.anonymous_secret = parsed["anonymous_secret"];
167
+ }
168
+ return creds;
169
+ }
170
+ async save(credentials) {
171
+ const fs = await import("fs/promises");
172
+ const nodePath = await import("path");
173
+ const filePath = await this.resolvePath();
174
+ const dir = nodePath.dirname(filePath);
175
+ await fs.mkdir(dir, { recursive: true, mode: 448 });
176
+ const data = {};
177
+ try {
178
+ const raw = await fs.readFile(filePath, "utf-8");
179
+ const parsed = (0, import_toml.parse)(raw);
180
+ for (const [k, v] of Object.entries(parsed)) {
181
+ if (typeof v === "string" || typeof v === "boolean" || typeof v === "number") {
182
+ data[k] = v;
183
+ }
184
+ }
185
+ } catch (err) {
186
+ if (err.code !== "ENOENT") throw err;
187
+ }
188
+ data["token"] = credentials.token;
189
+ if (credentials.is_anonymous !== void 0) {
190
+ data["is_anonymous"] = credentials.is_anonymous;
191
+ }
192
+ if (credentials.anonymous_id !== void 0) {
193
+ data["anonymous_id"] = credentials.anonymous_id;
194
+ }
195
+ if (credentials.anonymous_secret !== void 0) {
196
+ data["anonymous_secret"] = credentials.anonymous_secret;
197
+ }
198
+ const toml = (0, import_toml.stringify)(
199
+ data
200
+ );
201
+ await fs.writeFile(filePath, toml, { mode: 384 });
202
+ }
203
+ async clear() {
204
+ const fs = await import("fs/promises");
205
+ const filePath = await this.resolvePath();
206
+ try {
207
+ await fs.unlink(filePath);
208
+ } catch (err) {
209
+ if (err.code !== "ENOENT") throw err;
210
+ }
211
+ }
212
+ };
213
+ function defaultCredentialStore() {
214
+ return new FileCredentialStore();
215
+ }
216
+
217
+ // src/client.ts
218
+ function createDb9Client(options = {}) {
119
219
  const baseUrl = options.baseUrl ?? "https://db9.shared.aws.tidbcloud.com/api";
120
220
  let token = options.token;
121
221
  let tokenLoaded = !!token;
222
+ const store = options.credentialStore ?? defaultCredentialStore();
122
223
  const publicClient = createHttpClient({
123
224
  baseUrl,
124
225
  fetch: options.fetch
125
226
  });
126
227
  async function getAuthClient() {
127
- if (!token && !tokenLoaded && options.credentialStore) {
128
- const creds = await options.credentialStore.load();
129
- if (creds) token = creds.token;
228
+ if (!token && !tokenLoaded) {
229
+ const creds = await store.load();
230
+ if (creds?.token) token = creds.token;
130
231
  tokenLoaded = true;
131
232
  }
132
- if (!token) throw new Error("No authentication token available");
233
+ if (!token) {
234
+ const reg = await publicClient.post(
235
+ "/customer/anonymous-register"
236
+ );
237
+ token = reg.token;
238
+ await store.save({
239
+ token: reg.token,
240
+ is_anonymous: reg.is_anonymous,
241
+ anonymous_id: reg.anonymous_id,
242
+ anonymous_secret: reg.anonymous_secret
243
+ });
244
+ }
133
245
  return createHttpClient({
134
246
  baseUrl,
135
247
  fetch: options.fetch,
@@ -286,6 +398,6 @@ function createCustomerClient(options = {}) {
286
398
  }
287
399
  // Annotate the CommonJS export names for ESM import in node:
288
400
  0 && (module.exports = {
289
- createCustomerClient
401
+ createDb9Client
290
402
  });
291
- //# sourceMappingURL=customer.cjs.map
403
+ //# sourceMappingURL=client.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/errors.ts","../src/http.ts","../src/credentials.ts"],"sourcesContent":["import { createHttpClient, type FetchFn, type HttpClient } from './http';\nimport {\n defaultCredentialStore,\n type CredentialStore,\n} from './credentials';\nimport type {\n RegisterRequest,\n CustomerResponse,\n LoginRequest,\n LoginResponse,\n AnonymousRegisterResponse,\n AnonymousRefreshRequest,\n AnonymousRefreshResponse,\n AnonymousSecretResponse,\n ClaimRequest,\n ClaimResponse,\n TokenResponse,\n MessageResponse,\n CreateDatabaseRequest,\n DatabaseResponse,\n CustomerPasswordResetResponse,\n TenantObservabilityResponse,\n SqlResult,\n SchemaResponse,\n DumpRequest,\n DumpResponse,\n MigrationApplyRequest,\n MigrationApplyResponse,\n MigrationMetadata,\n BranchRequest,\n UserResponse,\n CreateUserRequest,\n} from './types';\n\nexport interface Db9ClientOptions {\n baseUrl?: string;\n token?: string;\n fetch?: FetchFn;\n credentialStore?: CredentialStore;\n}\n\nexport function createDb9Client(options: Db9ClientOptions = {}) {\n const baseUrl =\n options.baseUrl ?? 'https://db9.shared.aws.tidbcloud.com/api';\n let token = options.token;\n let tokenLoaded = !!token;\n const store = options.credentialStore ?? defaultCredentialStore();\n\n // Public HTTP client — no Authorization header\n const publicClient = createHttpClient({\n baseUrl,\n fetch: options.fetch,\n });\n\n // Lazy-loading authenticated HTTP client\n async function getAuthClient(): Promise<HttpClient> {\n if (!token && !tokenLoaded) {\n const creds = await store.load();\n if (creds?.token) token = creds.token;\n tokenLoaded = true;\n }\n if (!token) {\n const reg = await publicClient.post<AnonymousRegisterResponse>(\n '/customer/anonymous-register'\n );\n token = reg.token;\n await store.save({\n token: reg.token,\n is_anonymous: reg.is_anonymous,\n anonymous_id: reg.anonymous_id,\n anonymous_secret: reg.anonymous_secret,\n });\n }\n return createHttpClient({\n baseUrl,\n fetch: options.fetch,\n headers: { Authorization: `Bearer ${token}` },\n });\n }\n\n return {\n auth: {\n // Public endpoints (no token required)\n register: (req: RegisterRequest) =>\n publicClient.post<CustomerResponse>('/customer/register', req),\n\n login: (req: LoginRequest) =>\n publicClient.post<LoginResponse>('/customer/login', req),\n\n anonymousRegister: () =>\n publicClient.post<AnonymousRegisterResponse>(\n '/customer/anonymous-register'\n ),\n\n anonymousRefresh: (req: AnonymousRefreshRequest) =>\n publicClient.post<AnonymousRefreshResponse>(\n '/customer/anonymous-refresh',\n req\n ),\n\n // Authenticated endpoints\n me: async () => {\n const client = await getAuthClient();\n return client.get<CustomerResponse>('/customer/me');\n },\n\n getAnonymousSecret: async () => {\n const client = await getAuthClient();\n return client.get<AnonymousSecretResponse>(\n '/customer/anonymous-secret'\n );\n },\n\n claim: async (req: ClaimRequest) => {\n const client = await getAuthClient();\n return client.post<ClaimResponse>('/customer/claim', req);\n },\n },\n\n tokens: {\n list: async () => {\n const client = await getAuthClient();\n return client.get<TokenResponse[]>('/customer/tokens');\n },\n\n revoke: async (tokenId: string) => {\n const client = await getAuthClient();\n return client.del<MessageResponse>(`/customer/tokens/${tokenId}`);\n },\n },\n\n databases: {\n // ── CRUD ──────────────────────────────────────────────────\n create: async (req: CreateDatabaseRequest) => {\n const client = await getAuthClient();\n return client.post<DatabaseResponse>('/customer/databases', req);\n },\n\n list: async () => {\n const client = await getAuthClient();\n return client.get<DatabaseResponse[]>('/customer/databases');\n },\n\n get: async (databaseId: string) => {\n const client = await getAuthClient();\n return client.get<DatabaseResponse>(\n `/customer/databases/${databaseId}`\n );\n },\n\n delete: async (databaseId: string) => {\n const client = await getAuthClient();\n return client.del<MessageResponse>(\n `/customer/databases/${databaseId}`\n );\n },\n\n resetPassword: async (databaseId: string) => {\n const client = await getAuthClient();\n return client.post<CustomerPasswordResetResponse>(\n `/customer/databases/${databaseId}/reset-password`\n );\n },\n\n observability: async (databaseId: string) => {\n const client = await getAuthClient();\n return client.get<TenantObservabilityResponse>(\n `/customer/databases/${databaseId}/observability`\n );\n },\n\n // ── SQL Execution ─────────────────────────────────────────\n sql: async (databaseId: string, query: string) => {\n const client = await getAuthClient();\n return client.post<SqlResult>(\n `/customer/databases/${databaseId}/sql`,\n { query }\n );\n },\n\n sqlFile: async (databaseId: string, fileContent: string) => {\n const client = await getAuthClient();\n return client.post<SqlResult>(\n `/customer/databases/${databaseId}/sql`,\n { file_content: fileContent }\n );\n },\n\n // ── Schema & Dump ─────────────────────────────────────────\n schema: async (databaseId: string) => {\n const client = await getAuthClient();\n return client.get<SchemaResponse>(\n `/customer/databases/${databaseId}/schema`\n );\n },\n\n dump: async (databaseId: string, req?: DumpRequest) => {\n const client = await getAuthClient();\n return client.post<DumpResponse>(\n `/customer/databases/${databaseId}/dump`,\n req\n );\n },\n\n // ── Migrations ────────────────────────────────────────────\n applyMigration: async (\n databaseId: string,\n req: MigrationApplyRequest\n ) => {\n const client = await getAuthClient();\n return client.post<MigrationApplyResponse>(\n `/customer/databases/${databaseId}/migrations`,\n req\n );\n },\n\n listMigrations: async (databaseId: string) => {\n const client = await getAuthClient();\n return client.get<MigrationMetadata[]>(\n `/customer/databases/${databaseId}/migrations`\n );\n },\n\n // ── Branching ─────────────────────────────────────────────\n branch: async (databaseId: string, req: BranchRequest) => {\n const client = await getAuthClient();\n return client.post<DatabaseResponse>(\n `/customer/databases/${databaseId}/branch`,\n req\n );\n },\n\n // ── User Management ───────────────────────────────────────\n users: {\n list: async (databaseId: string) => {\n const client = await getAuthClient();\n return client.get<UserResponse[]>(\n `/customer/databases/${databaseId}/users`\n );\n },\n\n create: async (databaseId: string, req: CreateUserRequest) => {\n const client = await getAuthClient();\n return client.post<MessageResponse>(\n `/customer/databases/${databaseId}/users`,\n req\n );\n },\n\n delete: async (databaseId: string, username: string) => {\n const client = await getAuthClient();\n return client.del<MessageResponse>(\n `/customer/databases/${databaseId}/users/${username}`\n );\n },\n },\n },\n };\n}\n\nexport type Db9Client = ReturnType<typeof createDb9Client>;\n","export class Db9Error extends Error {\n readonly statusCode: number;\n readonly response?: Response;\n\n constructor(message: string, statusCode: number, response?: Response) {\n super(message);\n this.name = 'Db9Error';\n this.statusCode = statusCode;\n this.response = response;\n }\n\n static async fromResponse(response: Response): Promise<Db9Error> {\n // Parse { \"message\": string } body — the ONLY error format from the API\n let message: string;\n try {\n const body = (await response.json()) as { message?: string };\n message = body.message || response.statusText;\n } catch {\n message = response.statusText;\n }\n\n // Return specific subclass based on status code\n switch (response.status) {\n case 401:\n return new Db9AuthError(message, response);\n case 404:\n return new Db9NotFoundError(message, response);\n case 409:\n return new Db9ConflictError(message, response);\n default:\n return new Db9Error(message, response.status, response);\n }\n }\n}\n\nexport class Db9AuthError extends Db9Error {\n constructor(message: string, response?: Response) {\n super(message, 401, response);\n this.name = 'Db9AuthError';\n }\n}\n\nexport class Db9NotFoundError extends Db9Error {\n constructor(message: string, response?: Response) {\n super(message, 404, response);\n this.name = 'Db9NotFoundError';\n }\n}\n\nexport class Db9ConflictError extends Db9Error {\n constructor(message: string, response?: Response) {\n super(message, 409, response);\n this.name = 'Db9ConflictError';\n }\n}\n","import { Db9Error } from './errors';\n\nexport type FetchFn = typeof globalThis.fetch;\n\nexport interface HttpClientOptions {\n baseUrl: string;\n fetch?: FetchFn;\n headers?: Record<string, string>;\n}\n\nexport interface HttpClient {\n get<T>(path: string, params?: Record<string, string | undefined>): Promise<T>;\n post<T>(path: string, body?: unknown): Promise<T>;\n put<T>(path: string, body?: unknown): Promise<T>;\n del<T>(path: string): Promise<T>;\n}\n\nexport function createHttpClient(options: HttpClientOptions): HttpClient {\n const fetchFn = options.fetch ?? globalThis.fetch;\n const baseUrl = options.baseUrl.replace(/\\/$/, ''); // strip trailing slash\n\n async function request<T>(\n method: string,\n path: string,\n body?: unknown,\n params?: Record<string, string | undefined>\n ): Promise<T> {\n let url = `${baseUrl}${path}`;\n\n // Append query params for GET requests\n if (params) {\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n searchParams.set(key, value);\n }\n }\n const qs = searchParams.toString();\n if (qs) url += `?${qs}`;\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n\n const init: RequestInit = { method, headers };\n if (body !== undefined) {\n init.body = JSON.stringify(body);\n }\n\n const response = await fetchFn(url, init);\n\n if (!response.ok) {\n throw await Db9Error.fromResponse(response);\n }\n\n // Handle 204 No Content\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n }\n\n return {\n get: <T>(path: string, params?: Record<string, string | undefined>) =>\n request<T>('GET', path, undefined, params),\n post: <T>(path: string, body?: unknown) => request<T>('POST', path, body),\n put: <T>(path: string, body?: unknown) => request<T>('PUT', path, body),\n del: <T>(path: string) => request<T>('DELETE', path),\n };\n}\n","import { parse as parseToml, stringify as stringifyToml } from '@iarna/toml';\n\n// ---------------------------------------------------------------------------\n// Interfaces\n// ---------------------------------------------------------------------------\n\n/** Credential fields stored in `~/.db9/credentials` (TOML). */\nexport interface Credentials {\n token: string;\n is_anonymous?: boolean;\n anonymous_id?: string;\n anonymous_secret?: string;\n}\n\n/** Async credential persistence abstraction. */\nexport interface CredentialStore {\n load(): Promise<Credentials | null>;\n save(credentials: Credentials): Promise<void>;\n clear(): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// FileCredentialStore — TOML file at ~/.db9/credentials (matches db9 CLI)\n// ---------------------------------------------------------------------------\n\nexport class FileCredentialStore implements CredentialStore {\n private readonly customPath: string | undefined;\n\n /**\n * @param path — Override the credential file location.\n * Defaults to `~/.db9/credentials` (resolved lazily).\n */\n constructor(path?: string) {\n this.customPath = path;\n }\n\n /** Resolve the credential file path (lazy to avoid top-level `os` import). */\n private async resolvePath(): Promise<string> {\n if (this.customPath) return this.customPath;\n const os = await import('node:os');\n const nodePath = await import('node:path');\n return nodePath.join(os.homedir(), '.db9', 'credentials');\n }\n\n async load(): Promise<Credentials | null> {\n const fs = await import('node:fs/promises');\n const filePath = await this.resolvePath();\n\n let content: string;\n try {\n content = await fs.readFile(filePath, 'utf-8');\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n throw err;\n }\n\n const parsed = parseToml(content);\n const token = parsed['token'];\n if (typeof token !== 'string') return null;\n\n const creds: Credentials = { token };\n if (typeof parsed['is_anonymous'] === 'boolean') {\n creds.is_anonymous = parsed['is_anonymous'];\n }\n if (typeof parsed['anonymous_id'] === 'string') {\n creds.anonymous_id = parsed['anonymous_id'];\n }\n if (typeof parsed['anonymous_secret'] === 'string') {\n creds.anonymous_secret = parsed['anonymous_secret'];\n }\n\n return creds;\n }\n\n async save(credentials: Credentials): Promise<void> {\n const fs = await import('node:fs/promises');\n const nodePath = await import('node:path');\n const filePath = await this.resolvePath();\n const dir = nodePath.dirname(filePath);\n\n // Ensure directory exists with 0o700 (matches CLI: ensure_config_dir)\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n\n // Read → merge → write (preserves unknown fields as scalars)\n const data: Record<string, string | boolean | number> = {};\n try {\n const raw = await fs.readFile(filePath, 'utf-8');\n const parsed = parseToml(raw);\n for (const [k, v] of Object.entries(parsed)) {\n if (typeof v === 'string' || typeof v === 'boolean' || typeof v === 'number') {\n data[k] = v;\n }\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n\n // Merge: always update token, only override optional fields when provided\n data['token'] = credentials.token;\n if (credentials.is_anonymous !== undefined) {\n data['is_anonymous'] = credentials.is_anonymous;\n }\n if (credentials.anonymous_id !== undefined) {\n data['anonymous_id'] = credentials.anonymous_id;\n }\n if (credentials.anonymous_secret !== undefined) {\n data['anonymous_secret'] = credentials.anonymous_secret;\n }\n\n // Serialize and write with 0o600 permissions (matches CLI: save_token)\n const toml = stringifyToml(\n data as Parameters<typeof stringifyToml>[0],\n );\n await fs.writeFile(filePath, toml, { mode: 0o600 });\n }\n\n async clear(): Promise<void> {\n const fs = await import('node:fs/promises');\n const filePath = await this.resolvePath();\n\n try {\n await fs.unlink(filePath);\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// MemoryCredentialStore — in-memory, no persistence\n// ---------------------------------------------------------------------------\n\nexport class MemoryCredentialStore implements CredentialStore {\n private credentials: Credentials | null = null;\n\n async load(): Promise<Credentials | null> {\n return this.credentials ? { ...this.credentials } : null;\n }\n\n async save(credentials: Credentials): Promise<void> {\n this.credentials = {\n token: credentials.token,\n is_anonymous: credentials.is_anonymous ?? this.credentials?.is_anonymous,\n anonymous_id: credentials.anonymous_id ?? this.credentials?.anonymous_id,\n anonymous_secret: credentials.anonymous_secret ?? this.credentials?.anonymous_secret,\n };\n }\n\n async clear(): Promise<void> {\n this.credentials = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/** Returns a FileCredentialStore with the default path (`~/.db9/credentials`). */\nexport function defaultCredentialStore(): CredentialStore {\n return new FileCredentialStore();\n}\n"],"mappings":"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","names":["parseToml","stringifyToml"]}
@@ -0,0 +1 @@
1
+ export { y as Db9Client, z as Db9ClientOptions, ad as createDb9Client } from './client-CSOh3r_q.cjs';
@@ -0,0 +1 @@
1
+ export { y as Db9Client, z as Db9ClientOptions, ad as createDb9Client } from './client-CSOh3r_q.js';
@@ -88,22 +88,124 @@ function createHttpClient(options) {
88
88
  };
89
89
  }
90
90
 
91
- // src/customer.ts
92
- function createCustomerClient(options = {}) {
91
+ // src/credentials.ts
92
+ import { parse as parseToml, stringify as stringifyToml } from "@iarna/toml";
93
+ var FileCredentialStore = class {
94
+ customPath;
95
+ /**
96
+ * @param path — Override the credential file location.
97
+ * Defaults to `~/.db9/credentials` (resolved lazily).
98
+ */
99
+ constructor(path) {
100
+ this.customPath = path;
101
+ }
102
+ /** Resolve the credential file path (lazy to avoid top-level `os` import). */
103
+ async resolvePath() {
104
+ if (this.customPath) return this.customPath;
105
+ const os = await import("os");
106
+ const nodePath = await import("path");
107
+ return nodePath.join(os.homedir(), ".db9", "credentials");
108
+ }
109
+ async load() {
110
+ const fs = await import("fs/promises");
111
+ const filePath = await this.resolvePath();
112
+ let content;
113
+ try {
114
+ content = await fs.readFile(filePath, "utf-8");
115
+ } catch (err) {
116
+ if (err.code === "ENOENT") return null;
117
+ throw err;
118
+ }
119
+ const parsed = parseToml(content);
120
+ const token = parsed["token"];
121
+ if (typeof token !== "string") return null;
122
+ const creds = { token };
123
+ if (typeof parsed["is_anonymous"] === "boolean") {
124
+ creds.is_anonymous = parsed["is_anonymous"];
125
+ }
126
+ if (typeof parsed["anonymous_id"] === "string") {
127
+ creds.anonymous_id = parsed["anonymous_id"];
128
+ }
129
+ if (typeof parsed["anonymous_secret"] === "string") {
130
+ creds.anonymous_secret = parsed["anonymous_secret"];
131
+ }
132
+ return creds;
133
+ }
134
+ async save(credentials) {
135
+ const fs = await import("fs/promises");
136
+ const nodePath = await import("path");
137
+ const filePath = await this.resolvePath();
138
+ const dir = nodePath.dirname(filePath);
139
+ await fs.mkdir(dir, { recursive: true, mode: 448 });
140
+ const data = {};
141
+ try {
142
+ const raw = await fs.readFile(filePath, "utf-8");
143
+ const parsed = parseToml(raw);
144
+ for (const [k, v] of Object.entries(parsed)) {
145
+ if (typeof v === "string" || typeof v === "boolean" || typeof v === "number") {
146
+ data[k] = v;
147
+ }
148
+ }
149
+ } catch (err) {
150
+ if (err.code !== "ENOENT") throw err;
151
+ }
152
+ data["token"] = credentials.token;
153
+ if (credentials.is_anonymous !== void 0) {
154
+ data["is_anonymous"] = credentials.is_anonymous;
155
+ }
156
+ if (credentials.anonymous_id !== void 0) {
157
+ data["anonymous_id"] = credentials.anonymous_id;
158
+ }
159
+ if (credentials.anonymous_secret !== void 0) {
160
+ data["anonymous_secret"] = credentials.anonymous_secret;
161
+ }
162
+ const toml = stringifyToml(
163
+ data
164
+ );
165
+ await fs.writeFile(filePath, toml, { mode: 384 });
166
+ }
167
+ async clear() {
168
+ const fs = await import("fs/promises");
169
+ const filePath = await this.resolvePath();
170
+ try {
171
+ await fs.unlink(filePath);
172
+ } catch (err) {
173
+ if (err.code !== "ENOENT") throw err;
174
+ }
175
+ }
176
+ };
177
+ function defaultCredentialStore() {
178
+ return new FileCredentialStore();
179
+ }
180
+
181
+ // src/client.ts
182
+ function createDb9Client(options = {}) {
93
183
  const baseUrl = options.baseUrl ?? "https://db9.shared.aws.tidbcloud.com/api";
94
184
  let token = options.token;
95
185
  let tokenLoaded = !!token;
186
+ const store = options.credentialStore ?? defaultCredentialStore();
96
187
  const publicClient = createHttpClient({
97
188
  baseUrl,
98
189
  fetch: options.fetch
99
190
  });
100
191
  async function getAuthClient() {
101
- if (!token && !tokenLoaded && options.credentialStore) {
102
- const creds = await options.credentialStore.load();
103
- if (creds) token = creds.token;
192
+ if (!token && !tokenLoaded) {
193
+ const creds = await store.load();
194
+ if (creds?.token) token = creds.token;
104
195
  tokenLoaded = true;
105
196
  }
106
- if (!token) throw new Error("No authentication token available");
197
+ if (!token) {
198
+ const reg = await publicClient.post(
199
+ "/customer/anonymous-register"
200
+ );
201
+ token = reg.token;
202
+ await store.save({
203
+ token: reg.token,
204
+ is_anonymous: reg.is_anonymous,
205
+ anonymous_id: reg.anonymous_id,
206
+ anonymous_secret: reg.anonymous_secret
207
+ });
208
+ }
107
209
  return createHttpClient({
108
210
  baseUrl,
109
211
  fetch: options.fetch,
@@ -259,6 +361,6 @@ function createCustomerClient(options = {}) {
259
361
  };
260
362
  }
261
363
  export {
262
- createCustomerClient
364
+ createDb9Client
263
365
  };
264
- //# sourceMappingURL=customer.js.map
366
+ //# sourceMappingURL=client.js.map