dataiku-sdk 0.12.2 → 0.12.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/src/cli/commands/api-service.js +0 -1
- package/dist/src/cli/commands/notebook.js +5 -1
- package/dist/src/cli/output.js +1 -1
- package/dist/src/cli.js +42 -12
- package/dist/src/errors.d.ts +9 -1
- package/dist/src/errors.js +39 -6
- package/dist/src/resources/api-services.js +1 -0
- package/dist/src/resources/notebooks.js +9 -5
- package/dist/src/resources/sql.js +18 -25
- package/package.json +1 -1
|
@@ -59,7 +59,6 @@ export const apiServiceCommands = {
|
|
|
59
59
|
handler: async (c, a, f) => {
|
|
60
60
|
requireArgs(a, 1, "dss api-service list-packages <serviceId> [--project-key KEY]");
|
|
61
61
|
const projectKey = f["project-key"];
|
|
62
|
-
await c.apiServices.getSettings(a[0], projectKey);
|
|
63
62
|
return c.apiServices.listPackages(a[0], projectKey);
|
|
64
63
|
},
|
|
65
64
|
usage: "dss api-service list-packages <serviceId> [--project-key KEY]",
|
|
@@ -44,7 +44,11 @@ export const notebookCommands = {
|
|
|
44
44
|
const current = await c.notebooks.getJupyter(a[0], pk);
|
|
45
45
|
const next = {
|
|
46
46
|
...current,
|
|
47
|
-
cells: current.cells.map((cell) =>
|
|
47
|
+
cells: current.cells.map((cell) => {
|
|
48
|
+
if (cell.cell_type !== "code")
|
|
49
|
+
return cell;
|
|
50
|
+
return { ...cell, outputs: [], execution_count: 0, };
|
|
51
|
+
}),
|
|
48
52
|
};
|
|
49
53
|
return {
|
|
50
54
|
dryRun: true,
|
package/dist/src/cli/output.js
CHANGED
|
@@ -73,7 +73,7 @@ export function transientBodyWithTargetContext(body, target, elapsedMs) {
|
|
|
73
73
|
}
|
|
74
74
|
export function addTransientTargetContext(error, target, elapsedMs) {
|
|
75
75
|
if (error instanceof DataikuError && error.category === "transient") {
|
|
76
|
-
throw new DataikuError(error.status, error.statusText, transientBodyWithTargetContext(error.body, target, elapsedMs), error.retry, error.requestId);
|
|
76
|
+
throw new DataikuError(error.status, error.statusText, transientBodyWithTargetContext(error.body, target, elapsedMs), error.retry, error.requestId, { target, elapsedMs, });
|
|
77
77
|
}
|
|
78
78
|
throw error;
|
|
79
79
|
}
|
package/dist/src/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import { COMMANDS_RUN_HINT, missingActionError, noCommandError, requireArgs, unk
|
|
|
12
12
|
import { cliVersionResult, } from "./cli/version.js";
|
|
13
13
|
import { DataikuClient, } from "./client.js";
|
|
14
14
|
import { getCredentialsPath, } from "./config.js";
|
|
15
|
-
import { ClientValidationError, DataikuError, dataikuErrorCode, } from "./errors.js";
|
|
15
|
+
import { canonicalStatusText, ClientValidationError, DataikuError, dataikuErrorCode, } from "./errors.js";
|
|
16
16
|
import { AGENTS, detectAgents, findWorkspaceRoot, installSkill, planSkillInstalls, } from "./skill.js";
|
|
17
17
|
import { appendCleanupLedgerEntry, readCleanupLedger, } from "./utils/cleanup-ledger.js";
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
@@ -833,16 +833,41 @@ function rawCommandContext() {
|
|
|
833
833
|
: undefined),
|
|
834
834
|
};
|
|
835
835
|
}
|
|
836
|
-
|
|
836
|
+
const SAFE_RESPONSE_METADATA_KEYS = [
|
|
837
|
+
"requestId",
|
|
838
|
+
"request_id",
|
|
839
|
+
"errorId",
|
|
840
|
+
"elapsedMs",
|
|
841
|
+
];
|
|
842
|
+
function safeResponseMetadata(body) {
|
|
837
843
|
try {
|
|
838
844
|
const parsed = JSON.parse(body);
|
|
839
|
-
|
|
840
|
-
|
|
845
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
846
|
+
return {};
|
|
847
|
+
const metadata = {};
|
|
848
|
+
for (const key of SAFE_RESPONSE_METADATA_KEYS) {
|
|
849
|
+
const value = parsed[key];
|
|
850
|
+
if ((typeof value === "string" && value.length > 0)
|
|
851
|
+
|| (typeof value === "number" && Number.isFinite(value))
|
|
852
|
+
|| typeof value === "boolean") {
|
|
853
|
+
metadata[key] = value;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
return metadata;
|
|
841
857
|
}
|
|
842
858
|
catch {
|
|
843
|
-
return
|
|
859
|
+
return {};
|
|
844
860
|
}
|
|
845
861
|
}
|
|
862
|
+
function requestIdFromBody(body) {
|
|
863
|
+
const metadata = safeResponseMetadata(body);
|
|
864
|
+
for (const key of ["requestId", "request_id", "errorId",]) {
|
|
865
|
+
const value = metadata[key];
|
|
866
|
+
if (typeof value === "string")
|
|
867
|
+
return value;
|
|
868
|
+
}
|
|
869
|
+
return undefined;
|
|
870
|
+
}
|
|
846
871
|
const MISSING_PROJECT_KEY_ERROR_PREFIX = "projectKey is required";
|
|
847
872
|
function errorExitCode(err) {
|
|
848
873
|
if (err instanceof CommandResultFailure)
|
|
@@ -884,13 +909,18 @@ function buildErrorReport(err) {
|
|
|
884
909
|
};
|
|
885
910
|
}
|
|
886
911
|
if (err instanceof DataikuError) {
|
|
887
|
-
const errorMessage = err.category === "not_found"
|
|
888
|
-
&& err.message.includes("Dataiku instance not found")
|
|
889
|
-
&& context.resource
|
|
912
|
+
const errorMessage = err.category === "not_found" && context.resource
|
|
890
913
|
? `Not found: ${context.resource}${context.action ? ` ${context.action}` : ""}`
|
|
891
914
|
+ `${context.projectKey ? ` in project ${context.projectKey}` : ""}`
|
|
892
|
-
+
|
|
893
|
-
|
|
915
|
+
+ " — verify the object identifier and project key."
|
|
916
|
+
+ `\nHint: ${err.retryHint}`
|
|
917
|
+
: err.safeMessage;
|
|
918
|
+
const safeMetadata = safeResponseMetadata(err.body);
|
|
919
|
+
if (err.trustedTarget)
|
|
920
|
+
safeMetadata.target = err.trustedTarget;
|
|
921
|
+
if (err.trustedElapsedMs !== undefined)
|
|
922
|
+
safeMetadata.elapsedMs = err.trustedElapsedMs;
|
|
923
|
+
const safeBody = JSON.stringify(safeMetadata);
|
|
894
924
|
return {
|
|
895
925
|
type: "error",
|
|
896
926
|
ok: false,
|
|
@@ -904,8 +934,8 @@ function buildErrorReport(err) {
|
|
|
904
934
|
requestId: err.requestId ?? requestIdFromBody(err.body),
|
|
905
935
|
details: {
|
|
906
936
|
dssCategory: err.category,
|
|
907
|
-
statusText: err.
|
|
908
|
-
body:
|
|
937
|
+
statusText: canonicalStatusText(err.status),
|
|
938
|
+
body: safeBody,
|
|
909
939
|
...(err.retry ? { retry: err.retry, } : {}),
|
|
910
940
|
},
|
|
911
941
|
...context,
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export interface DataikuRetryMetadata {
|
|
|
15
15
|
delaysMs: number[];
|
|
16
16
|
timedOut: boolean;
|
|
17
17
|
}
|
|
18
|
+
export interface DataikuErrorTrustedMetadata {
|
|
19
|
+
target?: string;
|
|
20
|
+
elapsedMs?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function canonicalStatusText(status: number): string;
|
|
18
23
|
export declare class ClientValidationError extends Error {
|
|
19
24
|
readonly code: StableErrorCode;
|
|
20
25
|
readonly hint?: string;
|
|
@@ -31,7 +36,10 @@ export declare class DataikuError extends Error {
|
|
|
31
36
|
retryHint: string;
|
|
32
37
|
retry?: DataikuRetryMetadata;
|
|
33
38
|
requestId?: string;
|
|
34
|
-
|
|
39
|
+
readonly trustedTarget?: string;
|
|
40
|
+
readonly trustedElapsedMs?: number;
|
|
41
|
+
constructor(status: number, statusText: string, body: string, retry?: DataikuRetryMetadata, requestId?: string, trustedMetadata?: DataikuErrorTrustedMetadata);
|
|
42
|
+
get safeMessage(): string;
|
|
35
43
|
private static extractSummary;
|
|
36
44
|
private static formatRetryMetadata;
|
|
37
45
|
private static buildDetails;
|
package/dist/src/errors.js
CHANGED
|
@@ -12,6 +12,25 @@ export function dataikuErrorCode(category) {
|
|
|
12
12
|
return "internal_error";
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
const CANONICAL_STATUS_TEXT = {
|
|
16
|
+
400: "Bad Request",
|
|
17
|
+
401: "Unauthorized",
|
|
18
|
+
403: "Forbidden",
|
|
19
|
+
404: "Not Found",
|
|
20
|
+
408: "Request Timeout",
|
|
21
|
+
409: "Conflict",
|
|
22
|
+
422: "Unprocessable Entity",
|
|
23
|
+
425: "Too Early",
|
|
24
|
+
429: "Too Many Requests",
|
|
25
|
+
500: "Internal Server Error",
|
|
26
|
+
501: "Not Implemented",
|
|
27
|
+
502: "Bad Gateway",
|
|
28
|
+
503: "Service Unavailable",
|
|
29
|
+
504: "Gateway Timeout",
|
|
30
|
+
};
|
|
31
|
+
export function canonicalStatusText(status) {
|
|
32
|
+
return CANONICAL_STATUS_TEXT[status] ?? (status === 0 ? "Network Error" : "HTTP Error");
|
|
33
|
+
}
|
|
15
34
|
export class ClientValidationError extends Error {
|
|
16
35
|
code;
|
|
17
36
|
hint;
|
|
@@ -276,8 +295,10 @@ export class DataikuError extends Error {
|
|
|
276
295
|
retryHint;
|
|
277
296
|
retry;
|
|
278
297
|
requestId;
|
|
279
|
-
|
|
280
|
-
|
|
298
|
+
trustedTarget;
|
|
299
|
+
trustedElapsedMs;
|
|
300
|
+
constructor(status, statusText, body, retry, requestId, trustedMetadata) {
|
|
301
|
+
const details = DataikuError.buildDetails(status, body, retry);
|
|
281
302
|
super(details.message);
|
|
282
303
|
this.status = status;
|
|
283
304
|
this.statusText = statusText;
|
|
@@ -288,8 +309,20 @@ export class DataikuError extends Error {
|
|
|
288
309
|
this.retryHint = details.retryHint;
|
|
289
310
|
this.retry = retry;
|
|
290
311
|
this.requestId = requestId;
|
|
312
|
+
this.trustedTarget = trustedMetadata?.target;
|
|
313
|
+
this.trustedElapsedMs = trustedMetadata?.elapsedMs;
|
|
314
|
+
}
|
|
315
|
+
get safeMessage() {
|
|
316
|
+
const retrySummary = DataikuError.formatRetryMetadata(this.retry);
|
|
317
|
+
return [
|
|
318
|
+
`${this.status} ${canonicalStatusText(this.status)}`,
|
|
319
|
+
`Error type: ${this.category}`,
|
|
320
|
+
`Retryable: ${this.retryable ? "yes" : "no"}`,
|
|
321
|
+
`Hint: ${this.retryHint}`,
|
|
322
|
+
...(retrySummary ? [retrySummary,] : []),
|
|
323
|
+
].join("\n");
|
|
291
324
|
}
|
|
292
|
-
static extractSummary(_status,
|
|
325
|
+
static extractSummary(_status, body) {
|
|
293
326
|
try {
|
|
294
327
|
const parsed = JSON.parse(body);
|
|
295
328
|
if (parsed.message)
|
|
@@ -316,14 +349,14 @@ export class DataikuError extends Error {
|
|
|
316
349
|
`Timed out: ${retry.timedOut ? "yes" : "no"}`,
|
|
317
350
|
].join(" | ");
|
|
318
351
|
}
|
|
319
|
-
static buildDetails(status,
|
|
320
|
-
const summary = DataikuError.extractSummary(status,
|
|
352
|
+
static buildDetails(status, body, retry) {
|
|
353
|
+
const summary = DataikuError.extractSummary(status, body);
|
|
321
354
|
const taxonomy = classifyDataikuError(status, body);
|
|
322
355
|
const retrySummary = DataikuError.formatRetryMetadata(retry);
|
|
323
356
|
return {
|
|
324
357
|
...taxonomy,
|
|
325
358
|
message: [
|
|
326
|
-
`${status} ${
|
|
359
|
+
`${status} ${canonicalStatusText(status)}: ${summary}`,
|
|
327
360
|
`Error type: ${taxonomy.category}`,
|
|
328
361
|
`Retryable: ${taxonomy.retryable ? "yes" : "no"}`,
|
|
329
362
|
`Hint: ${taxonomy.retryHint}`,
|
|
@@ -28,6 +28,7 @@ export class ApiServicesResource extends BaseResource {
|
|
|
28
28
|
}
|
|
29
29
|
/** List deployable packages for an API service. */
|
|
30
30
|
async listPackages(serviceId, projectKey) {
|
|
31
|
+
await this.getSettings(serviceId, projectKey);
|
|
31
32
|
return this.client.get(`${this.servicePath(serviceId, projectKey)}/packages`);
|
|
32
33
|
}
|
|
33
34
|
/** Get an API service package summary. */
|
|
@@ -36,11 +36,15 @@ export class NotebooksResource extends BaseResource {
|
|
|
36
36
|
*/
|
|
37
37
|
async clearJupyterOutputs(name, projectKey) {
|
|
38
38
|
const notebook = await this.getJupyter(name, projectKey);
|
|
39
|
-
const clearedCells = notebook.cells.map((cell) =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
const clearedCells = notebook.cells.map((cell) => {
|
|
40
|
+
if (cell.cell_type !== "code")
|
|
41
|
+
return cell;
|
|
42
|
+
return {
|
|
43
|
+
...cell,
|
|
44
|
+
outputs: [],
|
|
45
|
+
execution_count: 0,
|
|
46
|
+
};
|
|
47
|
+
});
|
|
44
48
|
await this.saveJupyter(name, { ...notebook, cells: clearedCells, }, projectKey);
|
|
45
49
|
}
|
|
46
50
|
/** List running kernel sessions for a Jupyter notebook. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataikuError, } from "../errors.js";
|
|
1
|
+
import { ClientValidationError, DataikuError, } from "../errors.js";
|
|
2
2
|
import { BaseResource, } from "./base.js";
|
|
3
3
|
const UNSUPPORTED_SQL_DATASET_CONNECTION_DETAIL = "neither of sql nor hdfs type";
|
|
4
4
|
function isUnsupportedSqlDatasetConnectionError(error) {
|
|
@@ -161,28 +161,23 @@ export class SqlResource extends BaseResource {
|
|
|
161
161
|
const datasetFullName = opts.datasetFullName;
|
|
162
162
|
if (!datasetFullName)
|
|
163
163
|
return null;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (!connection)
|
|
174
|
-
return null;
|
|
175
|
-
return {
|
|
176
|
-
...opts,
|
|
177
|
-
connection,
|
|
178
|
-
datasetFullName: undefined,
|
|
179
|
-
database: opts.database ?? asString(params?.schema) ?? asString(params?.catalog),
|
|
180
|
-
projectKey,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
catch {
|
|
164
|
+
const identifier = splitDatasetIdentifier(datasetFullName, opts.projectKey);
|
|
165
|
+
const projectKey = identifier.projectKey
|
|
166
|
+
? identifier.projectKey
|
|
167
|
+
: this.resolveProjectKey(opts.projectKey);
|
|
168
|
+
const dsEnc = encodeURIComponent(identifier.datasetName);
|
|
169
|
+
const raw = await this.client.get(`/public/api/projects/${encodeURIComponent(projectKey)}/datasets/${dsEnc}`);
|
|
170
|
+
const params = asRecord(raw.params);
|
|
171
|
+
const connection = asString(params?.connection);
|
|
172
|
+
if (!connection)
|
|
184
173
|
return null;
|
|
185
|
-
|
|
174
|
+
return {
|
|
175
|
+
...opts,
|
|
176
|
+
connection,
|
|
177
|
+
datasetFullName: undefined,
|
|
178
|
+
database: opts.database ?? asString(params?.schema) ?? asString(params?.catalog),
|
|
179
|
+
projectKey,
|
|
180
|
+
};
|
|
186
181
|
}
|
|
187
182
|
/**
|
|
188
183
|
* Execute a SQL query end-to-end: start, stream all rows, verify, return combined result.
|
|
@@ -198,9 +193,7 @@ export class SqlResource extends BaseResource {
|
|
|
198
193
|
withSqlErrorContext(error);
|
|
199
194
|
const retryOpts = await this.resolveDatasetQueryFallback(queryOpts);
|
|
200
195
|
if (!retryOpts) {
|
|
201
|
-
throw new
|
|
202
|
-
cause: error,
|
|
203
|
-
});
|
|
196
|
+
throw new ClientValidationError(buildUnsupportedSqlDatasetConnectionMessage(queryOpts.datasetFullName));
|
|
204
197
|
}
|
|
205
198
|
try {
|
|
206
199
|
return await this.executeQuery(retryOpts);
|