@palveron/sdk 1.0.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,225 @@
1
+ type Decision = 'ALLOWED' | 'BLOCKED' | 'MODIFIED' | 'ERROR';
2
+ type RiskLevel = 'minimal' | 'limited' | 'high' | 'unacceptable';
3
+ type Sensitivity = 'low' | 'medium' | 'high';
4
+ interface PalveronConfig {
5
+ /** API key (starts with pv_live_ or pv_test_) */
6
+ apiKey: string;
7
+ /** Gateway base URL (default: https://gateway.palveron.com) */
8
+ baseUrl?: string;
9
+ /** Request timeout in ms (default: 30000) */
10
+ timeout?: number;
11
+ /** Max retry attempts on transient failures (default: 3) */
12
+ maxRetries?: number;
13
+ /** Base delay for exponential backoff in ms (default: 500) */
14
+ retryBaseDelay?: number;
15
+ /** Custom logger (default: console) */
16
+ logger?: PalveronLogger;
17
+ /** Custom headers added to every request */
18
+ headers?: Record<string, string>;
19
+ /** Circuit breaker: max consecutive failures before opening (default: 5) */
20
+ circuitBreakerThreshold?: number;
21
+ /** Circuit breaker: cooldown in ms before half-open retry (default: 30000) */
22
+ circuitBreakerCooldown?: number;
23
+ }
24
+ interface PalveronLogger {
25
+ debug(message: string, meta?: Record<string, unknown>): void;
26
+ info(message: string, meta?: Record<string, unknown>): void;
27
+ warn(message: string, meta?: Record<string, unknown>): void;
28
+ error(message: string, meta?: Record<string, unknown>): void;
29
+ }
30
+ interface Attachment {
31
+ /** MIME type (e.g. "image/png", "audio/wav", "application/pdf") */
32
+ contentType: string;
33
+ /** Base64-encoded data */
34
+ data: string;
35
+ /** Optional filename */
36
+ filename?: string;
37
+ /** Optional per-attachment metadata (GPS, resolution, etc.) */
38
+ metadata?: Record<string, unknown>;
39
+ }
40
+ interface RequestContext {
41
+ /** MCP server URL if applicable */
42
+ mcpServer?: string;
43
+ /** MCP tool name */
44
+ toolName?: string;
45
+ /** Agent chain depth for recursive calls */
46
+ chainDepth?: number;
47
+ /** Source system identifier ("ros2", "unity", "cursor-ide", etc.) */
48
+ sourceSystem?: string;
49
+ /** Session ID for conversation tracking */
50
+ sessionId?: string;
51
+ }
52
+ interface VerifyRequest {
53
+ /** The prompt or input text to verify */
54
+ prompt: string;
55
+ /** Pre-extracted text from attachments (optional, server extracts if absent) */
56
+ extractedText?: string;
57
+ /** Arbitrary metadata passed through to the trace */
58
+ metadata?: Record<string, unknown>;
59
+ /** Multi-modal attachments (images, audio, documents, code) */
60
+ attachments?: Attachment[];
61
+ /** Agentic context (MCP, tool chains, source systems) */
62
+ context?: RequestContext;
63
+ }
64
+ interface Finding {
65
+ risk: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
66
+ category: string;
67
+ description: string;
68
+ confidence: number;
69
+ }
70
+ interface VerifyResponse {
71
+ /** Governance decision */
72
+ decision: Decision;
73
+ /** Modified/sanitized output (present when decision is MODIFIED) */
74
+ output: string;
75
+ /** Human-readable reason for the decision */
76
+ reason: string;
77
+ /** Unique trace ID for audit trail */
78
+ traceId: string;
79
+ /** SHA-256 integrity hash of the governance decision */
80
+ integrityHash: string;
81
+ /** Whether this trace will be anchored to Flare blockchain */
82
+ shouldAnchor: boolean;
83
+ /** Flare blockchain status */
84
+ flareStatus: string;
85
+ /** Flare transaction hash (populated after anchoring) */
86
+ flareTxHash: string | null;
87
+ /** Detected content type */
88
+ contentType: string;
89
+ /** Security findings (secrets, PII, policy violations) */
90
+ findings: Finding[];
91
+ /** Server-side latency in milliseconds */
92
+ latencyMs: number;
93
+ }
94
+ interface PolicyListResponse {
95
+ policies: Array<{
96
+ id: string;
97
+ name: string;
98
+ prompt: string;
99
+ environment: string;
100
+ contentTypes: string[];
101
+ createdAt: string;
102
+ updatedAt: string;
103
+ }>;
104
+ }
105
+ interface HealthResponse {
106
+ status: 'healthy' | 'degraded' | 'unhealthy';
107
+ version: string;
108
+ uptime: number;
109
+ checks: Record<string, {
110
+ status: string;
111
+ latencyMs: number;
112
+ }>;
113
+ }
114
+ declare class PalveronError extends Error {
115
+ readonly code: string;
116
+ readonly statusCode: number;
117
+ readonly requestId: string | null;
118
+ readonly retryable: boolean;
119
+ constructor(message: string, opts: {
120
+ code: string;
121
+ statusCode: number;
122
+ requestId?: string | null;
123
+ retryable?: boolean;
124
+ });
125
+ }
126
+ declare class PalveronAuthenticationError extends PalveronError {
127
+ constructor(message: string, requestId?: string | null);
128
+ }
129
+ declare class PalveronRateLimitError extends PalveronError {
130
+ readonly retryAfterMs: number;
131
+ constructor(message: string, retryAfterMs: number, requestId?: string | null);
132
+ }
133
+ declare class PalveronValidationError extends PalveronError {
134
+ readonly field: string | null;
135
+ constructor(message: string, field?: string, requestId?: string | null);
136
+ }
137
+ declare class PalveronCircuitOpenError extends PalveronError {
138
+ constructor();
139
+ }
140
+ declare class PalveronTimeoutError extends PalveronError {
141
+ constructor(timeoutMs: number, requestId?: string | null);
142
+ }
143
+ declare class Palveron {
144
+ private readonly config;
145
+ private readonly circuit;
146
+ constructor(config: PalveronConfig);
147
+ /**
148
+ * Send a governance verification request.
149
+ * This is the primary method — every LLM call should go through this.
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * const result = await palveron.verify({ prompt: 'User input here' });
154
+ * if (result.decision === 'BLOCKED') {
155
+ * throw new Error(result.reason);
156
+ * }
157
+ * ```
158
+ */
159
+ verify(request: VerifyRequest): Promise<VerifyResponse>;
160
+ /**
161
+ * Quick verification for text-only prompts.
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const result = await palveron.check('Is this prompt safe?');
166
+ * console.log(result.decision); // 'ALLOWED'
167
+ * ```
168
+ */
169
+ check(prompt: string): Promise<VerifyResponse>;
170
+ /**
171
+ * Verify a prompt with a file attachment.
172
+ * Reads the file, Base64-encodes it, and sends it with the correct MIME type.
173
+ * Node.js only — use verify() with pre-encoded data in browsers.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const result = await palveron.verifyWithFile(
178
+ * 'Analyze this document',
179
+ * '/path/to/report.pdf'
180
+ * );
181
+ * ```
182
+ */
183
+ verifyWithFile(prompt: string, filePath: string): Promise<VerifyResponse>;
184
+ /**
185
+ * List all active policies for the project.
186
+ */
187
+ listPolicies(env?: string): Promise<PolicyListResponse>;
188
+ /**
189
+ * Check gateway health status.
190
+ */
191
+ health(): Promise<HealthResponse>;
192
+ /**
193
+ * Get SDK and connection diagnostics.
194
+ */
195
+ diagnostics(): {
196
+ sdkVersion: string;
197
+ baseUrl: string;
198
+ timeout: number;
199
+ maxRetries: number;
200
+ circuitState: string;
201
+ };
202
+ private request;
203
+ private backoffDelay;
204
+ private sleep;
205
+ private generateRequestId;
206
+ private inferMimeType;
207
+ }
208
+ /**
209
+ * Create a Palveron client instance.
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * import { createClient } from '@palveron/sdk';
214
+ *
215
+ * const palveron = createClient({
216
+ * apiKey: process.env.PALVERON_API_KEY!,
217
+ * baseUrl: 'https://gateway.acme.corp:8080', // on-prem
218
+ * });
219
+ *
220
+ * const result = await palveron.verify({ prompt: userInput });
221
+ * ```
222
+ */
223
+ declare function createClient(config: PalveronConfig): Palveron;
224
+
225
+ export { type Attachment, type Decision, type Finding, type HealthResponse, Palveron, PalveronAuthenticationError, PalveronCircuitOpenError, type PalveronConfig, PalveronError, type PalveronLogger, PalveronRateLimitError, PalveronTimeoutError, PalveronValidationError, type PolicyListResponse, type RequestContext, type RiskLevel, type Sensitivity, type VerifyRequest, type VerifyResponse, createClient, Palveron as default };
package/dist/index.js ADDED
@@ -0,0 +1,444 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
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
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ Palveron: () => Palveron,
34
+ PalveronAuthenticationError: () => PalveronAuthenticationError,
35
+ PalveronCircuitOpenError: () => PalveronCircuitOpenError,
36
+ PalveronError: () => PalveronError,
37
+ PalveronRateLimitError: () => PalveronRateLimitError,
38
+ PalveronTimeoutError: () => PalveronTimeoutError,
39
+ PalveronValidationError: () => PalveronValidationError,
40
+ createClient: () => createClient,
41
+ default: () => index_default
42
+ });
43
+ module.exports = __toCommonJS(index_exports);
44
+ var PalveronError = class extends Error {
45
+ code;
46
+ statusCode;
47
+ requestId;
48
+ retryable;
49
+ constructor(message, opts) {
50
+ super(message);
51
+ this.name = "PalveronError";
52
+ this.code = opts.code;
53
+ this.statusCode = opts.statusCode;
54
+ this.requestId = opts.requestId ?? null;
55
+ this.retryable = opts.retryable ?? false;
56
+ }
57
+ };
58
+ var PalveronAuthenticationError = class extends PalveronError {
59
+ constructor(message, requestId) {
60
+ super(message, { code: "AUTHENTICATION_FAILED", statusCode: 401, requestId, retryable: false });
61
+ this.name = "PalveronAuthenticationError";
62
+ }
63
+ };
64
+ var PalveronRateLimitError = class extends PalveronError {
65
+ retryAfterMs;
66
+ constructor(message, retryAfterMs, requestId) {
67
+ super(message, { code: "RATE_LIMITED", statusCode: 429, requestId, retryable: true });
68
+ this.name = "PalveronRateLimitError";
69
+ this.retryAfterMs = retryAfterMs;
70
+ }
71
+ };
72
+ var PalveronValidationError = class extends PalveronError {
73
+ field;
74
+ constructor(message, field, requestId) {
75
+ super(message, { code: "VALIDATION_ERROR", statusCode: 400, requestId, retryable: false });
76
+ this.name = "PalveronValidationError";
77
+ this.field = field ?? null;
78
+ }
79
+ };
80
+ var PalveronCircuitOpenError = class extends PalveronError {
81
+ constructor() {
82
+ super("Circuit breaker is open \u2014 too many consecutive failures. Retry later.", {
83
+ code: "CIRCUIT_OPEN",
84
+ statusCode: 503,
85
+ retryable: false
86
+ });
87
+ this.name = "PalveronCircuitOpenError";
88
+ }
89
+ };
90
+ var PalveronTimeoutError = class extends PalveronError {
91
+ constructor(timeoutMs, requestId) {
92
+ super(`Request timed out after ${timeoutMs}ms`, {
93
+ code: "TIMEOUT",
94
+ statusCode: 408,
95
+ requestId,
96
+ retryable: true
97
+ });
98
+ this.name = "PalveronTimeoutError";
99
+ }
100
+ };
101
+ var CircuitBreaker = class {
102
+ constructor(threshold, cooldownMs) {
103
+ this.threshold = threshold;
104
+ this.cooldownMs = cooldownMs;
105
+ }
106
+ threshold;
107
+ cooldownMs;
108
+ failures = 0;
109
+ lastFailure = 0;
110
+ state = "closed";
111
+ canRequest() {
112
+ if (this.state === "closed") return true;
113
+ if (this.state === "open") {
114
+ if (Date.now() - this.lastFailure >= this.cooldownMs) {
115
+ this.state = "half-open";
116
+ return true;
117
+ }
118
+ return false;
119
+ }
120
+ return true;
121
+ }
122
+ onSuccess() {
123
+ this.failures = 0;
124
+ this.state = "closed";
125
+ }
126
+ onFailure() {
127
+ this.failures++;
128
+ this.lastFailure = Date.now();
129
+ if (this.failures >= this.threshold) {
130
+ this.state = "open";
131
+ }
132
+ }
133
+ getState() {
134
+ return this.state;
135
+ }
136
+ };
137
+ var DEFAULT_BASE_URL = "https://gateway.palveron.com";
138
+ var DEFAULT_TIMEOUT = 3e4;
139
+ var DEFAULT_MAX_RETRIES = 3;
140
+ var DEFAULT_RETRY_BASE_DELAY = 500;
141
+ var SDK_VERSION = "1.0.0";
142
+ var Palveron = class {
143
+ config;
144
+ circuit;
145
+ constructor(config) {
146
+ if (!config.apiKey) throw new PalveronValidationError("apiKey is required");
147
+ this.config = {
148
+ apiKey: config.apiKey,
149
+ baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""),
150
+ timeout: config.timeout ?? DEFAULT_TIMEOUT,
151
+ maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,
152
+ retryBaseDelay: config.retryBaseDelay ?? DEFAULT_RETRY_BASE_DELAY,
153
+ logger: config.logger,
154
+ headers: config.headers
155
+ };
156
+ this.circuit = new CircuitBreaker(
157
+ config.circuitBreakerThreshold ?? 5,
158
+ config.circuitBreakerCooldown ?? 3e4
159
+ );
160
+ }
161
+ // ── Core: Verify ────────────────────────────────────────
162
+ /**
163
+ * Send a governance verification request.
164
+ * This is the primary method — every LLM call should go through this.
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const result = await palveron.verify({ prompt: 'User input here' });
169
+ * if (result.decision === 'BLOCKED') {
170
+ * throw new Error(result.reason);
171
+ * }
172
+ * ```
173
+ */
174
+ async verify(request) {
175
+ const body = {
176
+ prompt: request.prompt,
177
+ extracted_text: request.extractedText,
178
+ metadata: request.metadata,
179
+ attachments: request.attachments?.map((a) => ({
180
+ content_type: a.contentType,
181
+ data: a.data,
182
+ filename: a.filename,
183
+ metadata: a.metadata
184
+ })),
185
+ context: request.context ? {
186
+ mcp_server: request.context.mcpServer,
187
+ tool_name: request.context.toolName,
188
+ chain_depth: request.context.chainDepth,
189
+ source_system: request.context.sourceSystem,
190
+ session_id: request.context.sessionId
191
+ } : void 0
192
+ };
193
+ const start = Date.now();
194
+ const raw = await this.request("POST", "/api/v1/verify", body);
195
+ const latency = Date.now() - start;
196
+ return {
197
+ decision: raw.decision ?? "ERROR",
198
+ output: raw.output ?? "",
199
+ reason: raw.reason ?? "",
200
+ traceId: raw.trace_id ?? "",
201
+ integrityHash: raw.integrity_hash ?? "",
202
+ shouldAnchor: raw.should_anchor ?? false,
203
+ flareStatus: raw.flare_status ?? "",
204
+ flareTxHash: raw.flare_tx_hash ?? null,
205
+ contentType: raw.content_type ?? "text",
206
+ findings: raw.findings ?? [],
207
+ latencyMs: latency
208
+ };
209
+ }
210
+ // ── Convenience: Quick verify (string-only) ─────────────
211
+ /**
212
+ * Quick verification for text-only prompts.
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * const result = await palveron.check('Is this prompt safe?');
217
+ * console.log(result.decision); // 'ALLOWED'
218
+ * ```
219
+ */
220
+ async check(prompt) {
221
+ return this.verify({ prompt });
222
+ }
223
+ // ── Convenience: Verify with file ───────────────────────
224
+ /**
225
+ * Verify a prompt with a file attachment.
226
+ * Reads the file, Base64-encodes it, and sends it with the correct MIME type.
227
+ * Node.js only — use verify() with pre-encoded data in browsers.
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * const result = await palveron.verifyWithFile(
232
+ * 'Analyze this document',
233
+ * '/path/to/report.pdf'
234
+ * );
235
+ * ```
236
+ */
237
+ async verifyWithFile(prompt, filePath) {
238
+ const { readFile } = await import("fs/promises");
239
+ const { basename } = await import("path");
240
+ const buffer = await readFile(filePath);
241
+ const base64 = buffer.toString("base64");
242
+ const filename = basename(filePath);
243
+ const contentType = this.inferMimeType(filename);
244
+ return this.verify({
245
+ prompt,
246
+ attachments: [{ contentType, data: base64, filename }]
247
+ });
248
+ }
249
+ // ── Policies ────────────────────────────────────────────
250
+ /**
251
+ * List all active policies for the project.
252
+ */
253
+ async listPolicies(env = "prod") {
254
+ return this.request("GET", `/api/v1/policies?env=${env}`);
255
+ }
256
+ // ── Health ──────────────────────────────────────────────
257
+ /**
258
+ * Check gateway health status.
259
+ */
260
+ async health() {
261
+ return this.request("GET", "/health");
262
+ }
263
+ // ── Diagnostics ─────────────────────────────────────────
264
+ /**
265
+ * Get SDK and connection diagnostics.
266
+ */
267
+ diagnostics() {
268
+ return {
269
+ sdkVersion: SDK_VERSION,
270
+ baseUrl: this.config.baseUrl,
271
+ timeout: this.config.timeout,
272
+ maxRetries: this.config.maxRetries,
273
+ circuitState: this.circuit.getState()
274
+ };
275
+ }
276
+ // ─── Internal: HTTP with retry + circuit breaker ────────
277
+ async request(method, path, body) {
278
+ if (!this.circuit.canRequest()) {
279
+ throw new PalveronCircuitOpenError();
280
+ }
281
+ let lastError = null;
282
+ const maxAttempts = this.config.maxRetries + 1;
283
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
284
+ if (attempt > 0) {
285
+ const delay = this.backoffDelay(attempt);
286
+ this.config.logger?.debug(`Retry attempt ${attempt}/${this.config.maxRetries}`, { delay, path });
287
+ await this.sleep(delay);
288
+ }
289
+ const requestId = this.generateRequestId();
290
+ try {
291
+ const controller = new AbortController();
292
+ const timer = setTimeout(() => controller.abort(), this.config.timeout);
293
+ const headers = {
294
+ "Authorization": `Bearer ${this.config.apiKey}`,
295
+ "Content-Type": "application/json",
296
+ "Accept": "application/json",
297
+ "User-Agent": `palveron-sdk-typescript/${SDK_VERSION}`,
298
+ "X-Request-ID": requestId,
299
+ ...this.config.headers
300
+ };
301
+ const response = await fetch(`${this.config.baseUrl}${path}`, {
302
+ method,
303
+ headers,
304
+ body: body ? JSON.stringify(body) : void 0,
305
+ signal: controller.signal
306
+ });
307
+ clearTimeout(timer);
308
+ const responseRequestId = response.headers.get("x-request-id") ?? requestId;
309
+ if (response.ok) {
310
+ this.circuit.onSuccess();
311
+ return await response.json();
312
+ }
313
+ if (response.status === 401) {
314
+ this.circuit.onSuccess();
315
+ throw new PalveronAuthenticationError(
316
+ "Invalid API key or expired token",
317
+ responseRequestId
318
+ );
319
+ }
320
+ if (response.status === 429) {
321
+ const retryAfter = parseInt(response.headers.get("retry-after") ?? "5", 10) * 1e3;
322
+ throw new PalveronRateLimitError(
323
+ "Rate limit exceeded",
324
+ retryAfter,
325
+ responseRequestId
326
+ );
327
+ }
328
+ if (response.status === 400) {
329
+ const errorBody2 = await response.json().catch(() => ({}));
330
+ throw new PalveronValidationError(
331
+ errorBody2.error ?? "Invalid request",
332
+ errorBody2.field,
333
+ responseRequestId
334
+ );
335
+ }
336
+ if (response.status >= 500) {
337
+ this.circuit.onFailure();
338
+ const errorBody2 = await response.text().catch(() => "");
339
+ lastError = new PalveronError(
340
+ `Server error: ${response.status} ${response.statusText}`,
341
+ { code: "SERVER_ERROR", statusCode: response.status, requestId: responseRequestId, retryable: true }
342
+ );
343
+ this.config.logger?.warn(`Server error on attempt ${attempt + 1}`, {
344
+ status: response.status,
345
+ requestId: responseRequestId,
346
+ body: errorBody2.slice(0, 200)
347
+ });
348
+ continue;
349
+ }
350
+ const errorBody = await response.json().catch(() => ({}));
351
+ throw new PalveronError(
352
+ errorBody.error ?? `HTTP ${response.status}`,
353
+ { code: "CLIENT_ERROR", statusCode: response.status, requestId: responseRequestId, retryable: false }
354
+ );
355
+ } catch (error) {
356
+ if (error instanceof PalveronError && !error.retryable) throw error;
357
+ if (error instanceof DOMException && error.name === "AbortError") {
358
+ this.circuit.onFailure();
359
+ lastError = new PalveronTimeoutError(this.config.timeout, requestId);
360
+ continue;
361
+ }
362
+ if (error instanceof TypeError && error.message.includes("fetch")) {
363
+ this.circuit.onFailure();
364
+ lastError = new PalveronError("Network error \u2014 could not reach gateway", {
365
+ code: "NETWORK_ERROR",
366
+ statusCode: 0,
367
+ requestId,
368
+ retryable: true
369
+ });
370
+ continue;
371
+ }
372
+ if (error instanceof PalveronError) {
373
+ lastError = error;
374
+ continue;
375
+ }
376
+ throw error;
377
+ }
378
+ }
379
+ throw lastError ?? new PalveronError("Max retries exceeded", {
380
+ code: "MAX_RETRIES",
381
+ statusCode: 0,
382
+ retryable: false
383
+ });
384
+ }
385
+ // ─── Helpers ────────────────────────────────────────────
386
+ backoffDelay(attempt) {
387
+ const base = this.config.retryBaseDelay * Math.pow(2, attempt - 1);
388
+ const jitter = base * 0.2 * Math.random();
389
+ return Math.min(base + jitter, 3e4);
390
+ }
391
+ sleep(ms) {
392
+ return new Promise((resolve) => setTimeout(resolve, ms));
393
+ }
394
+ generateRequestId() {
395
+ const ts = Date.now().toString(36);
396
+ const rand = Math.random().toString(36).slice(2, 8);
397
+ return `pv_${ts}_${rand}`;
398
+ }
399
+ inferMimeType(filename) {
400
+ const ext = filename.split(".").pop()?.toLowerCase();
401
+ const map = {
402
+ png: "image/png",
403
+ jpg: "image/jpeg",
404
+ jpeg: "image/jpeg",
405
+ gif: "image/gif",
406
+ webp: "image/webp",
407
+ svg: "image/svg+xml",
408
+ pdf: "application/pdf",
409
+ wav: "audio/wav",
410
+ mp3: "audio/mpeg",
411
+ ogg: "audio/ogg",
412
+ mp4: "video/mp4",
413
+ py: "text/x-python",
414
+ js: "text/javascript",
415
+ ts: "text/typescript",
416
+ rs: "text/x-rust",
417
+ go: "text/x-go",
418
+ java: "text/x-java",
419
+ c: "text/x-c",
420
+ cpp: "text/x-c++",
421
+ txt: "text/plain",
422
+ json: "application/json",
423
+ csv: "text/csv",
424
+ xml: "application/xml"
425
+ };
426
+ return map[ext ?? ""] ?? "application/octet-stream";
427
+ }
428
+ };
429
+ function createClient(config) {
430
+ return new Palveron(config);
431
+ }
432
+ var index_default = Palveron;
433
+ // Annotate the CommonJS export names for ESM import in node:
434
+ 0 && (module.exports = {
435
+ Palveron,
436
+ PalveronAuthenticationError,
437
+ PalveronCircuitOpenError,
438
+ PalveronError,
439
+ PalveronRateLimitError,
440
+ PalveronTimeoutError,
441
+ PalveronValidationError,
442
+ createClient
443
+ });
444
+ //# sourceMappingURL=index.js.map