dataiku-sdk 0.12.5 → 0.12.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,6 +29,7 @@ Bun is the primary development runtime and package manager. Examples below assum
29
29
  - `--fields a,b,c` projects those fields from an object or array-of-objects result; dotted paths (`a.b.c`) drill into nested objects, and missing fields become `null`; string and scalar results pass through unchanged.
30
30
  - No prompts, help screens, tables, banners, or prose output are part of the contract.
31
31
  - Exit codes: `0` success, `1` usage/configuration error, `2` DSS/internal error, `3` transient DSS error, `4` a failed long-running result or synchronous assertion.
32
+ - `--retries N` controls idempotent GET retries only. `dss sql query --start-retries N` explicitly retries transient failures while starting a query; use it only when executing the SQL more than once is safe.
32
33
  - The exit code is the success signal. For portable multi-step mutations, prefer `dss batch`; shell chaining and pipeline exit semantics differ across POSIX shells, Windows PowerShell, PowerShell 7, and Command Prompt.
33
34
  - `--raw` is only for recipe payload commands. Without `--output`, stdout is raw bytes; with `--output PATH`, stdout is the JSON string equal to `PATH` and the file contains the exact raw bytes.
34
35
 
@@ -3,7 +3,7 @@ import { mkdir, writeFile, } from "node:fs/promises";
3
3
  import { dirname, resolve, } from "node:path";
4
4
  import { readStdinText, stripUtf8Bom, } from "../coerce.js";
5
5
  import { UsageError, } from "../usage.js";
6
- const SQL_QUERY_USAGE = "dss sql query (SQL | --sql QUERY | --sql-file PATH | --sql - | --stdin) (--connection CONN | --dataset FULL_NAME) [--database DB] [--output PATH|--output-file PATH] [--preview N] [--request-timeout MS] [--project-key KEY]";
6
+ const SQL_QUERY_USAGE = "dss sql query (SQL | --sql QUERY | --sql-file PATH | --sql - | --stdin) (--connection CONN | --dataset FULL_NAME) [--database DB] [--output PATH|--output-file PATH] [--preview N] [--start-retries N] [--request-timeout MS] [--project-key KEY]";
7
7
  const DEFAULT_SQL_PREVIEW_ROWS = 5;
8
8
  /**
9
9
  * Parse `--preview N` into a non-negative row count. Rejects non-integers,
@@ -21,6 +21,19 @@ function parseSqlPreviewCount(value) {
21
21
  }
22
22
  return parsed;
23
23
  }
24
+ function parseSqlStartRetries(value) {
25
+ if (value === undefined)
26
+ return undefined;
27
+ if (typeof value !== "string") {
28
+ throw new UsageError(`--start-retries requires a positive integer. Usage: ${SQL_QUERY_USAGE}`, "validation_failed");
29
+ }
30
+ const trimmed = value.trim();
31
+ const parsed = Number(trimmed);
32
+ if (trimmed.length === 0 || !Number.isInteger(parsed) || parsed < 1) {
33
+ throw new UsageError(`--start-retries must be a positive integer (got "${value}"). Usage: ${SQL_QUERY_USAGE}`, "validation_failed");
34
+ }
35
+ return parsed;
36
+ }
24
37
  function resolveSqlInput(args, flags) {
25
38
  const sources = [];
26
39
  if (typeof flags["sql"] === "string") {
@@ -80,6 +93,7 @@ export const sqlCommands = {
80
93
  datasetFullName,
81
94
  database: f["database"],
82
95
  projectKey: f["project-key"],
96
+ retryMaxAttempts: parseSqlStartRetries(f["start-retries"]),
83
97
  });
84
98
  if (!outputFile)
85
99
  return result;
@@ -97,13 +111,14 @@ export const sqlCommands = {
97
111
  };
98
112
  },
99
113
  usage: SQL_QUERY_USAGE,
100
- description: "Run a SQL query against a DSS connection or dataset.",
114
+ description: "Run a SQL query against a DSS connection or dataset. --start-retries may execute the SQL more than once; use it only when repetition is safe.",
101
115
  examples: [
102
116
  "dss sql query 'SELECT * FROM orders LIMIT 10' --connection my_pg",
103
117
  "dss sql query --sql-file query.sql --connection my_pg",
104
118
  "echo 'SELECT 1' | dss sql query --stdin --dataset MYPROJ.orders",
105
119
  "dss sql query --sql-file query.sql --connection my_pg --output results.json --request-timeout 120000",
106
120
  "dss sql query --sql-file query.sql --connection my_pg --output results.json --preview 10",
121
+ "dss sql query 'SELECT 1' --connection my_pg --start-retries 4",
107
122
  ],
108
123
  },
109
124
  };
@@ -160,6 +160,7 @@ export const VALUE_FLAGS = new Set([
160
160
  "sql",
161
161
  "schema",
162
162
  "sql-file",
163
+ "start-retries",
163
164
  "standard",
164
165
  "state",
165
166
  "streaming-endpoint",
@@ -165,7 +165,13 @@ export declare class DataikuClient {
165
165
  text: string;
166
166
  truncated: boolean;
167
167
  }>;
168
- post<T = unknown>(path: string, body?: unknown): Promise<T>;
168
+ /**
169
+ * POST with optional transient retry. Only opt in when repeating the request
170
+ * is safe: the server may have accepted an attempt whose response was lost.
171
+ */
172
+ post<T = unknown>(path: string, body?: unknown, options?: {
173
+ retryMaxAttempts?: number;
174
+ }): Promise<T>;
169
175
  postText(path: string, body?: unknown): Promise<string>;
