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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/credentials.ts","../src/client.ts"],"sourcesContent":["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","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"],"mappings":";AAAO,IAAM,WAAN,MAAM,kBAAiB,MAAM;AAAA,EACzB;AAAA,EACA;AAAA,EAET,YAAY,SAAiB,YAAoB,UAAqB;AACpE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,aAAa;AAClB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,aAAa,aAAa,UAAuC;AAE/D,QAAI;AACJ,QAAI;AACF,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,gBAAU,KAAK,WAAW,SAAS;AAAA,IACrC,QAAQ;AACN,gBAAU,SAAS;AAAA,IACrB;AAGA,YAAQ,SAAS,QAAQ;AAAA,MACvB,KAAK;AACH,eAAO,IAAI,aAAa,SAAS,QAAQ;AAAA,MAC3C,KAAK;AACH,eAAO,IAAI,iBAAiB,SAAS,QAAQ;AAAA,MAC/C,KAAK;AACH,eAAO,IAAI,iBAAiB,SAAS,QAAQ;AAAA,MAC/C;AACE,eAAO,IAAI,UAAS,SAAS,SAAS,QAAQ,QAAQ;AAAA,IAC1D;AAAA,EACF;AACF;AAEO,IAAM,eAAN,cAA2B,SAAS;AAAA,EACzC,YAAY,SAAiB,UAAqB;AAChD,UAAM,SAAS,KAAK,QAAQ;AAC5B,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,mBAAN,cAA+B,SAAS;AAAA,EAC7C,YAAY,SAAiB,UAAqB;AAChD,UAAM,SAAS,KAAK,QAAQ;AAC5B,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,mBAAN,cAA+B,SAAS;AAAA,EAC7C,YAAY,SAAiB,UAAqB;AAChD,UAAM,SAAS,KAAK,QAAQ;AAC5B,SAAK,OAAO;AAAA,EACd;AACF;;;ACrCO,SAAS,iBAAiB,SAAwC;AACvE,QAAM,UAAU,QAAQ,SAAS,WAAW;AAC5C,QAAM,UAAU,QAAQ,QAAQ,QAAQ,OAAO,EAAE;AAEjD,iBAAe,QACb,QACA,MACA,MACA,QACY;AACZ,QAAI,MAAM,GAAG,OAAO,GAAG,IAAI;AAG3B,QAAI,QAAQ;AACV,YAAM,eAAe,IAAI,gBAAgB;AACzC,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAI,UAAU,QAAW;AACvB,uBAAa,IAAI,KAAK,KAAK;AAAA,QAC7B;AAAA,MACF;AACA,YAAM,KAAK,aAAa,SAAS;AACjC,UAAI,GAAI,QAAO,IAAI,EAAE;AAAA,IACvB;AAEA,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,GAAG,QAAQ;AAAA,IACb;AAEA,UAAM,OAAoB,EAAE,QAAQ,QAAQ;AAC5C,QAAI,SAAS,QAAW;AACtB,WAAK,OAAO,KAAK,UAAU,IAAI;AAAA,IACjC;AAEA,UAAM,WAAW,MAAM,QAAQ,KAAK,IAAI;AAExC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,MAAM,SAAS,aAAa,QAAQ;AAAA,IAC5C;AAGA,QAAI,SAAS,WAAW,KAAK;AAC3B,aAAO;AAAA,IACT;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAEA,SAAO;AAAA,IACL,KAAK,CAAI,MAAc,WACrB,QAAW,OAAO,MAAM,QAAW,MAAM;AAAA,IAC3C,MAAM,CAAI,MAAc,SAAmB,QAAW,QAAQ,MAAM,IAAI;AAAA,IACxE,KAAK,CAAI,MAAc,SAAmB,QAAW,OAAO,MAAM,IAAI;AAAA,IACtE,KAAK,CAAI,SAAiB,QAAW,UAAU,IAAI;AAAA,EACrD;AACF;;;ACxEA,SAAS,SAAS,WAAW,aAAa,qBAAqB;AAyBxD,IAAM,sBAAN,MAAqD;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,YAAY,MAAe;AACzB,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGA,MAAc,cAA+B;AAC3C,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,UAAM,KAAK,MAAM,OAAO,IAAS;AACjC,UAAM,WAAW,MAAM,OAAO,MAAW;AACzC,WAAO,SAAS,KAAK,GAAG,QAAQ,GAAG,QAAQ,aAAa;AAAA,EAC1D;AAAA,EAEA,MAAM,OAAoC;AACxC,UAAM,KAAK,MAAM,OAAO,aAAkB;AAC1C,UAAM,WAAW,MAAM,KAAK,YAAY;AAExC,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,GAAG,SAAS,UAAU,OAAO;AAAA,IAC/C,SAAS,KAAc;AACrB,UAAK,IAA8B,SAAS,SAAU,QAAO;AAC7D,YAAM;AAAA,IACR;AAEA,UAAM,SAAS,UAAU,OAAO;AAChC,UAAM,QAAQ,OAAO,OAAO;AAC5B,QAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,UAAM,QAAqB,EAAE,MAAM;AACnC,QAAI,OAAO,OAAO,cAAc,MAAM,WAAW;AAC/C,YAAM,eAAe,OAAO,cAAc;AAAA,IAC5C;AACA,QAAI,OAAO,OAAO,cAAc,MAAM,UAAU;AAC9C,YAAM,eAAe,OAAO,cAAc;AAAA,IAC5C;AACA,QAAI,OAAO,OAAO,kBAAkB,MAAM,UAAU;AAClD,YAAM,mBAAmB,OAAO,kBAAkB;AAAA,IACpD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAK,aAAyC;AAClD,UAAM,KAAK,MAAM,OAAO,aAAkB;AAC1C,UAAM,WAAW,MAAM,OAAO,MAAW;AACzC,UAAM,WAAW,MAAM,KAAK,YAAY;AACxC,UAAM,MAAM,SAAS,QAAQ,QAAQ;AAGrC,UAAM,GAAG,MAAM,KAAK,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAGpD,UAAM,OAAkD,CAAC;AACzD,QAAI;AACF,YAAM,MAAM,MAAM,GAAG,SAAS,UAAU,OAAO;AAC/C,YAAM,SAAS,UAAU,GAAG;AAC5B,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,YAAI,OAAO,MAAM,YAAY,OAAO,MAAM,aAAa,OAAO,MAAM,UAAU;AAC5E,eAAK,CAAC,IAAI;AAAA,QACZ;AAAA,MACF;AAAA,IACF,SAAS,KAAc;AACrB,UAAK,IAA8B,SAAS,SAAU,OAAM;AAAA,IAC9D;AAGA,SAAK,OAAO,IAAI,YAAY;AAC5B,QAAI,YAAY,iBAAiB,QAAW;AAC1C,WAAK,cAAc,IAAI,YAAY;AAAA,IACrC;AACA,QAAI,YAAY,iBAAiB,QAAW;AAC1C,WAAK,cAAc,IAAI,YAAY;AAAA,IACrC;AACA,QAAI,YAAY,qBAAqB,QAAW;AAC9C,WAAK,kBAAkB,IAAI,YAAY;AAAA,IACzC;AAGA,UAAM,OAAO;AAAA,MACX;AAAA,IACF;AACA,UAAM,GAAG,UAAU,UAAU,MAAM,EAAE,MAAM,IAAM,CAAC;AAAA,EACpD;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,KAAK,MAAM,OAAO,aAAkB;AAC1C,UAAM,WAAW,MAAM,KAAK,YAAY;AAExC,QAAI;AACF,YAAM,GAAG,OAAO,QAAQ;AAAA,IAC1B,SAAS,KAAc;AACrB,UAAK,IAA8B,SAAS,SAAU,OAAM;AAAA,IAC9D;AAAA,EACF;AACF;AAgCO,SAAS,yBAA0C;AACxD,SAAO,IAAI,oBAAoB;AACjC;;;ACvHO,SAAS,gBAAgB,UAA4B,CAAC,GAAG;AAC9D,QAAM,UACJ,QAAQ,WAAW;AACrB,MAAI,QAAQ,QAAQ;AACpB,MAAI,cAAc,CAAC,CAAC;AACpB,QAAM,QAAQ,QAAQ,mBAAmB,uBAAuB;AAGhE,QAAM,eAAe,iBAAiB;AAAA,IACpC;AAAA,IACA,OAAO,QAAQ;AAAA,EACjB,CAAC;AAGD,iBAAe,gBAAqC;AAClD,QAAI,CAAC,SAAS,CAAC,aAAa;AAC1B,YAAM,QAAQ,MAAM,MAAM,KAAK;AAC/B,UAAI,OAAO,MAAO,SAAQ,MAAM;AAChC,oBAAc;AAAA,IAChB;AACA,QAAI,CAAC,OAAO;AACV,YAAM,MAAM,MAAM,aAAa;AAAA,QAC7B;AAAA,MACF;AACA,cAAQ,IAAI;AACZ,YAAM,MAAM,KAAK;AAAA,QACf,OAAO,IAAI;AAAA,QACX,cAAc,IAAI;AAAA,QAClB,cAAc,IAAI;AAAA,QAClB,kBAAkB,IAAI;AAAA,MACxB,CAAC;AAAA,IACH;AACA,WAAO,iBAAiB;AAAA,MACtB;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,SAAS,EAAE,eAAe,UAAU,KAAK,GAAG;AAAA,IAC9C,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM;AAAA;AAAA,MAEJ,UAAU,CAAC,QACT,aAAa,KAAuB,sBAAsB,GAAG;AAAA,MAE/D,OAAO,CAAC,QACN,aAAa,KAAoB,mBAAmB,GAAG;AAAA,MAEzD,mBAAmB,MACjB,aAAa;AAAA,QACX;AAAA,MACF;AAAA,MAEF,kBAAkB,CAAC,QACjB,aAAa;AAAA,QACX;AAAA,QACA;AAAA,MACF;AAAA;AAAA,MAGF,IAAI,YAAY;AACd,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO,IAAsB,cAAc;AAAA,MACpD;AAAA,MAEA,oBAAoB,YAAY;AAC9B,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,MAEA,OAAO,OAAO,QAAsB;AAClC,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO,KAAoB,mBAAmB,GAAG;AAAA,MAC1D;AAAA,IACF;AAAA,IAEA,QAAQ;AAAA,MACN,MAAM,YAAY;AAChB,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO,IAAqB,kBAAkB;AAAA,MACvD;AAAA,MAEA,QAAQ,OAAO,YAAoB;AACjC,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO,IAAqB,oBAAoB,OAAO,EAAE;AAAA,MAClE;AAAA,IACF;AAAA,IAEA,WAAW;AAAA;AAAA,MAET,QAAQ,OAAO,QAA+B;AAC5C,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO,KAAuB,uBAAuB,GAAG;AAAA,MACjE;AAAA,MAEA,MAAM,YAAY;AAChB,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO,IAAwB,qBAAqB;AAAA,MAC7D;AAAA,MAEA,KAAK,OAAO,eAAuB;AACjC,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,QACnC;AAAA,MACF;AAAA,MAEA,QAAQ,OAAO,eAAuB;AACpC,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,QACnC;AAAA,MACF;AAAA,MAEA,eAAe,OAAO,eAAuB;AAC3C,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,QACnC;AAAA,MACF;AAAA,MAEA,eAAe,OAAO,eAAuB;AAC3C,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,QACnC;AAAA,MACF;AAAA;AAAA,MAGA,KAAK,OAAO,YAAoB,UAAkB;AAChD,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,UACjC,EAAE,MAAM;AAAA,QACV;AAAA,MACF;AAAA,MAEA,SAAS,OAAO,YAAoB,gBAAwB;AAC1D,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,UACjC,EAAE,cAAc,YAAY;AAAA,QAC9B;AAAA,MACF;AAAA;AAAA,MAGA,QAAQ,OAAO,eAAuB;AACpC,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,QACnC;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,YAAoB,QAAsB;AACrD,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,UACjC;AAAA,QACF;AAAA,MACF;AAAA;AAAA,MAGA,gBAAgB,OACd,YACA,QACG;AACH,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,UACjC;AAAA,QACF;AAAA,MACF;AAAA,MAEA,gBAAgB,OAAO,eAAuB;AAC5C,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,QACnC;AAAA,MACF;AAAA;AAAA,MAGA,QAAQ,OAAO,YAAoB,QAAuB;AACxD,cAAM,SAAS,MAAM,cAAc;AACnC,eAAO,OAAO;AAAA,UACZ,uBAAuB,UAAU;AAAA,UACjC;AAAA,QACF;AAAA,MACF;AAAA;AAAA,MAGA,OAAO;AAAA,QACL,MAAM,OAAO,eAAuB;AAClC,gBAAM,SAAS,MAAM,cAAc;AACnC,iBAAO,OAAO;AAAA,YACZ,uBAAuB,UAAU;AAAA,UACnC;AAAA,QACF;AAAA,QAEA,QAAQ,OAAO,YAAoB,QAA2B;AAC5D,gBAAM,SAAS,MAAM,cAAc;AACnC,iBAAO,OAAO;AAAA,YACZ,uBAAuB,UAAU;AAAA,YACjC;AAAA,UACF;AAAA,QACF;AAAA,QAEA,QAAQ,OAAO,YAAoB,aAAqB;AACtD,gBAAM,SAAS,MAAM,cAAc;AACnC,iBAAO,OAAO;AAAA,YACZ,uBAAuB,UAAU,UAAU,QAAQ;AAAA,UACrD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/dist/index.cjs CHANGED
@@ -36,8 +36,7 @@ __export(index_exports, {
36
36
  Db9NotFoundError: () => Db9NotFoundError,
37
37
  FileCredentialStore: () => FileCredentialStore,
38
38
  MemoryCredentialStore: () => MemoryCredentialStore,
39
- createAdminClient: () => createAdminClient,
40
- createCustomerClient: () => createCustomerClient,
39
+ createDb9Client: () => createDb9Client,
41
40
  defaultCredentialStore: () => defaultCredentialStore,
42
41
  instantDatabase: () => instantDatabase
43
42
  });
@@ -133,22 +132,141 @@ function createHttpClient(options) {
133
132
  };
134
133
  }
135
134
 
136
- // src/customer.ts
137
- function createCustomerClient(options = {}) {
135
+ // src/credentials.ts
136
+ var import_toml = require("@iarna/toml");
137
+ var FileCredentialStore = class {
138
+ customPath;
139
+ /**
140
+ * @param path — Override the credential file location.
141
+ * Defaults to `~/.db9/credentials` (resolved lazily).
142
+ */
143
+ constructor(path) {
144
+ this.customPath = path;
145
+ }
146
+ /** Resolve the credential file path (lazy to avoid top-level `os` import). */
147
+ async resolvePath() {
148
+ if (this.customPath) return this.customPath;
149
+ const os = await import("os");
150
+ const nodePath = await import("path");
151
+ return nodePath.join(os.homedir(), ".db9", "credentials");
152
+ }
153
+ async load() {
154
+ const fs = await import("fs/promises");
155
+ const filePath = await this.resolvePath();
156
+ let content;
157
+ try {
158
+ content = await fs.readFile(filePath, "utf-8");
159
+ } catch (err) {
160
+ if (err.code === "ENOENT") return null;
161
+ throw err;
162
+ }
163
+ const parsed = (0, import_toml.parse)(content);
164
+ const token = parsed["token"];
165
+ if (typeof token !== "string") return null;
166
+ const creds = { token };
167
+ if (typeof parsed["is_anonymous"] === "boolean") {
168
+ creds.is_anonymous = parsed["is_anonymous"];
169
+ }
170
+ if (typeof parsed["anonymous_id"] === "string") {
171
+ creds.anonymous_id = parsed["anonymous_id"];
172
+ }
173
+ if (typeof parsed["anonymous_secret"] === "string") {
174
+ creds.anonymous_secret = parsed["anonymous_secret"];
175
+ }
176
+ return creds;
177
+ }
178
+ async save(credentials) {
179
+ const fs = await import("fs/promises");
180
+ const nodePath = await import("path");
181
+ const filePath = await this.resolvePath();
182
+ const dir = nodePath.dirname(filePath);
183
+ await fs.mkdir(dir, { recursive: true, mode: 448 });
184
+ const data = {};
185
+ try {
186
+ const raw = await fs.readFile(filePath, "utf-8");
187
+ const parsed = (0, import_toml.parse)(raw);
188
+ for (const [k, v] of Object.entries(parsed)) {
189
+ if (typeof v === "string" || typeof v === "boolean" || typeof v === "number") {
190
+ data[k] = v;
191
+ }
192
+ }
193
+ } catch (err) {
194
+ if (err.code !== "ENOENT") throw err;
195
+ }
196
+ data["token"] = credentials.token;
197
+ if (credentials.is_anonymous !== void 0) {
198
+ data["is_anonymous"] = credentials.is_anonymous;
199
+ }
200
+ if (credentials.anonymous_id !== void 0) {
201
+ data["anonymous_id"] = credentials.anonymous_id;
202
+ }
203
+ if (credentials.anonymous_secret !== void 0) {
204
+ data["anonymous_secret"] = credentials.anonymous_secret;
205
+ }
206
+ const toml = (0, import_toml.stringify)(
207
+ data
208
+ );
209
+ await fs.writeFile(filePath, toml, { mode: 384 });
210
+ }
211
+ async clear() {
212
+ const fs = await import("fs/promises");
213
+ const filePath = await this.resolvePath();
214
+ try {
215
+ await fs.unlink(filePath);
216
+ } catch (err) {
217
+ if (err.code !== "ENOENT") throw err;
218
+ }
219
+ }
220
+ };
221
+ var MemoryCredentialStore = class {
222
+ credentials = null;
223
+ async load() {
224
+ return this.credentials ? { ...this.credentials } : null;
225
+ }
226
+ async save(credentials) {
227
+ this.credentials = {
228
+ token: credentials.token,
229
+ is_anonymous: credentials.is_anonymous ?? this.credentials?.is_anonymous,
230
+ anonymous_id: credentials.anonymous_id ?? this.credentials?.anonymous_id,
231
+ anonymous_secret: credentials.anonymous_secret ?? this.credentials?.anonymous_secret
232
+ };
233
+ }
234
+ async clear() {
235
+ this.credentials = null;
236
+ }
237
+ };
238
+ function defaultCredentialStore() {
239
+ return new FileCredentialStore();
240
+ }
241
+
242
+ // src/client.ts
243
+ function createDb9Client(options = {}) {
138
244
  const baseUrl = options.baseUrl ?? "https://db9.shared.aws.tidbcloud.com/api";
139
245
  let token = options.token;
140
246
  let tokenLoaded = !!token;
247
+ const store = options.credentialStore ?? defaultCredentialStore();
141
248
  const publicClient = createHttpClient({
142
249
  baseUrl,
143
250
  fetch: options.fetch
144
251
  });
145
252
  async function getAuthClient() {
146
- if (!token && !tokenLoaded && options.credentialStore) {
147
- const creds = await options.credentialStore.load();
148
- if (creds) token = creds.token;
253
+ if (!token && !tokenLoaded) {
254
+ const creds = await store.load();
255
+ if (creds?.token) token = creds.token;
149
256
  tokenLoaded = true;
150
257
  }
151
- if (!token) throw new Error("No authentication token available");
258
+ if (!token) {
259
+ const reg = await publicClient.post(
260
+ "/customer/anonymous-register"
261
+ );
262
+ token = reg.token;
263
+ await store.save({
264
+ token: reg.token,
265
+ is_anonymous: reg.is_anonymous,
266
+ anonymous_id: reg.anonymous_id,
267
+ anonymous_secret: reg.anonymous_secret
268
+ });
269
+ }
152
270
  return createHttpClient({
153
271
  baseUrl,
154
272
  fetch: options.fetch,
@@ -304,286 +422,13 @@ function createCustomerClient(options = {}) {
304
422
  };
305
423
  }
306
424
 
307
- // src/credentials.ts
308
- var import_toml = require("@iarna/toml");
309
- var FileCredentialStore = class {
310
- customPath;
311
- /**
312
- * @param path — Override the credential file location.
313
- * Defaults to `~/.db9/credentials` (resolved lazily).
314
- */
315
- constructor(path) {
316
- this.customPath = path;
317
- }
318
- /** Resolve the credential file path (lazy to avoid top-level `os` import). */
319
- async resolvePath() {
320
- if (this.customPath) return this.customPath;
321
- const os = await import("os");
322
- const nodePath = await import("path");
323
- return nodePath.join(os.homedir(), ".db9", "credentials");
324
- }
325
- async load() {
326
- const fs = await import("fs/promises");
327
- const filePath = await this.resolvePath();
328
- let content;
329
- try {
330
- content = await fs.readFile(filePath, "utf-8");
331
- } catch (err) {
332
- if (err.code === "ENOENT") return null;
333
- throw err;
334
- }
335
- const parsed = (0, import_toml.parse)(content);
336
- const token = parsed["token"];
337
- if (typeof token !== "string") return null;
338
- const creds = { token };
339
- if (typeof parsed["is_anonymous"] === "boolean") {
340
- creds.is_anonymous = parsed["is_anonymous"];
341
- }
342
- if (typeof parsed["anonymous_id"] === "string") {
343
- creds.anonymous_id = parsed["anonymous_id"];
344
- }
345
- if (typeof parsed["anonymous_secret"] === "string") {
346
- creds.anonymous_secret = parsed["anonymous_secret"];
347
- }
348
- return creds;
349
- }
350
- async save(credentials) {
351
- const fs = await import("fs/promises");
352
- const nodePath = await import("path");
353
- const filePath = await this.resolvePath();
354
- const dir = nodePath.dirname(filePath);
355
- await fs.mkdir(dir, { recursive: true, mode: 448 });
356
- const data = {};
357
- try {
358
- const raw = await fs.readFile(filePath, "utf-8");
359
- const parsed = (0, import_toml.parse)(raw);
360
- for (const [k, v] of Object.entries(parsed)) {
361
- if (typeof v === "string" || typeof v === "boolean" || typeof v === "number") {
362
- data[k] = v;
363
- }
364
- }
365
- } catch (err) {
366
- if (err.code !== "ENOENT") throw err;
367
- }
368
- data["token"] = credentials.token;
369
- if (credentials.is_anonymous !== void 0) {
370
- data["is_anonymous"] = credentials.is_anonymous;
371
- }
372
- if (credentials.anonymous_id !== void 0) {
373
- data["anonymous_id"] = credentials.anonymous_id;
374
- }
375
- if (credentials.anonymous_secret !== void 0) {
376
- data["anonymous_secret"] = credentials.anonymous_secret;
377
- }
378
- const toml = (0, import_toml.stringify)(
379
- data
380
- );
381
- await fs.writeFile(filePath, toml, { mode: 384 });
382
- }
383
- async clear() {
384
- const fs = await import("fs/promises");
385
- const filePath = await this.resolvePath();
386
- try {
387
- await fs.unlink(filePath);
388
- } catch (err) {
389
- if (err.code !== "ENOENT") throw err;
390
- }
391
- }
392
- };
393
- var MemoryCredentialStore = class {
394
- credentials = null;
395
- async load() {
396
- return this.credentials ? { ...this.credentials } : null;
397
- }
398
- async save(credentials) {
399
- this.credentials = {
400
- token: credentials.token,
401
- is_anonymous: credentials.is_anonymous ?? this.credentials?.is_anonymous,
402
- anonymous_id: credentials.anonymous_id ?? this.credentials?.anonymous_id,
403
- anonymous_secret: credentials.anonymous_secret ?? this.credentials?.anonymous_secret
404
- };
405
- }
406
- async clear() {
407
- this.credentials = null;
408
- }
409
- };
410
- function defaultCredentialStore() {
411
- return new FileCredentialStore();
412
- }
413
-
414
- // src/admin.ts
415
- function createAdminClient(options = {}) {
416
- const baseUrl = options.baseUrl ?? "https://db9.shared.aws.tidbcloud.com/api";
417
- const headers = {};
418
- if (options.apiKey) {
419
- headers["X-API-Key"] = options.apiKey;
420
- }
421
- const client = createHttpClient({
422
- baseUrl,
423
- fetch: options.fetch,
424
- headers
425
- });
426
- return {
427
- tenants: {
428
- list: (params) => {
429
- const queryParams = {};
430
- if (params) {
431
- if (params.page !== void 0)
432
- queryParams.page = String(params.page);
433
- if (params.size !== void 0)
434
- queryParams.size = String(params.size);
435
- if (params.state !== void 0) queryParams.state = params.state;
436
- if (params.q !== void 0) queryParams.q = params.q;
437
- if (params.cursor !== void 0) queryParams.cursor = params.cursor;
438
- if (params.tag !== void 0) queryParams.tag = params.tag;
439
- }
440
- return client.get("/tenants", queryParams);
441
- },
442
- create: (req) => client.post("/tenants", req),
443
- get: (tenantId) => client.get(`/tenants/${tenantId}`),
444
- update: (tenantId, req) => client.put(`/tenants/${tenantId}`, req),
445
- delete: (tenantId) => client.del(`/tenants/${tenantId}`),
446
- remove: (tenantId) => client.post(`/tenants/${tenantId}/remove`),
447
- batchCreate: (req) => client.post("/tenants/batch", req),
448
- batchDelete: (req) => client.post("/tenants/batch/delete", req),
449
- batchUpdate: (req) => client.put("/tenants/batch", req),
450
- connect: (tenantId, req) => client.post(
451
- `/tenants/${tenantId}/connect`,
452
- req
453
- ),
454
- // query() needs X-Tenant-Session header — create a one-off client
455
- query: async (tenantId, sessionId, req) => {
456
- const sessionClient = createHttpClient({
457
- baseUrl,
458
- fetch: options.fetch,
459
- headers: {
460
- ...headers,
461
- "X-Tenant-Session": sessionId
462
- }
463
- });
464
- return sessionClient.post(
465
- `/tenants/${tenantId}/query`,
466
- req
467
- );
468
- }
469
- },
470
- system: {
471
- health: () => client.get("/health"),
472
- info: () => client.get("/info")
473
- },
474
- users: {
475
- list: async (tenantId, sessionId) => {
476
- const sessionClient = createHttpClient({
477
- baseUrl,
478
- fetch: options.fetch,
479
- headers: {
480
- ...headers,
481
- "X-Tenant-Session": sessionId
482
- }
483
- });
484
- return sessionClient.get(
485
- `/tenants/${tenantId}/users`
486
- );
487
- },
488
- create: async (tenantId, sessionId, req) => {
489
- const sessionClient = createHttpClient({
490
- baseUrl,
491
- fetch: options.fetch,
492
- headers: {
493
- ...headers,
494
- "X-Tenant-Session": sessionId
495
- }
496
- });
497
- return sessionClient.post(
498
- `/tenants/${tenantId}/users`,
499
- req
500
- );
501
- },
502
- delete: async (tenantId, sessionId, username) => {
503
- const sessionClient = createHttpClient({
504
- baseUrl,
505
- fetch: options.fetch,
506
- headers: {
507
- ...headers,
508
- "X-Tenant-Session": sessionId
509
- }
510
- });
511
- return sessionClient.del(
512
- `/tenants/${tenantId}/users/${username}`
513
- );
514
- },
515
- resetPassword: async (tenantId, sessionId, username) => {
516
- const sessionClient = createHttpClient({
517
- baseUrl,
518
- fetch: options.fetch,
519
- headers: {
520
- ...headers,
521
- "X-Tenant-Session": sessionId
522
- }
523
- });
524
- return sessionClient.post(
525
- `/tenants/${tenantId}/users/${username}/password`
526
- );
527
- }
528
- },
529
- observability: {
530
- get: (tenantId) => client.get(
531
- `/tenants/${tenantId}/observability`
532
- ),
533
- bootstrap: (tenantId, req) => client.post(
534
- `/tenants/${tenantId}/observability/bootstrap`,
535
- req
536
- )
537
- },
538
- audit: {
539
- list: (params) => {
540
- const queryParams = {};
541
- if (params) {
542
- if (params.tenant_id !== void 0)
543
- queryParams.tenant_id = params.tenant_id;
544
- if (params.operation_type !== void 0)
545
- queryParams.operation_type = params.operation_type;
546
- if (params.resource_type !== void 0)
547
- queryParams.resource_type = params.resource_type;
548
- if (params.success !== void 0)
549
- queryParams.success = String(params.success);
550
- if (params.limit !== void 0)
551
- queryParams.limit = String(params.limit);
552
- if (params.offset !== void 0)
553
- queryParams.offset = String(params.offset);
554
- }
555
- return client.get("/audit-logs", queryParams);
556
- }
557
- }
558
- };
559
- }
560
-
561
425
  // src/index.ts
562
426
  async function instantDatabase(options = {}) {
563
- const store = options.credentialStore ?? defaultCredentialStore();
564
427
  const dbName = options.name ?? "default";
565
- const creds = await store.load();
566
- let token;
567
- if (creds?.token) {
568
- token = creds.token;
569
- } else {
570
- const publicClient = createCustomerClient({
571
- baseUrl: options.baseUrl,
572
- fetch: options.fetch
573
- });
574
- const regResult = await publicClient.auth.anonymousRegister();
575
- token = regResult.token;
576
- await store.save({
577
- token: regResult.token,
578
- is_anonymous: regResult.is_anonymous,
579
- anonymous_id: regResult.anonymous_id,
580
- anonymous_secret: regResult.anonymous_secret
581
- });
582
- }
583
- const client = createCustomerClient({
428
+ const client = createDb9Client({
584
429
  baseUrl: options.baseUrl,
585
430
  fetch: options.fetch,
586
- token
431
+ credentialStore: options.credentialStore
587
432
  });
588
433
  const existing = await client.databases.list();
589
434
  const found = existing.find((db) => db.name === dbName);
@@ -616,8 +461,7 @@ function toResult(db) {
616
461
  Db9NotFoundError,
617
462
  FileCredentialStore,
618
463
  MemoryCredentialStore,
619
- createAdminClient,
620
- createCustomerClient,
464
+ createDb9Client,
621
465
  defaultCredentialStore,
622
466
  instantDatabase
623
467
  });