deepline 0.0.1 → 0.1.1

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.
Files changed (100) hide show
  1. package/README.md +324 -0
  2. package/dist/cli/index.js +6750 -503
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/index.mjs +6735 -512
  5. package/dist/cli/index.mjs.map +1 -1
  6. package/dist/index.d.mts +2349 -32
  7. package/dist/index.d.ts +2349 -32
  8. package/dist/index.js +1631 -82
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +1617 -83
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +3256 -0
  13. package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +710 -0
  14. package/dist/repo/apps/play-runner-workers/src/entry.ts +5070 -0
  15. package/dist/repo/apps/play-runner-workers/src/runtime/README.md +21 -0
  16. package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +177 -0
  17. package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +52 -0
  18. package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +100 -0
  19. package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +184 -0
  20. package/dist/repo/sdk/src/cli/commands/auth.ts +482 -0
  21. package/dist/repo/sdk/src/cli/commands/billing.ts +188 -0
  22. package/dist/repo/sdk/src/cli/commands/csv.ts +123 -0
  23. package/dist/repo/sdk/src/cli/commands/db.ts +119 -0
  24. package/dist/repo/sdk/src/cli/commands/feedback.ts +40 -0
  25. package/dist/repo/sdk/src/cli/commands/org.ts +117 -0
  26. package/dist/repo/sdk/src/cli/commands/play.ts +3200 -0
  27. package/dist/repo/sdk/src/cli/commands/tools.ts +687 -0
  28. package/dist/repo/sdk/src/cli/dataset-stats.ts +341 -0
  29. package/dist/repo/sdk/src/cli/index.ts +138 -0
  30. package/dist/repo/sdk/src/cli/progress.ts +135 -0
  31. package/dist/repo/sdk/src/cli/trace.ts +61 -0
  32. package/dist/repo/sdk/src/cli/utils.ts +145 -0
  33. package/dist/repo/sdk/src/client.ts +1188 -0
  34. package/dist/repo/sdk/src/compat.ts +77 -0
  35. package/dist/repo/sdk/src/config.ts +285 -0
  36. package/dist/repo/sdk/src/errors.ts +125 -0
  37. package/dist/repo/sdk/src/http.ts +391 -0
  38. package/dist/repo/sdk/src/index.ts +139 -0
  39. package/dist/repo/sdk/src/play.ts +1330 -0
  40. package/dist/repo/sdk/src/plays/bundle-play-file.ts +133 -0
  41. package/dist/repo/sdk/src/plays/harness-stub.ts +210 -0
  42. package/dist/repo/sdk/src/plays/local-file-discovery.ts +326 -0
  43. package/dist/repo/sdk/src/tool-output.ts +489 -0
  44. package/dist/repo/sdk/src/types.ts +669 -0
  45. package/dist/repo/sdk/src/version.ts +2 -0
  46. package/dist/repo/sdk/src/worker-play-entry.ts +286 -0
  47. package/dist/repo/shared_libs/observability/node-tracing.ts +129 -0
  48. package/dist/repo/shared_libs/observability/tracing.ts +98 -0
  49. package/dist/repo/shared_libs/play-runtime/backend.ts +139 -0
  50. package/dist/repo/shared_libs/play-runtime/batch-runtime.ts +182 -0
  51. package/dist/repo/shared_libs/play-runtime/batching-types.ts +91 -0
  52. package/dist/repo/shared_libs/play-runtime/context.ts +3999 -0
  53. package/dist/repo/shared_libs/play-runtime/coordinator-headers.ts +78 -0
  54. package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +250 -0
  55. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +713 -0
  56. package/dist/repo/shared_libs/play-runtime/dataset-id.ts +10 -0
  57. package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +304 -0
  58. package/dist/repo/shared_libs/play-runtime/db-session.ts +462 -0
  59. package/dist/repo/shared_libs/play-runtime/dedup-backend.ts +0 -0
  60. package/dist/repo/shared_libs/play-runtime/default-batch-strategies.ts +124 -0
  61. package/dist/repo/shared_libs/play-runtime/execution-plan.ts +262 -0
  62. package/dist/repo/shared_libs/play-runtime/live-events.ts +214 -0
  63. package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +50 -0
  64. package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +114 -0
  65. package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +158 -0
  66. package/dist/repo/shared_libs/play-runtime/profiles.ts +90 -0
  67. package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +172 -0
  68. package/dist/repo/shared_libs/play-runtime/protocol.ts +121 -0
  69. package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +42 -0
  70. package/dist/repo/shared_libs/play-runtime/result-normalization.ts +33 -0
  71. package/dist/repo/shared_libs/play-runtime/runtime-actions.ts +208 -0
  72. package/dist/repo/shared_libs/play-runtime/runtime-api.ts +1873 -0
  73. package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +2 -0
  74. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +201 -0
  75. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +48 -0
  76. package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +84 -0
  77. package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +174 -0
  78. package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +147 -0
  79. package/dist/repo/shared_libs/play-runtime/suspension.ts +68 -0
  80. package/dist/repo/shared_libs/play-runtime/tool-batch-executor.ts +146 -0
  81. package/dist/repo/shared_libs/play-runtime/tool-result.ts +387 -0
  82. package/dist/repo/shared_libs/play-runtime/tracing.ts +31 -0
  83. package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +75 -0
  84. package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +140 -0
  85. package/dist/repo/shared_libs/plays/artifact-transport.ts +14 -0
  86. package/dist/repo/shared_libs/plays/artifact-types.ts +49 -0
  87. package/dist/repo/shared_libs/plays/bundling/index.ts +1346 -0
  88. package/dist/repo/shared_libs/plays/compiler-manifest.ts +186 -0
  89. package/dist/repo/shared_libs/plays/contracts.ts +51 -0
  90. package/dist/repo/shared_libs/plays/dataset.ts +308 -0
  91. package/dist/repo/shared_libs/plays/definition.ts +264 -0
  92. package/dist/repo/shared_libs/plays/file-refs.ts +11 -0
  93. package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +206 -0
  94. package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +164 -0
  95. package/dist/repo/shared_libs/plays/row-identity.ts +302 -0
  96. package/dist/repo/shared_libs/plays/runtime-validation.ts +415 -0
  97. package/dist/repo/shared_libs/plays/static-pipeline.ts +560 -0
  98. package/dist/repo/shared_libs/temporal/constants.ts +39 -0
  99. package/dist/repo/shared_libs/temporal/preview-config.ts +153 -0
  100. package/package.json +14 -12
