pacificdb-client 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2026-07-02)
4
+
5
+ Initial release.
6
+
7
+ - `PacificDBClient` with connection-string auth against the PacificDB gateway
8
+ (`POST /api/v1/db/sessions`) and short-lived session tokens.
9
+ - Collection API: `insertOne`, `findOne`, `find`, `updateOne`, `deleteOne`.
10
+ - Model API: `db.model(name, schema)` with client-side type validation.
11
+ - Retry with exponential backoff + jitter for `server_busy`, `not_leader`,
12
+ 429, 503, and timeouts; one transparent session refresh on 401.
13
+ - Typed error hierarchy with request IDs.
14
+ - Redacted logging helpers (`redactConnectionString`, `redactSecrets`).
15
+ - Read/write timeouts; TLS by default (`allowInsecure` opt-in for local dev).
16
+ - Dual ESM/CJS build with TypeScript declarations.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hitesh Reddy K
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # pacificdb-client
2
+
3
+ Official PacificDB client for Node.js (>= 18) and modern runtimes with `fetch`.
4
+
5
+ - Connection-string auth with short-lived database sessions
6
+ - Automatic session refresh and retry with exponential backoff (+jitter)
7
+ - Typed errors, request IDs, redacted logging (secrets never reach your logs)
8
+ - Read/write timeouts, TLS-by-default (`http://` requires an explicit opt-in)
9
+ - ESM + CJS builds with TypeScript declarations
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install pacificdb-client
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```ts
20
+ import { PacificDBClient } from "pacificdb-client";
21
+
22
+ const db = new PacificDBClient(process.env.PACIFICDB_URI!);
23
+ await db.connect();
24
+
25
+ const users = db.collection("users");
26
+
27
+ await users.insertOne({ name: "Hitesh", age: 20 });
28
+ const user = await users.findOne({ name: "Hitesh" });
29
+ await users.updateOne({ name: "Hitesh" }, { $set: { age: 21 } });
30
+ await users.deleteOne({ name: "Hitesh" });
31
+
32
+ await db.close();
33
+ ```
34
+
35
+ ## Model API
36
+
37
+ ```ts
38
+ const User = db.model("users", {
39
+ name: String,
40
+ age: Number,
41
+ email: String,
42
+ });
43
+
44
+ await User.create({ name: "Hitesh", age: 20, email: "x@y.com" });
45
+ const found = await User.findOne({ email: "x@y.com" });
46
+ ```
47
+
48
+ Schema types are validated client-side on `create` (`String`, `Number`, `Boolean`).
49
+
50
+ ## Connection string
51
+
52
+ ```
53
+ pacificdb://<dbUsername>:<dbPassword>@<clusterHost>/<databaseName>
54
+ ?projectId=<projectId>&clusterId=<clusterId>&databaseId=<databaseId>
55
+ &tls=true&authSource=admin&appName=<appName>
56
+ ```
57
+
58
+ Passwords must be URL-encoded; the parser decodes them. `tls` defaults to `true`.
59
+ The connection string is shown once when you create a database user — store it
60
+ in a secret manager and pass it via `PACIFICDB_URI`.
61
+
62
+ ## Options
63
+
64
+ ```ts
65
+ new PacificDBClient(uri, {
66
+ apiUrl: "https://gateway.internal:8443", // override https://<clusterHost>
67
+ allowInsecure: false, // must be true to use an http:// gateway (dev only)
68
+ readTimeoutMs: 30_000,
69
+ writeTimeoutMs: 30_000,
70
+ retryLimit: 3, // retries for server_busy / not_leader / 429 / 503 / timeouts
71
+ retryBackoffMs: 250, // exponential base, with jitter
72
+ logger: { debug: console.debug, warn: console.warn }, // secrets are redacted
73
+ });
74
+ ```
75
+
76
+ ## Errors
77
+
78
+ All errors extend `PacificDBError` and carry `code` and `requestId`:
79
+
80
+ | Class | Meaning |
81
+ | --- | --- |
82
+ | `PacificDBConfigError` | Bad connection string or options |
83
+ | `PacificDBAuthError` | Invalid credentials or expired session |
84
+ | `PacificDBClientError` | Non-retriable 4xx |
85
+ | `PacificDBServerError` | 5xx / `server_busy` / `not_leader` (retried) |
86
+ | `PacificDBTimeoutError` | Request exceeded its timeout (retried) |
87
+
88
+ ## Security notes
89
+
90
+ - Passwords and session tokens are never logged; use `redactConnectionString`
91
+ / `redactSecrets` if you log request context yourself.
92
+ - The client refuses to send credentials over plaintext HTTP unless you set
93
+ `allowInsecure: true`.
94
+
95
+ ## Development
96
+
97
+ ```bash
98
+ npm run build # tsup: ESM + CJS + d.ts
99
+ npm test # node --test against dist/
100
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ PacificDBAuthError: () => PacificDBAuthError,
24
+ PacificDBClient: () => PacificDBClient,
25
+ PacificDBClientError: () => PacificDBClientError,
26
+ PacificDBConfigError: () => PacificDBConfigError,
27
+ PacificDBError: () => PacificDBError,
28
+ PacificDBServerError: () => PacificDBServerError,
29
+ PacificDBTimeoutError: () => PacificDBTimeoutError,
30
+ buildConnectionString: () => buildConnectionString,
31
+ parseConnectionString: () => parseConnectionString,
32
+ redactConnectionString: () => redactConnectionString,
33
+ redactSecrets: () => redactSecrets
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/errors.ts
38
+ var PacificDBError = class extends Error {
39
+ code;
40
+ requestId;
41
+ constructor(message, code = "PACIFICDB_ERROR", requestId) {
42
+ super(message);
43
+ this.name = new.target.name;
44
+ this.code = code;
45
+ this.requestId = requestId;
46
+ }
47
+ };
48
+ var PacificDBConfigError = class extends PacificDBError {
49
+ constructor(message) {
50
+ super(message, "CONFIG_ERROR");
51
+ }
52
+ };
53
+ var PacificDBAuthError = class extends PacificDBError {
54
+ constructor(message, requestId) {
55
+ super(message, "AUTH_ERROR", requestId);
56
+ }
57
+ };
58
+ var PacificDBClientError = class extends PacificDBError {
59
+ status;
60
+ constructor(message, code, status, requestId) {
61
+ super(message, code, requestId);
62
+ this.status = status;
63
+ }
64
+ };
65
+ var PacificDBServerError = class extends PacificDBError {
66
+ status;
67
+ constructor(message, code, status, requestId) {
68
+ super(message, code, requestId);
69
+ this.status = status;
70
+ }
71
+ };
72
+ var PacificDBTimeoutError = class extends PacificDBError {
73
+ constructor(timeoutMs, requestId) {
74
+ super(`PacificDB request timed out after ${timeoutMs}ms`, "TIMEOUT", requestId);
75
+ }
76
+ };
77
+
78
+ // src/connectionString.ts
79
+ var SECRET_KEYS = /* @__PURE__ */ new Set(["password", "token", "secret", "key", "sessiontoken", "connectionstring"]);
80
+ function parseConnectionString(uri) {
81
+ let url;
82
+ try {
83
+ url = new URL(uri);
84
+ } catch (error) {
85
+ throw new PacificDBConfigError(`Invalid PacificDB connection string: ${error.message}`);
86
+ }
87
+ const protocol = url.protocol.replace(":", "");
88
+ if (protocol !== "pacificdb") {
89
+ throw new PacificDBConfigError("PacificDB connection strings must use the pacificdb:// protocol.");
90
+ }
91
+ if (!url.username || !url.password) {
92
+ throw new PacificDBConfigError("PacificDB connection string requires a database username and password.");
93
+ }
94
+ const databaseName = decodeURIComponent(url.pathname.replace(/^\/+/, ""));
95
+ if (!databaseName) {
96
+ throw new PacificDBConfigError("PacificDB connection string requires a database name path.");
97
+ }
98
+ const orgId = url.searchParams.get("orgId") || url.searchParams.get("organizationId") || "";
99
+ const projectId = url.searchParams.get("projectId") || "";
100
+ const clusterId = url.searchParams.get("clusterId") || "";
101
+ const databaseId = url.searchParams.get("databaseId") || "";
102
+ if (!orgId || !projectId || !clusterId || !databaseId) {
103
+ throw new PacificDBConfigError("PacificDB connection string requires orgId, projectId, clusterId, and databaseId.");
104
+ }
105
+ const tlsRaw = url.searchParams.get("tls");
106
+ return {
107
+ protocol: "pacificdb",
108
+ username: decodeURIComponent(url.username),
109
+ password: decodeURIComponent(url.password),
110
+ clusterHost: url.host,
111
+ databaseName,
112
+ orgId,
113
+ projectId,
114
+ clusterId,
115
+ databaseId,
116
+ tls: tlsRaw === null ? true : tlsRaw !== "false",
117
+ authSource: url.searchParams.get("authSource") || "admin",
118
+ appName: url.searchParams.get("appName") || void 0
119
+ };
120
+ }
121
+ function buildConnectionString(input) {
122
+ const url = new URL(`pacificdb://${input.clusterHost}/${encodeURIComponent(input.databaseName)}`);
123
+ url.username = encodeURIComponent(input.username);
124
+ url.password = encodeURIComponent(input.password);
125
+ if (input.orgId) url.searchParams.set("orgId", input.orgId);
126
+ url.searchParams.set("projectId", input.projectId);
127
+ url.searchParams.set("clusterId", input.clusterId);
128
+ url.searchParams.set("databaseId", input.databaseId);
129
+ url.searchParams.set("tls", String(input.tls !== false));
130
+ url.searchParams.set("authSource", input.authSource || "admin");
131
+ if (input.appName) url.searchParams.set("appName", input.appName);
132
+ return url.toString();
133
+ }
134
+ function redactConnectionString(uri) {
135
+ try {
136
+ const url = new URL(uri);
137
+ if (url.password) url.password = "REDACTED";
138
+ return url.toString();
139
+ } catch {
140
+ return uri.replace(/(pacificdb:\/\/[^:]+:)[^@]+@/i, "$1REDACTED@");
141
+ }
142
+ }
143
+ function redactSecrets(value) {
144
+ if (!value || typeof value !== "object") return value;
145
+ if (Array.isArray(value)) return value.map(redactSecrets);
146
+ const out = {};
147
+ for (const [key, item] of Object.entries(value)) {
148
+ out[key] = SECRET_KEYS.has(key.toLowerCase()) ? "REDACTED" : redactSecrets(item);
149
+ }
150
+ return out;
151
+ }
152
+
153
+ // src/client.ts
154
+ var RETRIABLE_CODES = /* @__PURE__ */ new Set(["server_busy", "not_leader", "TIMEOUT", "RATE_LIMITED", "HTTP_503", "HTTP_429", "ENGINE_UNAVAILABLE"]);
155
+ function randomRequestId() {
156
+ return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
157
+ }
158
+ var PacificDBClient = class {
159
+ connection;
160
+ fetchImpl;
161
+ apiUrl;
162
+ readTimeoutMs;
163
+ writeTimeoutMs;
164
+ retryLimit;
165
+ retryBackoffMs;
166
+ logger;
167
+ sessionToken = "";
168
+ connected = false;
169
+ constructor(uri, options = {}) {
170
+ this.connection = parseConnectionString(uri);
171
+ this.apiUrl = (options.apiUrl || `https://${this.connection.clusterHost}`).replace(/\/+$/, "");
172
+ if (this.apiUrl.startsWith("http://") && !options.allowInsecure) {
173
+ throw new PacificDBConfigError(
174
+ "Refusing to send database credentials over http://. Use https, or pass { allowInsecure: true } for local development."
175
+ );
176
+ }
177
+ const fetchImpl = options.fetch || (typeof fetch !== "undefined" ? fetch : void 0);
178
+ if (!fetchImpl) {
179
+ throw new PacificDBConfigError("No fetch implementation available. Use Node.js >= 18 or pass options.fetch.");
180
+ }
181
+ this.fetchImpl = fetchImpl;
182
+ this.readTimeoutMs = options.readTimeoutMs ?? 3e4;
183
+ this.writeTimeoutMs = options.writeTimeoutMs ?? 3e4;
184
+ this.retryLimit = options.retryLimit ?? 3;
185
+ this.retryBackoffMs = options.retryBackoffMs ?? 250;
186
+ this.logger = options.logger;
187
+ }
188
+ /** The redacted URI (safe for logs/errors). */
189
+ get redactedUri() {
190
+ return redactConnectionString(
191
+ `pacificdb://${encodeURIComponent(this.connection.username)}:x@${this.connection.clusterHost}/${this.connection.databaseName}`
192
+ );
193
+ }
194
+ async connect() {
195
+ await this.authenticate();
196
+ this.connected = true;
197
+ }
198
+ async authenticate() {
199
+ const result = await this.request("POST", "/api/v1/db/sessions", {
200
+ username: this.connection.username,
201
+ password: this.connection.password,
202
+ orgId: this.connection.orgId,
203
+ projectId: this.connection.projectId,
204
+ clusterId: this.connection.clusterId,
205
+ databaseId: this.connection.databaseId,
206
+ databaseName: this.connection.databaseName,
207
+ authSource: this.connection.authSource
208
+ }, { requireSession: false, isWrite: true });
209
+ if (!result?.sessionToken) {
210
+ throw new PacificDBAuthError("Database authentication did not return a session token.");
211
+ }
212
+ this.sessionToken = result.sessionToken;
213
+ this.logger?.debug?.("pacificdb.session.created", { database: this.connection.databaseName });
214
+ }
215
+ async close() {
216
+ if (!this.sessionToken) return;
217
+ try {
218
+ await this.request("DELETE", "/api/v1/db/sessions/current", void 0, { isWrite: true });
219
+ } catch {
220
+ } finally {
221
+ this.sessionToken = "";
222
+ this.connected = false;
223
+ }
224
+ }
225
+ collection(name) {
226
+ const encoded = encodeURIComponent(name);
227
+ return {
228
+ insertOne: async (document) => {
229
+ const r = await this.request(
230
+ "POST",
231
+ `/api/v1/db/collections/${encoded}/documents`,
232
+ { document },
233
+ { isWrite: true }
234
+ );
235
+ return { inserted: r?.inserted !== false, id: r?.id ?? null };
236
+ },
237
+ findOne: async (filter) => {
238
+ const r = await this.request(
239
+ "POST",
240
+ `/api/v1/db/collections/${encoded}/find`,
241
+ { query: filter, limit: 1 },
242
+ { isWrite: false }
243
+ );
244
+ return r?.documents?.[0] ?? null;
245
+ },
246
+ find: async (filter, options = {}) => {
247
+ const r = await this.request(
248
+ "POST",
249
+ `/api/v1/db/collections/${encoded}/find`,
250
+ { query: filter, ...options },
251
+ { isWrite: false }
252
+ );
253
+ return r?.documents ?? [];
254
+ },
255
+ updateOne: (filter, update) => this.request("PATCH", `/api/v1/db/collections/${encoded}/documents`, { filter, update }, { isWrite: true }),
256
+ deleteOne: (filter) => this.request("DELETE", `/api/v1/db/collections/${encoded}/documents`, { filter }, { isWrite: true })
257
+ };
258
+ }
259
+ model(name, schema) {
260
+ const collection = this.collection(name);
261
+ const validate = (document) => {
262
+ for (const [field, type] of Object.entries(schema)) {
263
+ const value = document[field];
264
+ if (value === void 0 || value === null) continue;
265
+ const expected = typeof type === "function" ? type.name?.toLowerCase() : void 0;
266
+ if (expected && expected !== "object" && typeof value !== expected) {
267
+ throw new PacificDBConfigError(`Field "${field}" expected ${expected}, got ${typeof value}.`);
268
+ }
269
+ }
270
+ };
271
+ return {
272
+ create: async (document) => {
273
+ validate(document);
274
+ return collection.insertOne(document);
275
+ },
276
+ findOne: (filter) => collection.findOne(filter),
277
+ find: (filter, options) => collection.find(filter, options),
278
+ updateOne: (filter, update) => collection.updateOne(filter, update),
279
+ deleteOne: (filter) => collection.deleteOne(filter)
280
+ };
281
+ }
282
+ async request(method, path, body, opts = {}) {
283
+ const { requireSession = true, isWrite = false } = opts;
284
+ if (requireSession && !this.sessionToken) {
285
+ throw new PacificDBAuthError("Call connect() before issuing database operations.");
286
+ }
287
+ const timeoutMs = isWrite ? this.writeTimeoutMs : this.readTimeoutMs;
288
+ const url = new URL(path, `${this.apiUrl}/`);
289
+ url.searchParams.set("projectId", this.connection.projectId);
290
+ url.searchParams.set("clusterId", this.connection.clusterId);
291
+ url.searchParams.set("databaseId", this.connection.databaseId);
292
+ let refreshed = false;
293
+ let lastError = null;
294
+ for (let attempt = 0; attempt <= this.retryLimit; attempt++) {
295
+ const requestId = randomRequestId();
296
+ const controller = new AbortController();
297
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
298
+ try {
299
+ const response = await this.fetchImpl(url, {
300
+ method,
301
+ signal: controller.signal,
302
+ headers: {
303
+ "content-type": "application/json",
304
+ "x-request-id": requestId,
305
+ ...this.sessionToken ? { authorization: `Bearer ${this.sessionToken}` } : {}
306
+ },
307
+ body: body === void 0 ? void 0 : JSON.stringify(body)
308
+ });
309
+ clearTimeout(timer);
310
+ const json = await response.json().catch(() => ({}));
311
+ if (response.ok && json.success !== false) {
312
+ return json.data ?? json;
313
+ }
314
+ const errObj = typeof json.error === "object" ? json.error : void 0;
315
+ const code = errObj?.code || (typeof json.error === "string" ? json.error : "") || `HTTP_${response.status}`;
316
+ const message = errObj?.message || `PacificDB request failed (${code})`;
317
+ if (response.status === 401 && this.connected && !refreshed && requireSession) {
318
+ refreshed = true;
319
+ this.logger?.debug?.("pacificdb.session.refresh", { requestId });
320
+ await this.authenticate();
321
+ attempt--;
322
+ continue;
323
+ }
324
+ if (response.status === 401) {
325
+ throw new PacificDBAuthError(message, requestId);
326
+ }
327
+ const retriable = RETRIABLE_CODES.has(code) || response.status === 429 || response.status === 503;
328
+ if (!retriable || attempt === this.retryLimit) {
329
+ if (response.status >= 500) throw new PacificDBServerError(message, code, response.status, requestId);
330
+ throw new PacificDBClientError(message, code, response.status, requestId);
331
+ }
332
+ const retryAfter = Number(response.headers.get("retry-after-ms") || json.retry_after_ms || 0);
333
+ lastError = new PacificDBServerError(message, code, response.status, requestId);
334
+ await this.backoff(attempt, retryAfter);
335
+ } catch (error) {
336
+ clearTimeout(timer);
337
+ if (error instanceof PacificDBClientError || error instanceof PacificDBAuthError || error instanceof PacificDBConfigError || error instanceof PacificDBServerError) {
338
+ if (error instanceof PacificDBServerError && attempt < this.retryLimit) {
339
+ lastError = error;
340
+ await this.backoff(attempt, 0);
341
+ continue;
342
+ }
343
+ throw error;
344
+ }
345
+ const isAbort = error.name === "AbortError";
346
+ lastError = isAbort ? new PacificDBTimeoutError(timeoutMs) : error;
347
+ this.logger?.warn?.("pacificdb.request.retry", {
348
+ attempt,
349
+ code: isAbort ? "TIMEOUT" : "NETWORK_ERROR",
350
+ target: this.redactedUri
351
+ });
352
+ if (attempt === this.retryLimit) break;
353
+ await this.backoff(attempt, 0);
354
+ }
355
+ }
356
+ throw lastError || new PacificDBServerError("PacificDB request failed.", "UNKNOWN", 0);
357
+ }
358
+ backoff(attempt, retryAfterMs) {
359
+ const base = retryAfterMs || this.retryBackoffMs * Math.pow(2, attempt);
360
+ const jitter = Math.floor(Math.random() * this.retryBackoffMs);
361
+ return new Promise((resolve) => setTimeout(resolve, base + jitter));
362
+ }
363
+ };
364
+ // Annotate the CommonJS export names for ESM import in node:
365
+ 0 && (module.exports = {
366
+ PacificDBAuthError,
367
+ PacificDBClient,
368
+ PacificDBClientError,
369
+ PacificDBConfigError,
370
+ PacificDBError,
371
+ PacificDBServerError,
372
+ PacificDBTimeoutError,
373
+ buildConnectionString,
374
+ parseConnectionString,
375
+ redactConnectionString,
376
+ redactSecrets
377
+ });
@@ -0,0 +1,142 @@
1
+ /**
2
+ * PacificDB connection string parsing, building, and redaction.
3
+ *
4
+ * Format:
5
+ * pacificdb://<user>:<password>@<clusterHost>/<databaseName>
6
+ * ?projectId=..&clusterId=..&databaseId=..&tls=true&authSource=admin&appName=..
7
+ */
8
+ interface PacificConnectionString {
9
+ protocol: 'pacificdb';
10
+ username: string;
11
+ password: string;
12
+ clusterHost: string;
13
+ databaseName: string;
14
+ orgId: string;
15
+ projectId: string;
16
+ clusterId: string;
17
+ databaseId: string;
18
+ tls: boolean;
19
+ authSource: string;
20
+ appName?: string;
21
+ }
22
+ declare function parseConnectionString(uri: string): PacificConnectionString;
23
+ declare function buildConnectionString(input: Omit<PacificConnectionString, 'protocol'>): string;
24
+ /** Replace the password portion of a URI with REDACTED. Never throws. */
25
+ declare function redactConnectionString(uri: string): string;
26
+ /** Deep-copy a value with secret-looking keys replaced by REDACTED. */
27
+ declare function redactSecrets(value: unknown): unknown;
28
+
29
+ /**
30
+ * PacificDBClient - database client over the PacificDB gateway data plane.
31
+ *
32
+ * Auth: exchanges the connection string credentials for a short-lived database
33
+ * session (POST /api/v1/db/sessions), then sends Bearer session tokens.
34
+ * Sessions are transparently refreshed once when the server reports 401.
35
+ *
36
+ * Retries: exponential backoff with jitter for server_busy / not_leader /
37
+ * 429 / 503 / timeouts, bounded by retryLimit.
38
+ *
39
+ * Logging: optional logger receives structured events; connection strings and
40
+ * passwords are always redacted before they reach the logger.
41
+ */
42
+
43
+ interface PacificDBLogger {
44
+ debug?(message: string, fields?: Record<string, unknown>): void;
45
+ warn?(message: string, fields?: Record<string, unknown>): void;
46
+ }
47
+ interface PacificDBClientOptions {
48
+ /** Override the gateway base URL (defaults to https://<clusterHost>). */
49
+ apiUrl?: string;
50
+ /** Allow http:// gateways (local development only). */
51
+ allowInsecure?: boolean;
52
+ fetch?: typeof fetch;
53
+ /** Timeout for read operations (find). Default 30s. */
54
+ readTimeoutMs?: number;
55
+ /** Timeout for write operations (insert/update/delete). Default 30s. */
56
+ writeTimeoutMs?: number;
57
+ retryLimit?: number;
58
+ retryBackoffMs?: number;
59
+ logger?: PacificDBLogger;
60
+ appName?: string;
61
+ }
62
+ interface FindOptions {
63
+ limit?: number;
64
+ skip?: number;
65
+ sort?: Record<string, 1 | -1>;
66
+ }
67
+ interface CollectionHandle<T extends Record<string, unknown> = Record<string, unknown>> {
68
+ insertOne(document: T): Promise<{
69
+ inserted: boolean;
70
+ id: string | null;
71
+ }>;
72
+ findOne(filter: Partial<T>): Promise<T | null>;
73
+ find(filter: Partial<T>, options?: FindOptions): Promise<T[]>;
74
+ updateOne(filter: Partial<T>, update: Record<string, unknown>): Promise<unknown>;
75
+ deleteOne(filter: Partial<T>): Promise<unknown>;
76
+ }
77
+ interface ModelHandle<T extends Record<string, unknown> = Record<string, unknown>> {
78
+ create(document: T): Promise<{
79
+ inserted: boolean;
80
+ id: string | null;
81
+ }>;
82
+ findOne(filter: Partial<T>): Promise<T | null>;
83
+ find(filter: Partial<T>, options?: FindOptions): Promise<T[]>;
84
+ updateOne(filter: Partial<T>, update: Record<string, unknown>): Promise<unknown>;
85
+ deleteOne(filter: Partial<T>): Promise<unknown>;
86
+ }
87
+ type ModelSchema = Record<string, unknown>;
88
+ declare class PacificDBClient {
89
+ readonly connection: PacificConnectionString;
90
+ private readonly fetchImpl;
91
+ private readonly apiUrl;
92
+ private readonly readTimeoutMs;
93
+ private readonly writeTimeoutMs;
94
+ private readonly retryLimit;
95
+ private readonly retryBackoffMs;
96
+ private readonly logger?;
97
+ private sessionToken;
98
+ private connected;
99
+ constructor(uri: string, options?: PacificDBClientOptions);
100
+ /** The redacted URI (safe for logs/errors). */
101
+ get redactedUri(): string;
102
+ connect(): Promise<void>;
103
+ private authenticate;
104
+ close(): Promise<void>;
105
+ collection<T extends Record<string, unknown> = Record<string, unknown>>(name: string): CollectionHandle<T>;
106
+ model<T extends Record<string, unknown> = Record<string, unknown>>(name: string, schema: ModelSchema): ModelHandle<T>;
107
+ private request;
108
+ private backoff;
109
+ }
110
+
111
+ /**
112
+ * Typed error hierarchy for the PacificDB client.
113
+ */
114
+ declare class PacificDBError extends Error {
115
+ readonly code: string;
116
+ readonly requestId?: string;
117
+ constructor(message: string, code?: string, requestId?: string);
118
+ }
119
+ /** Invalid connection string or client configuration. */
120
+ declare class PacificDBConfigError extends PacificDBError {
121
+ constructor(message: string);
122
+ }
123
+ /** Authentication or session failure (401-class). */
124
+ declare class PacificDBAuthError extends PacificDBError {
125
+ constructor(message: string, requestId?: string);
126
+ }
127
+ /** Non-retriable client-side failure (4xx-class). */
128
+ declare class PacificDBClientError extends PacificDBError {
129
+ readonly status: number;
130
+ constructor(message: string, code: string, status: number, requestId?: string);
131
+ }
132
+ /** Retriable server-side failure (5xx-class, server_busy, not_leader). */
133
+ declare class PacificDBServerError extends PacificDBError {
134
+ readonly status: number;
135
+ constructor(message: string, code: string, status: number, requestId?: string);
136
+ }
137
+ /** Request exceeded the configured timeout. */
138
+ declare class PacificDBTimeoutError extends PacificDBError {
139
+ constructor(timeoutMs: number, requestId?: string);
140
+ }
141
+
142
+ export { type CollectionHandle, type FindOptions, type ModelHandle, type PacificConnectionString, PacificDBAuthError, PacificDBClient, PacificDBClientError, type PacificDBClientOptions, PacificDBConfigError, PacificDBError, type PacificDBLogger, PacificDBServerError, PacificDBTimeoutError, buildConnectionString, parseConnectionString, redactConnectionString, redactSecrets };