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.
@@ -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: 'unchanged' | 'create_then_delete_previous';
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
- return this.http.request<MonitorDeployResult>('/api/v2/monitors/deploy', {
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.1',
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
+ }
@@ -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 = index + 1;
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
- const sandbox = await createOneShotDaytonaSandbox({
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.1",
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
- return this.http.request("/api/v2/monitors/deploy", {
5743
- method: "POST",
5744
- body: definition
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 customer launch currently includes Company Radar and Contact Radar; use
26189
- \`deepline monitors available\` for the exact live tool ids.
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",
@@ -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.1",
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
- return this.http.request("/api/v2/monitors/deploy", {
5728
- method: "POST",
5729
- body: definition
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 customer launch currently includes Company Radar and Contact Radar; use
26225
- \`deepline monitors available\` for the exact live tool ids.
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.1",
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
- return this.http.request("/api/v2/monitors/deploy", {
5466
- method: "POST",
5467
- body: definition
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.1",
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
- return this.http.request("/api/v2/monitors/deploy", {
5392
- method: "POST",
5393
- body: definition
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(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {