deepline 0.3.55 → 0.3.57

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.
@@ -83,6 +83,7 @@ import type {
83
83
  InferenceQuote,
84
84
  } from './types.js';
85
85
  import type { MonitorDefinition } from './monitors.js';
86
+ import type { MonitorFleetDefinition } from './monitor-fleets.js';
86
87
  import type { PlayStagedFileRef } from './plays/local-file-discovery.js';
87
88
  import type { PlayCompilerManifest } from '../../shared_libs/plays/compiler-manifest.js';
88
89
  import type { EnrichCompiledConfig } from './cli/enrich-play-compiler.js';
@@ -848,6 +849,90 @@ export type MonitorReactivateResult = Record<string, unknown>;
848
849
  export type MonitorTestResult = Record<string, unknown>;
849
850
  export type MonitorValidateResult = Record<string, unknown>;
850
851
 
852
+ /**
853
+ * Server-owned fleet response envelope.
854
+ *
855
+ * The server computes `status` (`converging` | `converged` | `degraded` |
856
+ * `deactivating` | `deactivated`) and the SDK never recomputes it: a client
857
+ * that derives its own verdict from counts drifts from the control plane the
858
+ * moment the server changes what "converged" means.
859
+ */
860
+ export type MonitorFleetResult = Record<string, unknown>;
861
+
862
+ /** Server-computed fleet verdict. Never derived client-side. */
863
+ export type MonitorFleetStatus =
864
+ | 'converging'
865
+ | 'converged'
866
+ | 'degraded'
867
+ | 'deactivating'
868
+ | 'deactivated';
869
+
870
+ export type MonitorFleetSyncOptions = {
871
+ /** Return the plan without changing fleet state (`dry_run: true`). */
872
+ dryRun?: boolean;
873
+ /** Optimistic concurrency: refuse the write unless the fleet is at this generation. */
874
+ expectedGeneration?: number;
875
+ /** Stable retry key; generated by the caller when omitted. */
876
+ idempotencyKey?: string;
877
+ };
878
+
879
+ export type MonitorFleetGetOptions = {
880
+ /** Include bounded per-member drift rows. */
881
+ drift?: boolean;
882
+ /** Maximum drift rows to return. */
883
+ limit?: number;
884
+ };
885
+
886
+ export type MonitorFleetDeactivateOptions = {
887
+ /** Return the blast radius without deactivating anything. */
888
+ dryRun?: boolean;
889
+ idempotencyKey?: string;
890
+ };
891
+
892
+ export type MonitorFleetWaitOptions = {
893
+ /** Give up after this long. Default 10 minutes. */
894
+ timeoutMs?: number;
895
+ /** Poll cadence. Default 2 seconds. */
896
+ pollIntervalMs?: number;
897
+ /** Called with every polled snapshot, including the terminal one. */
898
+ onProgress?: (payload: MonitorFleetResult) => void;
899
+ /**
900
+ * Which terminal state ends the wait. `converged` (default) also stops on
901
+ * `degraded` and `deactivated`; `deactivated` stops on `deactivated` and
902
+ * `degraded`. A timeout is not an error: the last snapshot is returned and
903
+ * the caller reads `status` to decide the verdict.
904
+ */
905
+ until?: 'converged' | 'deactivated';
906
+ };
907
+
908
+ export type MonitorFleetsNamespace = {
909
+ /**
910
+ * Create, update, or re-plan a fleet. Pass a definition to admit new source
911
+ * of truth; pass a fleet id to re-plan from the stored definition.
912
+ */
913
+ sync: (
914
+ definitionOrId: string | MonitorFleetDefinition,
915
+ options?: MonitorFleetSyncOptions,
916
+ ) => Promise<MonitorFleetResult>;
917
+ /** One fleet by id, or every fleet in the workspace when the id is omitted. */
918
+ get: (
919
+ fleetId?: string,
920
+ options?: MonitorFleetGetOptions,
921
+ ) => Promise<MonitorFleetResult>;
922
+ /** Every fleet in the workspace. */
923
+ list: () => Promise<MonitorFleetResult>;
924
+ /** Deactivate a fleet and the monitors it owns. */
925
+ deactivate: (
926
+ fleetId: string,
927
+ options?: MonitorFleetDeactivateOptions,
928
+ ) => Promise<MonitorFleetResult>;
929
+ /** Poll the fleet until the server reports a terminal status (or the timeout elapses). */
930
+ waitForConvergence: (
931
+ fleetId: string,
932
+ options?: MonitorFleetWaitOptions,
933
+ ) => Promise<MonitorFleetResult>;
934
+ };
935
+
851
936
  /**
852
937
  * Public monitors namespace exposed as `client.monitors`.
853
938
  *
@@ -909,6 +994,8 @@ export type MonitorsNamespace = {
909
994
  key: string,
910
995
  options?: { dryRun?: boolean },
911
996
  ) => Promise<MonitorReactivateResult>;
997
+ /** Define, reconcile, and control table-backed monitor fleets. */
998
+ fleets: MonitorFleetsNamespace;
912
999
  };
913
1000
 
