dataiku-sdk 3.4.0 → 3.6.0
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 +4 -4
- package/bin/dss.js +28 -2
- package/dist/build-metadata.json +1 -1
- package/dist/src/cli/coerce.d.ts +0 -1
- package/dist/src/cli/coerce.js +0 -5
- package/dist/src/cli/command-syntax.json +14524 -0
- package/dist/src/cli/commands/analysis.js +6 -9
- package/dist/src/cli/commands/api-deployer.js +15 -33
- package/dist/src/cli/commands/api-service.js +17 -27
- package/dist/src/cli/commands/app.js +25 -41
- package/dist/src/cli/commands/bundle.js +15 -24
- package/dist/src/cli/commands/business-app.js +10 -17
- package/dist/src/cli/commands/code-env.js +23 -36
- package/dist/src/cli/commands/code.js +4 -4
- package/dist/src/cli/commands/connection.js +12 -22
- package/dist/src/cli/commands/continuous-activity.js +6 -9
- package/dist/src/cli/commands/dashboard.js +8 -13
- package/dist/src/cli/commands/data-collection.js +9 -16
- package/dist/src/cli/commands/data-quality.js +14 -26
- package/dist/src/cli/commands/dataset.js +29 -54
- package/dist/src/cli/commands/discussion.js +7 -10
- package/dist/src/cli/commands/doctor.js +3 -3
- package/dist/src/cli/commands/flow-zone.js +8 -17
- package/dist/src/cli/commands/folder.js +12 -20
- package/dist/src/cli/commands/future.js +7 -10
- package/dist/src/cli/commands/group.js +7 -11
- package/dist/src/cli/commands/insight.js +7 -11
- package/dist/src/cli/commands/job.js +17 -26
- package/dist/src/cli/commands/knowledge-bank.js +5 -6
- package/dist/src/cli/commands/llm.js +5 -8
- package/dist/src/cli/commands/macro.js +9 -16
- package/dist/src/cli/commands/meaning.js +7 -11
- package/dist/src/cli/commands/metrics.js +7 -10
- package/dist/src/cli/commands/ml-task.js +12 -20
- package/dist/src/cli/commands/model-evaluation-store.js +7 -11
- package/dist/src/cli/commands/notebook.js +15 -27
- package/dist/src/cli/commands/plugin.js +35 -68
- package/dist/src/cli/commands/project-deployer.js +10 -22
- package/dist/src/cli/commands/project-folder.js +10 -17
- package/dist/src/cli/commands/project-git.js +38 -70
- package/dist/src/cli/commands/project-library.js +15 -23
- package/dist/src/cli/commands/project.js +9 -26
- package/dist/src/cli/commands/recipe.d.ts +16 -0
- package/dist/src/cli/commands/recipe.js +83 -94
- package/dist/src/cli/commands/saved-model.js +23 -39
- package/dist/src/cli/commands/scenario.js +20 -34
- package/dist/src/cli/commands/sql.js +4 -4
- package/dist/src/cli/commands/statistics.js +11 -18
- package/dist/src/cli/commands/streaming-endpoint.js +7 -11
- package/dist/src/cli/commands/user.js +11 -22
- package/dist/src/cli/commands/variable.js +3 -4
- package/dist/src/cli/commands/webapp.js +10 -16
- package/dist/src/cli/commands/wiki.js +9 -13
- package/dist/src/cli/commands/workspace.js +8 -14
- package/dist/src/cli/contract.d.ts +5 -15
- package/dist/src/cli/contract.js +157 -254
- package/dist/src/cli/doctor.js +1 -0
- package/dist/src/cli/env.d.ts +2 -0
- package/dist/src/cli/env.js +16 -1
- package/dist/src/cli/flags.d.ts +1 -0
- package/dist/src/cli/flags.js +4 -9
- package/dist/src/cli/helpers/app-permissions.js +7 -5
- package/dist/src/cli/helpers/flow-zone.js +8 -6
- package/dist/src/cli/helpers/recipe.js +2 -1
- package/dist/src/cli/syntax.d.ts +83 -0
- package/dist/src/cli/syntax.js +217 -0
- package/dist/src/cli/types.d.ts +3 -0
- package/dist/src/cli/usage.d.ts +1 -1
- package/dist/src/cli/usage.js +4 -2
- package/dist/src/cli/version.d.ts +0 -2
- package/dist/src/cli/version.js +6 -7
- package/dist/src/cli.js +132 -274
- package/dist/src/client.d.ts +2 -1
- package/dist/src/client.js +32 -17
- package/dist/src/errors.d.ts +12 -1
- package/dist/src/errors.js +28 -3
- package/dist/src/index.d.ts +1 -3
- package/dist/src/index.js +2 -2
- package/dist/src/resources/api-services.js +2 -3
- package/dist/src/resources/applications.js +2 -4
- package/dist/src/resources/base.d.ts +2 -0
- package/dist/src/resources/base.js +14 -2
- package/dist/src/resources/code-envs.js +3 -5
- package/dist/src/resources/data-quality.js +14 -13
- package/dist/src/resources/datasets.d.ts +13 -0
- package/dist/src/resources/datasets.js +5 -4
- package/dist/src/resources/flow-zones.js +4 -2
- package/dist/src/resources/folders.js +4 -2
- package/dist/src/resources/futures.js +1 -3
- package/dist/src/resources/insights.js +3 -2
- package/dist/src/resources/jobs.js +4 -6
- package/dist/src/resources/macros.d.ts +1 -1
- package/dist/src/resources/macros.js +3 -7
- package/dist/src/resources/notebooks.js +2 -3
- package/dist/src/resources/project-git.js +9 -11
- package/dist/src/resources/project-library.d.ts +0 -2
- package/dist/src/resources/project-library.js +2 -7
- package/dist/src/resources/projects.js +4 -3
- package/dist/src/resources/recipes.d.ts +28 -0
- package/dist/src/resources/recipes.js +117 -89
- package/dist/src/resources/saved-models.js +1 -13
- package/dist/src/resources/scenarios.js +1 -3
- package/dist/src/resources/sql.js +9 -8
- package/dist/src/resources/statistics.js +3 -4
- package/dist/src/resources/variables.js +2 -1
- package/dist/src/resources/webapps.js +2 -3
- package/dist/src/schemas.d.ts +1 -2
- package/dist/src/schemas.js +1 -1
- package/dist/src/skill.js +6 -7
- package/dist/src/utils/cleanup-ledger.js +9 -8
- package/dist/src/utils/deep-merge.js +2 -4
- package/dist/src/utils/flow-map.js +1 -6
- package/dist/src/utils/polling.d.ts +3 -0
- package/dist/src/utils/polling.js +3 -0
- package/dist/src/utils/project-archive.js +10 -14
- package/dist/src/utils/project-incarnation.js +3 -7
- package/dist/src/utils/records.d.ts +4 -0
- package/dist/src/utils/records.js +8 -0
- package/dist/src/utils/stable-hash.d.ts +3 -1
- package/dist/src/utils/stable-hash.js +2 -0
- package/package.json +10 -14
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +3 -4
- package/skills/dataiku-dss/references/authentication.md +3 -3
- package/skills/dataiku-dss/references/coding.md +1 -1
- package/skills/dataiku-dss/references/discovery.md +1 -1
- package/skills/dataiku-dss/references/mutations.md +0 -1
- package/dist/src/utils/pagination.d.ts +0 -8
- package/dist/src/utils/pagination.js +0 -23
- package/packages/types/dist/index.d.ts +0 -1062
- package/packages/types/dist/index.js +0 -871
package/dist/src/client.js
CHANGED
|
@@ -3,7 +3,7 @@ import { basename, } from "node:path";
|
|
|
3
3
|
import { getCACertificates, } from "node:tls";
|
|
4
4
|
import { Value, } from "@sinclair/typebox/value";
|
|
5
5
|
import { safeParseSchema, } from "./schemas.js";
|
|
6
|
-
import { classifyDataikuError, ClientValidationError, DataikuError,
|
|
6
|
+
import { classifyDataikuError, ClientValidationError, DataikuError, nonJsonResponseBody, } from "./errors.js";
|
|
7
7
|
import { AnalysesResource, } from "./resources/analyses.js";
|
|
8
8
|
import { ApiDeployerResource, } from "./resources/api-deployer.js";
|
|
9
9
|
import { ApiServicesResource, } from "./resources/api-services.js";
|
|
@@ -187,7 +187,7 @@ function buildFetchTlsOptions(config) {
|
|
|
187
187
|
}
|
|
188
188
|
catch (error) {
|
|
189
189
|
const message = error instanceof Error ? error.message : String(error);
|
|
190
|
-
throw new
|
|
190
|
+
throw new ClientValidationError(`Unable to read CA certificate bundle at ${caCertPath}: ${message}`, "invalid_flag_value", undefined, undefined, {
|
|
191
191
|
cause: error,
|
|
192
192
|
});
|
|
193
193
|
}
|
|
@@ -416,12 +416,14 @@ export class DataikuClient {
|
|
|
416
416
|
return (this.groupsResource ??= new GroupsResource(this));
|
|
417
417
|
}
|
|
418
418
|
constructor(config) {
|
|
419
|
+
/* oxlint-disable dss/no-direct-process-env -- SDK constructor defaults (DATAIKU_URL/DATAIKU_API_KEY) for library callers */
|
|
419
420
|
const envUrl = process.env["DATAIKU_URL"]?.trim();
|
|
420
421
|
const envApiKey = process.env["DATAIKU_API_KEY"]?.trim();
|
|
422
|
+
/* oxlint-enable dss/no-direct-process-env */
|
|
421
423
|
const url = config?.url?.trim() || envUrl;
|
|
422
424
|
const apiKey = config?.apiKey?.trim() || envApiKey;
|
|
423
425
|
if (!url || !apiKey) {
|
|
424
|
-
throw new
|
|
426
|
+
throw new ClientValidationError("Dataiku URL and API key are required: pass {url, apiKey} or set DATAIKU_URL/DATAIKU_API_KEY", "missing_required_flag");
|
|
425
427
|
}
|
|
426
428
|
if (hasEmbeddedUserinfo(url)) {
|
|
427
429
|
throw new ClientValidationError("Dataiku URL must not contain embedded credentials (userinfo). Authenticate with an API key instead.", "validation_failed", "Pass the DSS base URL without a username or password.", { urlHasEmbeddedUserinfo: true, });
|
|
@@ -463,12 +465,12 @@ export class DataikuClient {
|
|
|
463
465
|
return pk;
|
|
464
466
|
if (this.defaultProjectKey)
|
|
465
467
|
return this.defaultProjectKey;
|
|
466
|
-
throw new
|
|
468
|
+
throw new ClientValidationError("projectKey is required — pass it as a parameter or set projectKey in DataikuClientConfig", "missing_required_flag", "Pass --project-key or set DATAIKU_PROJECT_KEY.");
|
|
467
469
|
}
|
|
468
470
|
/* ---- public: HTTP verbs ---- */
|
|
469
471
|
async get(path, options) {
|
|
470
472
|
const deadlineAt = resolveGetDeadlineAt(options);
|
|
471
|
-
const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, { method: "GET", headers: this.getHeaders(), }, options?.noRetry === true ? 1 : undefined, deadlineAt);
|
|
473
|
+
const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, { method: "GET", headers: this.getHeaders(false), }, options?.noRetry === true ? 1 : undefined, deadlineAt);
|
|
472
474
|
return this.parseJsonResponse(res, deadlineAt);
|
|
473
475
|
}
|
|
474
476
|
/**
|
|
@@ -479,7 +481,7 @@ export class DataikuClient {
|
|
|
479
481
|
async getWithMetadata(path) {
|
|
480
482
|
const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
481
483
|
method: "GET",
|
|
482
|
-
headers: this.getHeaders(),
|
|
484
|
+
headers: this.getHeaders(false),
|
|
483
485
|
});
|
|
484
486
|
const data = await this.parseJsonResponse(res);
|
|
485
487
|
return { data, meta: this.responseMeta(res.headers), };
|
|
@@ -541,7 +543,7 @@ export class DataikuClient {
|
|
|
541
543
|
}
|
|
542
544
|
const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
543
545
|
method: "POST",
|
|
544
|
-
headers: this.getHeaders(),
|
|
546
|
+
headers: this.getHeaders(body !== undefined),
|
|
545
547
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
546
548
|
}, retryMaxAttempts);
|
|
547
549
|
return this.parseJsonResponse(res);
|
|
@@ -553,7 +555,7 @@ export class DataikuClient {
|
|
|
553
555
|
async postText(path, body) {
|
|
554
556
|
const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
555
557
|
method: "POST",
|
|
556
|
-
headers: this.getHeaders(),
|
|
558
|
+
headers: this.getHeaders(body !== undefined),
|
|
557
559
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
558
560
|
});
|
|
559
561
|
const { text, truncated, } = await this.readBoundedBodyText(res, this.maxResponseBodyBytes);
|
|
@@ -598,7 +600,7 @@ export class DataikuClient {
|
|
|
598
600
|
async put(path, body) {
|
|
599
601
|
const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
600
602
|
method: "PUT",
|
|
601
|
-
headers: this.getHeaders(),
|
|
603
|
+
headers: this.getHeaders(true),
|
|
602
604
|
body: JSON.stringify(body),
|
|
603
605
|
});
|
|
604
606
|
return this.parseJsonResponse(res);
|
|
@@ -606,13 +608,13 @@ export class DataikuClient {
|
|
|
606
608
|
async del(path) {
|
|
607
609
|
await this.fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
608
610
|
method: "DELETE",
|
|
609
|
-
headers: this.getHeaders(),
|
|
611
|
+
headers: this.getHeaders(false),
|
|
610
612
|
});
|
|
611
613
|
}
|
|
612
614
|
async putVoid(path, body) {
|
|
613
615
|
await this.fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
614
616
|
method: "PUT",
|
|
615
|
-
headers: this.getHeaders(),
|
|
617
|
+
headers: this.getHeaders(true),
|
|
616
618
|
body: JSON.stringify(body),
|
|
617
619
|
});
|
|
618
620
|
}
|
|
@@ -624,7 +626,7 @@ export class DataikuClient {
|
|
|
624
626
|
async putVoidNoBody(path) {
|
|
625
627
|
await this.fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
626
628
|
method: "PUT",
|
|
627
|
-
headers: this.getHeaders(),
|
|
629
|
+
headers: this.getHeaders(false),
|
|
628
630
|
});
|
|
629
631
|
}
|
|
630
632
|
/**
|
|
@@ -729,11 +731,12 @@ export class DataikuClient {
|
|
|
729
731
|
return response;
|
|
730
732
|
}
|
|
731
733
|
/* ---- private: headers ---- */
|
|
732
|
-
|
|
734
|
+
/** JSON request headers; Content-Type only when a body is sent. */
|
|
735
|
+
getHeaders(withBody) {
|
|
733
736
|
return {
|
|
734
737
|
Authorization: `Bearer ${this.apiKey}`,
|
|
735
738
|
Accept: "application/json",
|
|
736
|
-
"Content-Type": "application/json",
|
|
739
|
+
...(withBody ? { "Content-Type": "application/json", } : {}),
|
|
737
740
|
};
|
|
738
741
|
}
|
|
739
742
|
getAnyHeaders() {
|
|
@@ -810,8 +813,7 @@ export class DataikuClient {
|
|
|
810
813
|
return JSON.parse(text);
|
|
811
814
|
}
|
|
812
815
|
catch {
|
|
813
|
-
|
|
814
|
-
throw new DataikuError(res.status, res.statusText || "Invalid JSON response", `${NON_JSON_RESPONSE_MARKER}: ${summary}`, undefined, this.requestIdFromHeaders(res.headers));
|
|
816
|
+
throw new DataikuError(res.status, res.statusText || "Invalid JSON response", nonJsonResponseBody(text), undefined, this.requestIdFromHeaders(res.headers));
|
|
815
817
|
}
|
|
816
818
|
}
|
|
817
819
|
/* ---- private: bounded response body reading ---- */
|
|
@@ -1029,7 +1031,20 @@ export class DataikuClient {
|
|
|
1029
1031
|
elapsedMs: Date.now() - startedAt,
|
|
1030
1032
|
});
|
|
1031
1033
|
if (!res.ok) {
|
|
1032
|
-
|
|
1034
|
+
// The status is already known; a body that misses the deadline must not
|
|
1035
|
+
// turn a real 5xx/4xx into a bare transport timeout.
|
|
1036
|
+
let text = "";
|
|
1037
|
+
let truncated = false;
|
|
1038
|
+
try {
|
|
1039
|
+
({ text, truncated, } = await this.readBoundedBodyText(res, this.maxResponseBodyBytes, startedAt + attemptTimeoutMs));
|
|
1040
|
+
}
|
|
1041
|
+
catch (bodyError) {
|
|
1042
|
+
// Oversized bodies keep their own classified error; any other read
|
|
1043
|
+
// failure (deadline abort, dropped connection) keeps the known status.
|
|
1044
|
+
if (bodyError instanceof DataikuError && bodyError.status !== 0)
|
|
1045
|
+
throw bodyError;
|
|
1046
|
+
text = `(response body not received within ${attemptTimeoutMs}ms)`;
|
|
1047
|
+
}
|
|
1033
1048
|
const canRetry = retryEnabled && attempt < maxAttempts && isTransientError(res.status, text);
|
|
1034
1049
|
const serverDelayMs = canRetry ? retryAfterDelayMs(res.headers.get("retry-after")) : 0;
|
|
1035
1050
|
// A longer server wait declines automatic retry; never clamp it into an early request.
|
package/dist/src/errors.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare class ClientValidationError extends Error {
|
|
|
26
26
|
readonly code: StableErrorCode;
|
|
27
27
|
readonly hint?: string;
|
|
28
28
|
readonly details?: Record<string, unknown>;
|
|
29
|
-
constructor(message: string, code?: StableErrorCode, hint?: string, details?: Record<string, unknown
|
|
29
|
+
constructor(message: string, code?: StableErrorCode, hint?: string, details?: Record<string, unknown>, options?: ErrorOptions);
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Message prefix the client stamps on a 2xx body that is not JSON. The
|
|
@@ -34,6 +34,17 @@ export declare class ClientValidationError extends Error {
|
|
|
34
34
|
* taxonomy stay in sync as one contract.
|
|
35
35
|
*/
|
|
36
36
|
export declare const NON_JSON_RESPONSE_MARKER = "Expected JSON response body but got non-JSON content";
|
|
37
|
+
/** Body text for a 2xx response that should have been JSON; truncated to keep envelopes bounded. */
|
|
38
|
+
export declare function nonJsonResponseBody(text: string): string;
|
|
39
|
+
/** Prefix for a 2xx DSS response that lacks something the API documents (a body, an id, a job id). */
|
|
40
|
+
export declare const UNEXPECTED_RESPONSE_MARKER = "Unexpected DSS response";
|
|
41
|
+
/**
|
|
42
|
+
* The one representation of a malformed 2xx DSS response: a DataikuError whose
|
|
43
|
+
* body carries {@link UNEXPECTED_RESPONSE_MARKER}, classified `unexpected_response`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function unexpectedResponseError(detail: string, status?: number): DataikuError;
|
|
46
|
+
/** Prefix for a SQL query failure reported by DSS on a 2xx finish-streaming response. */
|
|
47
|
+
export declare const SQL_QUERY_FAILED_MARKER = "SQL query failed in DSS";
|
|
37
48
|
export declare function classifyDataikuError(status: number, body: string): DataikuErrorTaxonomy;
|
|
38
49
|
export declare class DataikuError extends Error {
|
|
39
50
|
status: number;
|
package/dist/src/errors.js
CHANGED
|
@@ -47,8 +47,8 @@ export class ClientValidationError extends Error {
|
|
|
47
47
|
code;
|
|
48
48
|
hint;
|
|
49
49
|
details;
|
|
50
|
-
constructor(message, code = "validation_failed", hint, details) {
|
|
51
|
-
super(message);
|
|
50
|
+
constructor(message, code = "validation_failed", hint, details, options) {
|
|
51
|
+
super(message, options);
|
|
52
52
|
this.name = "ClientValidationError";
|
|
53
53
|
this.code = code;
|
|
54
54
|
this.hint = hint;
|
|
@@ -61,6 +61,21 @@ export class ClientValidationError extends Error {
|
|
|
61
61
|
* taxonomy stay in sync as one contract.
|
|
62
62
|
*/
|
|
63
63
|
export const NON_JSON_RESPONSE_MARKER = "Expected JSON response body but got non-JSON content";
|
|
64
|
+
/** Body text for a 2xx response that should have been JSON; truncated to keep envelopes bounded. */
|
|
65
|
+
export function nonJsonResponseBody(text) {
|
|
66
|
+
return `${NON_JSON_RESPONSE_MARKER}: ${text.length > 300 ? `${text.slice(0, 300)}…` : text}`;
|
|
67
|
+
}
|
|
68
|
+
/** Prefix for a 2xx DSS response that lacks something the API documents (a body, an id, a job id). */
|
|
69
|
+
export const UNEXPECTED_RESPONSE_MARKER = "Unexpected DSS response";
|
|
70
|
+
/**
|
|
71
|
+
* The one representation of a malformed 2xx DSS response: a DataikuError whose
|
|
72
|
+
* body carries {@link UNEXPECTED_RESPONSE_MARKER}, classified `unexpected_response`.
|
|
73
|
+
*/
|
|
74
|
+
export function unexpectedResponseError(detail, status = 200) {
|
|
75
|
+
return new DataikuError(status, "Unexpected Response", `${UNEXPECTED_RESPONSE_MARKER}: ${detail}`);
|
|
76
|
+
}
|
|
77
|
+
/** Prefix for a SQL query failure reported by DSS on a 2xx finish-streaming response. */
|
|
78
|
+
export const SQL_QUERY_FAILED_MARKER = "SQL query failed in DSS";
|
|
64
79
|
const TLS_CERTIFICATE_HINT = "TLS certificate verification failed. Trust the DSS/corporate CA with --ca-cert PATH or NODE_EXTRA_CA_CERTS; use --insecure only for temporary troubleshooting.";
|
|
65
80
|
const BUSINESS_APPS_API_UNAVAILABLE_HINT = "Business Apps API is not available on this DSS instance. Use classic app commands or check DSS version/feature availability.";
|
|
66
81
|
const MAX_ERROR_SUMMARY_LENGTH = 200;
|
|
@@ -166,13 +181,23 @@ export function classifyDataikuError(status, body) {
|
|
|
166
181
|
// login page, HTML gateway) answered in place of the DSS API. Only the client's
|
|
167
182
|
// own parse-failure marker produces this prefix.
|
|
168
183
|
if (status >= 200 && status < 300
|
|
169
|
-
&& lowerBody.startsWith(NON_JSON_RESPONSE_MARKER.toLowerCase())
|
|
184
|
+
&& (lowerBody.startsWith(NON_JSON_RESPONSE_MARKER.toLowerCase())
|
|
185
|
+
|| lowerBody.startsWith(UNEXPECTED_RESPONSE_MARKER.toLowerCase()))) {
|
|
170
186
|
return {
|
|
171
187
|
category: "unexpected_response",
|
|
172
188
|
retryable: false,
|
|
173
189
|
retryHint: "DSS returned a non-JSON response to a JSON API request (typically a proxy, gateway, or login page). Verify the DSS URL and that no intermediary serves HTML; do not retry unchanged.",
|
|
174
190
|
};
|
|
175
191
|
}
|
|
192
|
+
// finish-streaming answers 2xx with the server-side failure text when the
|
|
193
|
+
// query itself failed (bad SQL, missing column, permissions on the source).
|
|
194
|
+
if (status >= 200 && status < 300 && lowerBody.startsWith(SQL_QUERY_FAILED_MARKER.toLowerCase())) {
|
|
195
|
+
return {
|
|
196
|
+
category: "validation",
|
|
197
|
+
retryable: false,
|
|
198
|
+
retryHint: "The SQL query failed in DSS. Fix the query or its inputs; do not retry unchanged.",
|
|
199
|
+
};
|
|
200
|
+
}
|
|
176
201
|
const isSqlInputConnectionMismatch = (status === 400 || status >= 500)
|
|
177
202
|
&& lowerBody.includes("s3 dataset")
|
|
178
203
|
&& lowerBody.includes("athena connection");
|
package/dist/src/index.d.ts
CHANGED
|
@@ -46,9 +46,7 @@ export { WebappsResource, } from "./resources/webapps.js";
|
|
|
46
46
|
export { WikiResource, } from "./resources/wiki.js";
|
|
47
47
|
export { WorkspacesResource, } from "./resources/workspaces.js";
|
|
48
48
|
export { computeNextPollDelayMs, } from "./utils/polling.js";
|
|
49
|
-
export
|
|
50
|
-
export type { SafeParseResult, } from "./schemas.js";
|
|
51
|
-
export type { BuildMode, CodeEnvActionResult, CodeEnvCreateOptions, CodeEnvDetails, CodeEnvGetLogOptions, CodeEnvLogResult, CodeEnvLogSummary, CodeEnvPackageList, CodeEnvSetPackagesOptions, CodeEnvSummary, CodeEnvUpdateImagesOptions, CodeEnvUpdatePackagesOptions, CodeEnvUsage, CodeEnvVersionForProject, CodeEnvWaitOptions, ConnectionSummary, DashboardDetails, DashboardSummary, DataQualityComputeResult, DataQualityProjectStatus, DataQualityRule, DataQualityRuleResult, DataQualityRules, DataQualityStatus, DataQualityStatusByPartition, DataQualityTimeline, DataQualityTimelineEntry, DatasetCreateOptions, DatasetDetails, DatasetSchema, DatasetSummary, FlowMapOptions, FlowZone, FlowZoneCreateOptions, FlowZoneItem, FlowZoneObjectType, FlowZonePosition, FlowZoneUpdateOptions, FolderCreateOptions, FolderDetails, FolderItem, FolderSummary, FutureState, FutureWaitResult, InsightDetails, InsightSummary, JobSummary, JobWaitResult, JupyterCell, JupyterNotebookContent, JupyterNotebookSummary, MacroDefinition, MacroRunStart, MacroState, MacroSummary, MacroSummaryArray, MacroWaitResult, NotebookSession, ProjectDetails, ProjectGitActionResult, ProjectGitDiffResult, ProjectGitFutureResponse, ProjectGitFutureState, ProjectGitLibraries, ProjectGitLibrary, ProjectGitLogResult, ProjectGitRemote, ProjectGitStatus, ProjectGitTag, ProjectGitTags, ProjectMetadata, ProjectSummary, ProjectTags, ProjectVariables, RecipeCreateOptions, RecipeCreateResult, RecipeDetails, RecipeSummary, ScenarioDetails, ScenarioStatus, ScenarioStepRun, ScenarioSummary, ScenarioWaitResult, SqlNotebookCell, SqlNotebookContent, SqlNotebookSummary, SqlQueryResponse, SqlQueryResult, SqlQuerySchema, WikiArticleData, WikiArticleMetadata, WikiSettings, WikiTaxonomyNode, } from "./schemas.js";
|
|
49
|
+
export * from "./schemas.js";
|
|
52
50
|
export { deepMerge, } from "./utils/deep-merge.js";
|
|
53
51
|
export { type AnalyzedFlowMap, type AnalyzedFlowNode, analyzeFlowMap, type FlowMapComponent, type FlowMapDiagnostic, type FlowMapRendering, type FlowMapZone, type FlowRenderFormat, flowTopologyFingerprint, renderFlowMap, } from "./utils/flow-analysis.js";
|
|
54
52
|
export { type NormalizedFlowEdge, type NormalizedFlowMap, type NormalizedFlowNode, normalizeFlowGraph, } from "./utils/flow-map.js";
|
package/dist/src/index.js
CHANGED
|
@@ -50,8 +50,8 @@ export { WebappsResource, } from "./resources/webapps.js";
|
|
|
50
50
|
export { WikiResource, } from "./resources/wiki.js";
|
|
51
51
|
export { WorkspacesResource, } from "./resources/workspaces.js";
|
|
52
52
|
export { computeNextPollDelayMs, } from "./utils/polling.js";
|
|
53
|
-
// Schemas
|
|
54
|
-
export
|
|
53
|
+
// Schemas, derived types, and parse helpers
|
|
54
|
+
export * from "./schemas.js";
|
|
55
55
|
// Utilities
|
|
56
56
|
export { deepMerge, } from "./utils/deep-merge.js";
|
|
57
57
|
export { analyzeFlowMap, flowTopologyFingerprint, renderFlowMap, } from "./utils/flow-analysis.js";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { ClientValidationError, } from "../errors.js";
|
|
2
|
-
import { stableHash, } from "../utils/stable-hash.js";
|
|
2
|
+
import { SHA256_HEX_PATTERN, stableHash, } from "../utils/stable-hash.js";
|
|
3
3
|
import { BaseResource, } from "./base.js";
|
|
4
|
-
const EXPECT_HASH_PATTERN = /^[0-9a-fA-F]{64}$/;
|
|
5
4
|
function assertExpectedSettingsHash(serviceId, expectHash, current, projectKey) {
|
|
6
|
-
if (!
|
|
5
|
+
if (!SHA256_HEX_PATTERN.test(expectHash)) {
|
|
7
6
|
throw new ClientValidationError("Expected API service settings hash must be a 64-character SHA-256 hex digest.", "validation_failed", "Use the hash value returned by a previous read.", { projectKey, serviceId, });
|
|
8
7
|
}
|
|
9
8
|
const actual = stableHash(current);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClientValidationError, DataikuError, } from "../errors.js";
|
|
2
2
|
import { projectIncarnationHash, } from "../utils/project-incarnation.js";
|
|
3
|
-
import { compareStrings, stableHash, stableJson, } from "../utils/stable-hash.js";
|
|
3
|
+
import { compareStrings, SHA256_HEX_PATTERN, stableHash, stableJson, } from "../utils/stable-hash.js";
|
|
4
4
|
import { BaseResource, } from "./base.js";
|
|
5
5
|
/**
|
|
6
6
|
* Source-verifiable app-manifest reference locations. Validation is scoped to
|
|
@@ -93,8 +93,6 @@ function omitRootFields(value, omitted) {
|
|
|
93
93
|
}
|
|
94
94
|
return result;
|
|
95
95
|
}
|
|
96
|
-
/** Lowercase or uppercase SHA-256 hex digest, as emitted by `stableHash`. */
|
|
97
|
-
const EXPECT_HASH_PATTERN = /^[0-9a-fA-F]{64}$/;
|
|
98
96
|
/**
|
|
99
97
|
* Project a manifest onto its version state. Only string values count: a
|
|
100
98
|
* non-string `version` is reported as null rather than coerced, so callers can
|
|
@@ -295,7 +293,7 @@ export class ApplicationsResource extends BaseResource {
|
|
|
295
293
|
}
|
|
296
294
|
const expectHash = update.expectHash;
|
|
297
295
|
if (expectHash !== undefined
|
|
298
|
-
&& (typeof expectHash !== "string" || !
|
|
296
|
+
&& (typeof expectHash !== "string" || !SHA256_HEX_PATTERN.test(expectHash))) {
|
|
299
297
|
throw new ClientValidationError("Expected manifest hash must be a 64-character SHA-256 hex digest.", "validation_failed", "Use the manifestHash value returned by the manifest-version read.", { projectKey: pk, });
|
|
300
298
|
}
|
|
301
299
|
if (update.dryRun !== undefined && typeof update.dryRun !== "boolean") {
|
|
@@ -3,6 +3,8 @@ import type { DataikuClient } from "../client.js";
|
|
|
3
3
|
export declare function requireArrayResponse<T>(value: unknown, operation: string): T[];
|
|
4
4
|
/** Validate identifiers without changing significant whitespace or encoding. */
|
|
5
5
|
export declare function requireNonEmpty(value: unknown, name: string): string;
|
|
6
|
+
export declare function requireObject(value: unknown, name: string): Record<string, unknown>;
|
|
7
|
+
export declare function requireNonEmptyArray(value: string[], name: string): string[];
|
|
6
8
|
export declare abstract class BaseResource {
|
|
7
9
|
protected readonly client: DataikuClient;
|
|
8
10
|
constructor(client: DataikuClient);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ClientValidationError,
|
|
1
|
+
import { ClientValidationError, unexpectedResponseError, } from "../errors.js";
|
|
2
2
|
/** Never disguise an unexpected successful HTTP payload as an empty listing. */
|
|
3
3
|
export function requireArrayResponse(value, operation) {
|
|
4
4
|
if (!Array.isArray(value)) {
|
|
5
|
-
throw
|
|
5
|
+
throw unexpectedResponseError(`${operation}: DSS did not return an array.`);
|
|
6
6
|
}
|
|
7
7
|
return value;
|
|
8
8
|
}
|
|
@@ -13,6 +13,18 @@ export function requireNonEmpty(value, name) {
|
|
|
13
13
|
}
|
|
14
14
|
return value;
|
|
15
15
|
}
|
|
16
|
+
export function requireObject(value, name) {
|
|
17
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
18
|
+
throw new ClientValidationError(`${name} must be a JSON object.`, "validation_failed");
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
export function requireNonEmptyArray(value, name) {
|
|
23
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
24
|
+
throw new ClientValidationError(`${name} must be a non-empty array.`, "validation_failed");
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
16
28
|
export class BaseResource {
|
|
17
29
|
client;
|
|
18
30
|
constructor(client) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClientValidationError, } from "../errors.js";
|
|
2
2
|
import { CodeEnvLogSummaryArraySchema, CodeEnvSummaryArraySchema, CodeEnvUsageArraySchema, CodeEnvVersionForProjectSchema, } from "../schemas.js";
|
|
3
|
+
import { isRecord, } from "../utils/records.js";
|
|
3
4
|
import { stableHash, } from "../utils/stable-hash.js";
|
|
4
5
|
import { BaseResource, } from "./base.js";
|
|
5
6
|
/** Byte cap applied to fetched code-env logs so stdout/JSON stays bounded. */
|
|
@@ -158,7 +159,7 @@ export class CodeEnvsResource extends BaseResource {
|
|
|
158
159
|
let raw;
|
|
159
160
|
if (envLang !== undefined || envName !== undefined) {
|
|
160
161
|
if (!envLang || !envName) {
|
|
161
|
-
throw new
|
|
162
|
+
throw new ClientValidationError("codeEnvs.listUsages requires both envLang and envName when either is provided", "validation_failed");
|
|
162
163
|
}
|
|
163
164
|
const langEnc = encodeURIComponent(envLang);
|
|
164
165
|
const nameEnc = encodeURIComponent(envName);
|
|
@@ -191,7 +192,7 @@ function tailLog(log, maxLines) {
|
|
|
191
192
|
*/
|
|
192
193
|
function assertDefinitionHash(envLang, envName, current, expected) {
|
|
193
194
|
const currentHash = stableHash(current);
|
|
194
|
-
if (currentHash === expected)
|
|
195
|
+
if (currentHash === expected.toLowerCase())
|
|
195
196
|
return;
|
|
196
197
|
throw new ClientValidationError(`Code env ${envLang}/${envName} changed since the expected definition hash was captured; refusing to overwrite it.`, "validation_failed", "Re-read the definition with dss code-env get-definition (definitionHash comes from code-env get), review the diff, and retry with the fresh hash.", {
|
|
197
198
|
envLang,
|
|
@@ -212,6 +213,3 @@ function normalizePackageList(packages) {
|
|
|
212
213
|
const lines = Array.isArray(packages) ? packages : packages.split(/\r?\n/);
|
|
213
214
|
return lines.map((line) => line.trim()).filter((line) => line.length > 0).join("\n");
|
|
214
215
|
}
|
|
215
|
-
function isRecord(value) {
|
|
216
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
217
|
-
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { DataikuError, } from "../errors.js";
|
|
1
|
+
import { DataikuError, unexpectedResponseError, } from "../errors.js";
|
|
2
2
|
import { DataQualityComputeResultSchema, DataQualityProjectStatusSchema, DataQualityRuleArraySchema, DataQualityRuleResultArraySchema, DataQualityRuleSchema, DataQualityRulesSchema, DataQualityStatusByPartitionSchema, DataQualityStatusSchema, DataQualityTimelineSchema, } from "../schemas.js";
|
|
3
3
|
import { deepMerge, } from "../utils/deep-merge.js";
|
|
4
4
|
import { BaseResource, } from "./base.js";
|
|
5
|
-
function
|
|
5
|
+
function dataQualityPath(projectKey, datasetName) {
|
|
6
6
|
return `/public/api/projects/${encodeURIComponent(projectKey)}/datasets/${encodeURIComponent(datasetName)}/data-quality`;
|
|
7
7
|
}
|
|
8
8
|
function addQuery(params, name, value) {
|
|
@@ -22,7 +22,7 @@ function projectPath(projectKey) {
|
|
|
22
22
|
export class DataQualityResource extends BaseResource {
|
|
23
23
|
async rules(datasetName, projectKey) {
|
|
24
24
|
const pk = this.resolveProjectKey(projectKey);
|
|
25
|
-
const raw = await this.client.get(`${
|
|
25
|
+
const raw = await this.client.get(`${dataQualityPath(pk, datasetName)}/rules`);
|
|
26
26
|
return this.client.safeParse(DataQualityRulesSchema, raw, "dataQuality.rules");
|
|
27
27
|
}
|
|
28
28
|
async listRules(datasetName, projectKey) {
|
|
@@ -31,21 +31,21 @@ export class DataQualityResource extends BaseResource {
|
|
|
31
31
|
}
|
|
32
32
|
async createRule(datasetName, opts) {
|
|
33
33
|
const pk = this.resolveProjectKey(opts.projectKey);
|
|
34
|
-
const raw = await this.client.post(`${
|
|
34
|
+
const raw = await this.client.post(`${dataQualityPath(pk, datasetName)}/rules`, opts.config);
|
|
35
35
|
return this.client.safeParse(DataQualityRuleSchema, raw, "dataQuality.createRule");
|
|
36
36
|
}
|
|
37
37
|
async updateRule(datasetName, ruleId, opts) {
|
|
38
38
|
const current = await this.getRule(datasetName, ruleId, opts.projectKey);
|
|
39
39
|
const next = deepMerge(current, opts.data);
|
|
40
40
|
const pk = this.resolveProjectKey(opts.projectKey);
|
|
41
|
-
await this.client.putVoid(`${
|
|
41
|
+
await this.client.putVoid(`${dataQualityPath(pk, datasetName)}/rules/${encodeURIComponent(ruleId)}`, next);
|
|
42
42
|
return this.client.safeParse(DataQualityRuleSchema, next, "dataQuality.updateRule");
|
|
43
43
|
}
|
|
44
44
|
async deleteRule(datasetName, ruleId, projectKey) {
|
|
45
45
|
const pk = this.resolveProjectKey(projectKey);
|
|
46
46
|
const params = new URLSearchParams();
|
|
47
47
|
params.set("ruleId", ruleId);
|
|
48
|
-
await this.client.del(`${
|
|
48
|
+
await this.client.del(`${dataQualityPath(pk, datasetName)}/rules/${encodeURIComponent(ruleId)}${queryString(params)}`);
|
|
49
49
|
}
|
|
50
50
|
async getRule(datasetName, ruleId, projectKey) {
|
|
51
51
|
const rules = await this.listRules(datasetName, projectKey);
|
|
@@ -57,14 +57,14 @@ export class DataQualityResource extends BaseResource {
|
|
|
57
57
|
}
|
|
58
58
|
async status(datasetName, projectKey) {
|
|
59
59
|
const pk = this.resolveProjectKey(projectKey);
|
|
60
|
-
const raw = await this.client.get(`${
|
|
60
|
+
const raw = await this.client.get(`${dataQualityPath(pk, datasetName)}/status-by-partition`);
|
|
61
61
|
return this.client.safeParse(DataQualityStatusSchema, raw, "dataQuality.status");
|
|
62
62
|
}
|
|
63
63
|
async statusByPartition(datasetName, opts = {}) {
|
|
64
64
|
const pk = this.resolveProjectKey(opts.projectKey);
|
|
65
65
|
const params = new URLSearchParams();
|
|
66
66
|
addQuery(params, "includeAllPartitions", opts.includeAllPartitions);
|
|
67
|
-
const raw = await this.client.get(`${
|
|
67
|
+
const raw = await this.client.get(`${dataQualityPath(pk, datasetName)}/status-by-partition${queryString(params)}`);
|
|
68
68
|
return this.client.safeParse(DataQualityStatusByPartitionSchema, raw, "dataQuality.statusByPartition");
|
|
69
69
|
}
|
|
70
70
|
async lastResults(datasetName, opts = {}) {
|
|
@@ -72,7 +72,7 @@ export class DataQualityResource extends BaseResource {
|
|
|
72
72
|
const params = new URLSearchParams();
|
|
73
73
|
addQuery(params, "partition", partitionValue(opts.partition));
|
|
74
74
|
addQuery(params, "ruleId", opts.ruleId);
|
|
75
|
-
const raw = await this.client.get(`${
|
|
75
|
+
const raw = await this.client.get(`${dataQualityPath(pk, datasetName)}/last-rules-result${queryString(params)}`);
|
|
76
76
|
return this.client.safeParse(DataQualityRuleResultArraySchema, raw, "dataQuality.lastResults");
|
|
77
77
|
}
|
|
78
78
|
async history(datasetName, opts = {}) {
|
|
@@ -83,7 +83,7 @@ export class DataQualityResource extends BaseResource {
|
|
|
83
83
|
addQuery(params, "resultsPerPage", opts.resultsPerPage);
|
|
84
84
|
addQuery(params, "page", opts.page);
|
|
85
85
|
addQuery(params, "ruleId", opts.ruleId);
|
|
86
|
-
const raw = await this.client.get(`${
|
|
86
|
+
const raw = await this.client.get(`${dataQualityPath(pk, datasetName)}/rules-history${queryString(params)}`);
|
|
87
87
|
return this.client.safeParse(DataQualityRuleResultArraySchema, raw, "dataQuality.history");
|
|
88
88
|
}
|
|
89
89
|
async computeRules(datasetName, opts = {}) {
|
|
@@ -91,13 +91,14 @@ export class DataQualityResource extends BaseResource {
|
|
|
91
91
|
const params = new URLSearchParams();
|
|
92
92
|
addQuery(params, "partition", partitionValue(opts.partition));
|
|
93
93
|
addQuery(params, "ruleId", opts.ruleId);
|
|
94
|
-
const raw = await this.client.post(`${
|
|
94
|
+
const raw = await this.client.post(`${dataQualityPath(pk, datasetName)}/actions/compute-rules${queryString(params)}`);
|
|
95
95
|
return this.client.safeParse(DataQualityComputeResultSchema, raw, "dataQuality.computeRules");
|
|
96
96
|
}
|
|
97
97
|
async computeRulesAndWait(datasetName, opts = {}) {
|
|
98
98
|
const future = await this.computeRules(datasetName, opts);
|
|
99
|
-
if (!future.jobId)
|
|
100
|
-
throw
|
|
99
|
+
if (!future.jobId) {
|
|
100
|
+
throw unexpectedResponseError("Data quality compute did not return a future jobId.");
|
|
101
|
+
}
|
|
101
102
|
return this.client.futures.wait(future.jobId, {
|
|
102
103
|
pollIntervalMs: opts.pollIntervalMs,
|
|
103
104
|
timeoutMs: opts.timeoutMs,
|
|
@@ -89,6 +89,19 @@ export interface UploadDatasetFileResult {
|
|
|
89
89
|
export declare function validateStreamColumns(headerRow: string[], expectedColumns: {
|
|
90
90
|
name: string;
|
|
91
91
|
}[]): string[];
|
|
92
|
+
/** Wire body for POST /datasets/; shared with `dataset create --plan` so the plan matches the request. */
|
|
93
|
+
export declare function buildDatasetCreateBody(opts: {
|
|
94
|
+
projectKey: string;
|
|
95
|
+
datasetName: string;
|
|
96
|
+
connection?: string;
|
|
97
|
+
dsType: string;
|
|
98
|
+
table?: string;
|
|
99
|
+
dbSchema?: string;
|
|
100
|
+
catalog?: string;
|
|
101
|
+
formatType?: string;
|
|
102
|
+
formatParams?: Record<string, unknown>;
|
|
103
|
+
managed?: boolean;
|
|
104
|
+
}): Record<string, unknown>;
|
|
92
105
|
export declare function buildDatasetCloneSettings(source: DatasetDetails, targetName: string, projectKey: string, opts: DatasetCloneOptions): Record<string, unknown>;
|
|
93
106
|
export declare class DatasetsResource extends BaseResource {
|
|
94
107
|
/** List all datasets in a project. */
|
|
@@ -462,7 +462,7 @@ function tsvToCsvTransform(maxDataRows, stats, onHeader, spreadsheetSafe = true)
|
|
|
462
462
|
catch (error) {
|
|
463
463
|
// Byte-limit overflow: destroy the transform so the pipeline
|
|
464
464
|
// cancels the response and the partial file is removed.
|
|
465
|
-
callback(error instanceof Error ? error : new
|
|
465
|
+
callback(error instanceof Error ? error : new ClientValidationError(String(error), "internal_error"));
|
|
466
466
|
return;
|
|
467
467
|
}
|
|
468
468
|
if (done) {
|
|
@@ -485,7 +485,7 @@ function tsvToCsvTransform(maxDataRows, stats, onHeader, spreadsheetSafe = true)
|
|
|
485
485
|
flushTsvStream(state, (row) => handleRow(row, (line) => queueLine(this, line)));
|
|
486
486
|
}
|
|
487
487
|
catch (error) {
|
|
488
|
-
callback(error instanceof Error ? error : new
|
|
488
|
+
callback(error instanceof Error ? error : new ClientValidationError(String(error), "internal_error"));
|
|
489
489
|
return;
|
|
490
490
|
}
|
|
491
491
|
// Emit the trailing partial batch; without this the last rows of a
|
|
@@ -518,7 +518,8 @@ function isMissingUploadedFilesTargetConnection(error) {
|
|
|
518
518
|
return (detail.includes("without a target connection")
|
|
519
519
|
|| detail.includes("target connection is required"));
|
|
520
520
|
}
|
|
521
|
-
|
|
521
|
+
/** Wire body for POST /datasets/; shared with `dataset create --plan` so the plan matches the request. */
|
|
522
|
+
export function buildDatasetCreateBody(opts) {
|
|
522
523
|
if (opts.dsType.toLowerCase() === "uploadedfiles") {
|
|
523
524
|
return {
|
|
524
525
|
projectKey: opts.projectKey,
|
|
@@ -637,7 +638,7 @@ export function buildDatasetCloneSettings(source, targetName, projectKey, opts)
|
|
|
637
638
|
&& source.managed === true
|
|
638
639
|
&& sourcePath !== undefined
|
|
639
640
|
&& settingsParams.path === sourcePath) {
|
|
640
|
-
throw new
|
|
641
|
+
throw new ClientValidationError(`Refusing to clone managed dataset "${source.name}" with the same storage path. Pass a new path or allowSamePath: true.`, "validation_failed");
|
|
641
642
|
}
|
|
642
643
|
return settings;
|
|
643
644
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ClientValidationError, } from "../errors.js";
|
|
1
2
|
import { FlowZoneArraySchema, FlowZoneSchema, } from "../schemas.js";
|
|
2
3
|
import { deepMerge, } from "../utils/deep-merge.js";
|
|
3
4
|
import { BaseResource, } from "./base.js";
|
|
@@ -48,8 +49,9 @@ export class FlowZonesResource extends BaseResource {
|
|
|
48
49
|
}
|
|
49
50
|
/** Move items into a flow zone. */
|
|
50
51
|
async moveItems(zoneId, items, projectKey) {
|
|
51
|
-
if (items.length === 0)
|
|
52
|
-
throw new
|
|
52
|
+
if (items.length === 0) {
|
|
53
|
+
throw new ClientValidationError("flowZones.moveItems requires at least one item", "validation_failed");
|
|
54
|
+
}
|
|
53
55
|
const raw = await this.client.post(`/public/api/projects/${this.enc(projectKey)}/flow/zones/${encodeURIComponent(zoneId)}/add-items`, items.map(normalizeZoneItem));
|
|
54
56
|
return this.client.safeParse(FlowZoneSchema, raw, "flowZones.moveItems");
|
|
55
57
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as nodePath from "node:path";
|
|
2
|
+
import { unexpectedResponseError, } from "../errors.js";
|
|
2
3
|
import { FolderDetailsSchema, FolderItemArraySchema, FolderSummaryArraySchema, } from "../schemas.js";
|
|
3
4
|
import { deepMerge, } from "../utils/deep-merge.js";
|
|
4
5
|
import { writeResponseToFile, } from "../utils/response-file.js";
|
|
@@ -70,8 +71,9 @@ export class FoldersResource extends BaseResource {
|
|
|
70
71
|
const normalizedPath = normalizeRemotePath(path);
|
|
71
72
|
const pEnc = encodeURIComponent(normalizedPath);
|
|
72
73
|
const res = await this.client.stream(`/public/api/projects/${this.enc(opts?.projectKey)}/managedfolders/${fEnc}/contents/${pEnc}`);
|
|
73
|
-
if (!res.body)
|
|
74
|
-
throw
|
|
74
|
+
if (!res.body) {
|
|
75
|
+
throw unexpectedResponseError("folders.download response did not include a body");
|
|
76
|
+
}
|
|
75
77
|
const dest = opts?.localPath
|
|
76
78
|
?? nodePath.resolve(process.cwd(), inferDownloadFileName(normalizedPath));
|
|
77
79
|
await writeResponseToFile(dest, res);
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { FutureStateSchema, FutureWaitResultSchema, } from "../schemas.js";
|
|
2
|
-
import { computeNextPollDelayMs, isRequestDeadlineError, } from "../utils/polling.js";
|
|
2
|
+
import { computeNextPollDelayMs, DEFAULT_POLL_INTERVAL_MS, DEFAULT_TIMEOUT_MS, isRequestDeadlineError, } from "../utils/polling.js";
|
|
3
3
|
import { BaseResource, } from "./base.js";
|
|
4
|
-
const DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
5
|
-
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
6
4
|
function sleep(ms) {
|
|
7
5
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
6
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ClientValidationError, unexpectedResponseError, } from "../errors.js";
|
|
1
2
|
import { InsightDetailsSchema, InsightSummaryArraySchema, } from "../schemas.js";
|
|
2
3
|
import { deepMerge, } from "../utils/deep-merge.js";
|
|
3
4
|
import { BaseResource, } from "./base.js";
|
|
@@ -33,7 +34,7 @@ export class InsightsResource extends BaseResource {
|
|
|
33
34
|
const pk = this.resolveProjectKey(opts.projectKey);
|
|
34
35
|
const prototype = applyInsightFields(opts.data ?? {}, opts);
|
|
35
36
|
if (!hasCreateShape(prototype)) {
|
|
36
|
-
throw new
|
|
37
|
+
throw new ClientValidationError("Insight create requires name and type, either as options or in data.", "validation_failed");
|
|
37
38
|
}
|
|
38
39
|
if (prototype.projectKey === undefined)
|
|
39
40
|
prototype.projectKey = pk;
|
|
@@ -43,7 +44,7 @@ export class InsightsResource extends BaseResource {
|
|
|
43
44
|
...(opts.payload !== undefined ? { payload: opts.payload, } : {}),
|
|
44
45
|
});
|
|
45
46
|
if (typeof created.id !== "string" || created.id.length === 0) {
|
|
46
|
-
throw
|
|
47
|
+
throw unexpectedResponseError("Insight create response did not include an id.");
|
|
47
48
|
}
|
|
48
49
|
return this.get(created.id, pk);
|
|
49
50
|
}
|