170
176
  put<T = unknown>(path: string, body: unknown): Promise<T>;
171
177
  del(path: string): Promise<void>;
@@ -406,12 +406,21 @@ export class DataikuClient {
406
406
  const usable = truncated ? trimToUtf8Boundary(collected) : collected;
407
407
  return { text: new TextDecoder().decode(usable), truncated, };
408
408
  }
409
- async post(path, body) {
409
+ /**
410
+ * POST with optional transient retry. Only opt in when repeating the request
411
+ * is safe: the server may have accepted an attempt whose response was lost.
412
+ */
413
+ async post(path, body, options) {
414
+ const retryMaxAttempts = options?.retryMaxAttempts;
415
+ if (retryMaxAttempts !== undefined
416
+ && (!Number.isInteger(retryMaxAttempts) || retryMaxAttempts < 1)) {
417
+ throw new ClientValidationError("retryMaxAttempts must be a positive integer.");
418
+ }
410
419
  const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
411
420
  method: "POST",
412
421
  headers: this.getHeaders(),
413
422
  body: body !== undefined ? JSON.stringify(body) : undefined,
414
- });
423
+ }, retryMaxAttempts);
415
424
  return this.parseJsonResponse(res);
416
425
  }
417
426
  async postText(path, body) {
@@ -538,10 +547,14 @@ export class DataikuClient {
538
547
  }
539
548
  }
540
549
  /* ---- private: retry loop ---- */