914
1001
  /** One credit grant pool reported by the billing subscription status endpoint. */
@@ -1801,6 +1888,19 @@ export class DeeplineClient {
1801
1888
  update: (key, patch) => this.updateMonitor(key, patch),
1802
1889
  delete: (key, options) => this.deleteMonitor(key, options),
1803
1890
  reactivate: (key, options) => this.reactivateMonitor(key, options),
1891
+ fleets: {
1892
+ sync: (definitionOrId, options) =>
1893
+ this.syncMonitorFleet(definitionOrId, options),
1894
+ get: (fleetId, options) =>
1895
+ fleetId === undefined
1896
+ ? this.listMonitorFleets()
1897
+ : this.getMonitorFleet(fleetId, options),
1898
+ list: () => this.listMonitorFleets(),
1899
+ deactivate: (fleetId, options) =>
1900
+ this.deactivateMonitorFleet(fleetId, options),
1901
+ waitForConvergence: (fleetId, options) =>
1902
+ this.waitForMonitorFleetConvergence(fleetId, options),
1903
+ },
1804
1904
  };
1805
1905
  }
1806
1906
 
@@ -4915,6 +5015,138 @@ export class DeeplineClient {
4915
5015
  );
4916
5016
  }
4917
5017
 
5018
+ // ——————————————————————————————————————————————————————————
5019
+ // Monitor Fleets
5020
+ // ——————————————————————————————————————————————————————————
5021
+
5022
+ private monitorFleetIdempotencyKey(operation: string): string {
5023
+ const uuid = globalThis.crypto?.randomUUID?.();
5024
+ return `monitor-fleet-${operation}-${uuid ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`;
5025
+ }
5026
+
5027
+ private monitorFleetHeaders(
5028
+ operation: string,
5029
+ idempotencyKey?: string,
5030
+ ): Record<string, string> {
5031
+ return {
5032
+ 'Idempotency-Key':
5033
+ idempotencyKey?.trim() || this.monitorFleetIdempotencyKey(operation),
5034
+ };
5035
+ }
5036
+
5037
+ private monitorFleetPath(fleetId: string): string {
5038
+ return `/api/v2/monitors/fleets/${encodeURIComponent(fleetId)}`;
5039
+ }
5040
+
5041
+ /**
5042
+ * Create, update, or re-plan one fleet.
5043
+ *
5044
+ * The fleet id is always the resource path, so the same definition PUT twice
5045
+ * is the same operation and the server can answer `replayed: true` instead of
5046
+ * building a second set of monitors. Re-planning an existing fleet from its
5047
+ * stored definition sends an EMPTY body: there is no second definition to
5048
+ * send, and an empty body cannot be mistaken for "replace the definition with
5049
+ * nothing".
5050
+ */
5051
+ async syncMonitorFleet(
5052
+ definitionOrId: string | MonitorFleetDefinition,
5053
+ options?: MonitorFleetSyncOptions,
5054
+ ): Promise<MonitorFleetResult> {
5055
+ const fleetId =
5056
+ typeof definitionOrId === 'string' ? definitionOrId : definitionOrId.id;
5057
+ const body: Record<string, unknown> = {
5058
+ ...(typeof definitionOrId === 'string'
5059
+ ? {}
5060
+ : { definition: definitionOrId }),
5061
+ ...(options?.dryRun ? { dry_run: true } : {}),
5062
+ ...(options?.expectedGeneration !== undefined
5063
+ ? { expected_generation: options.expectedGeneration }
5064
+ : {}),
5065
+ };
5066
+ return this.http.request<MonitorFleetResult>(
5067
+ this.monitorFleetPath(fleetId),
5068
+ {
5069
+ method: 'PUT',
5070
+ body,
5071
+ headers: this.monitorFleetHeaders('sync', options?.idempotencyKey),
5072
+ maxRetries: 0,
5073
+ exactUrlOnly: true,
5074
+ },
5075
+ );
5076
+ }
5077
+
5078
+ async listMonitorFleets(): Promise<MonitorFleetResult> {
5079
+ return this.http.request<MonitorFleetResult>('/api/v2/monitors/fleets', {
5080
+ method: 'GET',
5081
+ });
5082
+ }
5083
+
5084
+ async getMonitorFleet(
5085
+ fleetId: string,
5086
+ options?: MonitorFleetGetOptions,
5087
+ ): Promise<MonitorFleetResult> {
5088
+ const params = new URLSearchParams();
5089
+ if (options?.drift) params.set('drift', '1');
5090
+ if (options?.limit !== undefined)
5091
+ params.set('limit', String(options.limit));
5092
+ const query = params.toString();
5093
+ return this.http.request<MonitorFleetResult>(
5094
+ `${this.monitorFleetPath(fleetId)}${query ? `?${query}` : ''}`,
5095
+ { method: 'GET' },
5096
+ );
5097
+ }
5098
+
5099
+ async deactivateMonitorFleet(
5100
+ fleetId: string,
5101
+ options?: MonitorFleetDeactivateOptions,
5102
+ ): Promise<MonitorFleetResult> {
5103
+ return this.http.request<MonitorFleetResult>(
5104
+ this.monitorFleetPath(fleetId),
5105
+ {
5106
+ method: 'DELETE',
5107
+ body: options?.dryRun ? { dry_run: true } : {},
5108
+ headers: this.monitorFleetHeaders(
5109
+ 'deactivate',
5110
+ options?.idempotencyKey,
5111
+ ),
5112
+ maxRetries: 0,
5113
+ exactUrlOnly: true,
5114
+ },
5115
+ );
5116
+ }
5117
+
5118
+ /**
5119
+ * Poll one fleet until the server reports a terminal status.
5120
+ *
5121
+ * Convergence is the server's verdict, read from `status`. The timeout is not
5122
+ * a failure and does not throw: a fleet still `converging` after ten minutes
5123
+ * is healthy and slow, not broken, so the caller gets the last snapshot and
5124
+ * decides what that means. Throwing here would have made "still working" look
5125
+ * identical to "the request failed".
5126
+ */
5127
+ async waitForMonitorFleetConvergence(
5128
+ fleetId: string,
5129
+ options?: MonitorFleetWaitOptions,
5130
+ ): Promise<MonitorFleetResult> {
5131
+ const timeoutMs = Math.max(1, options?.timeoutMs ?? 10 * 60_000);
5132
+ const pollIntervalMs = Math.max(1, options?.pollIntervalMs ?? 2_000);
5133
+ const terminal: ReadonlySet<string> =
5134
+ options?.until === 'deactivated'
5135
+ ? new Set(['deactivated', 'degraded'])
5136
+ : new Set(['converged', 'degraded', 'deactivated']);
5137
+ const startedAt = Date.now();
5138
+ let latest = await this.getMonitorFleet(fleetId);
5139
+ while (true) {
5140
+ options?.onProgress?.(latest);
5141
+ const status =
5142
+ typeof latest.status === 'string' ? latest.status : undefined;
5143
+ if (status && terminal.has(status)) return latest;
5144
+ if (Date.now() - startedAt >= timeoutMs) return latest;
5145
+ await sleep(pollIntervalMs);
5146
+ latest = await this.getMonitorFleet(fleetId);
5147
+ }
5148
+ }
5149
+
4918
5150
  /**
4919
5151
  * Check API connectivity and server health.
4920
5152
  *
@@ -272,7 +272,7 @@ export class HttpClient {
272
272
  headers[RUNTIME_SCHEDULER_SCHEMA_OVERRIDE_HEADER] =
273
273
  runtimeSchedulerSchema.trim();
274
274
  }
275
- // Automated test harnesses (e.g. tests/v2-plays) set DEEPLINE_SYNTHETIC_RUN
275
+ // Automated test harnesses (e.g. tests/gauntlet-e2e-tests) set DEEPLINE_SYNTHETIC_RUN
276
276
  // so their intentionally failing plays do not page the SDK CLI error
277
277
  // channel. Honored server-side only in non-prod (see plays/run route).
278
278
  const syntheticRun =
@@ -84,6 +84,13 @@ export type {
84
84
  MonitorUpdateResult,
85
85
  MonitorDeleteResult,
86
86
  MonitorReactivateResult,
87
+ MonitorFleetDeactivateOptions,
88
+ MonitorFleetGetOptions,
89
+ MonitorFleetSyncOptions,
90
+ MonitorFleetStatus,
91
+ MonitorFleetWaitOptions,
92
+ MonitorFleetResult,
93
+ MonitorFleetsNamespace,
87
94
  IngestionStorageRepairResult,
88
95
  PlayStatus,
89
96
  PlaySheetRow,
@@ -103,6 +110,28 @@ export type {
103
110
  MonitorPayload,
104
111
  MonitorControls,
105
112
  } from './monitors.js';
113
+ export {
114
+ admitMonitorFleetAuthoringContract,
115
+ MONITOR_FLEET_AUTHORING_CONTRACT_CHANGELOG,
116
+ MONITOR_FLEET_AUTHORING_CONTRACT_EDITION,
117
+ MONITOR_FLEET_DOCUMENTATION,
118
+ MONITOR_FLEET_FRONTIER_MAX_ROWS,
119
+ MONITOR_FLEET_MAX_MEMBERS,
120
+ defineMonitorFleet,
121
+ fleetColumn,
122
+ fleetKey,
123
+ validateMonitorFleetDefinition,
124
+ } from './monitor-fleets.js';
125
+ export type {
126
+ AdmittedMonitorFleetAuthoringContract,
127
+ MonitorFleetAuthoringContractEdition,
128
+ MonitorFleetAuthoringContractResult,
129
+ MonitorFleetColumn,
130
+ MonitorFleetContractIssue,
131
+ MonitorFleetDefinition,
132
+ MonitorFleetExpression,
133
+ MonitorFleetTemplate,
134
+ } from './monitor-fleets.js';
106
135
  export { SDK_API_CONTRACT, SDK_VERSION } from './version.js';
107
136
  export {
108
137
  DEEPLINE_TOOL_CATEGORIES,