@@ -0,0 +1,77 @@
1
+ import { SDK_API_CONTRACT, SDK_VERSION } from "./version.js";
2
+
3
+ export type SdkCompatibilityStatus =
4
+ | "current"
5
+ | "update_available"
6
+ | "deprecated"
7
+ | "unsupported";
8
+
9
+ export type SdkCompatibilityResponse = {
10
+ ok: boolean;
11
+ status: SdkCompatibilityStatus;
12
+ current: string | null;
13
+ latest: string;
14
+ minimum_supported: string;
15
+ deprecated_below: string;
16
+ api_contract: string;
17
+ update_available: boolean;
18
+ update_required: boolean;
19
+ message: string;
20
+ update_command: string;
21
+ };
22
+
23
+ const CHECK_TIMEOUT_MS = 2_000;
24
+
25
+ function shouldSkipCompatibilityCheck(): boolean {
26
+ const value = process.env.DEEPLINE_SKIP_SDK_COMPAT_CHECK?.trim().toLowerCase();
27
+ return value === "1" || value === "true" || value === "yes";
28
+ }
29
+
30
+ export async function checkSdkCompatibility(baseUrl: string): Promise<{
31
+ response: SdkCompatibilityResponse | null;
32
+ error: Error | null;
33
+ }> {
34
+ if (shouldSkipCompatibilityCheck()) {
35
+ return { response: null, error: null };
36
+ }
37
+
38
+ const controller = new AbortController();
39
+ const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
40
+ try {
41
+ const url = new URL("/api/v2/sdk/compat", baseUrl);
42
+ url.searchParams.set("version", SDK_VERSION);
43
+ const response = await fetch(url, {
44
+ method: "GET",
45
+ headers: {
46
+ "User-Agent": `deepline-ts-sdk/${SDK_VERSION}`,
47
+ "X-Deepline-SDK-Version": SDK_VERSION,
48
+ "X-Deepline-API-Contract": SDK_API_CONTRACT,
49
+ },
50
+ signal: controller.signal,
51
+ });
52
+ const data = (await response.json().catch(() => null)) as
53
+ | SdkCompatibilityResponse
54
+ | null;
55
+ return { response: data, error: null };
56
+ } catch (error) {
57
+ return {
58
+ response: null,
59
+ error: error instanceof Error ? error : new Error(String(error)),
60
+ };
61
+ } finally {
62
+ clearTimeout(timeout);
63
+ }
64
+ }
65
+
66
+ export async function enforceSdkCompatibility(baseUrl: string): Promise<void> {
67
+ const { response, error } = await checkSdkCompatibility(baseUrl);
68
+ if (error || !response) {
69
+ return;
70
+ }
71
+ if (response.update_required) {
72
+ throw new Error(response.message);
73
+ }
74
+ if (response.status === "deprecated" || response.status === "update_available") {
75
+ process.stderr.write(`${response.message}\n`);
76
+ }
77
+ }
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Configuration resolution for the Deepline SDK.
3
+ *
4
+ * The SDK resolves configuration from multiple sources in a strict priority order,
5
+ * making it zero-config for common setups while allowing full override control.
6
+ *
7
+ * ## Resolution order
8
+ *
9
+ * ### Base URL
10
+ * 1. `options.baseUrl` (explicit constructor argument)
11
+ * 2. `DEEPLINE_ORIGIN_URL` environment variable
12
+ * 3. `DEEPLINE_API_BASE_URL` environment variable
13
+ * 4. Nearest checkout-local `.env.worktree`
14
+ * 5. `DEEPLINE_ORIGIN_URL` from the production host auth file
15
+ * 6. Production fallback: `https://code.deepline.com`
16
+ *
17
+ * ### API Key
18
+ * 1. `options.apiKey` (explicit constructor argument)
19
+ * 2. `DEEPLINE_API_KEY` environment variable
20
+ * 3. `DEEPLINE_API_KEY` from `~/.local/deepline/<host-slug>/.env` (SDK CLI config)
21
+ *
22
+ * If no API key is found from any source, a {@link ConfigError} is thrown.
23
+ *
24
+ * ## CLI env file format
25
+ *
26
+ * The CLI stores credentials in simple `KEY=VALUE` files (one per line).
27
+ * These are created by `deepline auth register`:
28
+ *
29
+ * ```
30
+ * ~/.local/deepline/code-deepline-com/.env # production
31
+ * ~/.local/deepline/localhost-3000/.env # local dev
32
+ * ```
33
+ *
34
+ * @module
35
+ */
36
+ import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
37
+ import { homedir } from 'node:os';
38
+ import { dirname, join, resolve } from 'node:path';
39
+ import type { DeeplineClientOptions, ResolvedConfig } from './types.js';
40
+ import { ConfigError } from './errors.js';
41
+
42
+ /** Production API base URL. */
43
+ const PROD_URL = 'https://code.deepline.com';
44
+
45
+ /** Default request timeout: 60 seconds. */
46
+ const DEFAULT_TIMEOUT = 60_000;
47
+
48
+ /** Default retry count for transient failures. */
49
+ const DEFAULT_MAX_RETRIES = 3;
50
+
51
+ /**
52
+ * Convert a base URL to a filesystem-safe slug for per-host config storage.
53
+ *
54
+ * @param baseUrl - Full URL (e.g. `"http://localhost:3000"`)
55
+ * @returns Slug like `"localhost-3000"` or `"code-deepline-com"`
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * baseUrlSlug('http://localhost:3000') // "localhost-3000"
60
+ * baseUrlSlug('https://code.deepline.com') // "code-deepline-com"
61
+ * baseUrlSlug('https://example.com:8080') // "example-com-8080"
62
+ * ```
63
+ */
64
+ function baseUrlSlug(baseUrl: string): string {
65
+ let url: URL;
66
+ try {
67
+ url = new URL(baseUrl);
68
+ } catch {
69
+ return 'unknown';
70
+ }
71
+ const host = url.hostname || 'unknown';
72
+ const port = url.port ? parseInt(url.port, 10) : null;
73
+ let slug = host.replace(/[^a-zA-Z0-9]/g, '-');
74
+ if (port && port !== 80 && port !== 443) {
75
+ slug = `${slug}-${port}`;
76
+ }
77
+ return slug.toLowerCase().replace(/^-+|-+$/g, '');
78
+ }
79
+
80
+ /**
81
+ * Parse a simple `KEY=VALUE` env file. Handles `#` comments and quoted values.
82
+ *
83
+ * @param filePath - Absolute path to the env file
84
+ * @returns Key-value pairs; empty object if file doesn't exist
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * // File: DEEPLINE_API_KEY="dl_test_abc123"
89
+ * const env = parseEnvFile('/path/to/.env');
90
+ * console.log(env.DEEPLINE_API_KEY); // "dl_test_abc123"
91
+ * ```
92
+ */
93
+ function parseEnvFile(filePath: string): Record<string, string> {
94
+ if (!existsSync(filePath)) return {};
95
+ const env: Record<string, string> = {};
96
+ const content = readFileSync(filePath, 'utf-8');
97
+ for (const line of content.split(/\r?\n/)) {
98
+ const trimmed = line.trim();
99
+ if (!trimmed || trimmed.startsWith('#')) continue;
100
+ const eqIndex = trimmed.indexOf('=');
101
+ if (eqIndex < 0) continue;
102
+ const key = trimmed.slice(0, eqIndex).trim();
103
+ let value = trimmed.slice(eqIndex + 1).trim();
104
+ // Strip surrounding quotes
105
+ if (
106
+ value.length >= 2 &&
107
+ ((value.startsWith('"') && value.endsWith('"')) ||
108
+ (value.startsWith("'") && value.endsWith("'")))
109
+ ) {
110
+ value = value.slice(1, -1);
111
+ }
112
+ if (key && value) {
113
+ env[key] = value;
114
+ }
115
+ }
116
+ return env;
117
+ }
118
+
119
+ function findNearestWorktreeEnv(startDir: string = process.cwd()): Record<string, string> {
120
+ let current = resolve(startDir);
121
+ while (true) {
122
+ const values = parseEnvFile(join(current, '.env.worktree'));
123
+ if (Object.keys(values).length > 0) return values;
124
+ const parent = dirname(current);
125
+ if (parent === current) return {};
126
+ current = parent;
127
+ }
128
+ }
129
+
130
+ function normalizeWorktreeBaseUrl(baseUrl: string, worktreeEnv = findNearestWorktreeEnv()): string {
131
+ const trimmed = baseUrl.trim().replace(/\/$/, '');
132
+ if (!trimmed) return trimmed;
133
+ try {
134
+ const parsed = new URL(trimmed);
135
+ if (parsed.hostname.endsWith('.localhost') && parsed.port === '1355') {
136
+ const port = worktreeEnv.WORKTREE_APP_PORT || worktreeEnv.PORT;
137
+ if (port) return `${parsed.protocol}//localhost:${port}`;
138
+ }
139
+ } catch {}
140
+ return trimmed;
141
+ }
142
+
143
+ function resolveWorktreeBaseUrl(): string {
144
+ const worktreeEnv = findNearestWorktreeEnv();
145
+ const declared =
146
+ worktreeEnv.DEEPLINE_API_BASE_URL ||
147
+ worktreeEnv.WORKTREE_PUBLIC_APP_URL ||
148
+ worktreeEnv.APP_URL ||
149
+ '';
150
+ if (declared) return normalizeWorktreeBaseUrl(declared, worktreeEnv);
151
+ const port = worktreeEnv.WORKTREE_APP_PORT || worktreeEnv.PORT || '';
152
+ return port ? `http://localhost:${port}` : '';
153
+ }
154
+
155
+ /**
156
+ * Load the SDK CLI env file for a specific Deepline host.
157
+ *
158
+ * @returns Key-value pairs from `~/.local/deepline/<host-slug>/.env`
159
+ */
160
+ function sdkCliEnvFilePath(baseUrl: string): string {
161
+ const home = process.env.HOME?.trim() || homedir();
162
+ return join(home, '.local', 'deepline', baseUrlSlug(baseUrl || PROD_URL), '.env');
163
+ }
164
+
165
+ function loadCliEnv(baseUrl = PROD_URL): Record<string, string> {
166
+ const envPath = sdkCliEnvFilePath(baseUrl);
167
+ return parseEnvFile(envPath);
168
+ }
169
+
170
+ export function hostEnvFilePath(baseUrl: string): string {
171
+ return sdkCliEnvFilePath(baseUrl);
172
+ }
173
+
174
+ export function saveHostEnvValues(baseUrl: string, values: Record<string, string>): void {
175
+ const filePath = sdkCliEnvFilePath(baseUrl);
176
+ const dir = dirname(filePath);
177
+ if (!existsSync(dir)) {
178
+ mkdirSync(dir, { recursive: true });
179
+ }
180
+
181
+ const existing = existsSync(filePath) ? parseEnvFile(filePath) : {};
182
+ const merged = { ...existing, ...values };
183
+ const lines = Object.entries(merged)
184
+ .filter(([, value]) => value !== '')
185
+ .map(([key, value]) => `${key}=${value}`);
186
+ writeFileSync(filePath, `${lines.join('\n')}\n`, 'utf-8');
187
+ }
188
+
189
+ /**
190
+ * Load the production SDK CLI env file.
191
+ *
192
+ * This gives `deepline` a stable production default without sharing credentials
193
+ * with local/worktree hosts.
194
+ */
195
+ function loadGlobalCliEnv(): Record<string, string> {
196
+ return loadCliEnv(PROD_URL);
197
+ }
198
+
199
+ /**
200
+ * Check if a URL points to a local development server.
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * isLocalhost('http://localhost:3000') // true
205
+ * isLocalhost('http://127.0.0.1:3000') // true
206
+ * isLocalhost('https://code.deepline.com') // false
207
+ * ```
208
+ */
209
+ /**
210
+ * Auto-detect the best base URL when none is explicitly provided.
211
+ *
212
+ * Checks environment variables first, then checkout-local worktree config,
213
+ * then SDK CLI config, before falling back to production.
214
+ */
215
+ function autoDetectBaseUrl(): string {
216
+ const envOrigin = process.env.DEEPLINE_ORIGIN_URL?.trim();
217
+ if (envOrigin) return normalizeWorktreeBaseUrl(envOrigin);
218
+
219
+ const envBase = process.env.DEEPLINE_API_BASE_URL?.trim();
220
+ if (envBase) return normalizeWorktreeBaseUrl(envBase);
221
+
222
+ const worktreeBaseUrl = resolveWorktreeBaseUrl();
223
+ if (worktreeBaseUrl) return worktreeBaseUrl;
224
+
225
+ const globalEnv = loadGlobalCliEnv();
226
+ const globalOrigin = globalEnv.DEEPLINE_ORIGIN_URL?.trim();
227
+ if (globalOrigin) return normalizeWorktreeBaseUrl(globalOrigin);
228
+
229
+ return PROD_URL;
230
+ }
231
+
232
+ /**
233
+ * Resolve SDK configuration from all available sources.
234
+ *
235
+ * Merges explicit options, environment variables, and CLI-managed config files
236
+ * into a fully validated {@link ResolvedConfig}. See the module-level docs for
237
+ * the complete resolution order.
238
+ *
239
+ * @param options - Optional overrides (highest priority)
240
+ * @returns Fully resolved configuration with all fields populated
241
+ * @throws {@link ConfigError} if no API key can be found from any source
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * import { resolveConfig } from 'deepline';
246
+ *
247
+ * // Auto-resolve everything:
248
+ * const config = resolveConfig();
249
+ * console.log(config.baseUrl); // "http://localhost:3000" or "https://code.deepline.com"
250
+ *
251
+ * // Override specific values:
252
+ * const config2 = resolveConfig({ baseUrl: 'http://localhost:4000', timeout: 10_000 });
253
+ * ```
254
+ */
255
+ export function resolveConfig(options?: DeeplineClientOptions): ResolvedConfig {
256
+ // Resolve base URL
257
+ const requestedBaseUrl =
258
+ options?.baseUrl?.trim() ||
259
+ autoDetectBaseUrl();
260
+ const baseUrl = normalizeWorktreeBaseUrl(requestedBaseUrl);
261
+
262
+ const cliEnv = loadCliEnv(baseUrl);
263
+
264
+ // Resolve API key: option > env var > SDK CLI env
265
+ const apiKey =
266
+ options?.apiKey?.trim() ||
267
+ process.env.DEEPLINE_API_KEY?.trim() ||
268
+ cliEnv.DEEPLINE_API_KEY ||
269
+ '';
270
+
271
+ if (!apiKey) {
272
+ throw new ConfigError(
273
+ `No API key found. Set DEEPLINE_API_KEY env var, pass apiKey option, or run: deepline auth register`,
274
+ );
275
+ }
276
+
277
+ return {
278
+ apiKey,
279
+ baseUrl,
280
+ timeout: options?.timeout ?? DEFAULT_TIMEOUT,
281
+ maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES,
282
+ };
283
+ }
284
+
285
+ export { baseUrlSlug, loadCliEnv, loadGlobalCliEnv, parseEnvFile, autoDetectBaseUrl, PROD_URL };
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Base error class for all Deepline SDK errors.
3
+ *
4
+ * Every error thrown by the SDK extends this class, so you can catch all
5
+ * Deepline-specific errors with a single `catch (e) { if (e instanceof DeeplineError) }`.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { DeeplineClient, DeeplineError, AuthError } from 'deepline';
10
+ *
11
+ * const client = new DeeplineClient();
12
+ * try {
13
+ * await client.executeTool('apollo_people_search', { query: 'cto' });
14
+ * } catch (err) {
15
+ * if (err instanceof AuthError) {
16
+ * console.error('Bad API key — run: deepline auth register');
17
+ * } else if (err instanceof DeeplineError) {
18
+ * console.error(`API error ${err.statusCode}: ${err.message}`);
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export class DeeplineError extends Error {
24
+ constructor(
25
+ message: string,
26
+ /** HTTP status code from the API response, if applicable. */
27
+ public statusCode?: number,
28
+ /** Machine-readable error code (e.g. `'AUTH_ERROR'`, `'RATE_LIMIT'`, `'CONFIG_ERROR'`). */
29
+ public code?: string,
30
+ /** Additional context from the API response body. */
31
+ public details?: Record<string, unknown>,
32
+ ) {
33
+ super(message);
34
+ this.name = 'DeeplineError';
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Thrown when the API rejects the request due to an invalid or missing API key.
40
+ *
41
+ * This maps to HTTP 401/403 responses. The SDK never retries auth errors —
42
+ * they fail immediately.
43
+ *
44
+ * Fix: run `deepline auth register` to obtain a valid key, or pass one via
45
+ * the `apiKey` option or `DEEPLINE_API_KEY` environment variable.
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * import { AuthError } from 'deepline';
50
+ *
51
+ * try {
52
+ * await client.listTools();
53
+ * } catch (err) {
54
+ * if (err instanceof AuthError) {
55
+ * // Redirect user to auth flow
56
+ * }
57
+ * }
58
+ * ```
59
+ */
60
+ export class AuthError extends DeeplineError {
61
+ constructor(message = 'Authentication failed. Check your DEEPLINE_API_KEY.') {
62
+ super(message, 401, 'AUTH_ERROR');
63
+ this.name = 'AuthError';
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Thrown when the API returns HTTP 429 (Too Many Requests).
69
+ *
70
+ * The SDK retries rate-limited requests automatically up to `maxRetries` times
71
+ * with exponential backoff. This error is only thrown when all retries are exhausted.
72
+ *
73
+ * Use {@link RateLimitError.retryAfterMs} to implement your own backoff if needed.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { RateLimitError } from 'deepline';
78
+ *
79
+ * try {
80
+ * await client.executeTool('apollo_people_search', { query: 'cto' });
81
+ * } catch (err) {
82
+ * if (err instanceof RateLimitError) {
83
+ * console.log(`Retry after ${err.retryAfterMs}ms`);
84
+ * await sleep(err.retryAfterMs);
85
+ * // retry...
86
+ * }
87
+ * }
88
+ * ```
89
+ */
90
+ export class RateLimitError extends DeeplineError {
91
+ /** Milliseconds to wait before retrying, from the `Retry-After` response header. Defaults to 5000. */
92
+ public retryAfterMs: number;
93
+
94
+ constructor(retryAfterMs = 5000, message?: string) {
95
+ super(message ?? `Rate limited. Retry after ${retryAfterMs}ms.`, 429, 'RATE_LIMIT');
96
+ this.name = 'RateLimitError';
97
+ this.retryAfterMs = retryAfterMs;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Thrown when the SDK cannot resolve a valid configuration.
103
+ *
104
+ * Most commonly: no API key found in any of the resolution sources
105
+ * (explicit option, environment variable, CLI env files).
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * import { ConfigError } from 'deepline';
110
+ *
111
+ * try {
112
+ * const client = new DeeplineClient();
113
+ * } catch (err) {
114
+ * if (err instanceof ConfigError) {
115
+ * console.error('Run: deepline auth register');
116
+ * }
117
+ * }
118
+ * ```
119
+ */
120
+ export class ConfigError extends DeeplineError {
121
+ constructor(message: string) {
122
+ super(message, undefined, 'CONFIG_ERROR');
123
+ this.name = 'ConfigError';
124
+ }
125
+ }