deepline 0.0.1 → 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/README.md +324 -0
- package/dist/cli/index.js +6592 -503
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +6575 -510
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +2349 -32
- package/dist/index.d.ts +2349 -32
- package/dist/index.js +1631 -82
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1617 -83
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -10
package/dist/index.js
CHANGED
|
@@ -22,11 +22,26 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
AuthError: () => AuthError,
|
|
24
24
|
ConfigError: () => ConfigError,
|
|
25
|
+
Deepline: () => Deepline,
|
|
25
26
|
DeeplineClient: () => DeeplineClient,
|
|
27
|
+
DeeplineContext: () => DeeplineContext,
|
|
26
28
|
DeeplineError: () => DeeplineError,
|
|
27
29
|
PROD_URL: () => PROD_URL,
|
|
28
30
|
RateLimitError: () => RateLimitError,
|
|
29
|
-
|
|
31
|
+
SDK_API_CONTRACT: () => SDK_API_CONTRACT,
|
|
32
|
+
SDK_VERSION: () => SDK_VERSION,
|
|
33
|
+
createToolCallResult: () => createToolCallResult,
|
|
34
|
+
defineInput: () => defineInput,
|
|
35
|
+
definePlay: () => definePlay,
|
|
36
|
+
defineWorkflow: () => defineWorkflow,
|
|
37
|
+
extractSummaryFields: () => extractSummaryFields,
|
|
38
|
+
getDefinedPlayMetadata: () => getDefinedPlayMetadata,
|
|
39
|
+
resolveConfig: () => resolveConfig,
|
|
40
|
+
steps: () => steps,
|
|
41
|
+
tryConvertToList: () => tryConvertToList,
|
|
42
|
+
when: () => when,
|
|
43
|
+
writeCsvOutputFile: () => writeCsvOutputFile,
|
|
44
|
+
writeJsonOutputFile: () => writeJsonOutputFile
|
|
30
45
|
});
|
|
31
46
|
module.exports = __toCommonJS(src_exports);
|
|
32
47
|
|
|
@@ -55,6 +70,7 @@ var AuthError = class extends DeeplineError {
|
|
|
55
70
|
}
|
|
56
71
|
};
|
|
57
72
|
var RateLimitError = class extends DeeplineError {
|
|
73
|
+
/** Milliseconds to wait before retrying, from the `Retry-After` response header. Defaults to 5000. */
|
|
58
74
|
retryAfterMs;
|
|
59
75
|
constructor(retryAfterMs = 5e3, message) {
|
|
60
76
|
super(message ?? `Rate limited. Retry after ${retryAfterMs}ms.`, 429, "RATE_LIMIT");
|
|
@@ -108,22 +124,62 @@ function parseEnvFile(filePath) {
|
|
|
108
124
|
}
|
|
109
125
|
return env;
|
|
110
126
|
}
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
function findNearestWorktreeEnv(startDir = process.cwd()) {
|
|
128
|
+
let current = (0, import_node_path.resolve)(startDir);
|
|
129
|
+
while (true) {
|
|
130
|
+
const values = parseEnvFile((0, import_node_path.join)(current, ".env.worktree"));
|
|
131
|
+
if (Object.keys(values).length > 0) return values;
|
|
132
|
+
const parent = (0, import_node_path.dirname)(current);
|
|
133
|
+
if (parent === current) return {};
|
|
134
|
+
current = parent;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function normalizeWorktreeBaseUrl(baseUrl, worktreeEnv = findNearestWorktreeEnv()) {
|
|
138
|
+
const trimmed = baseUrl.trim().replace(/\/$/, "");
|
|
139
|
+
if (!trimmed) return trimmed;
|
|
140
|
+
try {
|
|
141
|
+
const parsed = new URL(trimmed);
|
|
142
|
+
if (parsed.hostname.endsWith(".localhost") && parsed.port === "1355") {
|
|
143
|
+
const port = worktreeEnv.WORKTREE_APP_PORT || worktreeEnv.PORT;
|
|
144
|
+
if (port) return `${parsed.protocol}//localhost:${port}`;
|
|
145
|
+
}
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
return trimmed;
|
|
149
|
+
}
|
|
150
|
+
function resolveWorktreeBaseUrl() {
|
|
151
|
+
const worktreeEnv = findNearestWorktreeEnv();
|
|
152
|
+
const declared = worktreeEnv.DEEPLINE_API_BASE_URL || worktreeEnv.WORKTREE_PUBLIC_APP_URL || worktreeEnv.APP_URL || "";
|
|
153
|
+
if (declared) return normalizeWorktreeBaseUrl(declared, worktreeEnv);
|
|
154
|
+
const port = worktreeEnv.WORKTREE_APP_PORT || worktreeEnv.PORT || "";
|
|
155
|
+
return port ? `http://localhost:${port}` : "";
|
|
156
|
+
}
|
|
157
|
+
function sdkCliEnvFilePath(baseUrl) {
|
|
158
|
+
const home = process.env.HOME?.trim() || (0, import_node_os.homedir)();
|
|
159
|
+
return (0, import_node_path.join)(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL), ".env");
|
|
160
|
+
}
|
|
161
|
+
function loadCliEnv(baseUrl = PROD_URL) {
|
|
162
|
+
const envPath = sdkCliEnvFilePath(baseUrl);
|
|
114
163
|
return parseEnvFile(envPath);
|
|
115
164
|
}
|
|
165
|
+
function loadGlobalCliEnv() {
|
|
166
|
+
return loadCliEnv(PROD_URL);
|
|
167
|
+
}
|
|
116
168
|
function autoDetectBaseUrl() {
|
|
169
|
+
const envOrigin = process.env.DEEPLINE_ORIGIN_URL?.trim();
|
|
170
|
+
if (envOrigin) return normalizeWorktreeBaseUrl(envOrigin);
|
|
117
171
|
const envBase = process.env.DEEPLINE_API_BASE_URL?.trim();
|
|
118
|
-
if (envBase) return envBase;
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
|
|
172
|
+
if (envBase) return normalizeWorktreeBaseUrl(envBase);
|
|
173
|
+
const worktreeBaseUrl = resolveWorktreeBaseUrl();
|
|
174
|
+
if (worktreeBaseUrl) return worktreeBaseUrl;
|
|
175
|
+
const globalEnv = loadGlobalCliEnv();
|
|
176
|
+
const globalOrigin = globalEnv.DEEPLINE_ORIGIN_URL?.trim();
|
|
177
|
+
if (globalOrigin) return normalizeWorktreeBaseUrl(globalOrigin);
|
|
123
178
|
return PROD_URL;
|
|
124
179
|
}
|
|
125
180
|
function resolveConfig(options) {
|
|
126
|
-
const
|
|
181
|
+
const requestedBaseUrl = options?.baseUrl?.trim() || autoDetectBaseUrl();
|
|
182
|
+
const baseUrl = normalizeWorktreeBaseUrl(requestedBaseUrl);
|
|
127
183
|
const cliEnv = loadCliEnv(baseUrl);
|
|
128
184
|
const apiKey = options?.apiKey?.trim() || process.env.DEEPLINE_API_KEY?.trim() || cliEnv.DEEPLINE_API_KEY || "";
|
|
129
185
|
if (!apiKey) {
|
|
@@ -133,94 +189,214 @@ function resolveConfig(options) {
|
|
|
133
189
|
}
|
|
134
190
|
return {
|
|
135
191
|
apiKey,
|
|
136
|
-
baseUrl
|
|
192
|
+
baseUrl,
|
|
137
193
|
timeout: options?.timeout ?? DEFAULT_TIMEOUT,
|
|
138
194
|
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
|
|
139
195
|
};
|
|
140
196
|
}
|
|
141
197
|
|
|
142
|
-
// src/
|
|
198
|
+
// src/version.ts
|
|
143
199
|
var SDK_VERSION = "0.1.0";
|
|
200
|
+
var SDK_API_CONTRACT = "2026-04-plays-v1";
|
|
201
|
+
|
|
202
|
+
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
203
|
+
var COORDINATOR_URL_OVERRIDE_HEADER = "x-deepline-coordinator-url";
|
|
204
|
+
var WORKER_CALLBACK_URL_OVERRIDE_HEADER = "x-deepline-worker-callback-url";
|
|
205
|
+
|
|
206
|
+
// src/http.ts
|
|
144
207
|
var HttpClient = class {
|
|
145
208
|
constructor(config) {
|
|
146
209
|
this.config = config;
|
|
147
210
|
}
|
|
148
211
|
config;
|
|
149
|
-
|
|
150
|
-
const url = `${this.config.baseUrl}${path}`;
|
|
151
|
-
const method = options?.method ?? "GET";
|
|
212
|
+
authHeaders(extra) {
|
|
152
213
|
const headers = {
|
|
153
214
|
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
154
215
|
"User-Agent": `deepline-ts-sdk/${SDK_VERSION}`,
|
|
155
|
-
|
|
216
|
+
"X-Deepline-SDK-Version": SDK_VERSION,
|
|
217
|
+
"X-Deepline-API-Contract": SDK_API_CONTRACT,
|
|
218
|
+
...extra
|
|
156
219
|
};
|
|
220
|
+
const bypassToken = typeof process !== "undefined" ? process.env?.VERCEL_PROTECTION_BYPASS_TOKEN : void 0;
|
|
221
|
+
if (bypassToken) {
|
|
222
|
+
headers["x-vercel-protection-bypass"] = bypassToken;
|
|
223
|
+
}
|
|
224
|
+
const playArtifactR2Prefix = typeof process !== "undefined" ? process.env?.DEEPLINE_PLAY_ARTIFACT_R2_PREFIX : void 0;
|
|
225
|
+
if (playArtifactR2Prefix) {
|
|
226
|
+
headers["x-deepline-play-artifact-r2-prefix"] = playArtifactR2Prefix;
|
|
227
|
+
}
|
|
228
|
+
const coordinatorUrl = typeof process !== "undefined" ? process.env?.DEEPLINE_COORDINATOR_URL : void 0;
|
|
229
|
+
if (coordinatorUrl?.trim()) {
|
|
230
|
+
headers[COORDINATOR_URL_OVERRIDE_HEADER] = coordinatorUrl.trim();
|
|
231
|
+
}
|
|
232
|
+
const workerCallbackUrl = typeof process !== "undefined" ? process.env?.DEEPLINE_WORKER_CALLBACK_URL : void 0;
|
|
233
|
+
if (workerCallbackUrl?.trim()) {
|
|
234
|
+
headers[WORKER_CALLBACK_URL_OVERRIDE_HEADER] = workerCallbackUrl.trim();
|
|
235
|
+
}
|
|
236
|
+
return headers;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Send an HTTP request with automatic retries and error handling.
|
|
240
|
+
*
|
|
241
|
+
* @typeParam T - Expected response body type
|
|
242
|
+
* @param path - API path (e.g. `"/api/v2/tools"`)
|
|
243
|
+
* @param options - HTTP method, body, headers, and timeout
|
|
244
|
+
* @returns Parsed JSON response body
|
|
245
|
+
* @throws {@link AuthError} on HTTP 401/403 (immediate, no retry)
|
|
246
|
+
* @throws {@link RateLimitError} on HTTP 429 after all retries exhausted
|
|
247
|
+
* @throws {@link DeeplineError} on other API errors or connection failures
|
|
248
|
+
*/
|
|
249
|
+
async request(path, options) {
|
|
250
|
+
const baseUrl = this.config.baseUrl;
|
|
251
|
+
const url = `${baseUrl}${path}`;
|
|
252
|
+
const method = options?.method ?? "GET";
|
|
253
|
+
const headers = this.authHeaders(options?.headers);
|
|
157
254
|
if (options?.body !== void 0) {
|
|
158
255
|
headers["Content-Type"] = "application/json";
|
|
159
256
|
}
|
|
160
257
|
let lastError = null;
|
|
258
|
+
const candidateUrls = buildCandidateUrls(url);
|
|
259
|
+
let retryAfterDelayMs = null;
|
|
161
260
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
162
261
|
if (attempt > 0) {
|
|
163
262
|
const backoffMs = Math.min(1e3 * Math.pow(2, attempt - 1), 3e4);
|
|
164
|
-
|
|
263
|
+
const delayMs = retryAfterDelayMs === null ? backoffMs : Math.max(backoffMs, retryAfterDelayMs);
|
|
264
|
+
retryAfterDelayMs = null;
|
|
265
|
+
await sleep(delayMs);
|
|
165
266
|
}
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
267
|
+
for (const candidateUrl of candidateUrls) {
|
|
268
|
+
const controller = new AbortController();
|
|
269
|
+
const timeoutId = setTimeout(
|
|
270
|
+
() => controller.abort(),
|
|
271
|
+
options?.timeout ?? this.config.timeout
|
|
272
|
+
);
|
|
273
|
+
try {
|
|
274
|
+
const response = await fetch(candidateUrl, {
|
|
275
|
+
method,
|
|
276
|
+
headers,
|
|
277
|
+
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
278
|
+
signal: controller.signal
|
|
279
|
+
});
|
|
280
|
+
clearTimeout(timeoutId);
|
|
281
|
+
if (response.status === 401 || response.status === 403) {
|
|
282
|
+
throw new AuthError();
|
|
283
|
+
}
|
|
284
|
+
if (response.status === 429) {
|
|
285
|
+
const retryAfter = parseRetryAfter(response);
|
|
286
|
+
lastError = new RateLimitError(retryAfter);
|
|
287
|
+
if (attempt < this.config.maxRetries) {
|
|
288
|
+
retryAfterDelayMs = retryAfter;
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
throw lastError;
|
|
292
|
+
}
|
|
293
|
+
const body = await response.text();
|
|
294
|
+
let parsed;
|
|
295
|
+
try {
|
|
296
|
+
parsed = JSON.parse(body);
|
|
297
|
+
} catch {
|
|
298
|
+
parsed = body;
|
|
299
|
+
}
|
|
300
|
+
if (!response.ok) {
|
|
301
|
+
const msg = typeof parsed === "object" && parsed && "error" in parsed ? String(parsed.error) : `HTTP ${response.status}`;
|
|
302
|
+
throw new DeeplineError(msg, response.status, "API_ERROR", {
|
|
303
|
+
response: parsed
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return parsed;
|
|
307
|
+
} catch (error) {
|
|
308
|
+
clearTimeout(timeoutId);
|
|
309
|
+
if (error instanceof AuthError || error instanceof DeeplineError) {
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
if (error instanceof RateLimitError) {
|
|
313
|
+
lastError = error;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (attempt < this.config.maxRetries) continue;
|
|
320
|
+
}
|
|
321
|
+
if (lastError instanceof DeeplineError) {
|
|
322
|
+
throw lastError;
|
|
323
|
+
}
|
|
324
|
+
const errorMessage = lastError?.message ? `Unable to connect to ${baseUrl}. ${lastError.message}` : `Unable to connect to ${baseUrl}. Is the computer able to access the url?`;
|
|
325
|
+
throw new DeeplineError(errorMessage);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Send a GET request.
|
|
329
|
+
*
|
|
330
|
+
* @typeParam T - Expected response body type
|
|
331
|
+
* @param path - API path (e.g. `"/api/v2/tools"`)
|
|
332
|
+
*/
|
|
333
|
+
async get(path) {
|
|
334
|
+
return this.request(path, { method: "GET" });
|
|
335
|
+
}
|
|
336
|
+
async *streamSse(path, options) {
|
|
337
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
338
|
+
const method = options?.method ?? "GET";
|
|
339
|
+
const headers = this.authHeaders({
|
|
340
|
+
Accept: "text/event-stream",
|
|
341
|
+
...options?.headers
|
|
342
|
+
});
|
|
343
|
+
if (options?.body !== void 0) {
|
|
344
|
+
headers["Content-Type"] = "application/json";
|
|
345
|
+
}
|
|
346
|
+
let lastError = null;
|
|
347
|
+
for (const candidateUrl of buildCandidateUrls(url)) {
|
|
171
348
|
try {
|
|
172
|
-
const response = await fetch(
|
|
349
|
+
const response = await fetch(candidateUrl, {
|
|
173
350
|
method,
|
|
174
351
|
headers,
|
|
175
352
|
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
176
|
-
signal:
|
|
353
|
+
signal: options?.signal
|
|
177
354
|
});
|
|
178
|
-
clearTimeout(timeoutId);
|
|
179
355
|
if (response.status === 401 || response.status === 403) {
|
|
180
356
|
throw new AuthError();
|
|
181
357
|
}
|
|
182
|
-
if (response.status === 429) {
|
|
183
|
-
const retryAfter = parseRetryAfter(response);
|
|
184
|
-
lastError = new RateLimitError(retryAfter);
|
|
185
|
-
if (attempt < this.config.maxRetries) continue;
|
|
186
|
-
throw lastError;
|
|
187
|
-
}
|
|
188
|
-
const body = await response.text();
|
|
189
|
-
let parsed;
|
|
190
|
-
try {
|
|
191
|
-
parsed = JSON.parse(body);
|
|
192
|
-
} catch {
|
|
193
|
-
parsed = body;
|
|
194
|
-
}
|
|
195
358
|
if (!response.ok) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
response
|
|
199
|
-
|
|
359
|
+
throw new DeeplineError(
|
|
360
|
+
`HTTP ${response.status}`,
|
|
361
|
+
response.status,
|
|
362
|
+
"API_ERROR"
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
if (!response.body) {
|
|
366
|
+
throw new DeeplineError("SSE response did not include a body.");
|
|
200
367
|
}
|
|
201
|
-
|
|
368
|
+
yield* decodeSseStream(response.body);
|
|
369
|
+
return;
|
|
202
370
|
} catch (error) {
|
|
203
|
-
clearTimeout(timeoutId);
|
|
204
371
|
if (error instanceof AuthError || error instanceof DeeplineError) {
|
|
205
372
|
throw error;
|
|
206
373
|
}
|
|
207
|
-
if (error instanceof RateLimitError) {
|
|
208
|
-
lastError = error;
|
|
209
|
-
if (attempt < this.config.maxRetries) continue;
|
|
210
|
-
throw error;
|
|
211
|
-
}
|
|
212
374
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
213
|
-
if (attempt < this.config.maxRetries) continue;
|
|
214
375
|
}
|
|
215
376
|
}
|
|
216
|
-
throw
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return this.request(path, { method: "GET" });
|
|
377
|
+
throw new DeeplineError(
|
|
378
|
+
lastError?.message ? `Unable to stream from ${this.config.baseUrl}. ${lastError.message}` : `Unable to stream from ${this.config.baseUrl}.`
|
|
379
|
+
);
|
|
220
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* Send a POST request with a JSON body.
|
|
383
|
+
*
|
|
384
|
+
* @typeParam T - Expected response body type
|
|
385
|
+
* @param path - API path
|
|
386
|
+
* @param body - Request body (will be JSON-serialized)
|
|
387
|
+
*/
|
|
221
388
|
async post(path, body) {
|
|
222
389
|
return this.request(path, { method: "POST", body });
|
|
223
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* Send a DELETE request.
|
|
393
|
+
*
|
|
394
|
+
* @typeParam T - Expected response body type
|
|
395
|
+
* @param path - API path
|
|
396
|
+
*/
|
|
397
|
+
async delete(path) {
|
|
398
|
+
return this.request(path, { method: "DELETE" });
|
|
399
|
+
}
|
|
224
400
|
};
|
|
225
401
|
function parseRetryAfter(response) {
|
|
226
402
|
const header = response.headers.get("retry-after");
|
|
@@ -232,27 +408,218 @@ function parseRetryAfter(response) {
|
|
|
232
408
|
}
|
|
233
409
|
return 5e3;
|
|
234
410
|
}
|
|
411
|
+
function buildCandidateUrls(url) {
|
|
412
|
+
try {
|
|
413
|
+
const parsed = new URL(url);
|
|
414
|
+
const candidates = [url];
|
|
415
|
+
if (parsed.hostname === "localhost") {
|
|
416
|
+
const loopback = new URL(url);
|
|
417
|
+
loopback.hostname = "127.0.0.1";
|
|
418
|
+
candidates.push(loopback.toString());
|
|
419
|
+
}
|
|
420
|
+
return [...new Set(candidates)];
|
|
421
|
+
} catch {
|
|
422
|
+
return [url];
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
async function* decodeSseStream(body) {
|
|
426
|
+
const reader = body.getReader();
|
|
427
|
+
const decoder = new TextDecoder();
|
|
428
|
+
let buffered = "";
|
|
429
|
+
try {
|
|
430
|
+
while (true) {
|
|
431
|
+
const { value, done } = await reader.read();
|
|
432
|
+
if (done) break;
|
|
433
|
+
buffered += decoder.decode(value, { stream: true });
|
|
434
|
+
const frames = buffered.split(/\r?\n\r?\n/);
|
|
435
|
+
buffered = frames.pop() ?? "";
|
|
436
|
+
for (const frame of frames) {
|
|
437
|
+
const event2 = decodeSseFrame(frame);
|
|
438
|
+
if (event2) {
|
|
439
|
+
yield event2;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
buffered += decoder.decode();
|
|
444
|
+
const event = decodeSseFrame(buffered);
|
|
445
|
+
if (event) {
|
|
446
|
+
yield event;
|
|
447
|
+
}
|
|
448
|
+
} finally {
|
|
449
|
+
reader.releaseLock();
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function decodeSseFrame(frame) {
|
|
453
|
+
const data = frame.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice("data:".length).trimStart()).join("\n").trim();
|
|
454
|
+
if (!data) {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
const parsed = JSON.parse(data);
|
|
458
|
+
if (!parsed || typeof parsed !== "object" || typeof parsed.cursor !== "string" || typeof parsed.streamId !== "string" || typeof parsed.scope !== "string" || typeof parsed.type !== "string" || typeof parsed.at !== "string") {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
return parsed;
|
|
462
|
+
}
|
|
235
463
|
function sleep(ms) {
|
|
236
|
-
return new Promise((
|
|
464
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
237
465
|
}
|
|
238
466
|
|
|
239
467
|
// src/client.ts
|
|
468
|
+
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
469
|
+
function normalizePlayStatus(raw) {
|
|
470
|
+
const status = typeof raw.status === "string" ? raw.status : typeof raw.temporalStatus === "string" ? mapLegacyTemporalStatus(raw.temporalStatus) : "running";
|
|
471
|
+
const runId = typeof raw.runId === "string" ? raw.runId : typeof raw.workflowId === "string" ? raw.workflowId : "";
|
|
472
|
+
return {
|
|
473
|
+
...raw,
|
|
474
|
+
runId,
|
|
475
|
+
status
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
function mapLegacyTemporalStatus(status) {
|
|
479
|
+
switch (status.trim().toUpperCase()) {
|
|
480
|
+
case "PENDING":
|
|
481
|
+
return "queued";
|
|
482
|
+
case "COMPLETED":
|
|
483
|
+
return "completed";
|
|
484
|
+
case "FAILED":
|
|
485
|
+
return "failed";
|
|
486
|
+
case "CANCELLED":
|
|
487
|
+
case "TERMINATED":
|
|
488
|
+
case "TIMED_OUT":
|
|
489
|
+
return "cancelled";
|
|
490
|
+
case "RUNNING":
|
|
491
|
+
default:
|
|
492
|
+
return "running";
|
|
493
|
+
}
|
|
494
|
+
}
|
|
240
495
|
var DeeplineClient = class {
|
|
241
496
|
http;
|
|
242
497
|
config;
|
|
498
|
+
/**
|
|
499
|
+
* @param options - Optional overrides for API key, base URL, timeout, and retries.
|
|
500
|
+
* @throws {@link ConfigError} if no API key can be resolved from any source.
|
|
501
|
+
*/
|
|
243
502
|
constructor(options) {
|
|
244
503
|
this.config = resolveConfig(options);
|
|
245
504
|
this.http = new HttpClient(this.config);
|
|
246
505
|
}
|
|
506
|
+
/** The resolved base URL this client is targeting (e.g. `"http://localhost:3000"`). */
|
|
247
507
|
get baseUrl() {
|
|
248
508
|
return this.config.baseUrl;
|
|
249
509
|
}
|
|
250
|
-
|
|
510
|
+
compactSchema(schema) {
|
|
511
|
+
if (!schema) return null;
|
|
512
|
+
const fields = Array.isArray(schema.fields) ? schema.fields.map(
|
|
513
|
+
(field) => field && typeof field === "object" ? {
|
|
514
|
+
name: String(field.name ?? ""),
|
|
515
|
+
type: field.type ?? void 0,
|
|
516
|
+
required: field.required ?? void 0
|
|
517
|
+
} : null
|
|
518
|
+
).filter((field) => Boolean(field?.name)) : [];
|
|
519
|
+
return fields.length > 0 ? { fields } : schema;
|
|
520
|
+
}
|
|
521
|
+
playRunCommand(name) {
|
|
522
|
+
return `deepline plays run ${name} --input '{...}' --watch`;
|
|
523
|
+
}
|
|
524
|
+
summarizePlayListItem(play, options) {
|
|
525
|
+
const aliases = play.aliases?.length ? play.aliases : [play.name];
|
|
526
|
+
const runCommand = this.playRunCommand(play.name);
|
|
527
|
+
return {
|
|
528
|
+
name: play.name,
|
|
529
|
+
...play.reference ? { reference: play.reference } : {},
|
|
530
|
+
...play.displayName ? { displayName: play.displayName } : {},
|
|
531
|
+
origin: play.origin,
|
|
532
|
+
ownerType: play.ownerType,
|
|
533
|
+
canEdit: play.canEdit,
|
|
534
|
+
canClone: play.canClone,
|
|
535
|
+
aliases,
|
|
536
|
+
inputSchema: options?.compact ? this.compactSchema(play.inputSchema) : play.inputSchema ?? null,
|
|
537
|
+
outputSchema: options?.compact ? this.compactSchema(play.outputSchema) : play.outputSchema ?? null,
|
|
538
|
+
runCommand,
|
|
539
|
+
examples: [runCommand],
|
|
540
|
+
currentPublishedVersion: play.currentPublishedVersion ?? null,
|
|
541
|
+
isDraftDirty: play.isDraftDirty
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
summarizePlayDetail(detail, options) {
|
|
545
|
+
const play = detail.play;
|
|
546
|
+
return {
|
|
547
|
+
...this.summarizePlayListItem(play, options),
|
|
548
|
+
currentPublishedVersion: play.currentPublishedVersion ?? play.liveRevision?.version ?? null,
|
|
549
|
+
latestRunId: play.latestRunId ?? detail.latestRuns[0]?.workflowId ?? null
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
// ——————————————————————————————————————————————————————————
|
|
553
|
+
// Tools
|
|
554
|
+
// ——————————————————————————————————————————————————————————
|
|
555
|
+
/**
|
|
556
|
+
* List all available tools.
|
|
557
|
+
*
|
|
558
|
+
* Returns tool definitions including ID, provider, description, input/output schemas,
|
|
559
|
+
* and list extractor paths for automatic CSV conversion.
|
|
560
|
+
*
|
|
561
|
+
* @returns Array of tool definitions
|
|
562
|
+
*
|
|
563
|
+
* @example
|
|
564
|
+
* ```typescript
|
|
565
|
+
* const tools = await client.listTools();
|
|
566
|
+
* const searchTools = tools.filter(t => t.categories.includes('search'));
|
|
567
|
+
* console.log(`Found ${searchTools.length} search tools`);
|
|
568
|
+
* ```
|
|
569
|
+
*/
|
|
251
570
|
async listTools() {
|
|
252
|
-
const res = await this.http.get(
|
|
571
|
+
const res = await this.http.get(
|
|
572
|
+
"/api/v2/tools"
|
|
573
|
+
);
|
|
253
574
|
return res.tools;
|
|
254
575
|
}
|
|
255
|
-
/**
|
|
576
|
+
/**
|
|
577
|
+
* Get detailed metadata for a single tool.
|
|
578
|
+
*
|
|
579
|
+
* Returns everything from {@link ToolDefinition} plus pricing info, sample
|
|
580
|
+
* inputs/outputs, failure modes, and cost estimates.
|
|
581
|
+
*
|
|
582
|
+
* @param toolId - Tool identifier (e.g. `"apollo_people_search"`)
|
|
583
|
+
* @returns Full tool metadata
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```typescript
|
|
587
|
+
* const meta = await client.getTool('apollo_people_search');
|
|
588
|
+
* console.log(`Cost: ${meta.estimatedCreditsRange} credits`);
|
|
589
|
+
* console.log(`Input schema:`, meta.inputSchema);
|
|
590
|
+
* ```
|
|
591
|
+
*/
|
|
592
|
+
async getTool(toolId) {
|
|
593
|
+
return this.http.request(
|
|
594
|
+
`/api/v2/integrations/${encodeURIComponent(toolId)}/get`,
|
|
595
|
+
{
|
|
596
|
+
method: "GET",
|
|
597
|
+
headers: {
|
|
598
|
+
"x-deepline-tool-meta-only": "1"
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Execute a tool and return the extracted result.
|
|
605
|
+
*
|
|
606
|
+
* Sends the input payload to the tool and returns the `.result` field from the
|
|
607
|
+
* response. For the full response envelope (including job_id, credits, etc.),
|
|
608
|
+
* use {@link executeToolRaw}.
|
|
609
|
+
*
|
|
610
|
+
* @param toolId - Tool identifier (e.g. `"test_company_search"`)
|
|
611
|
+
* @param input - Tool-specific input parameters
|
|
612
|
+
* @returns The tool's output (shape varies by tool)
|
|
613
|
+
* @throws {@link DeeplineError} if the tool execution fails
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* ```typescript
|
|
617
|
+
* const company = await client.executeTool('test_company_search', {
|
|
618
|
+
* domain: 'stripe.com',
|
|
619
|
+
* });
|
|
620
|
+
* console.log(company); // { name: "Stripe", industry: "Financial Services", ... }
|
|
621
|
+
* ```
|
|
622
|
+
*/
|
|
256
623
|
async executeTool(toolId, input) {
|
|
257
624
|
const res = await this.http.post(
|
|
258
625
|
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
@@ -261,38 +628,602 @@ var DeeplineClient = class {
|
|
|
261
628
|
return res.result ?? res;
|
|
262
629
|
}
|
|
263
630
|
/**
|
|
264
|
-
*
|
|
265
|
-
*
|
|
631
|
+
* Execute a tool and return the full response envelope.
|
|
632
|
+
*
|
|
633
|
+
* Unlike {@link executeTool}, this returns the complete API response including
|
|
634
|
+
* `job_id`, `status`, `credits`, and the raw `result` object.
|
|
635
|
+
*
|
|
636
|
+
* @param toolId - Tool identifier
|
|
637
|
+
* @param input - Tool-specific input parameters
|
|
638
|
+
* @returns Full response with job metadata and result
|
|
639
|
+
*
|
|
640
|
+
* @example
|
|
641
|
+
* ```typescript
|
|
642
|
+
* const raw = await client.executeToolRaw('test_company_search', { domain: 'stripe.com' });
|
|
643
|
+
* console.log(`Job: ${raw.job_id}, Credits: ${raw.credits}`);
|
|
644
|
+
* console.log(`Result:`, raw.result);
|
|
645
|
+
* ```
|
|
646
|
+
*/
|
|
647
|
+
async executeToolRaw(toolId, input) {
|
|
648
|
+
return this.http.post(
|
|
649
|
+
`/api/v2/integrations/${encodeURIComponent(toolId)}/execute`,
|
|
650
|
+
{ payload: input }
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
async queryCustomerDb(input) {
|
|
654
|
+
return this.http.post("/api/v2/db/query", {
|
|
655
|
+
sql: input.sql,
|
|
656
|
+
...input.maxRows ? { max_rows: input.maxRows } : {}
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
// ——————————————————————————————————————————————————————————
|
|
660
|
+
// Plays — submission and lifecycle
|
|
661
|
+
// ——————————————————————————————————————————————————————————
|
|
662
|
+
/**
|
|
663
|
+
* Start a play run.
|
|
664
|
+
*
|
|
665
|
+
* Internal/advanced primitive. For normal callers, prefer the public
|
|
666
|
+
* entrypoints: the CLI, {@link Deepline.connect}, {@link submitPlay},
|
|
667
|
+
* or {@link runPlay}.
|
|
668
|
+
*
|
|
669
|
+
* Supported invocation surfaces intentionally share this same run contract:
|
|
670
|
+
* `deepline play run`, repo scripts such as `bun run deepline -- play run`,
|
|
671
|
+
* SDK context calls like `Deepline.connect().play(name).run()`, and direct
|
|
672
|
+
* `POST /api/v2/plays/run` calls all return a workflow/run id. The completed
|
|
673
|
+
* output is always retrievable from `getPlayStatus(runId).result` (or from
|
|
674
|
+
* `PlayJob.get()` for SDK context calls). Execution logs live under
|
|
675
|
+
* `progress.logs`; they are not part of the user output object.
|
|
676
|
+
*
|
|
677
|
+
* @param request - Play run configuration (name, code, input, etc.)
|
|
678
|
+
* @returns Workflow metadata including the `workflowId` for status polling
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* ```typescript
|
|
682
|
+
* // Run a live play by name:
|
|
683
|
+
* const started = await client.startPlayRun({
|
|
684
|
+
* name: 'email-waterfall',
|
|
685
|
+
* input: { linkedin_url: 'https://linkedin.com/in/jdoe', domain: 'acme.com' },
|
|
686
|
+
* });
|
|
687
|
+
* console.log(`Workflow: ${started.workflowId}`);
|
|
688
|
+
*
|
|
689
|
+
* // Run an ad hoc artifact-backed play:
|
|
690
|
+
* const started2 = await client.startPlayRun({
|
|
691
|
+
* artifactStorageKey: 'plays/v1/orgs/acme/plays/my-play/artifacts/playgraph_abc123.json',
|
|
692
|
+
* });
|
|
693
|
+
* ```
|
|
266
694
|
*/
|
|
267
|
-
async
|
|
695
|
+
async startPlayRun(request) {
|
|
268
696
|
return this.http.post("/api/v2/plays/run", {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
697
|
+
...request.name ? { name: request.name } : {},
|
|
698
|
+
...request.revisionId ? { revisionId: request.revisionId } : {},
|
|
699
|
+
...request.artifactStorageKey ? { artifactStorageKey: request.artifactStorageKey } : {},
|
|
700
|
+
...request.sourceCode ? { sourceCode: request.sourceCode } : {},
|
|
701
|
+
..."staticPipeline" in request ? { staticPipeline: request.staticPipeline } : {},
|
|
702
|
+
...request.artifactHash ? { artifactHash: request.artifactHash } : {},
|
|
703
|
+
...request.graphHash ? { graphHash: request.graphHash } : {},
|
|
704
|
+
...request.runtimeArtifact ? { runtimeArtifact: request.runtimeArtifact } : {},
|
|
705
|
+
...request.compilerManifest ? { compilerManifest: request.compilerManifest } : {},
|
|
706
|
+
...request.inputFileUpload ? { inputFileUpload: request.inputFileUpload } : {},
|
|
707
|
+
...request.packagedFileUploads?.length ? { packagedFileUploads: request.packagedFileUploads } : {},
|
|
708
|
+
...request.input ? { input: request.input } : {},
|
|
709
|
+
...request.inputFile ? { inputFile: request.inputFile } : {},
|
|
710
|
+
...request.packagedFiles?.length ? { packagedFiles: request.packagedFiles } : {},
|
|
711
|
+
...request.force ? { force: true } : {},
|
|
712
|
+
...typeof request.waitForCompletionMs === "number" ? { waitForCompletionMs: request.waitForCompletionMs } : {},
|
|
713
|
+
// Profile selection is the API's job, not the CLI's. The server
|
|
714
|
+
// hardcodes workers_edge as the default; tests that want a
|
|
715
|
+
// different profile pass `request.profile` explicitly.
|
|
716
|
+
...request.profile ? { profile: request.profile } : {}
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
async *startPlayRunStream(request, options) {
|
|
720
|
+
const body = {
|
|
721
|
+
...request.name ? { name: request.name } : {},
|
|
722
|
+
...request.revisionId ? { revisionId: request.revisionId } : {},
|
|
723
|
+
...request.artifactStorageKey ? { artifactStorageKey: request.artifactStorageKey } : {},
|
|
724
|
+
...request.sourceCode ? { sourceCode: request.sourceCode } : {},
|
|
725
|
+
..."staticPipeline" in request ? { staticPipeline: request.staticPipeline } : {},
|
|
726
|
+
...request.artifactHash ? { artifactHash: request.artifactHash } : {},
|
|
727
|
+
...request.graphHash ? { graphHash: request.graphHash } : {},
|
|
728
|
+
...request.runtimeArtifact ? { runtimeArtifact: request.runtimeArtifact } : {},
|
|
729
|
+
...request.compilerManifest ? { compilerManifest: request.compilerManifest } : {},
|
|
730
|
+
...request.inputFileUpload ? { inputFileUpload: request.inputFileUpload } : {},
|
|
731
|
+
...request.packagedFileUploads?.length ? { packagedFileUploads: request.packagedFileUploads } : {},
|
|
732
|
+
...request.input ? { input: request.input } : {},
|
|
733
|
+
...request.inputFile ? { inputFile: request.inputFile } : {},
|
|
734
|
+
...request.packagedFiles?.length ? { packagedFiles: request.packagedFiles } : {},
|
|
735
|
+
...request.force ? { force: true } : {},
|
|
736
|
+
...request.profile ? { profile: request.profile } : {}
|
|
737
|
+
};
|
|
738
|
+
for await (const event of this.http.streamSse(
|
|
739
|
+
"/api/v2/plays/run?stream=true",
|
|
740
|
+
{
|
|
741
|
+
method: "POST",
|
|
742
|
+
body,
|
|
743
|
+
signal: options?.signal
|
|
744
|
+
}
|
|
745
|
+
)) {
|
|
746
|
+
if (event.scope === "play") {
|
|
747
|
+
yield event;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Register a bundled play artifact.
|
|
753
|
+
*
|
|
754
|
+
* Internal/advanced primitive used by packaging flows. Public callers should
|
|
755
|
+
* prefer the CLI, {@link submitPlay}, or {@link runPlay}.
|
|
756
|
+
*/
|
|
757
|
+
async registerPlayArtifact(input) {
|
|
758
|
+
const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
|
|
759
|
+
name: input.name,
|
|
760
|
+
sourceCode: input.sourceCode,
|
|
761
|
+
artifact: input.artifact
|
|
762
|
+
});
|
|
763
|
+
return this.http.post("/api/v2/plays/artifacts", {
|
|
764
|
+
...input,
|
|
765
|
+
compilerManifest
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
async registerPlayArtifacts(artifacts) {
|
|
769
|
+
const compiledArtifacts = await Promise.all(
|
|
770
|
+
artifacts.map(async (artifact) => ({
|
|
771
|
+
...artifact,
|
|
772
|
+
compilerManifest: artifact.compilerManifest ?? await this.compilePlayManifest({
|
|
773
|
+
name: artifact.name,
|
|
774
|
+
sourceCode: artifact.sourceCode,
|
|
775
|
+
artifact: artifact.artifact
|
|
776
|
+
})
|
|
777
|
+
}))
|
|
778
|
+
);
|
|
779
|
+
return this.http.post("/api/v2/plays/artifacts", {
|
|
780
|
+
artifacts: compiledArtifacts
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
async compilePlayManifest(input) {
|
|
784
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input);
|
|
785
|
+
return response.compilerManifest;
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Check a bundled play artifact against the server's current play compiler.
|
|
789
|
+
*
|
|
790
|
+
* Unlike {@link registerPlayArtifact}, this does not store the artifact,
|
|
791
|
+
* publish a revision, or start a run. It is the authoritative cloud validation
|
|
792
|
+
* path used by `deepline play check`.
|
|
793
|
+
*/
|
|
794
|
+
async checkPlayArtifact(input) {
|
|
795
|
+
return this.http.post("/api/v2/plays/check", input);
|
|
796
|
+
}
|
|
797
|
+
async startPlayRunFromBundle(input) {
|
|
798
|
+
const compilerManifest = input.compilerManifest ?? await this.compilePlayManifest({
|
|
799
|
+
name: input.name,
|
|
800
|
+
sourceCode: input.sourceCode,
|
|
801
|
+
artifact: input.artifact
|
|
802
|
+
});
|
|
803
|
+
const registeredArtifact = await this.registerPlayArtifact({
|
|
804
|
+
name: input.name,
|
|
805
|
+
sourceCode: input.sourceCode,
|
|
806
|
+
artifact: input.artifact,
|
|
807
|
+
compilerManifest,
|
|
808
|
+
publish: false
|
|
272
809
|
});
|
|
810
|
+
if (!registeredArtifact.artifactStorageKey) {
|
|
811
|
+
throw new Error(
|
|
812
|
+
"registerPlayArtifact did not return an artifactStorageKey."
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
return this.startPlayRun({
|
|
816
|
+
name: input.name,
|
|
817
|
+
artifactStorageKey: registeredArtifact.artifactStorageKey,
|
|
818
|
+
compilerManifest,
|
|
819
|
+
...input.input ? { input: input.input } : {},
|
|
820
|
+
...input.inputFile ? { inputFile: input.inputFile } : {},
|
|
821
|
+
...input.packagedFiles?.length ? { packagedFiles: input.packagedFiles } : {},
|
|
822
|
+
...input.force ? { force: true } : {}
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Register a bundled play artifact and start a run from the live revision.
|
|
827
|
+
*
|
|
828
|
+
* Convenience wrapper around {@link registerPlayArtifact} plus
|
|
829
|
+
* {@link startPlayRun}. This is the canonical file-backed path used by wrappers.
|
|
830
|
+
* The returned id can be passed to {@link getPlayStatus} to retrieve the same
|
|
831
|
+
* durable `{ result }` object that the CLI prints after `--watch` completes.
|
|
832
|
+
*
|
|
833
|
+
* @param code - Source string fallback; the bundled artifact should be passed in `options.artifact`
|
|
834
|
+
* @param csvPath - Path to input CSV file, or `null`
|
|
835
|
+
* @param name - Play name (extracted from source if omitted)
|
|
836
|
+
* @param options - Additional submission options
|
|
837
|
+
* @returns Workflow metadata with `workflowId`
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* ```typescript
|
|
841
|
+
* const started = await client.submitPlay(
|
|
842
|
+
* originalSource,
|
|
843
|
+
* './leads.csv',
|
|
844
|
+
* 'bulk-enrich',
|
|
845
|
+
* { artifact: bundledArtifact, input: { limit: 100 } },
|
|
846
|
+
* );
|
|
847
|
+
* ```
|
|
848
|
+
*/
|
|
849
|
+
async submitPlay(code, csvPath, name, options) {
|
|
850
|
+
const runtimeInput = options?.input ? { ...options.input } : {};
|
|
851
|
+
if (csvPath) {
|
|
852
|
+
runtimeInput.file = csvPath;
|
|
853
|
+
}
|
|
854
|
+
const sourceCode = options?.sourceCode ?? code;
|
|
855
|
+
const artifact = options?.artifact;
|
|
856
|
+
if (!name?.trim()) {
|
|
857
|
+
throw new Error("submitPlay requires a play name.");
|
|
858
|
+
}
|
|
859
|
+
if (!artifact) {
|
|
860
|
+
throw new Error("submitPlay requires a bundled play artifact.");
|
|
861
|
+
}
|
|
862
|
+
const compilerManifest = options?.compilerManifest ?? await this.compilePlayManifest({
|
|
863
|
+
name,
|
|
864
|
+
sourceCode,
|
|
865
|
+
artifact
|
|
866
|
+
});
|
|
867
|
+
const registeredArtifact = await this.registerPlayArtifact({
|
|
868
|
+
name,
|
|
869
|
+
sourceCode,
|
|
870
|
+
artifact,
|
|
871
|
+
compilerManifest,
|
|
872
|
+
publish: false
|
|
873
|
+
});
|
|
874
|
+
if (!registeredArtifact.artifactStorageKey) {
|
|
875
|
+
throw new Error(
|
|
876
|
+
"registerPlayArtifact did not return an artifactStorageKey."
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
return this.startPlayRun({
|
|
880
|
+
name,
|
|
881
|
+
artifactStorageKey: registeredArtifact.artifactStorageKey,
|
|
882
|
+
sourceCode,
|
|
883
|
+
staticPipeline: registeredArtifact.staticPipeline ?? null,
|
|
884
|
+
artifactHash: typeof artifact.artifactHash === "string" ? artifact.artifactHash : void 0,
|
|
885
|
+
graphHash: typeof artifact.graphHash === "string" ? artifact.graphHash : void 0,
|
|
886
|
+
runtimeArtifact: artifact,
|
|
887
|
+
compilerManifest,
|
|
888
|
+
...Object.keys(runtimeInput).length > 0 ? { input: runtimeInput } : {},
|
|
889
|
+
...options?.inputFile ? { inputFile: options.inputFile } : {},
|
|
890
|
+
...options?.packagedFiles?.length ? { packagedFiles: options.packagedFiles } : {},
|
|
891
|
+
...options?.force ? { force: true } : {}
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Upload files to the staging area for use in play runs.
|
|
896
|
+
*
|
|
897
|
+
* Internal/advanced primitive used by packaging flows. Public callers should
|
|
898
|
+
* prefer the CLI, {@link submitPlay}, or {@link runPlay}.
|
|
899
|
+
*
|
|
900
|
+
* Staged files are referenced by their returned {@link PlayStagedFileRef}
|
|
901
|
+
* in subsequent {@link startPlayRun} calls via `inputFile` or `packagedFiles`.
|
|
902
|
+
*
|
|
903
|
+
* @param files - Array of files to stage (base64-encoded content)
|
|
904
|
+
* @returns Array of staged file references
|
|
905
|
+
*
|
|
906
|
+
* @example
|
|
907
|
+
* ```typescript
|
|
908
|
+
* const staged = await client.stagePlayFiles([{
|
|
909
|
+
* logicalPath: 'data/leads.csv',
|
|
910
|
+
* contentBase64: Buffer.from(csvContent).toString('base64'),
|
|
911
|
+
* contentHash: sha256(csvContent),
|
|
912
|
+
* contentType: 'text/csv',
|
|
913
|
+
* bytes: csvContent.length,
|
|
914
|
+
* }]);
|
|
915
|
+
* // Use staged[0] as inputFile in startPlayRun
|
|
916
|
+
* ```
|
|
917
|
+
*/
|
|
918
|
+
async stagePlayFiles(files) {
|
|
919
|
+
const response = await this.http.post(
|
|
920
|
+
"/api/v2/plays/files/stage",
|
|
921
|
+
{ files }
|
|
922
|
+
);
|
|
923
|
+
return response.files;
|
|
273
924
|
}
|
|
274
|
-
|
|
925
|
+
async resolveStagedPlayFiles(files) {
|
|
926
|
+
return this.http.post("/api/v2/plays/files/stage", { files });
|
|
927
|
+
}
|
|
928
|
+
// ——————————————————————————————————————————————————————————
|
|
929
|
+
// Plays — status and monitoring
|
|
930
|
+
// ——————————————————————————————————————————————————————————
|
|
931
|
+
/**
|
|
932
|
+
* Get the current status of a play execution.
|
|
933
|
+
*
|
|
934
|
+
* Internal/advanced primitive. Public callers should usually prefer
|
|
935
|
+
* {@link runPlay}, {@link PlayJob.get}, or `deepline play run --watch`.
|
|
936
|
+
*
|
|
937
|
+
* Poll this method until `status` reaches a terminal state:
|
|
938
|
+
* `'completed'`, `'failed'`, or `'cancelled'`.
|
|
939
|
+
*
|
|
940
|
+
* @param workflowId - Play-run id from {@link startPlayRun}
|
|
941
|
+
* @returns Current status with progress logs and partial results
|
|
942
|
+
*
|
|
943
|
+
* @example
|
|
944
|
+
* ```typescript
|
|
945
|
+
* const status = await client.getPlayStatus('play-abc123');
|
|
946
|
+
* console.log(`Status: ${status.status}`);
|
|
947
|
+
* console.log(`Logs: ${status.progress?.logs.length ?? 0} lines`);
|
|
948
|
+
* ```
|
|
949
|
+
*/
|
|
275
950
|
async getPlayStatus(workflowId) {
|
|
276
|
-
|
|
951
|
+
const response = await this.http.get(
|
|
952
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}`
|
|
953
|
+
);
|
|
954
|
+
return normalizePlayStatus(response);
|
|
277
955
|
}
|
|
278
|
-
/**
|
|
956
|
+
/**
|
|
957
|
+
* Get the lightweight tail-polling status for a play execution.
|
|
958
|
+
*
|
|
959
|
+
* This is intentionally smaller than {@link getPlayStatus}: it returns the
|
|
960
|
+
* fields needed for CLI log tailing while the run is in flight, without
|
|
961
|
+
* forcing the API to rebuild final result views on every poll. Call
|
|
962
|
+
* {@link getPlayStatus} once after a terminal state for the full result.
|
|
963
|
+
*/
|
|
964
|
+
async getPlayTailStatus(workflowId, options) {
|
|
965
|
+
const params = new URLSearchParams({ mode: "tail" });
|
|
966
|
+
if (typeof options?.afterLogIndex === "number") {
|
|
967
|
+
params.set("afterLogIndex", String(options.afterLogIndex));
|
|
968
|
+
}
|
|
969
|
+
if (typeof options?.waitMs === "number") {
|
|
970
|
+
params.set("waitMs", String(options.waitMs));
|
|
971
|
+
}
|
|
972
|
+
if (options?.terminalOnly) {
|
|
973
|
+
params.set("terminalOnly", "true");
|
|
974
|
+
}
|
|
975
|
+
const response = await this.http.get(
|
|
976
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}?${params.toString()}`
|
|
977
|
+
);
|
|
978
|
+
return normalizePlayStatus(response);
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Stream semantic play-run events using the same SSE feed as the dashboard.
|
|
982
|
+
*
|
|
983
|
+
* Consumers should still keep a polling fallback: SSE is the fast live-update
|
|
984
|
+
* transport, while the status endpoints remain the authoritative recovery path.
|
|
985
|
+
*/
|
|
986
|
+
async *streamPlayRunEvents(workflowId, options) {
|
|
987
|
+
const headers = options?.lastEventId && options.lastEventId.trim() ? { "Last-Event-ID": options.lastEventId.trim() } : void 0;
|
|
988
|
+
const params = new URLSearchParams({ stream: "true" });
|
|
989
|
+
params.set("mode", options?.mode ?? "cli");
|
|
990
|
+
for await (const event of this.http.streamSse(
|
|
991
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}?${params.toString()}`,
|
|
992
|
+
{ signal: options?.signal, headers }
|
|
993
|
+
)) {
|
|
994
|
+
if (event.scope === "play") {
|
|
995
|
+
yield event;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Cancel a running play execution.
|
|
1001
|
+
*
|
|
1002
|
+
* Sends a stop request for the run.
|
|
1003
|
+
*
|
|
1004
|
+
* @param workflowId - Temporal workflow ID to cancel
|
|
1005
|
+
*
|
|
1006
|
+
* @example
|
|
1007
|
+
* ```typescript
|
|
1008
|
+
* await client.cancelPlay('play-abc123');
|
|
1009
|
+
* ```
|
|
1010
|
+
*/
|
|
279
1011
|
async cancelPlay(workflowId) {
|
|
280
|
-
await this.http.request(
|
|
1012
|
+
await this.http.request(
|
|
1013
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}/stop`,
|
|
1014
|
+
{ method: "POST" }
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Stop a running play execution, including open HITL waits.
|
|
1019
|
+
*
|
|
1020
|
+
* @param workflowId - Temporal workflow ID to stop
|
|
1021
|
+
* @param options.reason - Optional audit/debug reason
|
|
1022
|
+
*/
|
|
1023
|
+
async stopPlay(workflowId, options) {
|
|
1024
|
+
return this.http.post(
|
|
1025
|
+
`/api/v2/plays/run/${encodeURIComponent(workflowId)}/stop`,
|
|
1026
|
+
options?.reason ? { reason: options.reason } : {}
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* List recent runs for a named play.
|
|
1031
|
+
*
|
|
1032
|
+
* Returns runs sorted by start time (newest first), including workflow IDs,
|
|
1033
|
+
* status, timestamps, and metadata.
|
|
1034
|
+
*
|
|
1035
|
+
* @param playName - The play name to query
|
|
1036
|
+
* @returns Array of run summaries (empty array if no runs exist)
|
|
1037
|
+
*
|
|
1038
|
+
* @example
|
|
1039
|
+
* ```typescript
|
|
1040
|
+
* const runs = await client.listPlayRuns('email-waterfall');
|
|
1041
|
+
* for (const run of runs) {
|
|
1042
|
+
* console.log(`${run.workflowId}: ${run.status} (${run.executionTime})`);
|
|
1043
|
+
* }
|
|
1044
|
+
* ```
|
|
1045
|
+
*/
|
|
1046
|
+
async listPlayRuns(playName) {
|
|
1047
|
+
const encodedName = encodeURIComponent(playName);
|
|
1048
|
+
const response = await this.http.get(
|
|
1049
|
+
`/api/v2/plays/${encodedName}/runs`
|
|
1050
|
+
);
|
|
1051
|
+
return response.runs ?? [];
|
|
1052
|
+
}
|
|
1053
|
+
async listPlays() {
|
|
1054
|
+
const response = await this.http.get(
|
|
1055
|
+
"/api/v2/plays"
|
|
1056
|
+
);
|
|
1057
|
+
return response.plays ?? [];
|
|
1058
|
+
}
|
|
1059
|
+
async searchPlays(options) {
|
|
1060
|
+
const query = options.query.trim().toLowerCase();
|
|
1061
|
+
const terms = query.split(/\s+/).filter(Boolean);
|
|
1062
|
+
const plays = await this.listPlays();
|
|
1063
|
+
return plays.filter((play) => {
|
|
1064
|
+
if (options.origin && (play.origin ?? "owned") !== options.origin) {
|
|
1065
|
+
return false;
|
|
1066
|
+
}
|
|
1067
|
+
const haystack = [
|
|
1068
|
+
play.name,
|
|
1069
|
+
play.reference,
|
|
1070
|
+
play.displayName,
|
|
1071
|
+
play.origin,
|
|
1072
|
+
...play.aliases ?? [],
|
|
1073
|
+
play.inputSchema ? JSON.stringify(play.inputSchema) : ""
|
|
1074
|
+
].filter(Boolean).join(" ").toLowerCase();
|
|
1075
|
+
return terms.every((term) => haystack.includes(term));
|
|
1076
|
+
}).map((play) => this.summarizePlayListItem(play, options));
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Get the full definition and state of a named play.
|
|
1080
|
+
*
|
|
1081
|
+
* Returns the play's revision state (draft, live), recent runs,
|
|
1082
|
+
* sheet processing summary, and database URL.
|
|
1083
|
+
*
|
|
1084
|
+
* @param name - Play name
|
|
1085
|
+
* @returns Complete play detail
|
|
1086
|
+
*
|
|
1087
|
+
* @example
|
|
1088
|
+
* ```typescript
|
|
1089
|
+
* const detail = await client.getPlay('email-waterfall');
|
|
1090
|
+
* console.log(`Live: v${detail.play.currentPublishedVersion}`);
|
|
1091
|
+
* console.log(`Draft dirty: ${detail.play.isDraftDirty}`);
|
|
1092
|
+
* console.log(`Total runs: ${detail.play.runCount}`);
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
async getPlay(name) {
|
|
1096
|
+
const encodedName = encodeURIComponent(name);
|
|
1097
|
+
return this.http.get(`/api/v2/plays/${encodedName}`);
|
|
1098
|
+
}
|
|
1099
|
+
async describePlay(name, options) {
|
|
1100
|
+
const detail = await this.getPlay(name);
|
|
1101
|
+
return this.summarizePlayDetail(detail, options);
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Clear run history and durable sheet/result data for a play without deleting
|
|
1105
|
+
* the play definition or revisions.
|
|
1106
|
+
*/
|
|
1107
|
+
async clearPlayHistory(name, request = {}) {
|
|
1108
|
+
const encodedName = encodeURIComponent(name);
|
|
1109
|
+
return this.http.post(
|
|
1110
|
+
`/api/v2/plays/${encodedName}/history/clear`,
|
|
1111
|
+
request
|
|
1112
|
+
);
|
|
281
1113
|
}
|
|
282
1114
|
/**
|
|
283
|
-
*
|
|
284
|
-
*
|
|
1115
|
+
* List saved versions for a named play.
|
|
1116
|
+
*
|
|
1117
|
+
* Returns immutable revision snapshots newest-first, including the revision
|
|
1118
|
+
* id needed for exact-version runs and live-version switching.
|
|
1119
|
+
*
|
|
1120
|
+
* @param name - Play name
|
|
1121
|
+
* @returns Version list (newest first)
|
|
1122
|
+
*/
|
|
1123
|
+
async listPlayVersions(name) {
|
|
1124
|
+
const encodedName = encodeURIComponent(name);
|
|
1125
|
+
const response = await this.http.get(
|
|
1126
|
+
`/api/v2/plays/${encodedName}/versions`
|
|
1127
|
+
);
|
|
1128
|
+
return response.versions ?? [];
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Make a play revision live.
|
|
1132
|
+
*
|
|
1133
|
+
* When `revisionId` is omitted, the current working revision becomes live.
|
|
1134
|
+
* The live version is what executes when the play is run by name without
|
|
1135
|
+
* specifying an explicit revision.
|
|
1136
|
+
*
|
|
1137
|
+
* @param name - Play name
|
|
1138
|
+
* @param request - Optional explicit revision to make live
|
|
1139
|
+
* @returns Result with the new live version number
|
|
1140
|
+
*
|
|
1141
|
+
* @example
|
|
1142
|
+
* ```typescript
|
|
1143
|
+
* const result = await client.publishPlayVersion('email-waterfall');
|
|
1144
|
+
* if (result.success) {
|
|
1145
|
+
* console.log(`Live v${result.liveVersion}`);
|
|
1146
|
+
* }
|
|
1147
|
+
* ```
|
|
1148
|
+
*/
|
|
1149
|
+
async publishPlayVersion(name, request = {}) {
|
|
1150
|
+
const encodedName = encodeURIComponent(name);
|
|
1151
|
+
return this.http.post(
|
|
1152
|
+
`/api/v2/plays/${encodedName}/live`,
|
|
1153
|
+
request
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Delete an org-owned play definition, including its revisions, trigger
|
|
1158
|
+
* bindings, and local run records. Deepline prebuilt plays are read-only.
|
|
1159
|
+
*/
|
|
1160
|
+
async deletePlay(name) {
|
|
1161
|
+
const encodedName = encodeURIComponent(name);
|
|
1162
|
+
return this.http.delete(`/api/v2/plays/${encodedName}`);
|
|
1163
|
+
}
|
|
1164
|
+
// ——————————————————————————————————————————————————————————
|
|
1165
|
+
// Plays — high-level orchestration
|
|
1166
|
+
// ——————————————————————————————————————————————————————————
|
|
1167
|
+
/**
|
|
1168
|
+
* Run a play end-to-end: submit, poll until terminal, return result.
|
|
1169
|
+
*
|
|
1170
|
+
* This is the highest-level play execution method. It submits the play,
|
|
1171
|
+
* polls for status updates, and returns a structured result with logs
|
|
1172
|
+
* and timing. Supports cancellation via `AbortSignal`.
|
|
1173
|
+
*
|
|
1174
|
+
* @param code - Source string fallback; pass the bundled artifact in `options.artifact`
|
|
1175
|
+
* @param csvPath - Input CSV path, or `null`
|
|
1176
|
+
* @param name - Play name
|
|
1177
|
+
* @param options - Execution options
|
|
1178
|
+
* @returns Final execution result with success/failure, output, logs, and duration
|
|
1179
|
+
*
|
|
1180
|
+
* @example
|
|
1181
|
+
* ```typescript
|
|
1182
|
+
* const result = await client.runPlay(bundledCode, null, 'my-play', {
|
|
1183
|
+
* input: { domain: 'stripe.com' },
|
|
1184
|
+
* onProgress: (status) => {
|
|
1185
|
+
* const logs = status.progress?.logs ?? [];
|
|
1186
|
+
* console.log(`[${status.status}] ${logs.length} log lines`);
|
|
1187
|
+
* },
|
|
1188
|
+
* pollIntervalMs: 1000,
|
|
1189
|
+
* });
|
|
1190
|
+
*
|
|
1191
|
+
* if (result.success) {
|
|
1192
|
+
* console.log('Output:', result.result);
|
|
1193
|
+
* } else {
|
|
1194
|
+
* console.error(`Failed after ${result.durationMs}ms:`, result.error);
|
|
1195
|
+
* }
|
|
1196
|
+
* ```
|
|
1197
|
+
*
|
|
1198
|
+
* @example Cancellation
|
|
1199
|
+
* ```typescript
|
|
1200
|
+
* const controller = new AbortController();
|
|
1201
|
+
* setTimeout(() => controller.abort(), 30_000); // 30s timeout
|
|
1202
|
+
*
|
|
1203
|
+
* const result = await client.runPlay(code, null, 'slow-play', {
|
|
1204
|
+
* signal: controller.signal,
|
|
1205
|
+
* });
|
|
1206
|
+
* // result.success === false, result.error === 'Cancelled by user'
|
|
1207
|
+
* ```
|
|
285
1208
|
*/
|
|
286
1209
|
async runPlay(code, csvPath, name, options) {
|
|
287
|
-
const { workflowId } = await this.submitPlay(code, csvPath, name
|
|
288
|
-
|
|
1210
|
+
const { workflowId } = await this.submitPlay(code, csvPath, name, {
|
|
1211
|
+
input: options?.input,
|
|
1212
|
+
sourceCode: options?.sourceCode,
|
|
1213
|
+
artifact: options?.artifact,
|
|
1214
|
+
compilerManifest: options?.compilerManifest,
|
|
1215
|
+
inputFile: options?.inputFile,
|
|
1216
|
+
packagedFiles: options?.packagedFiles,
|
|
1217
|
+
force: options?.force
|
|
1218
|
+
});
|
|
1219
|
+
const pollInterval = options?.pollIntervalMs ?? 500;
|
|
289
1220
|
const start = Date.now();
|
|
290
1221
|
while (true) {
|
|
291
1222
|
if (options?.signal?.aborted) {
|
|
292
1223
|
await this.cancelPlay(workflowId);
|
|
293
1224
|
return {
|
|
294
1225
|
success: false,
|
|
295
|
-
workflowId,
|
|
1226
|
+
runId: workflowId,
|
|
296
1227
|
logs: [],
|
|
297
1228
|
durationMs: Date.now() - start,
|
|
298
1229
|
error: "Cancelled by user"
|
|
@@ -300,33 +1231,651 @@ var DeeplineClient = class {
|
|
|
300
1231
|
}
|
|
301
1232
|
const status = await this.getPlayStatus(workflowId);
|
|
302
1233
|
options?.onProgress?.(status);
|
|
303
|
-
|
|
304
|
-
if (terminal.includes(status.temporalStatus)) {
|
|
1234
|
+
if (TERMINAL_PLAY_STATUSES.has(status.status)) {
|
|
305
1235
|
return {
|
|
306
|
-
success: status.
|
|
307
|
-
workflowId,
|
|
1236
|
+
success: status.status === "completed",
|
|
1237
|
+
runId: status.runId || workflowId,
|
|
308
1238
|
result: status.result,
|
|
309
1239
|
logs: status.progress?.logs ?? [],
|
|
310
1240
|
durationMs: Date.now() - start,
|
|
311
|
-
error: status.progress?.error ?? (status.
|
|
1241
|
+
error: status.progress?.error ?? (status.status !== "completed" ? status.status : void 0)
|
|
312
1242
|
};
|
|
313
1243
|
}
|
|
314
|
-
await new Promise((
|
|
1244
|
+
await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
|
|
315
1245
|
}
|
|
316
1246
|
}
|
|
317
|
-
|
|
1247
|
+
// ——————————————————————————————————————————————————————————
|
|
1248
|
+
// Health
|
|
1249
|
+
// ——————————————————————————————————————————————————————————
|
|
1250
|
+
/**
|
|
1251
|
+
* Check API connectivity and server health.
|
|
1252
|
+
*
|
|
1253
|
+
* @returns Health status with API version
|
|
1254
|
+
*
|
|
1255
|
+
* @example
|
|
1256
|
+
* ```typescript
|
|
1257
|
+
* const health = await client.health();
|
|
1258
|
+
* console.log(`API: ${health.status} (${health.version})`);
|
|
1259
|
+
* // { status: "ok", version: "v2" }
|
|
1260
|
+
* ```
|
|
1261
|
+
*/
|
|
318
1262
|
async health() {
|
|
319
|
-
return this.http.get(
|
|
1263
|
+
return this.http.get(
|
|
1264
|
+
"/api/v2/health"
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
// src/tool-output.ts
|
|
1270
|
+
var import_node_fs2 = require("fs");
|
|
1271
|
+
var import_node_os2 = require("os");
|
|
1272
|
+
var import_node_path2 = require("path");
|
|
1273
|
+
function isPlainObject(value) {
|
|
1274
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1275
|
+
}
|
|
1276
|
+
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1277
|
+
var PHONE_KEY_PATTERN = /(^|[_-])(phone|mobile|cell|telephone|tel)([_-]|$)|phone|mobile|telephone/i;
|
|
1278
|
+
function normalizeScalarString(value) {
|
|
1279
|
+
if (typeof value === "string") {
|
|
1280
|
+
const trimmed = value.trim();
|
|
1281
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1282
|
+
}
|
|
1283
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1284
|
+
return String(value);
|
|
1285
|
+
}
|
|
1286
|
+
return null;
|
|
1287
|
+
}
|
|
1288
|
+
function looksLikeEmail(value) {
|
|
1289
|
+
const candidate = normalizeScalarString(value);
|
|
1290
|
+
if (!candidate || !EMAIL_PATTERN.test(candidate)) return null;
|
|
1291
|
+
return candidate;
|
|
1292
|
+
}
|
|
1293
|
+
function looksLikePhone(value) {
|
|
1294
|
+
const candidate = normalizeScalarString(value);
|
|
1295
|
+
if (!candidate) return null;
|
|
1296
|
+
const digits = candidate.replace(/\D/g, "");
|
|
1297
|
+
if (digits.length < 7 || digits.length > 16) return null;
|
|
1298
|
+
return candidate;
|
|
1299
|
+
}
|
|
1300
|
+
function findEmail(value, depth = 0) {
|
|
1301
|
+
if (depth > 6) return null;
|
|
1302
|
+
const direct = looksLikeEmail(value);
|
|
1303
|
+
if (direct) return direct;
|
|
1304
|
+
if (Array.isArray(value)) {
|
|
1305
|
+
for (const entry of value) {
|
|
1306
|
+
const nested = findEmail(entry, depth + 1);
|
|
1307
|
+
if (nested) return nested;
|
|
1308
|
+
}
|
|
1309
|
+
return null;
|
|
1310
|
+
}
|
|
1311
|
+
if (!isPlainObject(value)) return null;
|
|
1312
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1313
|
+
if (/email/i.test(key)) {
|
|
1314
|
+
const keyed = looksLikeEmail(child);
|
|
1315
|
+
if (keyed) return keyed;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
for (const child of Object.values(value)) {
|
|
1319
|
+
const nested = findEmail(child, depth + 1);
|
|
1320
|
+
if (nested) return nested;
|
|
1321
|
+
}
|
|
1322
|
+
return null;
|
|
1323
|
+
}
|
|
1324
|
+
function findPhone(value, depth = 0) {
|
|
1325
|
+
if (depth > 6) return null;
|
|
1326
|
+
if (Array.isArray(value)) {
|
|
1327
|
+
for (const entry of value) {
|
|
1328
|
+
const nested = findPhone(entry, depth + 1);
|
|
1329
|
+
if (nested) return nested;
|
|
1330
|
+
}
|
|
1331
|
+
return null;
|
|
1332
|
+
}
|
|
1333
|
+
if (!isPlainObject(value)) return null;
|
|
1334
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1335
|
+
if (PHONE_KEY_PATTERN.test(key)) {
|
|
1336
|
+
const keyed = looksLikePhone(child);
|
|
1337
|
+
if (keyed) return keyed;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
for (const child of Object.values(value)) {
|
|
1341
|
+
const nested = findPhone(child, depth + 1);
|
|
1342
|
+
if (nested) return nested;
|
|
1343
|
+
}
|
|
1344
|
+
return null;
|
|
1345
|
+
}
|
|
1346
|
+
var DeeplineToolCallResult = class {
|
|
1347
|
+
constructor(value) {
|
|
1348
|
+
this.value = value;
|
|
1349
|
+
}
|
|
1350
|
+
value;
|
|
1351
|
+
getEmail() {
|
|
1352
|
+
return findEmail(this.value);
|
|
1353
|
+
}
|
|
1354
|
+
getPhone() {
|
|
1355
|
+
return findPhone(this.value);
|
|
1356
|
+
}
|
|
1357
|
+
tryList(options) {
|
|
1358
|
+
return tryConvertToList(this.value, options)?.rows ?? null;
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
function createToolCallResult(value) {
|
|
1362
|
+
return new DeeplineToolCallResult(value);
|
|
1363
|
+
}
|
|
1364
|
+
function getByDottedPath(root, dottedPath) {
|
|
1365
|
+
let current = root;
|
|
1366
|
+
for (const segment of String(dottedPath || "").split(".").filter(Boolean)) {
|
|
1367
|
+
if (!isPlainObject(current) || !(segment in current)) {
|
|
1368
|
+
return null;
|
|
1369
|
+
}
|
|
1370
|
+
current = current[segment];
|
|
1371
|
+
}
|
|
1372
|
+
return current;
|
|
1373
|
+
}
|
|
1374
|
+
function normalizeRows(value) {
|
|
1375
|
+
if (!Array.isArray(value)) return null;
|
|
1376
|
+
return value.map((entry) => {
|
|
1377
|
+
if (isPlainObject(entry)) return entry;
|
|
1378
|
+
return { value: entry };
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
function candidateRoots(payload) {
|
|
1382
|
+
const roots = [{ path: null, value: payload }];
|
|
1383
|
+
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
1384
|
+
roots.push({ path: "result", value: payload.result });
|
|
1385
|
+
if (isPlainObject(payload.result.data)) {
|
|
1386
|
+
roots.push({ path: "result.data", value: payload.result.data });
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
return roots;
|
|
1390
|
+
}
|
|
1391
|
+
function findBestArrayCandidate(value, pathPrefix = "", depth = 0) {
|
|
1392
|
+
if (depth > 5) return null;
|
|
1393
|
+
const directRows = normalizeRows(value);
|
|
1394
|
+
const hasObjectRow = directRows?.some((row) => Object.keys(row).some((key) => key !== "value")) ?? false;
|
|
1395
|
+
let best = directRows && directRows.length > 0 && hasObjectRow ? { path: pathPrefix, rows: directRows } : null;
|
|
1396
|
+
if (!isPlainObject(value)) {
|
|
1397
|
+
return best;
|
|
1398
|
+
}
|
|
1399
|
+
for (const [key, child] of Object.entries(value)) {
|
|
1400
|
+
const childPath = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
1401
|
+
const candidate = findBestArrayCandidate(child, childPath, depth + 1);
|
|
1402
|
+
if (!candidate) continue;
|
|
1403
|
+
if (!best || candidate.rows.length > best.rows.length) {
|
|
1404
|
+
best = candidate;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
return best;
|
|
1408
|
+
}
|
|
1409
|
+
function tryConvertToList(payload, options) {
|
|
1410
|
+
const listExtractorPaths = Array.isArray(options?.listExtractorPaths) ? options?.listExtractorPaths.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
|
|
1411
|
+
if (listExtractorPaths.length > 0) {
|
|
1412
|
+
for (const root of candidateRoots(payload)) {
|
|
1413
|
+
for (const extractorPath of listExtractorPaths) {
|
|
1414
|
+
const resolved = getByDottedPath(root.value, extractorPath);
|
|
1415
|
+
const rows = normalizeRows(resolved);
|
|
1416
|
+
if (rows && rows.length > 0) {
|
|
1417
|
+
const sourcePath = root.path ? `${root.path}.${extractorPath}` : extractorPath;
|
|
1418
|
+
return { rows, strategy: "configured_paths", sourcePath };
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
for (const root of candidateRoots(payload)) {
|
|
1424
|
+
const candidate = findBestArrayCandidate(root.value, root.path ?? "");
|
|
1425
|
+
if (!candidate || candidate.rows.length === 0) continue;
|
|
1426
|
+
return {
|
|
1427
|
+
rows: candidate.rows,
|
|
1428
|
+
strategy: "auto_detected",
|
|
1429
|
+
sourcePath: candidate.path || root.path
|
|
1430
|
+
};
|
|
1431
|
+
}
|
|
1432
|
+
return null;
|
|
1433
|
+
}
|
|
1434
|
+
function ensureOutputDir() {
|
|
1435
|
+
const outputDir = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".local", "share", "deepline", "data");
|
|
1436
|
+
(0, import_node_fs2.mkdirSync)(outputDir, { recursive: true });
|
|
1437
|
+
return outputDir;
|
|
1438
|
+
}
|
|
1439
|
+
function writeJsonOutputFile(payload, stem) {
|
|
1440
|
+
const outputDir = ensureOutputDir();
|
|
1441
|
+
const outputPath = (0, import_node_path2.join)(outputDir, `${stem}_${Date.now()}.json`);
|
|
1442
|
+
(0, import_node_fs2.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
1443
|
+
return outputPath;
|
|
1444
|
+
}
|
|
1445
|
+
function writeCsvOutputFile(rows, stem) {
|
|
1446
|
+
const outputDir = ensureOutputDir();
|
|
1447
|
+
const outputPath = (0, import_node_path2.join)(outputDir, `${stem}_${Date.now()}.csv`);
|
|
1448
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1449
|
+
const columns = [];
|
|
1450
|
+
for (const row of rows) {
|
|
1451
|
+
for (const key of Object.keys(row)) {
|
|
1452
|
+
if (!seen.has(key)) {
|
|
1453
|
+
seen.add(key);
|
|
1454
|
+
columns.push(key);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
const escapeCell = (value) => {
|
|
1459
|
+
const normalized = value == null ? "" : typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : JSON.stringify(value);
|
|
1460
|
+
if (/[",\n]/.test(normalized)) {
|
|
1461
|
+
return `"${normalized.replace(/"/g, '""')}"`;
|
|
1462
|
+
}
|
|
1463
|
+
return normalized;
|
|
1464
|
+
};
|
|
1465
|
+
const lines = [];
|
|
1466
|
+
lines.push(columns.map(escapeCell).join(","));
|
|
1467
|
+
for (const row of rows) {
|
|
1468
|
+
lines.push(columns.map((column) => escapeCell(row[column])).join(","));
|
|
1469
|
+
}
|
|
1470
|
+
(0, import_node_fs2.writeFileSync)(outputPath, `${lines.join("\n")}
|
|
1471
|
+
`, "utf-8");
|
|
1472
|
+
const previewRows = rows.slice(0, 5);
|
|
1473
|
+
const previewColumns = columns.slice(0, 5);
|
|
1474
|
+
const preview = [
|
|
1475
|
+
previewColumns.join(","),
|
|
1476
|
+
...previewRows.map((row) => previewColumns.map((column) => escapeCell(row[column])).join(","))
|
|
1477
|
+
].join("\n");
|
|
1478
|
+
return {
|
|
1479
|
+
path: outputPath,
|
|
1480
|
+
rowCount: rows.length,
|
|
1481
|
+
columns,
|
|
1482
|
+
preview
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
function extractSummaryFields(payload) {
|
|
1486
|
+
const candidates = candidateRoots(payload);
|
|
1487
|
+
for (const candidate of candidates) {
|
|
1488
|
+
if (!isPlainObject(candidate.value)) continue;
|
|
1489
|
+
const summaryEntries = Object.entries(candidate.value).filter(([, value]) => {
|
|
1490
|
+
return value == null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
1491
|
+
});
|
|
1492
|
+
if (summaryEntries.length === 0) continue;
|
|
1493
|
+
return Object.fromEntries(summaryEntries);
|
|
1494
|
+
}
|
|
1495
|
+
return {};
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
// src/play.ts
|
|
1499
|
+
var DeeplineConditionalStepResolver = class _DeeplineConditionalStepResolver {
|
|
1500
|
+
constructor(when2, run, elseValue) {
|
|
1501
|
+
this.when = when2;
|
|
1502
|
+
this.run = run;
|
|
1503
|
+
this.elseValue = elseValue;
|
|
1504
|
+
}
|
|
1505
|
+
when;
|
|
1506
|
+
run;
|
|
1507
|
+
elseValue;
|
|
1508
|
+
kind = "conditional";
|
|
1509
|
+
else(value) {
|
|
1510
|
+
return new _DeeplineConditionalStepResolver(this.when, this.run, value);
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
var DeeplineStepProgram = class _DeeplineStepProgram {
|
|
1514
|
+
constructor(steps2, returnResolver) {
|
|
1515
|
+
this.steps = steps2;
|
|
1516
|
+
this.returnResolver = returnResolver;
|
|
1517
|
+
}
|
|
1518
|
+
steps;
|
|
1519
|
+
returnResolver;
|
|
1520
|
+
kind = "steps";
|
|
1521
|
+
step(name, resolver) {
|
|
1522
|
+
if (!name.trim()) {
|
|
1523
|
+
throw new Error(
|
|
1524
|
+
"steps().step(name, ...) requires a non-empty step name."
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
1527
|
+
return new _DeeplineStepProgram(
|
|
1528
|
+
[
|
|
1529
|
+
...this.steps,
|
|
1530
|
+
{
|
|
1531
|
+
name,
|
|
1532
|
+
resolver
|
|
1533
|
+
}
|
|
1534
|
+
],
|
|
1535
|
+
this.returnResolver
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
return(resolver) {
|
|
1539
|
+
return new _DeeplineStepProgram(this.steps, resolver);
|
|
1540
|
+
}
|
|
1541
|
+
};
|
|
1542
|
+
function steps() {
|
|
1543
|
+
return new DeeplineStepProgram([]);
|
|
1544
|
+
}
|
|
1545
|
+
function when(predicate, resolver) {
|
|
1546
|
+
return new DeeplineConditionalStepResolver(predicate, resolver, null);
|
|
1547
|
+
}
|
|
1548
|
+
var PLAY_METADATA_SYMBOL = /* @__PURE__ */ Symbol.for("deepline.play.metadata");
|
|
1549
|
+
var DeeplinePlayJobImpl = class {
|
|
1550
|
+
constructor(client, runId) {
|
|
1551
|
+
this.client = client;
|
|
1552
|
+
this.id = runId;
|
|
1553
|
+
}
|
|
1554
|
+
client;
|
|
1555
|
+
id;
|
|
1556
|
+
async status() {
|
|
1557
|
+
return this.client.getPlayStatus(this.id);
|
|
1558
|
+
}
|
|
1559
|
+
async tail(options) {
|
|
1560
|
+
const intervalMs = options?.intervalMs ?? 500;
|
|
1561
|
+
const onLog = options?.onLog ?? ((line) => console.log(line));
|
|
1562
|
+
const terminalStates = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
1563
|
+
let lastLogIndex = 0;
|
|
1564
|
+
while (true) {
|
|
1565
|
+
const status = await this.status();
|
|
1566
|
+
const logs = status.progress?.logs ?? [];
|
|
1567
|
+
for (let index = lastLogIndex; index < logs.length; index += 1) {
|
|
1568
|
+
onLog(logs[index]);
|
|
1569
|
+
}
|
|
1570
|
+
lastLogIndex = logs.length;
|
|
1571
|
+
if (terminalStates.has(status.status)) {
|
|
1572
|
+
return status;
|
|
1573
|
+
}
|
|
1574
|
+
await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
async get(options) {
|
|
1578
|
+
const intervalMs = options?.intervalMs ?? 500;
|
|
1579
|
+
const terminalStates = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
1580
|
+
while (true) {
|
|
1581
|
+
const status = await this.status();
|
|
1582
|
+
if (terminalStates.has(status.status)) {
|
|
1583
|
+
if (status.status !== "completed") {
|
|
1584
|
+
throw new DeeplineError(
|
|
1585
|
+
status.progress?.error || `Play run ${this.id} ended with ${status.status}.`
|
|
1586
|
+
);
|
|
1587
|
+
}
|
|
1588
|
+
const payload = status.result;
|
|
1589
|
+
return (payload && "output" in payload ? payload.output : status.result) ?? null;
|
|
1590
|
+
}
|
|
1591
|
+
await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
async cancel() {
|
|
1595
|
+
await this.client.cancelPlay(this.id);
|
|
1596
|
+
}
|
|
1597
|
+
async stop(options) {
|
|
1598
|
+
return this.client.stopPlay(this.id, options);
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
function createNamedPlayHandle(clientFactory, name) {
|
|
1602
|
+
return {
|
|
1603
|
+
name,
|
|
1604
|
+
get: () => clientFactory().getPlay(name),
|
|
1605
|
+
runs: () => clientFactory().listPlayRuns(name),
|
|
1606
|
+
versions: () => clientFactory().listPlayVersions(name),
|
|
1607
|
+
publish: (options) => clientFactory().publishPlayVersion(name, options),
|
|
1608
|
+
clearHistory: (options) => clientFactory().clearPlayHistory(name, options),
|
|
1609
|
+
async run(input, options) {
|
|
1610
|
+
const client = clientFactory();
|
|
1611
|
+
const started = await client.startPlayRun({
|
|
1612
|
+
name,
|
|
1613
|
+
...options?.revisionId ? { revisionId: options.revisionId } : {},
|
|
1614
|
+
input
|
|
1615
|
+
});
|
|
1616
|
+
return new DeeplinePlayJobImpl(client, started.workflowId);
|
|
1617
|
+
},
|
|
1618
|
+
async runSync(input, options) {
|
|
1619
|
+
const job = await this.run(input, options);
|
|
1620
|
+
return job.get();
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
var DeeplineContext = class {
|
|
1625
|
+
client;
|
|
1626
|
+
constructor(options) {
|
|
1627
|
+
this.client = new DeeplineClient(options);
|
|
1628
|
+
}
|
|
1629
|
+
/**
|
|
1630
|
+
* Tool operations namespace.
|
|
1631
|
+
*
|
|
1632
|
+
* @example
|
|
1633
|
+
* ```typescript
|
|
1634
|
+
* const tools = await ctx.tools.list();
|
|
1635
|
+
* const meta = await ctx.tools.get('apollo_people_search');
|
|
1636
|
+
* const result = await ctx.tools.execute({
|
|
1637
|
+
* tool: 'test_company_search',
|
|
1638
|
+
* input: { domain: 'stripe.com' },
|
|
1639
|
+
* });
|
|
1640
|
+
* const rows = result.tryList({ listExtractorPaths: ['people'] });
|
|
1641
|
+
* const email = result.getEmail();
|
|
1642
|
+
* ```
|
|
1643
|
+
*/
|
|
1644
|
+
get tools() {
|
|
1645
|
+
return {
|
|
1646
|
+
/** List all available tools. */
|
|
1647
|
+
list: () => this.client.listTools(),
|
|
1648
|
+
/** Get detailed metadata for a tool. */
|
|
1649
|
+
get: (toolId) => this.client.getTool(toolId),
|
|
1650
|
+
/** Execute a tool and return an ergonomic result wrapper. */
|
|
1651
|
+
execute: async (request) => createToolCallResult(
|
|
1652
|
+
await this.client.executeTool(request.tool, request.input)
|
|
1653
|
+
)
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
get plays() {
|
|
1657
|
+
return {
|
|
1658
|
+
list: () => this.client.listPlays(),
|
|
1659
|
+
get: (name) => this.play(name)
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
get prebuilt() {
|
|
1663
|
+
const explicit = {
|
|
1664
|
+
companyToContact: {
|
|
1665
|
+
playName: "prebuilt/company-to-contact",
|
|
1666
|
+
name: "prebuilt/company-to-contact"
|
|
1667
|
+
},
|
|
1668
|
+
personToPhone: {
|
|
1669
|
+
playName: "prebuilt/person-to-phone",
|
|
1670
|
+
name: "prebuilt/person-to-phone"
|
|
1671
|
+
},
|
|
1672
|
+
personToEmail: {
|
|
1673
|
+
playName: "prebuilt/person-to-email",
|
|
1674
|
+
name: "prebuilt/person-to-email"
|
|
1675
|
+
},
|
|
1676
|
+
personLinkedinToEmail: {
|
|
1677
|
+
playName: "prebuilt/person-linkedin-to-email",
|
|
1678
|
+
name: "prebuilt/person-linkedin-to-email"
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
return new Proxy(
|
|
1682
|
+
{},
|
|
1683
|
+
{
|
|
1684
|
+
get: (_target, prop) => {
|
|
1685
|
+
if (typeof prop !== "string") return void 0;
|
|
1686
|
+
if (prop in explicit) {
|
|
1687
|
+
return explicit[prop];
|
|
1688
|
+
}
|
|
1689
|
+
const playName = prop.startsWith("prebuilt/") ? prop : `prebuilt/${prop}`;
|
|
1690
|
+
return {
|
|
1691
|
+
playName,
|
|
1692
|
+
name: playName
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Get a named play handle for remote lifecycle operations.
|
|
1700
|
+
*
|
|
1701
|
+
* @typeParam TInput - Expected input type
|
|
1702
|
+
* @typeParam TOutput - Expected output type
|
|
1703
|
+
* @param name - Play name (as registered on the server)
|
|
1704
|
+
* @returns Named play handle with run, versions, get, publish, etc.
|
|
1705
|
+
*
|
|
1706
|
+
* @example
|
|
1707
|
+
* ```typescript
|
|
1708
|
+
* const play = ctx.play<{ domain: string }>('email-waterfall');
|
|
1709
|
+
* const job = await play.run({ domain: 'stripe.com' });
|
|
1710
|
+
* const result = await job.get();
|
|
1711
|
+
* ```
|
|
1712
|
+
*/
|
|
1713
|
+
play(name) {
|
|
1714
|
+
return createNamedPlayHandle(() => this.client, name);
|
|
1715
|
+
}
|
|
1716
|
+
async runPlay(playOrRef, input) {
|
|
1717
|
+
const name = typeof playOrRef === "string" ? playOrRef : playOrRef.playName ?? playOrRef.name ?? "";
|
|
1718
|
+
return await this.play(name).runSync(input);
|
|
1719
|
+
}
|
|
1720
|
+
};
|
|
1721
|
+
var Deepline = class {
|
|
1722
|
+
/**
|
|
1723
|
+
* Create a connected SDK context.
|
|
1724
|
+
*
|
|
1725
|
+
* Resolves configuration from options, environment variables, and CLI config
|
|
1726
|
+
* files. See {@link resolveConfig} for the resolution order.
|
|
1727
|
+
*
|
|
1728
|
+
* @param options - Optional overrides for API key, base URL, etc.
|
|
1729
|
+
* @returns Ready-to-use SDK context
|
|
1730
|
+
* @throws {@link ConfigError} if no API key can be resolved
|
|
1731
|
+
*
|
|
1732
|
+
* @example
|
|
1733
|
+
* ```typescript
|
|
1734
|
+
* // Auto-config (uses env vars / CLI auth):
|
|
1735
|
+
* const ctx = await Deepline.connect();
|
|
1736
|
+
*
|
|
1737
|
+
* // Explicit config:
|
|
1738
|
+
* const ctx2 = await Deepline.connect({
|
|
1739
|
+
* apiKey: 'dl_test_...',
|
|
1740
|
+
* baseUrl: 'http://localhost:3000',
|
|
1741
|
+
* });
|
|
1742
|
+
* ```
|
|
1743
|
+
*/
|
|
1744
|
+
static async connect(options) {
|
|
1745
|
+
return new DeeplineContext(options);
|
|
320
1746
|
}
|
|
321
1747
|
};
|
|
1748
|
+
function defineInput(schema) {
|
|
1749
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
1750
|
+
throw new Error(
|
|
1751
|
+
"defineInput<T>(schema) requires a JSON-schema-like object."
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
return { schema };
|
|
1755
|
+
}
|
|
1756
|
+
function definePlay(nameOrConfig, maybeFn, maybeBindings) {
|
|
1757
|
+
const config = typeof nameOrConfig === "string" ? {
|
|
1758
|
+
name: nameOrConfig,
|
|
1759
|
+
fn: maybeFn,
|
|
1760
|
+
bindings: maybeBindings,
|
|
1761
|
+
inputSchema: void 0,
|
|
1762
|
+
billing: maybeBindings?.billing
|
|
1763
|
+
} : {
|
|
1764
|
+
name: nameOrConfig.id,
|
|
1765
|
+
fn: nameOrConfig.run,
|
|
1766
|
+
bindings: nameOrConfig.bindings,
|
|
1767
|
+
inputSchema: nameOrConfig.input.schema,
|
|
1768
|
+
billing: nameOrConfig.billing
|
|
1769
|
+
};
|
|
1770
|
+
const name = config.name;
|
|
1771
|
+
const fn = config.fn;
|
|
1772
|
+
const bindings = config.bindings;
|
|
1773
|
+
const billing = config.billing;
|
|
1774
|
+
const inputSchema = config.inputSchema;
|
|
1775
|
+
if (typeof fn !== "function") {
|
|
1776
|
+
throw new Error("definePlay(...) requires an async run function.");
|
|
1777
|
+
}
|
|
1778
|
+
if (name.includes("/")) {
|
|
1779
|
+
throw new Error(
|
|
1780
|
+
'definePlay(name, ...) play names cannot contain "/". Slash is reserved for qualified references like "prebuilt/example" or "self/example".'
|
|
1781
|
+
);
|
|
1782
|
+
}
|
|
1783
|
+
const normalizedName = name.trim().replace(/[^a-z0-9]+/gi, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
1784
|
+
if (!normalizedName) {
|
|
1785
|
+
throw new Error(
|
|
1786
|
+
"definePlay(name, ...) requires a play name with at least one letter or number. Use only letters, numbers, underscores, or hyphens."
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
if (normalizedName.length > 63) {
|
|
1790
|
+
throw new Error(
|
|
1791
|
+
`definePlay("${name}", ...) is too long after normalization (${normalizedName.length}/63). Shorten the play name to 63 characters or fewer. Normalized value: "${normalizedName}".`
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1794
|
+
const metadata = {
|
|
1795
|
+
name,
|
|
1796
|
+
...bindings ? { bindings } : {},
|
|
1797
|
+
...inputSchema ? { inputSchema } : {},
|
|
1798
|
+
...billing ? { billing } : {}
|
|
1799
|
+
};
|
|
1800
|
+
const play = fn;
|
|
1801
|
+
Object.defineProperty(play, PLAY_METADATA_SYMBOL, {
|
|
1802
|
+
value: metadata,
|
|
1803
|
+
enumerable: false,
|
|
1804
|
+
configurable: false,
|
|
1805
|
+
writable: false
|
|
1806
|
+
});
|
|
1807
|
+
Object.defineProperty(play, "playName", {
|
|
1808
|
+
value: name,
|
|
1809
|
+
enumerable: true,
|
|
1810
|
+
configurable: false,
|
|
1811
|
+
writable: false
|
|
1812
|
+
});
|
|
1813
|
+
Object.defineProperty(play, "bindings", {
|
|
1814
|
+
value: bindings,
|
|
1815
|
+
enumerable: true,
|
|
1816
|
+
configurable: false,
|
|
1817
|
+
writable: false
|
|
1818
|
+
});
|
|
1819
|
+
const handle = createNamedPlayHandle(
|
|
1820
|
+
() => new DeeplineClient(),
|
|
1821
|
+
name
|
|
1822
|
+
);
|
|
1823
|
+
for (const key of [
|
|
1824
|
+
"name",
|
|
1825
|
+
"get",
|
|
1826
|
+
"runs",
|
|
1827
|
+
"versions",
|
|
1828
|
+
"publish",
|
|
1829
|
+
"run",
|
|
1830
|
+
"runSync"
|
|
1831
|
+
]) {
|
|
1832
|
+
Object.defineProperty(play, key, {
|
|
1833
|
+
value: handle[key],
|
|
1834
|
+
enumerable: false,
|
|
1835
|
+
configurable: false,
|
|
1836
|
+
writable: false
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
return play;
|
|
1840
|
+
}
|
|
1841
|
+
var defineWorkflow = definePlay;
|
|
1842
|
+
function getDefinedPlayMetadata(value) {
|
|
1843
|
+
if (typeof value !== "function") {
|
|
1844
|
+
return null;
|
|
1845
|
+
}
|
|
1846
|
+
const metadata = value[PLAY_METADATA_SYMBOL];
|
|
1847
|
+
if (!metadata || typeof metadata !== "object") {
|
|
1848
|
+
return null;
|
|
1849
|
+
}
|
|
1850
|
+
const candidate = metadata;
|
|
1851
|
+
if (!candidate.name || typeof candidate.name !== "string") {
|
|
1852
|
+
return null;
|
|
1853
|
+
}
|
|
1854
|
+
return candidate;
|
|
1855
|
+
}
|
|
322
1856
|
// Annotate the CommonJS export names for ESM import in node:
|
|
323
1857
|
0 && (module.exports = {
|
|
324
1858
|
AuthError,
|
|
325
1859
|
ConfigError,
|
|
1860
|
+
Deepline,
|
|
326
1861
|
DeeplineClient,
|
|
1862
|
+
DeeplineContext,
|
|
327
1863
|
DeeplineError,
|
|
328
1864
|
PROD_URL,
|
|
329
1865
|
RateLimitError,
|
|
330
|
-
|
|
1866
|
+
SDK_API_CONTRACT,
|
|
1867
|
+
SDK_VERSION,
|
|
1868
|
+
createToolCallResult,
|
|
1869
|
+
defineInput,
|
|
1870
|
+
definePlay,
|
|
1871
|
+
defineWorkflow,
|
|
1872
|
+
extractSummaryFields,
|
|
1873
|
+
getDefinedPlayMetadata,
|
|
1874
|
+
resolveConfig,
|
|
1875
|
+
steps,
|
|
1876
|
+
tryConvertToList,
|
|
1877
|
+
when,
|
|
1878
|
+
writeCsvOutputFile,
|
|
1879
|
+
writeJsonOutputFile
|
|
331
1880
|
});
|
|
332
1881
|
//# sourceMappingURL=index.js.map
|