deepline 0.2.1 → 0.2.3
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/dist/bundling-sources/sdk/src/client.ts +73 -3
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/observability/scheduled-job-errors.ts +95 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +71 -7
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +23 -0
- package/dist/cli/index.js +140 -7
- package/dist/cli/index.mjs +140 -7
- package/dist/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +41 -5
- package/dist/index.mjs +41 -5
- package/package.json +1 -1
|
@@ -686,6 +686,13 @@ export type MonitorListEntry = {
|
|
|
686
686
|
status?: string;
|
|
687
687
|
tool?: string;
|
|
688
688
|
name?: string;
|
|
689
|
+
configured?: boolean;
|
|
690
|
+
active?: boolean;
|
|
691
|
+
provider?: string;
|
|
692
|
+
output_table?: string | null;
|
|
693
|
+
webhook_state?: string;
|
|
694
|
+
last_received_event?: string | null;
|
|
695
|
+
bound_plays?: Array<Record<string, unknown>>;
|
|
689
696
|
[key: string]: unknown;
|
|
690
697
|
};
|
|
691
698
|
|
|
@@ -744,7 +751,10 @@ export type MonitorUpdateChangeSummary = {
|
|
|
744
751
|
};
|
|
745
752
|
upstream: {
|
|
746
753
|
resource_replaced: boolean;
|
|
747
|
-
strategy:
|
|
754
|
+
strategy:
|
|
755
|
+
| 'unchanged'
|
|
756
|
+
| 'create_then_delete_previous'
|
|
757
|
+
| 'deferred_until_reactivation';
|
|
748
758
|
};
|
|
749
759
|
};
|
|
750
760
|
export type MonitorUpdateResult = {
|
|
@@ -753,6 +763,8 @@ export type MonitorUpdateResult = {
|
|
|
753
763
|
};
|
|
754
764
|
export type MonitorDeleteResult = Record<string, unknown>;
|
|
755
765
|
export type MonitorReactivateResult = Record<string, unknown>;
|
|
766
|
+
export type MonitorTestResult = Record<string, unknown>;
|
|
767
|
+
export type MonitorValidateResult = Record<string, unknown>;
|
|
756
768
|
|
|
757
769
|
/**
|
|
758
770
|
* Public monitors namespace exposed as `client.monitors`.
|
|
@@ -788,6 +800,12 @@ export type MonitorsNamespace = {
|
|
|
788
800
|
list: (options?: MonitorsListOptions) => Promise<MonitorsListResult>;
|
|
789
801
|
/** Fetch one deployed monitor by public key (without dependents). */
|
|
790
802
|
get: (key: string) => Promise<MonitorDetail>;
|
|
803
|
+
/** Send an explicit payload through the deployed monitor's normal webhook path. */
|
|
804
|
+
test: (
|
|
805
|
+
key: string,
|
|
806
|
+
payload: Record<string, unknown>,
|
|
807
|
+
) => Promise<MonitorTestResult>;
|
|
808
|
+
validate: (key: string) => Promise<MonitorValidateResult>;
|
|
791
809
|
/** List the published plays depending on one monitor's output streams. */
|
|
792
810
|
dependents: (key: string) => Promise<MonitorDependents>;
|
|
793
811
|
/** Update a deployed monitor by public key. */
|
|
@@ -1486,6 +1504,8 @@ export class DeeplineClient {
|
|
|
1486
1504
|
deploy: (definition, options) => this.deployMonitor(definition, options),
|
|
1487
1505
|
list: (options) => this.listMonitors(options),
|
|
1488
1506
|
get: (key) => this.getMonitor(key),
|
|
1507
|
+
test: (key, payload) => this.testMonitorWebhook(key, payload),
|
|
1508
|
+
validate: (key) => this.validateMonitor(key),
|
|
1489
1509
|
dependents: (key) => this.getMonitorDependents(key),
|
|
1490
1510
|
update: (key, patch) => this.updateMonitor(key, patch),
|
|
1491
1511
|
delete: (key, options) => this.deleteMonitor(key, options),
|
|
@@ -4082,10 +4102,33 @@ export class DeeplineClient {
|
|
|
4082
4102
|
body: definition,
|
|
4083
4103
|
});
|
|
4084
4104
|
}
|
|
4085
|
-
|
|
4105
|
+
const deployed = await this.http.request<MonitorDeployResult>(
|
|
4106
|
+
'/api/v2/monitors/deploy',
|
|
4107
|
+
{
|
|
4086
4108
|
method: 'POST',
|
|
4087
4109
|
body: definition,
|
|
4088
|
-
|
|
4110
|
+
},
|
|
4111
|
+
);
|
|
4112
|
+
if (definition.tool !== 'deepline.deanonymizer') return deployed;
|
|
4113
|
+
|
|
4114
|
+
// Deanonymizer remains an ordinary monitor deploy. Its provider-specific
|
|
4115
|
+
// post-deploy work creates/reuses the tracker and returns the artifact a
|
|
4116
|
+
// caller needs to install it; there is intentionally no separate setup
|
|
4117
|
+
// command in the public monitor lifecycle.
|
|
4118
|
+
const setup = await this.setupMonitor(
|
|
4119
|
+
definition.tool,
|
|
4120
|
+
definition.payload ?? {},
|
|
4121
|
+
);
|
|
4122
|
+
return {
|
|
4123
|
+
...deployed,
|
|
4124
|
+
monitor: {
|
|
4125
|
+
...(deployed.monitor && typeof deployed.monitor === 'object'
|
|
4126
|
+
? deployed.monitor
|
|
4127
|
+
: {}),
|
|
4128
|
+
tracking: setup.tracking ?? null,
|
|
4129
|
+
ip2company: setup.ip2company ?? null,
|
|
4130
|
+
},
|
|
4131
|
+
};
|
|
4089
4132
|
}
|
|
4090
4133
|
|
|
4091
4134
|
/** List deployed monitors. Prefer `client.monitors.list(...)`. */
|
|
@@ -4116,6 +4159,33 @@ export class DeeplineClient {
|
|
|
4116
4159
|
);
|
|
4117
4160
|
}
|
|
4118
4161
|
|
|
4162
|
+
async testMonitorWebhook(
|
|
4163
|
+
key: string,
|
|
4164
|
+
payload: Record<string, unknown>,
|
|
4165
|
+
): Promise<MonitorTestResult> {
|
|
4166
|
+
return this.http.request<MonitorTestResult>(
|
|
4167
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
|
|
4168
|
+
{ method: 'POST', body: { payload } },
|
|
4169
|
+
);
|
|
4170
|
+
}
|
|
4171
|
+
|
|
4172
|
+
async setupMonitor(
|
|
4173
|
+
tool: string,
|
|
4174
|
+
payload: Record<string, unknown>,
|
|
4175
|
+
): Promise<Record<string, unknown>> {
|
|
4176
|
+
return this.http.request<Record<string, unknown>>(
|
|
4177
|
+
`/api/v2/monitors/setup/${encodeURIComponent(tool)}`,
|
|
4178
|
+
{ method: 'POST', body: payload },
|
|
4179
|
+
);
|
|
4180
|
+
}
|
|
4181
|
+
|
|
4182
|
+
async validateMonitor(key: string): Promise<MonitorValidateResult> {
|
|
4183
|
+
return this.http.request<MonitorValidateResult>(
|
|
4184
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/validate`,
|
|
4185
|
+
{ method: 'POST', body: {} },
|
|
4186
|
+
);
|
|
4187
|
+
}
|
|
4188
|
+
|
|
4119
4189
|
/** Published plays depending on one monitor. Prefer `client.monitors.dependents(...)`. */
|
|
4120
4190
|
async getMonitorDependents(key: string): Promise<MonitorDependents> {
|
|
4121
4191
|
return this.http.request<MonitorDependents>(
|
|
@@ -160,7 +160,7 @@ export const SDK_RELEASE = {
|
|
|
160
160
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
161
161
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
162
162
|
// release keeps lazy paging semantics independent of row residency.
|
|
163
|
-
version: '0.2.
|
|
163
|
+
version: '0.2.3',
|
|
164
164
|
contracts: {
|
|
165
165
|
api: {
|
|
166
166
|
name: 'sdk-http-api',
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { redactTelemetryText } from './redaction';
|
|
2
|
+
|
|
3
|
+
const MAX_ERROR_SUMMARY_LENGTH = 900;
|
|
4
|
+
|
|
5
|
+
const SECRET_ASSIGNMENT =
|
|
6
|
+
/\b((?:[A-Za-z][A-Za-z0-9_-]*[_-])?(?:token|secret|password|api[_ -]?key|access[_ -]?key))\b(\s*[:=]\s*)([^\s,;]+)/gi;
|
|
7
|
+
const AUTHORIZATION_VALUE =
|
|
8
|
+
/\bauthorization\b(\s*[:=]\s*)(?:Bearer\s+)?[^\s,;|]+/gi;
|
|
9
|
+
const BEARER_TOKEN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/gi;
|
|
10
|
+
const SLACK_WEBHOOK =
|
|
11
|
+
/https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9/_-]+/gi;
|
|
12
|
+
const URL_SECRET = /([?&](?:token|secret|key|signature|sig|code)=)[^&\s]+/gi;
|
|
13
|
+
const BARE_CREDENTIAL_PATTERNS = [
|
|
14
|
+
/\bgh[pousr]_[A-Za-z0-9_]{20,}\b/gi,
|
|
15
|
+
/\bgithub_pat_[A-Za-z0-9_]{20,}\b/gi,
|
|
16
|
+
/\b(?:xaat|xain)-[A-Za-z0-9_-]{16,}\b/gi,
|
|
17
|
+
/\bsk-ant-(?:api|oat)[A-Za-z0-9_-]{8,}\b/gi,
|
|
18
|
+
/\bxox(?:a|b|p|r|s)-[A-Za-z0-9-]{10,}\b/gi,
|
|
19
|
+
] as const;
|
|
20
|
+
|
|
21
|
+
export type ScheduledJobFailure = {
|
|
22
|
+
jobId: string;
|
|
23
|
+
jobName: string;
|
|
24
|
+
scheduler: string;
|
|
25
|
+
error: unknown;
|
|
26
|
+
runUrl?: string | null;
|
|
27
|
+
stage?: string | null;
|
|
28
|
+
attempt?: number | null;
|
|
29
|
+
occurredAt?: string;
|
|
30
|
+
test?: boolean;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export function sanitizeScheduledJobError(
|
|
34
|
+
error: unknown,
|
|
35
|
+
maxLength = MAX_ERROR_SUMMARY_LENGTH,
|
|
36
|
+
): string {
|
|
37
|
+
const raw =
|
|
38
|
+
error instanceof Error
|
|
39
|
+
? `${error.name}: ${error.message}`
|
|
40
|
+
: typeof error === 'string'
|
|
41
|
+
? error
|
|
42
|
+
: safeJson(error);
|
|
43
|
+
let compact = redactTelemetryText(raw)
|
|
44
|
+
.replace(/\u001b\[[0-9;]*m/g, '')
|
|
45
|
+
.replace(/\r/g, '')
|
|
46
|
+
.split('\n')
|
|
47
|
+
.map((line) => line.trim())
|
|
48
|
+
.filter(Boolean)
|
|
49
|
+
.join(' | ')
|
|
50
|
+
.replace(
|
|
51
|
+
AUTHORIZATION_VALUE,
|
|
52
|
+
(_match, separator) => `Authorization${separator}[REDACTED]`,
|
|
53
|
+
)
|
|
54
|
+
.replace(BEARER_TOKEN, 'Bearer [REDACTED]')
|
|
55
|
+
.replace(SLACK_WEBHOOK, '[REDACTED_SLACK_WEBHOOK]')
|
|
56
|
+
.replace(SECRET_ASSIGNMENT, (_match, label, separator) => {
|
|
57
|
+
return `${label}${separator}[REDACTED]`;
|
|
58
|
+
})
|
|
59
|
+
.replace(URL_SECRET, '$1[REDACTED]')
|
|
60
|
+
.replace(/\s+/g, ' ')
|
|
61
|
+
.trim();
|
|
62
|
+
for (const pattern of BARE_CREDENTIAL_PATTERNS) {
|
|
63
|
+
compact = compact.replace(pattern, '[REDACTED_CREDENTIAL]');
|
|
64
|
+
}
|
|
65
|
+
if (!compact) return 'No error detail was captured.';
|
|
66
|
+
return compact.length <= maxLength
|
|
67
|
+
? compact
|
|
68
|
+
: `${compact.slice(0, Math.max(0, maxLength - 1))}…`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function formatScheduledJobFailure(input: ScheduledJobFailure): string {
|
|
72
|
+
const title = input.test
|
|
73
|
+
? '[TEST] Scheduled job failure alert'
|
|
74
|
+
: 'Scheduled job failed';
|
|
75
|
+
return [
|
|
76
|
+
title,
|
|
77
|
+
`Job: ${input.jobName} (${input.jobId})`,
|
|
78
|
+
`Scheduler: ${input.scheduler}`,
|
|
79
|
+
input.stage ? `Stage: ${input.stage}` : null,
|
|
80
|
+
input.attempt ? `Attempt: ${input.attempt}` : null,
|
|
81
|
+
`Error: ${sanitizeScheduledJobError(input.error)}`,
|
|
82
|
+
`Occurred: ${input.occurredAt ?? new Date().toISOString()}`,
|
|
83
|
+
input.runUrl ? `Diagnostics: ${input.runUrl}` : null,
|
|
84
|
+
]
|
|
85
|
+
.filter((line): line is string => Boolean(line))
|
|
86
|
+
.join('\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function safeJson(value: unknown): string {
|
|
90
|
+
try {
|
|
91
|
+
return JSON.stringify(value) ?? String(value);
|
|
92
|
+
} catch {
|
|
93
|
+
return String(value);
|
|
94
|
+
}
|
|
95
|
+
}
|
package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
STANDARD_PLAY_SANDBOX_RUNTIME_LIMITS,
|
|
10
10
|
validatePlaySandboxRuntimeLimits,
|
|
11
11
|
} from '@shared_libs/play-runtime/sandbox-runtime-limits';
|
|
12
|
+
import type { PlayRunnerRuntimeLifecycleEvent } from '../types';
|
|
12
13
|
|
|
13
14
|
const DAYTONA_CREATE_TIMEOUT_SECONDS = 10;
|
|
14
15
|
const DAYTONA_CREATE_RETRY_DELAYS_MS = [0, 500, 1_500] as const;
|
|
@@ -41,6 +42,10 @@ export type DaytonaStageEmitter = (
|
|
|
41
42
|
extra?: Record<string, unknown>,
|
|
42
43
|
) => void;
|
|
43
44
|
|
|
45
|
+
type DaytonaCreateCallObserver = (
|
|
46
|
+
event: PlayRunnerRuntimeLifecycleEvent,
|
|
47
|
+
) => Promise<void>;
|
|
48
|
+
|
|
44
49
|
export type AcquiredDaytonaSandbox = {
|
|
45
50
|
sandbox: DaytonaSandbox;
|
|
46
51
|
daytonaOrganizationId: string;
|
|
@@ -104,6 +109,16 @@ type DaytonaCreateResult = {
|
|
|
104
109
|
attemptElapsedMs: number;
|
|
105
110
|
};
|
|
106
111
|
|
|
112
|
+
function daytonaCreateErrorClass(
|
|
113
|
+
error: unknown,
|
|
114
|
+
): 'timeout' | 'capacity' | 'rate_limit' | 'other' {
|
|
115
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
116
|
+
if (/timed out|timeout/i.test(message)) return 'timeout';
|
|
117
|
+
if (/total cpu limit|capacity/i.test(message)) return 'capacity';
|
|
118
|
+
if (/too many requests|rate limit|429/i.test(message)) return 'rate_limit';
|
|
119
|
+
return 'other';
|
|
120
|
+
}
|
|
121
|
+
|
|
107
122
|
async function rejectAcquiredSandbox(
|
|
108
123
|
sandbox: DaytonaSandbox,
|
|
109
124
|
reason: string,
|
|
@@ -307,11 +322,13 @@ async function createRetriedOneShotDaytonaSandbox(input: {
|
|
|
307
322
|
orgId: string;
|
|
308
323
|
context: DaytonaExecutionContext;
|
|
309
324
|
emitStage: DaytonaStageEmitter;
|
|
325
|
+
observeCreateCall?: DaytonaCreateCallObserver;
|
|
326
|
+
nextProviderAttempt: () => number;
|
|
310
327
|
startedAt: number;
|
|
311
328
|
}): Promise<DaytonaCreateResult> {
|
|
312
329
|
const errors: string[] = [];
|
|
313
330
|
for (const [index, delayMs] of DAYTONA_CREATE_RETRY_DELAYS_MS.entries()) {
|
|
314
|
-
const attempt =
|
|
331
|
+
const attempt = input.nextProviderAttempt();
|
|
315
332
|
const sandboxName = `dl-${crypto.randomUUID()}`;
|
|
316
333
|
if (delayMs > 0) {
|
|
317
334
|
input.emitStage('create:retry', {
|
|
@@ -323,19 +340,26 @@ async function createRetriedOneShotDaytonaSandbox(input: {
|
|
|
323
340
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
324
341
|
}
|
|
325
342
|
const attemptStartedAt = Date.now();
|
|
343
|
+
await input.observeCreateCall?.({
|
|
344
|
+
type: 'daytona_create_call_started',
|
|
345
|
+
occurredAtMs: attemptStartedAt,
|
|
346
|
+
providerAttempt: attempt,
|
|
347
|
+
});
|
|
348
|
+
let sandbox: DaytonaSandbox;
|
|
326
349
|
try {
|
|
327
|
-
|
|
350
|
+
sandbox = await createOneShotDaytonaSandbox({
|
|
328
351
|
daytona: input.daytona,
|
|
329
352
|
orgId: input.orgId,
|
|
330
353
|
context: input.context,
|
|
331
354
|
sandboxName,
|
|
332
355
|
});
|
|
333
|
-
return {
|
|
334
|
-
sandbox,
|
|
335
|
-
attempt,
|
|
336
|
-
attemptElapsedMs: Date.now() - attemptStartedAt,
|
|
337
|
-
};
|
|
338
356
|
} catch (error) {
|
|
357
|
+
await input.observeCreateCall?.({
|
|
358
|
+
type: 'daytona_create_call_failed',
|
|
359
|
+
occurredAtMs: Date.now(),
|
|
360
|
+
providerAttempt: attempt,
|
|
361
|
+
errorClass: daytonaCreateErrorClass(error),
|
|
362
|
+
});
|
|
339
363
|
const message = error instanceof Error ? error.message : String(error);
|
|
340
364
|
errors.push(message);
|
|
341
365
|
input.emitStage('create:attempt_failed', {
|
|
@@ -366,7 +390,38 @@ async function createRetriedOneShotDaytonaSandbox(input: {
|
|
|
366
390
|
{ cause: error },
|
|
367
391
|
);
|
|
368
392
|
}
|
|
393
|
+
continue;
|
|
369
394
|
}
|
|
395
|
+
// The outcome must be attributed immediately after Daytona acknowledges
|
|
396
|
+
// creation, before resource-policy validation can reject it. Otherwise a
|
|
397
|
+
// created-but-rejected sandbox is indistinguishable from an unknown
|
|
398
|
+
// create result. Do not turn a failed *post-create* journal write into a
|
|
399
|
+
// new provider create: the sandbox is already real. The missing durable
|
|
400
|
+
// outcome is deliberately loud in worker logs and makes the capture gate
|
|
401
|
+
// fail as incomplete telemetry, while the normal resource ledger still
|
|
402
|
+
// records the known sandbox for cleanup below.
|
|
403
|
+
const acquiredAt = Date.now();
|
|
404
|
+
try {
|
|
405
|
+
await input.observeCreateCall?.({
|
|
406
|
+
type: 'daytona_create_call_succeeded',
|
|
407
|
+
occurredAtMs: acquiredAt,
|
|
408
|
+
providerAttempt: attempt,
|
|
409
|
+
sandboxId: sandbox.id,
|
|
410
|
+
});
|
|
411
|
+
} catch {
|
|
412
|
+
console.error('[play-runner.daytona.create_lifecycle_event_unrecorded]', {
|
|
413
|
+
workflowId: input.context.workflowId ?? null,
|
|
414
|
+
runId: input.context.runId ?? null,
|
|
415
|
+
attempt,
|
|
416
|
+
sandboxId: sandbox.id,
|
|
417
|
+
eventType: 'daytona_create_call_succeeded',
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
sandbox,
|
|
422
|
+
attempt,
|
|
423
|
+
attemptElapsedMs: acquiredAt - attemptStartedAt,
|
|
424
|
+
};
|
|
370
425
|
}
|
|
371
426
|
const message = `Daytona sandbox create failed across ${errors.length} bounded attempts: ${errors.join('; ')}`;
|
|
372
427
|
const fallbackReason =
|
|
@@ -385,6 +440,8 @@ async function acquireOneShotDaytonaSandbox(input: {
|
|
|
385
440
|
orgId: string;
|
|
386
441
|
context: DaytonaExecutionContext;
|
|
387
442
|
emitStage: DaytonaStageEmitter;
|
|
443
|
+
observeCreateCall?: DaytonaCreateCallObserver;
|
|
444
|
+
nextProviderAttempt: () => number;
|
|
388
445
|
startedAt: number;
|
|
389
446
|
}): Promise<AcquiredDaytonaSandbox> {
|
|
390
447
|
const limits = validatePlaySandboxRuntimeLimits(
|
|
@@ -464,11 +521,13 @@ export function createOneShotDaytonaSandboxLifecycle(input: {
|
|
|
464
521
|
daytona: DaytonaClient;
|
|
465
522
|
context: DaytonaExecutionContext;
|
|
466
523
|
emitStage: DaytonaStageEmitter;
|
|
524
|
+
observeCreateCall?: DaytonaCreateCallObserver;
|
|
467
525
|
startedAt?: number;
|
|
468
526
|
}): OneShotDaytonaSandboxLifecycle {
|
|
469
527
|
const orgId = validateDaytonaExecutionContext(input.context);
|
|
470
528
|
const startedAt = input.startedAt ?? Date.now();
|
|
471
529
|
let disposed = false;
|
|
530
|
+
let providerAttempt = 0;
|
|
472
531
|
const acquiredSandboxes = new Map<string, AcquiredDaytonaSandbox>();
|
|
473
532
|
let latestAcquiredSandboxPromise: Promise<AcquiredDaytonaSandbox>;
|
|
474
533
|
const createFreshSandbox = () => {
|
|
@@ -477,6 +536,11 @@ export function createOneShotDaytonaSandboxLifecycle(input: {
|
|
|
477
536
|
orgId,
|
|
478
537
|
context: input.context,
|
|
479
538
|
emitStage: input.emitStage,
|
|
539
|
+
observeCreateCall: input.observeCreateCall,
|
|
540
|
+
nextProviderAttempt: () => {
|
|
541
|
+
providerAttempt += 1;
|
|
542
|
+
return providerAttempt;
|
|
543
|
+
},
|
|
480
544
|
startedAt,
|
|
481
545
|
}).then((acquired) => {
|
|
482
546
|
acquiredSandboxes.set(acquired.sandbox.id, acquired);
|
|
@@ -670,6 +670,7 @@ function prepareDaytonaExecution(
|
|
|
670
670
|
context: input.context,
|
|
671
671
|
emitStage: (stage, extra) =>
|
|
672
672
|
emitDaytonaStage(callbacks, input.context, stage, extra),
|
|
673
|
+
observeCreateCall: callbacks?.onRuntimeLifecycleEvent,
|
|
673
674
|
});
|
|
674
675
|
return {
|
|
675
676
|
kind: 'daytona',
|
|
@@ -40,6 +40,22 @@ export type RuntimeResourceTerminalReason =
|
|
|
40
40
|
| 'cancelled'
|
|
41
41
|
| 'lease_expired';
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Safe, provider-edge lifecycle evidence. The scheduler records these before
|
|
45
|
+
* relying on a non-idempotent provider outcome; raw provider responses,
|
|
46
|
+
* commands, inputs, and credentials are intentionally not part of the type.
|
|
47
|
+
*/
|
|
48
|
+
export type PlayRunnerRuntimeLifecycleEvent = {
|
|
49
|
+
type:
|
|
50
|
+
| 'daytona_create_call_started'
|
|
51
|
+
| 'daytona_create_call_succeeded'
|
|
52
|
+
| 'daytona_create_call_failed';
|
|
53
|
+
occurredAtMs: number;
|
|
54
|
+
providerAttempt: number;
|
|
55
|
+
sandboxId?: string;
|
|
56
|
+
errorClass?: 'timeout' | 'capacity' | 'rate_limit' | 'other';
|
|
57
|
+
};
|
|
58
|
+
|
|
43
59
|
export class RuntimeResourceFenceLostError extends Error {
|
|
44
60
|
constructor(message: string) {
|
|
45
61
|
super(message);
|
|
@@ -55,6 +71,13 @@ export interface PlayRunnerCallbacks {
|
|
|
55
71
|
onRuntimeResourceAcquired?: (
|
|
56
72
|
resource: PlayRunnerRuntimeResource,
|
|
57
73
|
) => void | Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Durable scheduler-owned evidence for a provider create call. Backends
|
|
76
|
+
* await this callback at the create boundary; it is not best-effort logging.
|
|
77
|
+
*/
|
|
78
|
+
onRuntimeLifecycleEvent?: (
|
|
79
|
+
event: PlayRunnerRuntimeLifecycleEvent,
|
|
80
|
+
) => Promise<void>;
|
|
58
81
|
/**
|
|
59
82
|
* Scheduler-owned readiness read for a detached runner attempt. Daytona uses
|
|
60
83
|
* this direct control-plane port before parking; it is never serialized into
|
package/dist/cli/index.js
CHANGED
|
@@ -1040,7 +1040,7 @@ var SDK_RELEASE = {
|
|
|
1040
1040
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1041
1041
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1042
1042
|
// release keeps lazy paging semantics independent of row residency.
|
|
1043
|
-
version: "0.2.
|
|
1043
|
+
version: "0.2.3",
|
|
1044
1044
|
contracts: {
|
|
1045
1045
|
api: {
|
|
1046
1046
|
name: "sdk-http-api",
|
|
@@ -3778,6 +3778,8 @@ var DeeplineClient = class {
|
|
|
3778
3778
|
deploy: (definition, options2) => this.deployMonitor(definition, options2),
|
|
3779
3779
|
list: (options2) => this.listMonitors(options2),
|
|
3780
3780
|
get: (key) => this.getMonitor(key),
|
|
3781
|
+
test: (key, payload) => this.testMonitorWebhook(key, payload),
|
|
3782
|
+
validate: (key) => this.validateMonitor(key),
|
|
3781
3783
|
dependents: (key) => this.getMonitorDependents(key),
|
|
3782
3784
|
update: (key, patch) => this.updateMonitor(key, patch),
|
|
3783
3785
|
delete: (key, options2) => this.deleteMonitor(key, options2),
|
|
@@ -5739,10 +5741,26 @@ var DeeplineClient = class {
|
|
|
5739
5741
|
body: definition
|
|
5740
5742
|
});
|
|
5741
5743
|
}
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5744
|
+
const deployed = await this.http.request(
|
|
5745
|
+
"/api/v2/monitors/deploy",
|
|
5746
|
+
{
|
|
5747
|
+
method: "POST",
|
|
5748
|
+
body: definition
|
|
5749
|
+
}
|
|
5750
|
+
);
|
|
5751
|
+
if (definition.tool !== "deepline.deanonymizer") return deployed;
|
|
5752
|
+
const setup = await this.setupMonitor(
|
|
5753
|
+
definition.tool,
|
|
5754
|
+
definition.payload ?? {}
|
|
5755
|
+
);
|
|
5756
|
+
return {
|
|
5757
|
+
...deployed,
|
|
5758
|
+
monitor: {
|
|
5759
|
+
...deployed.monitor && typeof deployed.monitor === "object" ? deployed.monitor : {},
|
|
5760
|
+
tracking: setup.tracking ?? null,
|
|
5761
|
+
ip2company: setup.ip2company ?? null
|
|
5762
|
+
}
|
|
5763
|
+
};
|
|
5746
5764
|
}
|
|
5747
5765
|
/** List deployed monitors. Prefer `client.monitors.list(...)`. */
|
|
5748
5766
|
async listMonitors(options) {
|
|
@@ -5766,6 +5784,24 @@ var DeeplineClient = class {
|
|
|
5766
5784
|
{ method: "GET" }
|
|
5767
5785
|
);
|
|
5768
5786
|
}
|
|
5787
|
+
async testMonitorWebhook(key, payload) {
|
|
5788
|
+
return this.http.request(
|
|
5789
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
|
|
5790
|
+
{ method: "POST", body: { payload } }
|
|
5791
|
+
);
|
|
5792
|
+
}
|
|
5793
|
+
async setupMonitor(tool, payload) {
|
|
5794
|
+
return this.http.request(
|
|
5795
|
+
`/api/v2/monitors/setup/${encodeURIComponent(tool)}`,
|
|
5796
|
+
{ method: "POST", body: payload }
|
|
5797
|
+
);
|
|
5798
|
+
}
|
|
5799
|
+
async validateMonitor(key) {
|
|
5800
|
+
return this.http.request(
|
|
5801
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/validate`,
|
|
5802
|
+
{ method: "POST", body: {} }
|
|
5803
|
+
);
|
|
5804
|
+
}
|
|
5769
5805
|
/** Published plays depending on one monitor. Prefer `client.monitors.dependents(...)`. */
|
|
5770
5806
|
async getMonitorDependents(key) {
|
|
5771
5807
|
return this.http.request(
|
|
@@ -25753,6 +25789,26 @@ function renderMonitorDeployCompletion(payload) {
|
|
|
25753
25789
|
if (pricingLine) {
|
|
25754
25790
|
lines.push("", `Pricing: ${pricingLine}`);
|
|
25755
25791
|
}
|
|
25792
|
+
const guidance = asRecord2(payload.setup_guidance);
|
|
25793
|
+
if (guidance) {
|
|
25794
|
+
const callbackUrl = asString(guidance.callback_url);
|
|
25795
|
+
const steps = Array.isArray(guidance.steps) ? guidance.steps : [];
|
|
25796
|
+
const docs = Array.isArray(guidance.documentation) ? guidance.documentation : [];
|
|
25797
|
+
lines.push("", asString(guidance.title) ?? "Provider setup:");
|
|
25798
|
+
if (callbackUrl) lines.push(` Callback URL: ${callbackUrl}`);
|
|
25799
|
+
for (const step of steps)
|
|
25800
|
+
if (asString(step)) lines.push(` \u2022 ${asString(step)}`);
|
|
25801
|
+
for (const raw of docs) {
|
|
25802
|
+
const doc = asRecord2(raw);
|
|
25803
|
+
const label = asString(doc?.label);
|
|
25804
|
+
const url = asString(doc?.url);
|
|
25805
|
+
if (label && url) lines.push(` Docs: ${label} \u2014 ${url}`);
|
|
25806
|
+
}
|
|
25807
|
+
const payloadExample = asRecord2(guidance.payload_example);
|
|
25808
|
+
if (payloadExample) {
|
|
25809
|
+
lines.push(` Payload example: ${JSON.stringify(payloadExample)}`);
|
|
25810
|
+
}
|
|
25811
|
+
}
|
|
25756
25812
|
lines.push(
|
|
25757
25813
|
"",
|
|
25758
25814
|
"This monitor streams new rows into your Customer DB \u2014 there is no manual run.",
|
|
@@ -25970,9 +26026,21 @@ function renderDeployedListText(payload, requestedStatus) {
|
|
|
25970
26026
|
const status = asString(entry.status);
|
|
25971
26027
|
const tool = asString(entry.tool);
|
|
25972
26028
|
const name = asString(entry.name);
|
|
26029
|
+
const outputTable = asString(entry.output_table);
|
|
26030
|
+
const webhookState = asString(entry.webhook_state);
|
|
26031
|
+
const boundPlays = Array.isArray(entry.bound_plays) ? entry.bound_plays.length : void 0;
|
|
25973
26032
|
lines.push(
|
|
25974
26033
|
` ${key}${status ? ` ${status}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
|
|
25975
26034
|
);
|
|
26035
|
+
if (outputTable || webhookState || boundPlays !== void 0) {
|
|
26036
|
+
lines.push(
|
|
26037
|
+
` ${[
|
|
26038
|
+
outputTable ? `table: ${outputTable}` : null,
|
|
26039
|
+
webhookState ? `webhook: ${webhookState}` : null,
|
|
26040
|
+
boundPlays !== void 0 ? `bound Plays: ${boundPlays}` : null
|
|
26041
|
+
].filter(Boolean).join(" ")}`
|
|
26042
|
+
);
|
|
26043
|
+
}
|
|
25976
26044
|
}
|
|
25977
26045
|
const applied = asString(payload.status_filter_applied) ?? requestedStatus ?? "active";
|
|
25978
26046
|
lines.push(
|
|
@@ -26054,6 +26122,8 @@ function renderMonitorGet(payload) {
|
|
|
26054
26122
|
const billing = asRecord2(payload.billing);
|
|
26055
26123
|
const nextRenewalAt = billing ? asString(billing.next_renewal_at) : void 0;
|
|
26056
26124
|
const dependents = asRecord2(payload.dependents);
|
|
26125
|
+
const webhook = asRecord2(payload.webhook);
|
|
26126
|
+
const guidance = asRecord2(payload.setup_guidance);
|
|
26057
26127
|
const plays = dependents && Array.isArray(dependents.plays) ? dependents.plays : [];
|
|
26058
26128
|
const lines = [
|
|
26059
26129
|
`Monitor: ${key}`,
|
|
@@ -26065,6 +26135,36 @@ function renderMonitorGet(payload) {
|
|
|
26065
26135
|
if (definition) {
|
|
26066
26136
|
lines.push("", "Current definition:", ` ${JSON.stringify(definition)}`);
|
|
26067
26137
|
}
|
|
26138
|
+
if (webhook) {
|
|
26139
|
+
lines.push("", `Webhook: ${asString(webhook.state) ?? "unknown"}`);
|
|
26140
|
+
const callbackUrl = asString(webhook.callback_url);
|
|
26141
|
+
if (callbackUrl) lines.push(` Callback URL (sensitive): ${callbackUrl}`);
|
|
26142
|
+
}
|
|
26143
|
+
if (guidance) {
|
|
26144
|
+
lines.push("", asString(guidance.title) ?? "Provider setup:");
|
|
26145
|
+
for (const step of Array.isArray(guidance.steps) ? guidance.steps : []) {
|
|
26146
|
+
const text = asString(step);
|
|
26147
|
+
if (text) lines.push(` \u2022 ${text}`);
|
|
26148
|
+
}
|
|
26149
|
+
for (const raw of Array.isArray(guidance.documentation) ? guidance.documentation : []) {
|
|
26150
|
+
const doc = asRecord2(raw);
|
|
26151
|
+
const label = asString(doc?.label);
|
|
26152
|
+
const url = asString(doc?.url);
|
|
26153
|
+
if (label && url) lines.push(` Docs: ${label} \u2014 ${url}`);
|
|
26154
|
+
}
|
|
26155
|
+
const payloadExample = asRecord2(guidance.payload_example);
|
|
26156
|
+
if (payloadExample) {
|
|
26157
|
+
lines.push(` Payload example: ${JSON.stringify(payloadExample)}`);
|
|
26158
|
+
}
|
|
26159
|
+
}
|
|
26160
|
+
const samplePayload2 = asRecord2(payload.sample_payload);
|
|
26161
|
+
if (samplePayload2) {
|
|
26162
|
+
lines.push(
|
|
26163
|
+
"",
|
|
26164
|
+
`Sample test payload: ${JSON.stringify(samplePayload2)}`,
|
|
26165
|
+
` deepline monitors test ${key} '${JSON.stringify(samplePayload2)}' --json`
|
|
26166
|
+
);
|
|
26167
|
+
}
|
|
26068
26168
|
lines.push("", `Dependent published plays (${plays.length}):`);
|
|
26069
26169
|
if (plays.length === 0) {
|
|
26070
26170
|
lines.push(" none");
|
|
@@ -26096,6 +26196,20 @@ async function handleMonitorsGet(key, options) {
|
|
|
26096
26196
|
text: renderMonitorGet(detail)
|
|
26097
26197
|
});
|
|
26098
26198
|
}
|
|
26199
|
+
async function handleMonitorsTest(key, payload, options) {
|
|
26200
|
+
const explicitPayload = parseJsonObjectArg(payload, "<payload>");
|
|
26201
|
+
const result = await new DeeplineClient().monitors.test(key, explicitPayload);
|
|
26202
|
+
const text = `Webhook test for ${key}: ${result.accepted === true ? "accepted" : "rejected"}
|
|
26203
|
+
persisted rows: ${asFiniteNumber(result.persisted_rows) ?? 0}
|
|
26204
|
+
bound Plays dispatched: ${asFiniteNumber(result.dispatched_bound_plays) ?? 0}
|
|
26205
|
+
`;
|
|
26206
|
+
printCommandEnvelope(result, { json: options.json, text });
|
|
26207
|
+
}
|
|
26208
|
+
async function handleMonitorsValidate(key, options) {
|
|
26209
|
+
const result = await new DeeplineClient().monitors.validate(key);
|
|
26210
|
+
printCommandEnvelope(result, { json: options.json });
|
|
26211
|
+
if (result.valid === false) process.exitCode = 7;
|
|
26212
|
+
}
|
|
26099
26213
|
async function confirmMonitorDelete(key, options) {
|
|
26100
26214
|
const rl = (0, import_promises4.createInterface)({
|
|
26101
26215
|
input: process.stdin,
|
|
@@ -26185,8 +26299,8 @@ Notes:
|
|
|
26185
26299
|
Deepline monitors are Deepline-native signal feeds: a monitor writes events
|
|
26186
26300
|
into a Customer DB table; a play reacts to each new row via a
|
|
26187
26301
|
sqlListeners trigger \u2014 see \`deepline plays bootstrap monitor-triggered\`.
|
|
26188
|
-
The
|
|
26189
|
-
\`deepline monitors
|
|
26302
|
+
The Monitors rollout controls access to the live provider catalog; use
|
|
26303
|
+
\`deepline tools list --categories monitors\` for the exact tool ids available to you.
|
|
26190
26304
|
Access is granted by a Deepline admin via Admin -> Rollouts; until then these
|
|
26191
26305
|
commands return a clear monitor_access_required error.
|
|
26192
26306
|
|
|
@@ -26296,6 +26410,25 @@ Examples:
|
|
|
26296
26410
|
`
|
|
26297
26411
|
)
|
|
26298
26412
|
).action(monitorsAction(handleMonitorsGet));
|
|
26413
|
+
withJsonOption(
|
|
26414
|
+
monitors.command("test <key> <payload>").description(
|
|
26415
|
+
"Send an explicit payload through a monitor\u2019s webhook ingestion path."
|
|
26416
|
+
).addHelpText(
|
|
26417
|
+
"after",
|
|
26418
|
+
`
|
|
26419
|
+
Notes:
|
|
26420
|
+
<payload> must be an explicit JSON object. The command uses the deployed
|
|
26421
|
+
monitor\u2019s real validation, persistence, and inline Play dispatch path; it does
|
|
26422
|
+
not synthesize a provider event or accept an omitted payload.
|
|
26423
|
+
|
|
26424
|
+
Examples:
|
|
26425
|
+
deepline monitors test rb2b-website-visitors '{"LinkedIn URL":"https://www.linkedin.com/in/example","Website":"https://example.com"}' --json
|
|
26426
|
+
`
|
|
26427
|
+
)
|
|
26428
|
+
).action(monitorsAction(handleMonitorsTest));
|
|
26429
|
+
withJsonOption(
|
|
26430
|
+
monitors.command("validate <key>").description("Validate a deployed monitor\u2019s provider configuration.")
|
|
26431
|
+
).action(monitorsAction(handleMonitorsValidate));
|
|
26299
26432
|
withJsonOption(
|
|
26300
26433
|
monitors.command("check [definition]").description("Validate a monitor definition without deploying it.").addHelpText(
|
|
26301
26434
|
"after",
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1025,7 +1025,7 @@ var SDK_RELEASE = {
|
|
|
1025
1025
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1026
1026
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1027
1027
|
// release keeps lazy paging semantics independent of row residency.
|
|
1028
|
-
version: "0.2.
|
|
1028
|
+
version: "0.2.3",
|
|
1029
1029
|
contracts: {
|
|
1030
1030
|
api: {
|
|
1031
1031
|
name: "sdk-http-api",
|
|
@@ -3763,6 +3763,8 @@ var DeeplineClient = class {
|
|
|
3763
3763
|
deploy: (definition, options2) => this.deployMonitor(definition, options2),
|
|
3764
3764
|
list: (options2) => this.listMonitors(options2),
|
|
3765
3765
|
get: (key) => this.getMonitor(key),
|
|
3766
|
+
test: (key, payload) => this.testMonitorWebhook(key, payload),
|
|
3767
|
+
validate: (key) => this.validateMonitor(key),
|
|
3766
3768
|
dependents: (key) => this.getMonitorDependents(key),
|
|
3767
3769
|
update: (key, patch) => this.updateMonitor(key, patch),
|
|
3768
3770
|
delete: (key, options2) => this.deleteMonitor(key, options2),
|
|
@@ -5724,10 +5726,26 @@ var DeeplineClient = class {
|
|
|
5724
5726
|
body: definition
|
|
5725
5727
|
});
|
|
5726
5728
|
}
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5729
|
+
const deployed = await this.http.request(
|
|
5730
|
+
"/api/v2/monitors/deploy",
|
|
5731
|
+
{
|
|
5732
|
+
method: "POST",
|
|
5733
|
+
body: definition
|
|
5734
|
+
}
|
|
5735
|
+
);
|
|
5736
|
+
if (definition.tool !== "deepline.deanonymizer") return deployed;
|
|
5737
|
+
const setup = await this.setupMonitor(
|
|
5738
|
+
definition.tool,
|
|
5739
|
+
definition.payload ?? {}
|
|
5740
|
+
);
|
|
5741
|
+
return {
|
|
5742
|
+
...deployed,
|
|
5743
|
+
monitor: {
|
|
5744
|
+
...deployed.monitor && typeof deployed.monitor === "object" ? deployed.monitor : {},
|
|
5745
|
+
tracking: setup.tracking ?? null,
|
|
5746
|
+
ip2company: setup.ip2company ?? null
|
|
5747
|
+
}
|
|
5748
|
+
};
|
|
5731
5749
|
}
|
|
5732
5750
|
/** List deployed monitors. Prefer `client.monitors.list(...)`. */
|
|
5733
5751
|
async listMonitors(options) {
|
|
@@ -5751,6 +5769,24 @@ var DeeplineClient = class {
|
|
|
5751
5769
|
{ method: "GET" }
|
|
5752
5770
|
);
|
|
5753
5771
|
}
|
|
5772
|
+
async testMonitorWebhook(key, payload) {
|
|
5773
|
+
return this.http.request(
|
|
5774
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
|
|
5775
|
+
{ method: "POST", body: { payload } }
|
|
5776
|
+
);
|
|
5777
|
+
}
|
|
5778
|
+
async setupMonitor(tool, payload) {
|
|
5779
|
+
return this.http.request(
|
|
5780
|
+
`/api/v2/monitors/setup/${encodeURIComponent(tool)}`,
|
|
5781
|
+
{ method: "POST", body: payload }
|
|
5782
|
+
);
|
|
5783
|
+
}
|
|
5784
|
+
async validateMonitor(key) {
|
|
5785
|
+
return this.http.request(
|
|
5786
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/validate`,
|
|
5787
|
+
{ method: "POST", body: {} }
|
|
5788
|
+
);
|
|
5789
|
+
}
|
|
5754
5790
|
/** Published plays depending on one monitor. Prefer `client.monitors.dependents(...)`. */
|
|
5755
5791
|
async getMonitorDependents(key) {
|
|
5756
5792
|
return this.http.request(
|
|
@@ -25789,6 +25825,26 @@ function renderMonitorDeployCompletion(payload) {
|
|
|
25789
25825
|
if (pricingLine) {
|
|
25790
25826
|
lines.push("", `Pricing: ${pricingLine}`);
|
|
25791
25827
|
}
|
|
25828
|
+
const guidance = asRecord2(payload.setup_guidance);
|
|
25829
|
+
if (guidance) {
|
|
25830
|
+
const callbackUrl = asString(guidance.callback_url);
|
|
25831
|
+
const steps = Array.isArray(guidance.steps) ? guidance.steps : [];
|
|
25832
|
+
const docs = Array.isArray(guidance.documentation) ? guidance.documentation : [];
|
|
25833
|
+
lines.push("", asString(guidance.title) ?? "Provider setup:");
|
|
25834
|
+
if (callbackUrl) lines.push(` Callback URL: ${callbackUrl}`);
|
|
25835
|
+
for (const step of steps)
|
|
25836
|
+
if (asString(step)) lines.push(` \u2022 ${asString(step)}`);
|
|
25837
|
+
for (const raw of docs) {
|
|
25838
|
+
const doc = asRecord2(raw);
|
|
25839
|
+
const label = asString(doc?.label);
|
|
25840
|
+
const url = asString(doc?.url);
|
|
25841
|
+
if (label && url) lines.push(` Docs: ${label} \u2014 ${url}`);
|
|
25842
|
+
}
|
|
25843
|
+
const payloadExample = asRecord2(guidance.payload_example);
|
|
25844
|
+
if (payloadExample) {
|
|
25845
|
+
lines.push(` Payload example: ${JSON.stringify(payloadExample)}`);
|
|
25846
|
+
}
|
|
25847
|
+
}
|
|
25792
25848
|
lines.push(
|
|
25793
25849
|
"",
|
|
25794
25850
|
"This monitor streams new rows into your Customer DB \u2014 there is no manual run.",
|
|
@@ -26006,9 +26062,21 @@ function renderDeployedListText(payload, requestedStatus) {
|
|
|
26006
26062
|
const status = asString(entry.status);
|
|
26007
26063
|
const tool = asString(entry.tool);
|
|
26008
26064
|
const name = asString(entry.name);
|
|
26065
|
+
const outputTable = asString(entry.output_table);
|
|
26066
|
+
const webhookState = asString(entry.webhook_state);
|
|
26067
|
+
const boundPlays = Array.isArray(entry.bound_plays) ? entry.bound_plays.length : void 0;
|
|
26009
26068
|
lines.push(
|
|
26010
26069
|
` ${key}${status ? ` ${status}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
|
|
26011
26070
|
);
|
|
26071
|
+
if (outputTable || webhookState || boundPlays !== void 0) {
|
|
26072
|
+
lines.push(
|
|
26073
|
+
` ${[
|
|
26074
|
+
outputTable ? `table: ${outputTable}` : null,
|
|
26075
|
+
webhookState ? `webhook: ${webhookState}` : null,
|
|
26076
|
+
boundPlays !== void 0 ? `bound Plays: ${boundPlays}` : null
|
|
26077
|
+
].filter(Boolean).join(" ")}`
|
|
26078
|
+
);
|
|
26079
|
+
}
|
|
26012
26080
|
}
|
|
26013
26081
|
const applied = asString(payload.status_filter_applied) ?? requestedStatus ?? "active";
|
|
26014
26082
|
lines.push(
|
|
@@ -26090,6 +26158,8 @@ function renderMonitorGet(payload) {
|
|
|
26090
26158
|
const billing = asRecord2(payload.billing);
|
|
26091
26159
|
const nextRenewalAt = billing ? asString(billing.next_renewal_at) : void 0;
|
|
26092
26160
|
const dependents = asRecord2(payload.dependents);
|
|
26161
|
+
const webhook = asRecord2(payload.webhook);
|
|
26162
|
+
const guidance = asRecord2(payload.setup_guidance);
|
|
26093
26163
|
const plays = dependents && Array.isArray(dependents.plays) ? dependents.plays : [];
|
|
26094
26164
|
const lines = [
|
|
26095
26165
|
`Monitor: ${key}`,
|
|
@@ -26101,6 +26171,36 @@ function renderMonitorGet(payload) {
|
|
|
26101
26171
|
if (definition) {
|
|
26102
26172
|
lines.push("", "Current definition:", ` ${JSON.stringify(definition)}`);
|
|
26103
26173
|
}
|
|
26174
|
+
if (webhook) {
|
|
26175
|
+
lines.push("", `Webhook: ${asString(webhook.state) ?? "unknown"}`);
|
|
26176
|
+
const callbackUrl = asString(webhook.callback_url);
|
|
26177
|
+
if (callbackUrl) lines.push(` Callback URL (sensitive): ${callbackUrl}`);
|
|
26178
|
+
}
|
|
26179
|
+
if (guidance) {
|
|
26180
|
+
lines.push("", asString(guidance.title) ?? "Provider setup:");
|
|
26181
|
+
for (const step of Array.isArray(guidance.steps) ? guidance.steps : []) {
|
|
26182
|
+
const text = asString(step);
|
|
26183
|
+
if (text) lines.push(` \u2022 ${text}`);
|
|
26184
|
+
}
|
|
26185
|
+
for (const raw of Array.isArray(guidance.documentation) ? guidance.documentation : []) {
|
|
26186
|
+
const doc = asRecord2(raw);
|
|
26187
|
+
const label = asString(doc?.label);
|
|
26188
|
+
const url = asString(doc?.url);
|
|
26189
|
+
if (label && url) lines.push(` Docs: ${label} \u2014 ${url}`);
|
|
26190
|
+
}
|
|
26191
|
+
const payloadExample = asRecord2(guidance.payload_example);
|
|
26192
|
+
if (payloadExample) {
|
|
26193
|
+
lines.push(` Payload example: ${JSON.stringify(payloadExample)}`);
|
|
26194
|
+
}
|
|
26195
|
+
}
|
|
26196
|
+
const samplePayload2 = asRecord2(payload.sample_payload);
|
|
26197
|
+
if (samplePayload2) {
|
|
26198
|
+
lines.push(
|
|
26199
|
+
"",
|
|
26200
|
+
`Sample test payload: ${JSON.stringify(samplePayload2)}`,
|
|
26201
|
+
` deepline monitors test ${key} '${JSON.stringify(samplePayload2)}' --json`
|
|
26202
|
+
);
|
|
26203
|
+
}
|
|
26104
26204
|
lines.push("", `Dependent published plays (${plays.length}):`);
|
|
26105
26205
|
if (plays.length === 0) {
|
|
26106
26206
|
lines.push(" none");
|
|
@@ -26132,6 +26232,20 @@ async function handleMonitorsGet(key, options) {
|
|
|
26132
26232
|
text: renderMonitorGet(detail)
|
|
26133
26233
|
});
|
|
26134
26234
|
}
|
|
26235
|
+
async function handleMonitorsTest(key, payload, options) {
|
|
26236
|
+
const explicitPayload = parseJsonObjectArg(payload, "<payload>");
|
|
26237
|
+
const result = await new DeeplineClient().monitors.test(key, explicitPayload);
|
|
26238
|
+
const text = `Webhook test for ${key}: ${result.accepted === true ? "accepted" : "rejected"}
|
|
26239
|
+
persisted rows: ${asFiniteNumber(result.persisted_rows) ?? 0}
|
|
26240
|
+
bound Plays dispatched: ${asFiniteNumber(result.dispatched_bound_plays) ?? 0}
|
|
26241
|
+
`;
|
|
26242
|
+
printCommandEnvelope(result, { json: options.json, text });
|
|
26243
|
+
}
|
|
26244
|
+
async function handleMonitorsValidate(key, options) {
|
|
26245
|
+
const result = await new DeeplineClient().monitors.validate(key);
|
|
26246
|
+
printCommandEnvelope(result, { json: options.json });
|
|
26247
|
+
if (result.valid === false) process.exitCode = 7;
|
|
26248
|
+
}
|
|
26135
26249
|
async function confirmMonitorDelete(key, options) {
|
|
26136
26250
|
const rl = createInterface({
|
|
26137
26251
|
input: process.stdin,
|
|
@@ -26221,8 +26335,8 @@ Notes:
|
|
|
26221
26335
|
Deepline monitors are Deepline-native signal feeds: a monitor writes events
|
|
26222
26336
|
into a Customer DB table; a play reacts to each new row via a
|
|
26223
26337
|
sqlListeners trigger \u2014 see \`deepline plays bootstrap monitor-triggered\`.
|
|
26224
|
-
The
|
|
26225
|
-
\`deepline monitors
|
|
26338
|
+
The Monitors rollout controls access to the live provider catalog; use
|
|
26339
|
+
\`deepline tools list --categories monitors\` for the exact tool ids available to you.
|
|
26226
26340
|
Access is granted by a Deepline admin via Admin -> Rollouts; until then these
|
|
26227
26341
|
commands return a clear monitor_access_required error.
|
|
26228
26342
|
|
|
@@ -26332,6 +26446,25 @@ Examples:
|
|
|
26332
26446
|
`
|
|
26333
26447
|
)
|
|
26334
26448
|
).action(monitorsAction(handleMonitorsGet));
|
|
26449
|
+
withJsonOption(
|
|
26450
|
+
monitors.command("test <key> <payload>").description(
|
|
26451
|
+
"Send an explicit payload through a monitor\u2019s webhook ingestion path."
|
|
26452
|
+
).addHelpText(
|
|
26453
|
+
"after",
|
|
26454
|
+
`
|
|
26455
|
+
Notes:
|
|
26456
|
+
<payload> must be an explicit JSON object. The command uses the deployed
|
|
26457
|
+
monitor\u2019s real validation, persistence, and inline Play dispatch path; it does
|
|
26458
|
+
not synthesize a provider event or accept an omitted payload.
|
|
26459
|
+
|
|
26460
|
+
Examples:
|
|
26461
|
+
deepline monitors test rb2b-website-visitors '{"LinkedIn URL":"https://www.linkedin.com/in/example","Website":"https://example.com"}' --json
|
|
26462
|
+
`
|
|
26463
|
+
)
|
|
26464
|
+
).action(monitorsAction(handleMonitorsTest));
|
|
26465
|
+
withJsonOption(
|
|
26466
|
+
monitors.command("validate <key>").description("Validate a deployed monitor\u2019s provider configuration.")
|
|
26467
|
+
).action(monitorsAction(handleMonitorsValidate));
|
|
26335
26468
|
withJsonOption(
|
|
26336
26469
|
monitors.command("check [definition]").description("Validate a monitor definition without deploying it.").addHelpText(
|
|
26337
26470
|
"after",
|
package/dist/index.d.mts
CHANGED
|
@@ -1930,6 +1930,13 @@ type MonitorListEntry = {
|
|
|
1930
1930
|
status?: string;
|
|
1931
1931
|
tool?: string;
|
|
1932
1932
|
name?: string;
|
|
1933
|
+
configured?: boolean;
|
|
1934
|
+
active?: boolean;
|
|
1935
|
+
provider?: string;
|
|
1936
|
+
output_table?: string | null;
|
|
1937
|
+
webhook_state?: string;
|
|
1938
|
+
last_received_event?: string | null;
|
|
1939
|
+
bound_plays?: Array<Record<string, unknown>>;
|
|
1933
1940
|
[key: string]: unknown;
|
|
1934
1941
|
};
|
|
1935
1942
|
/**
|
|
@@ -1992,7 +1999,7 @@ type MonitorUpdateChangeSummary = {
|
|
|
1992
1999
|
};
|
|
1993
2000
|
upstream: {
|
|
1994
2001
|
resource_replaced: boolean;
|
|
1995
|
-
strategy: 'unchanged' | 'create_then_delete_previous';
|
|
2002
|
+
strategy: 'unchanged' | 'create_then_delete_previous' | 'deferred_until_reactivation';
|
|
1996
2003
|
};
|
|
1997
2004
|
};
|
|
1998
2005
|
type MonitorUpdateResult = {
|
|
@@ -2001,6 +2008,8 @@ type MonitorUpdateResult = {
|
|
|
2001
2008
|
};
|
|
2002
2009
|
type MonitorDeleteResult = Record<string, unknown>;
|
|
2003
2010
|
type MonitorReactivateResult = Record<string, unknown>;
|
|
2011
|
+
type MonitorTestResult = Record<string, unknown>;
|
|
2012
|
+
type MonitorValidateResult = Record<string, unknown>;
|
|
2004
2013
|
/**
|
|
2005
2014
|
* Public monitors namespace exposed as `client.monitors`.
|
|
2006
2015
|
*
|
|
@@ -2033,6 +2042,9 @@ type MonitorsNamespace = {
|
|
|
2033
2042
|
list: (options?: MonitorsListOptions) => Promise<MonitorsListResult>;
|
|
2034
2043
|
/** Fetch one deployed monitor by public key (without dependents). */
|
|
2035
2044
|
get: (key: string) => Promise<MonitorDetail>;
|
|
2045
|
+
/** Send an explicit payload through the deployed monitor's normal webhook path. */
|
|
2046
|
+
test: (key: string, payload: Record<string, unknown>) => Promise<MonitorTestResult>;
|
|
2047
|
+
validate: (key: string) => Promise<MonitorValidateResult>;
|
|
2036
2048
|
/** List the published plays depending on one monitor's output streams. */
|
|
2037
2049
|
dependents: (key: string) => Promise<MonitorDependents>;
|
|
2038
2050
|
/** Update a deployed monitor by public key. */
|
|
@@ -3162,6 +3174,9 @@ declare class DeeplineClient {
|
|
|
3162
3174
|
listMonitors(options?: MonitorsListOptions): Promise<MonitorsListResult>;
|
|
3163
3175
|
/** Fetch one deployed monitor by public key. Prefer `client.monitors.get(...)`. */
|
|
3164
3176
|
getMonitor(key: string): Promise<MonitorDetail>;
|
|
3177
|
+
testMonitorWebhook(key: string, payload: Record<string, unknown>): Promise<MonitorTestResult>;
|
|
3178
|
+
setupMonitor(tool: string, payload: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
3179
|
+
validateMonitor(key: string): Promise<MonitorValidateResult>;
|
|
3165
3180
|
/** Published plays depending on one monitor. Prefer `client.monitors.dependents(...)`. */
|
|
3166
3181
|
getMonitorDependents(key: string): Promise<MonitorDependents>;
|
|
3167
3182
|
/** Update a deployed monitor by public key. Prefer `client.monitors.update(...)`. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1930,6 +1930,13 @@ type MonitorListEntry = {
|
|
|
1930
1930
|
status?: string;
|
|
1931
1931
|
tool?: string;
|
|
1932
1932
|
name?: string;
|
|
1933
|
+
configured?: boolean;
|
|
1934
|
+
active?: boolean;
|
|
1935
|
+
provider?: string;
|
|
1936
|
+
output_table?: string | null;
|
|
1937
|
+
webhook_state?: string;
|
|
1938
|
+
last_received_event?: string | null;
|
|
1939
|
+
bound_plays?: Array<Record<string, unknown>>;
|
|
1933
1940
|
[key: string]: unknown;
|
|
1934
1941
|
};
|
|
1935
1942
|
/**
|
|
@@ -1992,7 +1999,7 @@ type MonitorUpdateChangeSummary = {
|
|
|
1992
1999
|
};
|
|
1993
2000
|
upstream: {
|
|
1994
2001
|
resource_replaced: boolean;
|
|
1995
|
-
strategy: 'unchanged' | 'create_then_delete_previous';
|
|
2002
|
+
strategy: 'unchanged' | 'create_then_delete_previous' | 'deferred_until_reactivation';
|
|
1996
2003
|
};
|
|
1997
2004
|
};
|
|
1998
2005
|
type MonitorUpdateResult = {
|
|
@@ -2001,6 +2008,8 @@ type MonitorUpdateResult = {
|
|
|
2001
2008
|
};
|
|
2002
2009
|
type MonitorDeleteResult = Record<string, unknown>;
|
|
2003
2010
|
type MonitorReactivateResult = Record<string, unknown>;
|
|
2011
|
+
type MonitorTestResult = Record<string, unknown>;
|
|
2012
|
+
type MonitorValidateResult = Record<string, unknown>;
|
|
2004
2013
|
/**
|
|
2005
2014
|
* Public monitors namespace exposed as `client.monitors`.
|
|
2006
2015
|
*
|
|
@@ -2033,6 +2042,9 @@ type MonitorsNamespace = {
|
|
|
2033
2042
|
list: (options?: MonitorsListOptions) => Promise<MonitorsListResult>;
|
|
2034
2043
|
/** Fetch one deployed monitor by public key (without dependents). */
|
|
2035
2044
|
get: (key: string) => Promise<MonitorDetail>;
|
|
2045
|
+
/** Send an explicit payload through the deployed monitor's normal webhook path. */
|
|
2046
|
+
test: (key: string, payload: Record<string, unknown>) => Promise<MonitorTestResult>;
|
|
2047
|
+
validate: (key: string) => Promise<MonitorValidateResult>;
|
|
2036
2048
|
/** List the published plays depending on one monitor's output streams. */
|
|
2037
2049
|
dependents: (key: string) => Promise<MonitorDependents>;
|
|
2038
2050
|
/** Update a deployed monitor by public key. */
|
|
@@ -3162,6 +3174,9 @@ declare class DeeplineClient {
|
|
|
3162
3174
|
listMonitors(options?: MonitorsListOptions): Promise<MonitorsListResult>;
|
|
3163
3175
|
/** Fetch one deployed monitor by public key. Prefer `client.monitors.get(...)`. */
|
|
3164
3176
|
getMonitor(key: string): Promise<MonitorDetail>;
|
|
3177
|
+
testMonitorWebhook(key: string, payload: Record<string, unknown>): Promise<MonitorTestResult>;
|
|
3178
|
+
setupMonitor(tool: string, payload: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
3179
|
+
validateMonitor(key: string): Promise<MonitorValidateResult>;
|
|
3165
3180
|
/** Published plays depending on one monitor. Prefer `client.monitors.dependents(...)`. */
|
|
3166
3181
|
getMonitorDependents(key: string): Promise<MonitorDependents>;
|
|
3167
3182
|
/** Update a deployed monitor by public key. Prefer `client.monitors.update(...)`. */
|
package/dist/index.js
CHANGED
|
@@ -763,7 +763,7 @@ var SDK_RELEASE = {
|
|
|
763
763
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
764
764
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
765
765
|
// release keeps lazy paging semantics independent of row residency.
|
|
766
|
-
version: "0.2.
|
|
766
|
+
version: "0.2.3",
|
|
767
767
|
contracts: {
|
|
768
768
|
api: {
|
|
769
769
|
name: "sdk-http-api",
|
|
@@ -3501,6 +3501,8 @@ var DeeplineClient = class {
|
|
|
3501
3501
|
deploy: (definition, options2) => this.deployMonitor(definition, options2),
|
|
3502
3502
|
list: (options2) => this.listMonitors(options2),
|
|
3503
3503
|
get: (key) => this.getMonitor(key),
|
|
3504
|
+
test: (key, payload) => this.testMonitorWebhook(key, payload),
|
|
3505
|
+
validate: (key) => this.validateMonitor(key),
|
|
3504
3506
|
dependents: (key) => this.getMonitorDependents(key),
|
|
3505
3507
|
update: (key, patch) => this.updateMonitor(key, patch),
|
|
3506
3508
|
delete: (key, options2) => this.deleteMonitor(key, options2),
|
|
@@ -5462,10 +5464,26 @@ var DeeplineClient = class {
|
|
|
5462
5464
|
body: definition
|
|
5463
5465
|
});
|
|
5464
5466
|
}
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5467
|
+
const deployed = await this.http.request(
|
|
5468
|
+
"/api/v2/monitors/deploy",
|
|
5469
|
+
{
|
|
5470
|
+
method: "POST",
|
|
5471
|
+
body: definition
|
|
5472
|
+
}
|
|
5473
|
+
);
|
|
5474
|
+
if (definition.tool !== "deepline.deanonymizer") return deployed;
|
|
5475
|
+
const setup = await this.setupMonitor(
|
|
5476
|
+
definition.tool,
|
|
5477
|
+
definition.payload ?? {}
|
|
5478
|
+
);
|
|
5479
|
+
return {
|
|
5480
|
+
...deployed,
|
|
5481
|
+
monitor: {
|
|
5482
|
+
...deployed.monitor && typeof deployed.monitor === "object" ? deployed.monitor : {},
|
|
5483
|
+
tracking: setup.tracking ?? null,
|
|
5484
|
+
ip2company: setup.ip2company ?? null
|
|
5485
|
+
}
|
|
5486
|
+
};
|
|
5469
5487
|
}
|
|
5470
5488
|
/** List deployed monitors. Prefer `client.monitors.list(...)`. */
|
|
5471
5489
|
async listMonitors(options) {
|
|
@@ -5489,6 +5507,24 @@ var DeeplineClient = class {
|
|
|
5489
5507
|
{ method: "GET" }
|
|
5490
5508
|
);
|
|
5491
5509
|
}
|
|
5510
|
+
async testMonitorWebhook(key, payload) {
|
|
5511
|
+
return this.http.request(
|
|
5512
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
|
|
5513
|
+
{ method: "POST", body: { payload } }
|
|
5514
|
+
);
|
|
5515
|
+
}
|
|
5516
|
+
async setupMonitor(tool, payload) {
|
|
5517
|
+
return this.http.request(
|
|
5518
|
+
`/api/v2/monitors/setup/${encodeURIComponent(tool)}`,
|
|
5519
|
+
{ method: "POST", body: payload }
|
|
5520
|
+
);
|
|
5521
|
+
}
|
|
5522
|
+
async validateMonitor(key) {
|
|
5523
|
+
return this.http.request(
|
|
5524
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/validate`,
|
|
5525
|
+
{ method: "POST", body: {} }
|
|
5526
|
+
);
|
|
5527
|
+
}
|
|
5492
5528
|
/** Published plays depending on one monitor. Prefer `client.monitors.dependents(...)`. */
|
|
5493
5529
|
async getMonitorDependents(key) {
|
|
5494
5530
|
return this.http.request(
|
package/dist/index.mjs
CHANGED
|
@@ -689,7 +689,7 @@ var SDK_RELEASE = {
|
|
|
689
689
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
690
690
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
691
691
|
// release keeps lazy paging semantics independent of row residency.
|
|
692
|
-
version: "0.2.
|
|
692
|
+
version: "0.2.3",
|
|
693
693
|
contracts: {
|
|
694
694
|
api: {
|
|
695
695
|
name: "sdk-http-api",
|
|
@@ -3427,6 +3427,8 @@ var DeeplineClient = class {
|
|
|
3427
3427
|
deploy: (definition, options2) => this.deployMonitor(definition, options2),
|
|
3428
3428
|
list: (options2) => this.listMonitors(options2),
|
|
3429
3429
|
get: (key) => this.getMonitor(key),
|
|
3430
|
+
test: (key, payload) => this.testMonitorWebhook(key, payload),
|
|
3431
|
+
validate: (key) => this.validateMonitor(key),
|
|
3430
3432
|
dependents: (key) => this.getMonitorDependents(key),
|
|
3431
3433
|
update: (key, patch) => this.updateMonitor(key, patch),
|
|
3432
3434
|
delete: (key, options2) => this.deleteMonitor(key, options2),
|
|
@@ -5388,10 +5390,26 @@ var DeeplineClient = class {
|
|
|
5388
5390
|
body: definition
|
|
5389
5391
|
});
|
|
5390
5392
|
}
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5393
|
+
const deployed = await this.http.request(
|
|
5394
|
+
"/api/v2/monitors/deploy",
|
|
5395
|
+
{
|
|
5396
|
+
method: "POST",
|
|
5397
|
+
body: definition
|
|
5398
|
+
}
|
|
5399
|
+
);
|
|
5400
|
+
if (definition.tool !== "deepline.deanonymizer") return deployed;
|
|
5401
|
+
const setup = await this.setupMonitor(
|
|
5402
|
+
definition.tool,
|
|
5403
|
+
definition.payload ?? {}
|
|
5404
|
+
);
|
|
5405
|
+
return {
|
|
5406
|
+
...deployed,
|
|
5407
|
+
monitor: {
|
|
5408
|
+
...deployed.monitor && typeof deployed.monitor === "object" ? deployed.monitor : {},
|
|
5409
|
+
tracking: setup.tracking ?? null,
|
|
5410
|
+
ip2company: setup.ip2company ?? null
|
|
5411
|
+
}
|
|
5412
|
+
};
|
|
5395
5413
|
}
|
|
5396
5414
|
/** List deployed monitors. Prefer `client.monitors.list(...)`. */
|
|
5397
5415
|
async listMonitors(options) {
|
|
@@ -5415,6 +5433,24 @@ var DeeplineClient = class {
|
|
|
5415
5433
|
{ method: "GET" }
|
|
5416
5434
|
);
|
|
5417
5435
|
}
|
|
5436
|
+
async testMonitorWebhook(key, payload) {
|
|
5437
|
+
return this.http.request(
|
|
5438
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/test`,
|
|
5439
|
+
{ method: "POST", body: { payload } }
|
|
5440
|
+
);
|
|
5441
|
+
}
|
|
5442
|
+
async setupMonitor(tool, payload) {
|
|
5443
|
+
return this.http.request(
|
|
5444
|
+
`/api/v2/monitors/setup/${encodeURIComponent(tool)}`,
|
|
5445
|
+
{ method: "POST", body: payload }
|
|
5446
|
+
);
|
|
5447
|
+
}
|
|
5448
|
+
async validateMonitor(key) {
|
|
5449
|
+
return this.http.request(
|
|
5450
|
+
`/api/v2/monitors/deployed/${encodeURIComponent(key)}/validate`,
|
|
5451
|
+
{ method: "POST", body: {} }
|
|
5452
|
+
);
|
|
5453
|
+
}
|
|
5418
5454
|
/** Published plays depending on one monitor. Prefer `client.monitors.dependents(...)`. */
|
|
5419
5455
|
async getMonitorDependents(key) {
|
|
5420
5456
|
return this.http.request(
|