541
- async fetchWithRetry(url, init) {
550
+ async fetchWithRetry(url, init, retryMaxAttempts) {
542
551
  const method = (init.method ?? "GET").toUpperCase();
543
- const retryEnabled = shouldRetryMethod(method);
544
- const maxAttempts = retryEnabled ? this.retryMaxAttempts : 1;
552
+ const retryEnabled = shouldRetryMethod(method) || retryMaxAttempts !== undefined;
553
+ const maxAttempts = retryMaxAttempts === undefined
554
+ ? retryEnabled
555
+ ? this.retryMaxAttempts
556
+ : 1
557
+ : Math.min(retryMaxAttempts, MAX_RETRY_ATTEMPTS_CAP);
545
558
  const delaysMs = [];
546
559
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
547
560
  let timedOut = false;
@@ -9,6 +9,11 @@ type SqlQueryOptions = {
9
9
  postQueries?: string[];
10
10
  type?: string;
11
11
  projectKey?: string;
12
+ /**
13
+ * Opt in to transient retries while starting the query. The SQL may execute
14
+ * more than once when DSS accepts a request but loses its response.
15
+ */
16
+ retryMaxAttempts?: number;
12
17
  };
13
18
  export declare class SqlResource extends BaseResource {
14
19
  private resolveOptionalProjectKey;
@@ -126,11 +126,12 @@ export class SqlResource extends BaseResource {
126
126
  * or `datasetFullName` (run against a dataset's connection).
127
127
  */
128
128
  async startQuery(opts) {
129
+ const { retryMaxAttempts, ...queryOpts } = opts;
129
130
  return this.client.post("/public/api/sql/queries/", {
130
- ...opts,
131
- projectKey: opts.projectKey ?? this.resolveOptionalProjectKey(opts.projectKey),
132
- type: opts.type ?? "sql",
133
- });
131
+ ...queryOpts,
132
+ projectKey: queryOpts.projectKey ?? this.resolveOptionalProjectKey(queryOpts.projectKey),
133
+ type: queryOpts.type ?? "sql",
134
+ }, retryMaxAttempts === undefined ? undefined : { retryMaxAttempts, });
134
135
  }
135
136
  /**
136
137
  * Stream results of a started query as parsed JSON (array of arrays).
package/dist/src/skill.js CHANGED
@@ -45,7 +45,7 @@ For disposable agent tests, set \`DSS_CONFIG_DIR\` to a temporary directory so s
45
45
  - Use \`--dry-run\` only when that action's registry entry has \`dryRun:true\`. \`--plan\` explains the operation; \`--dry-run\` exercises the action-specific simulation path. Never add an unsupported flag.
46
46
  - When a create/upload action advertises \`--record-cleanup\`, pass \`--record-cleanup cleanup.jsonl\`. \`dss cleanup --file cleanup.jsonl\` previews the recorded cleanup steps in reverse order and does not mutate DSS; add \`--apply\` only after checking the preview.
47
47
  - For JSON payload actions, follow \`inputContract\`, \`requiredFlags\`, and \`requiredOneOf\`. Prefer \`--data-file PATH\` or \`--stdin\` when advertised instead of inline \`--data\`; this preserves exact JSON across shells and keeps large or sensitive payloads out of process arguments.
48
- - Authenticated actions advertise \`--request-timeout MS\` and \`--retries N\`. Long-running actions separately advertise controls such as \`--timeout MS\`, \`--poll-interval MS\`, and log limits; use only the flags in that action's registry entry.
48
+ - Authenticated actions advertise \`--request-timeout MS\` and \`--retries N\`; \`--retries\` applies to idempotent GET requests. Long-running actions separately advertise controls such as \`--timeout MS\`, \`--poll-interval MS\`, and log limits; use only the flags in that action's registry entry.
49
49
  - Before live mutation tests, use \`dss fixtures --json\` to discover compatible test resources instead of guessing project objects.
50
50
 
51
51
  ## Authentication
@@ -179,6 +179,7 @@ Mutations print a small JSON ack to stdout and exit 0 on success (e.g. \`{"updat
179
179
  - \`dss api-service list-packages SERVICE\` first verifies the parent service through its settings. A \`not_found\` error means the service is missing (verify the service ID and project key); an empty array means the service exists but has no deployable packages. Do not reinterpret \`not_found\` as an empty package list or retry the lower-level packages route.
180
180
  - \`dss notebook clear-jupyter-outputs NAME --dry-run\` returns the full \`current\` and \`next\` notebook states. Applying it clears \`outputs\` and resets \`execution_count\` to \`0\` only on code cells, preserving markdown and raw cells unchanged.
181
181
  - \`dss sql query ... --dataset PROJECT.NAME\` first queries through the dataset. If DSS rejects that dataset connection as neither SQL nor HDFS, the CLI reads dataset metadata and retries with \`params.connection\` (using its schema or catalog as the database when available). A readable dataset with no usable connection exits with \`validation_failed\` and advises \`--connection\`; dataset metadata \`404\` and \`403\` errors propagate as \`not_found\` and \`permission_denied\`.
182
+ - \`dss sql query ... --start-retries N\` opts the query-start POST into transient retries with exponential backoff. A lost response can cause DSS to execute the SQL more than once, so use it only for SQL whose repetition is safe; ordinary \`--retries N\` remains GET-only.
182
183
 
183
184
  ## Error envelope
184
185
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dataiku-sdk",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "description": "Dataiku DSS SDK and CLI for programmatic access to DSS REST APIs",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -43,7 +43,9 @@
43
43
  "dprint": "^0.55.2",
44
44
  "js-tiktoken": "1.0.21",
45
45
  "oxlint": "^1.78.0",
46
- "typescript": "^7.0.2"
46
+ "typescript": "^7.0.2",
47
+ "typescript-language-server": "5.3.0",
48
+ "typescript-language-service": "npm:typescript@5.9.3"
47
49
  },
48
50
  "dependencies": {
49
51
  "@sinclair/typebox": "^0.34.52"