dataiku-sdk 3.3.0 → 3.5.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 +6 -4
- package/dist/build-metadata.json +1 -1
- 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 +22 -39
- 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 +5 -5
- 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 +28 -51
- 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 -25
- 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 +11 -18
- 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 +39 -71
- 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 +21 -35
- 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 +179 -461
- package/dist/src/cli/doctor.js +1 -0
- package/dist/src/cli/env.d.ts +2 -0
- package/dist/src/cli/env.js +15 -1
- package/dist/src/cli/helpers/app-permissions.js +2 -1
- package/dist/src/cli/helpers/flow-zone.js +2 -1
- package/dist/src/cli/helpers/recipe.js +2 -1
- package/dist/src/cli/output-schemas.d.ts +24 -0
- package/dist/src/cli/output-schemas.js +233 -0
- 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.js +2 -0
- package/dist/src/cli.js +37 -64
- package/dist/src/client.d.ts +10 -1
- package/dist/src/client.js +27 -11
- package/dist/src/errors.d.ts +12 -1
- package/dist/src/errors.js +34 -7
- package/dist/src/generated/action-output-schemas.json +1735 -0
- 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/code-envs.js +2 -2
- package/dist/src/resources/data-quality.js +4 -3
- package/dist/src/resources/datasets.d.ts +13 -0
- package/dist/src/resources/datasets.js +42 -8
- package/dist/src/resources/flow-zones.d.ts +6 -2
- package/dist/src/resources/flow-zones.js +10 -5
- package/dist/src/resources/folders.js +4 -2
- package/dist/src/resources/futures.d.ts +2 -0
- package/dist/src/resources/futures.js +39 -27
- package/dist/src/resources/insights.js +3 -2
- package/dist/src/resources/jobs.js +41 -31
- package/dist/src/resources/macros.js +2 -4
- package/dist/src/resources/ml-tasks.js +28 -19
- package/dist/src/resources/notebooks.js +2 -3
- package/dist/src/resources/plugins.d.ts +0 -2
- package/dist/src/resources/plugins.js +0 -3
- package/dist/src/resources/project-git.d.ts +6 -12
- package/dist/src/resources/project-git.js +31 -58
- package/dist/src/resources/project-library.d.ts +0 -2
- package/dist/src/resources/project-library.js +2 -7
- package/dist/src/resources/projects.d.ts +4 -2
- package/dist/src/resources/projects.js +37 -36
- package/dist/src/resources/recipes.d.ts +28 -0
- package/dist/src/resources/recipes.js +116 -84
- package/dist/src/resources/sql.js +8 -3
- package/dist/src/resources/statistics.js +2 -1
- 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/git-reference.d.ts +12 -0
- package/dist/src/utils/git-reference.js +38 -0
- package/dist/src/utils/polling.d.ts +3 -0
- package/dist/src/utils/polling.js +3 -0
- package/dist/src/utils/project-archive.js +2 -2
- package/dist/src/utils/stable-hash.d.ts +3 -1
- package/dist/src/utils/stable-hash.js +2 -0
- package/package.json +8 -8
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +3 -2
- package/skills/dataiku-dss/references/app-releases.md +2 -3
- package/skills/dataiku-dss/references/authentication.md +7 -7
- package/skills/dataiku-dss/references/coding.md +1 -1
- package/skills/dataiku-dss/references/mutations.md +1 -1
- package/skills/dataiku-dss/references/troubleshooting.md +2 -2
- package/dist/src/utils/pagination.d.ts +0 -8
- package/dist/src/utils/pagination.js +0 -23
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") {
|
|
@@ -158,7 +158,7 @@ export class CodeEnvsResource extends BaseResource {
|
|
|
158
158
|
let raw;
|
|
159
159
|
if (envLang !== undefined || envName !== undefined) {
|
|
160
160
|
if (!envLang || !envName) {
|
|
161
|
-
throw new
|
|
161
|
+
throw new ClientValidationError("codeEnvs.listUsages requires both envLang and envName when either is provided", "validation_failed");
|
|
162
162
|
}
|
|
163
163
|
const langEnc = encodeURIComponent(envLang);
|
|
164
164
|
const nameEnc = encodeURIComponent(envName);
|
|
@@ -191,7 +191,7 @@ function tailLog(log, maxLines) {
|
|
|
191
191
|
*/
|
|
192
192
|
function assertDefinitionHash(envLang, envName, current, expected) {
|
|
193
193
|
const currentHash = stableHash(current);
|
|
194
|
-
if (currentHash === expected)
|
|
194
|
+
if (currentHash === expected.toLowerCase())
|
|
195
195
|
return;
|
|
196
196
|
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
197
|
envLang,
|
|
@@ -1,4 +1,4 @@
|
|
|
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";
|
|
@@ -96,8 +96,9 @@ export class DataQualityResource extends BaseResource {
|
|
|
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. */
|
|
@@ -394,12 +394,39 @@ async function collectTsvRowCount(body, stopAfter, timeoutMs) {
|
|
|
394
394
|
reader.releaseLock();
|
|
395
395
|
}
|
|
396
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Encoded CSV bytes accumulated before one stream push. Rows are joined into
|
|
399
|
+
* batch-sized chunks so large downloads do not pay per-row stream overhead; a
|
|
400
|
+
* single escaped row may exceed the budget (rows are never split), and the
|
|
401
|
+
* batch is always flushed at EOF so trailing rows are never dropped.
|
|
402
|
+
*/
|
|
403
|
+
const CSV_BATCH_BYTES = 64 * 1024;
|
|
397
404
|
function tsvToCsvTransform(maxDataRows, stats, onHeader, spreadsheetSafe = true) {
|
|
398
405
|
const state = createTsvStreamState();
|
|
399
406
|
const decoder = new StringDecoder("utf-8");
|
|
400
407
|
const maxRows = Math.max(1, maxDataRows);
|
|
401
408
|
let headerSeen = false;
|
|
402
409
|
let done = false;
|
|
410
|
+
// Bounded CSV output batching: emitted rows accumulate here and are joined
|
|
411
|
+
// into a single push once the batch reaches CSV_BATCH_BYTES, so memory stays
|
|
412
|
+
// bounded by the batch budget plus one escaped row (the join briefly holds a
|
|
413
|
+
// second copy of the batch) while per-row push/callback overhead disappears.
|
|
414
|
+
let batchLines = [];
|
|
415
|
+
let batchBytes = 0;
|
|
416
|
+
const flushBatch = (target) => {
|
|
417
|
+
if (batchLines.length === 0)
|
|
418
|
+
return;
|
|
419
|
+
const csv = batchLines.join("");
|
|
420
|
+
batchLines = [];
|
|
421
|
+
batchBytes = 0;
|
|
422
|
+
target.push(csv);
|
|
423
|
+
};
|
|
424
|
+
const queueLine = (target, line) => {
|
|
425
|
+
batchLines.push(line);
|
|
426
|
+
batchBytes += Buffer.byteLength(line);
|
|
427
|
+
if (batchBytes >= CSV_BATCH_BYTES)
|
|
428
|
+
flushBatch(target);
|
|
429
|
+
};
|
|
403
430
|
let columnCount = 0;
|
|
404
431
|
const handleRow = (row, push) => {
|
|
405
432
|
if (done)
|
|
@@ -430,16 +457,19 @@ function tsvToCsvTransform(maxDataRows, stats, onHeader, spreadsheetSafe = true)
|
|
|
430
457
|
return;
|
|
431
458
|
}
|
|
432
459
|
try {
|
|
433
|
-
consumeTsvChunk(decoder.write(chunk), state, (row) => handleRow(row, (line) => this
|
|
460
|
+
consumeTsvChunk(decoder.write(chunk), state, (row) => handleRow(row, (line) => queueLine(this, line)));
|
|
434
461
|
}
|
|
435
462
|
catch (error) {
|
|
436
463
|
// Byte-limit overflow: destroy the transform so the pipeline
|
|
437
464
|
// cancels the response and the partial file is removed.
|
|
438
|
-
callback(error instanceof Error ? error : new
|
|
465
|
+
callback(error instanceof Error ? error : new ClientValidationError(String(error), "internal_error"));
|
|
439
466
|
return;
|
|
440
467
|
}
|
|
441
|
-
if (done)
|
|
468
|
+
if (done) {
|
|
469
|
+
// Truncation reached: emit the batch queued so far before EOF.
|
|
470
|
+
flushBatch(this);
|
|
442
471
|
this.push(null);
|
|
472
|
+
}
|
|
443
473
|
callback();
|
|
444
474
|
},
|
|
445
475
|
flush(callback) {
|
|
@@ -450,14 +480,17 @@ function tsvToCsvTransform(maxDataRows, stats, onHeader, spreadsheetSafe = true)
|
|
|
450
480
|
try {
|
|
451
481
|
const tail = decoder.end();
|
|
452
482
|
if (tail !== "") {
|
|
453
|
-
consumeTsvChunk(tail, state, (row) => handleRow(row, (line) => this
|
|
483
|
+
consumeTsvChunk(tail, state, (row) => handleRow(row, (line) => queueLine(this, line)));
|
|
454
484
|
}
|
|
455
|
-
flushTsvStream(state, (row) => handleRow(row, (line) => this
|
|
485
|
+
flushTsvStream(state, (row) => handleRow(row, (line) => queueLine(this, line)));
|
|
456
486
|
}
|
|
457
487
|
catch (error) {
|
|
458
|
-
callback(error instanceof Error ? error : new
|
|
488
|
+
callback(error instanceof Error ? error : new ClientValidationError(String(error), "internal_error"));
|
|
459
489
|
return;
|
|
460
490
|
}
|
|
491
|
+
// Emit the trailing partial batch; without this the last rows of a
|
|
492
|
+
// download (below the batch budget) would be silently dropped.
|
|
493
|
+
flushBatch(this);
|
|
461
494
|
callback();
|
|
462
495
|
},
|
|
463
496
|
});
|
|
@@ -485,7 +518,8 @@ function isMissingUploadedFilesTargetConnection(error) {
|
|
|
485
518
|
return (detail.includes("without a target connection")
|
|
486
519
|
|| detail.includes("target connection is required"));
|
|
487
520
|
}
|
|
488
|
-
|
|
521
|
+
/** Wire body for POST /datasets/; shared with `dataset create --plan` so the plan matches the request. */
|
|
522
|
+
export function buildDatasetCreateBody(opts) {
|
|
489
523
|
if (opts.dsType.toLowerCase() === "uploadedfiles") {
|
|
490
524
|
return {
|
|
491
525
|
projectKey: opts.projectKey,
|
|
@@ -604,7 +638,7 @@ export function buildDatasetCloneSettings(source, targetName, projectKey, opts)
|
|
|
604
638
|
&& source.managed === true
|
|
605
639
|
&& sourcePath !== undefined
|
|
606
640
|
&& settingsParams.path === sourcePath) {
|
|
607
|
-
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");
|
|
608
642
|
}
|
|
609
643
|
return settings;
|
|
610
644
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DataikuGetOptions } from "../client.js";
|
|
1
2
|
import type { FlowZone, FlowZoneCreateOptions, FlowZoneObjectType, FlowZoneUpdateOptions } from "../schemas.js";
|
|
2
3
|
import { BaseResource } from "./base.js";
|
|
3
4
|
export type FlowZoneItemInput = {
|
|
@@ -6,8 +7,11 @@ export type FlowZoneItemInput = {
|
|
|
6
7
|
projectKey?: string;
|
|
7
8
|
};
|
|
8
9
|
export declare class FlowZonesResource extends BaseResource {
|
|
9
|
-
/**
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* List all flow zones in a project. Pass `timeoutMs` to bound the whole
|
|
12
|
+
* request (attempts, backoff, and body read) by a total budget.
|
|
13
|
+
*/
|
|
14
|
+
list(projectKey?: string, options?: DataikuGetOptions): Promise<FlowZone[]>;
|
|
11
15
|
/** Get one flow zone by id. */
|
|
12
16
|
get(zoneId: string, projectKey?: string): Promise<FlowZone>;
|
|
13
17
|
/** Create a flow zone. */
|
|
@@ -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";
|
|
@@ -9,9 +10,12 @@ function normalizeZoneItem(item) {
|
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
export class FlowZonesResource extends BaseResource {
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* List all flow zones in a project. Pass `timeoutMs` to bound the whole
|
|
15
|
+
* request (attempts, backoff, and body read) by a total budget.
|
|
16
|
+
*/
|
|
17
|
+
async list(projectKey, options) {
|
|
18
|
+
const raw = await this.client.get(`/public/api/projects/${this.enc(projectKey)}/flow/zones`, options);
|
|
15
19
|
return this.client.safeParse(FlowZoneArraySchema, raw, "flowZones.list");
|
|
16
20
|
}
|
|
17
21
|
/** Get one flow zone by id. */
|
|
@@ -45,8 +49,9 @@ export class FlowZonesResource extends BaseResource {
|
|
|
45
49
|
}
|
|
46
50
|
/** Move items into a flow zone. */
|
|
47
51
|
async moveItems(zoneId, items, projectKey) {
|
|
48
|
-
if (items.length === 0)
|
|
49
|
-
throw new
|
|
52
|
+
if (items.length === 0) {
|
|
53
|
+
throw new ClientValidationError("flowZones.moveItems requires at least one item", "validation_failed");
|
|
54
|
+
}
|
|
50
55
|
const raw = await this.client.post(`/public/api/projects/${this.enc(projectKey)}/flow/zones/${encodeURIComponent(zoneId)}/add-items`, items.map(normalizeZoneItem));
|
|
51
56
|
return this.client.safeParse(FlowZoneSchema, raw, "flowZones.moveItems");
|
|
52
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);
|
|
@@ -7,11 +7,13 @@ export interface FutureWaitOptions {
|
|
|
7
7
|
export declare class FuturesResource extends BaseResource {
|
|
8
8
|
get(futureId: string, opts?: {
|
|
9
9
|
timeoutMs?: number;
|
|
10
|
+
noRetry?: boolean;
|
|
10
11
|
}): Promise<FutureState>;
|
|
11
12
|
peek(futureId: string): Promise<FutureState>;
|
|
12
13
|
state(futureId: string, opts?: {
|
|
13
14
|
peek?: boolean;
|
|
14
15
|
timeoutMs?: number;
|
|
16
|
+
noRetry?: boolean;
|
|
15
17
|
}): Promise<FutureState>;
|
|
16
18
|
abort(futureId: string): Promise<void>;
|
|
17
19
|
wait(futureId: string, opts?: FutureWaitOptions): Promise<FutureWaitResult>;
|
|
@@ -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
|
}
|
|
@@ -25,7 +23,11 @@ function waitState(state) {
|
|
|
25
23
|
}
|
|
26
24
|
export class FuturesResource extends BaseResource {
|
|
27
25
|
async get(futureId, opts = {}) {
|
|
28
|
-
return this.state(futureId, {
|
|
26
|
+
return this.state(futureId, {
|
|
27
|
+
peek: false,
|
|
28
|
+
timeoutMs: opts.timeoutMs,
|
|
29
|
+
noRetry: opts.noRetry,
|
|
30
|
+
});
|
|
29
31
|
}
|
|
30
32
|
async peek(futureId) {
|
|
31
33
|
return this.state(futureId, { peek: true, });
|
|
@@ -33,7 +35,7 @@ export class FuturesResource extends BaseResource {
|
|
|
33
35
|
async state(futureId, opts = {}) {
|
|
34
36
|
const params = new URLSearchParams();
|
|
35
37
|
params.set("peek", String(opts.peek === true));
|
|
36
|
-
const raw = await this.client.get(`/public/api/futures/${encodeURIComponent(futureId)}?${params.toString()}`, { timeoutMs: opts.timeoutMs, });
|
|
38
|
+
const raw = await this.client.get(`/public/api/futures/${encodeURIComponent(futureId)}?${params.toString()}`, { timeoutMs: opts.timeoutMs, noRetry: opts.noRetry, });
|
|
37
39
|
return this.client.safeParse(FutureStateSchema, raw, "futures.state");
|
|
38
40
|
}
|
|
39
41
|
async abort(futureId) {
|
|
@@ -51,16 +53,37 @@ export class FuturesResource extends BaseResource {
|
|
|
51
53
|
const timeoutMs = Math.max(0, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
52
54
|
const startedAt = Date.now();
|
|
53
55
|
let pollCount = 0;
|
|
56
|
+
let lastState;
|
|
54
57
|
while (true) {
|
|
58
|
+
const elapsedBeforeMs = Date.now() - startedAt;
|
|
59
|
+
// The first observation always happens, even when the budget is
|
|
60
|
+
// already spent. A later poll is never started after the deadline:
|
|
61
|
+
// the loop reports the structured timeout from the last observed
|
|
62
|
+
// state instead of issuing a request the budget cannot cover.
|
|
63
|
+
if (lastState !== undefined && elapsedBeforeMs >= timeoutMs) {
|
|
64
|
+
return this.client.safeParse(FutureWaitResultSchema, {
|
|
65
|
+
futureId,
|
|
66
|
+
jobId: lastState.jobId,
|
|
67
|
+
state: waitState(lastState),
|
|
68
|
+
elapsedMs: elapsedBeforeMs,
|
|
69
|
+
pollCount,
|
|
70
|
+
success: false,
|
|
71
|
+
timedOut: true,
|
|
72
|
+
hasResult: lastState.hasResult === true,
|
|
73
|
+
alive: lastState.alive,
|
|
74
|
+
aborted: lastState.aborted,
|
|
75
|
+
unknown: lastState.unknown,
|
|
76
|
+
}, "futures.wait");
|
|
77
|
+
}
|
|
55
78
|
pollCount += 1;
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
const remainingMs = timeoutMs -
|
|
79
|
+
// Requests issued while budget remains are bounded by the remaining
|
|
80
|
+
// time; a spent budget still issues exactly one transport attempt
|
|
81
|
+
// (no retries, client requestTimeoutMs cap) so the first observation
|
|
82
|
+
// reaches the server instead of failing before any attempt.
|
|
83
|
+
const remainingMs = timeoutMs - elapsedBeforeMs;
|
|
61
84
|
let state;
|
|
62
85
|
try {
|
|
63
|
-
state = await this.get(futureId, remainingMs > 0 ? { timeoutMs: remainingMs, } :
|
|
86
|
+
state = await this.get(futureId, remainingMs > 0 ? { timeoutMs: remainingMs, } : { noRetry: true, });
|
|
64
87
|
}
|
|
65
88
|
catch (error) {
|
|
66
89
|
// The poll budget ran out mid-request: report the structured
|
|
@@ -76,6 +99,7 @@ export class FuturesResource extends BaseResource {
|
|
|
76
99
|
timedOut: true,
|
|
77
100
|
}, "futures.wait");
|
|
78
101
|
}
|
|
102
|
+
lastState = state;
|
|
79
103
|
const elapsedMs = Date.now() - startedAt;
|
|
80
104
|
const status = waitState(state);
|
|
81
105
|
if (isFinished(state)) {
|
|
@@ -94,22 +118,10 @@ export class FuturesResource extends BaseResource {
|
|
|
94
118
|
};
|
|
95
119
|
return this.client.safeParse(FutureWaitResultSchema, result, "futures.wait");
|
|
96
120
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
state: status,
|
|
102
|
-
elapsedMs,
|
|
103
|
-
pollCount,
|
|
104
|
-
success: false,
|
|
105
|
-
timedOut: true,
|
|
106
|
-
hasResult: state.hasResult === true,
|
|
107
|
-
alive: state.alive,
|
|
108
|
-
aborted: state.aborted,
|
|
109
|
-
unknown: state.unknown,
|
|
110
|
-
};
|
|
111
|
-
return this.client.safeParse(FutureWaitResultSchema, result, "futures.wait");
|
|
112
|
-
}
|
|
121
|
+
// Deadline reached: the guard at the top of the loop reports the
|
|
122
|
+
// timeout from this observation without issuing another request.
|
|
123
|
+
if (elapsedMs >= timeoutMs)
|
|
124
|
+
continue;
|
|
113
125
|
// Only the remaining budget is slept: a longer sleep would report an
|
|
114
126
|
// elapsed time the caller never authorized.
|
|
115
127
|
const nextDelayMs = computeNextPollDelayMs({
|
|
@@ -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
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { DataikuError, } from "../errors.js";
|
|
1
|
+
import { ClientValidationError, DataikuError, } from "../errors.js";
|
|
2
2
|
import { JobSummaryArraySchema, } from "../schemas.js";
|
|
3
|
-
import { computeNextPollDelayMs, isRequestDeadlineError, } from "../utils/polling.js";
|
|
3
|
+
import { computeNextPollDelayMs, DEFAULT_POLL_INTERVAL_MS, DEFAULT_TIMEOUT_MS, isRequestDeadlineError, } from "../utils/polling.js";
|
|
4
4
|
import { BaseResource, } from "./base.js";
|
|
5
|
-
const DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
6
|
-
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
7
5
|
const DEFAULT_MAX_LOG_LINES = 500;
|
|
8
6
|
/**
|
|
9
7
|
* Default bytes retained from a job log body (default 10 MiB). Logs larger
|
|
@@ -51,7 +49,7 @@ function jobBuildOutput(target, defaultProjectKey, defaultPartition, defaultTarg
|
|
|
51
49
|
}
|
|
52
50
|
function jobBuildDefinition(targets, defaultProjectKey, opts) {
|
|
53
51
|
if (targets.length === 0) {
|
|
54
|
-
throw new
|
|
52
|
+
throw new ClientValidationError("At least one build target is required.", "validation_failed");
|
|
55
53
|
}
|
|
56
54
|
const payload = {
|
|
57
55
|
outputs: targets.map((target) => jobBuildOutput(target, defaultProjectKey, opts?.partition, opts?.targetType)),
|
|
@@ -203,7 +201,7 @@ export class JobsResource extends BaseResource {
|
|
|
203
201
|
const jobId = parsed.searchParams.get("jobId") ?? undefined;
|
|
204
202
|
const activity = parsed.searchParams.get("activityId") ?? undefined;
|
|
205
203
|
if (!projectKey || !jobId || !activity) {
|
|
206
|
-
throw new
|
|
204
|
+
throw new ClientValidationError("Log URL must include projectKey, jobId, and activityId query parameters.", "validation_failed");
|
|
207
205
|
}
|
|
208
206
|
return this.log(jobId, {
|
|
209
207
|
activity,
|
|
@@ -289,19 +287,44 @@ export class JobsResource extends BaseResource {
|
|
|
289
287
|
const timeout = Math.max(baseIntervalMs, opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
290
288
|
const startedAt = Date.now();
|
|
291
289
|
let pollCount = 0;
|
|
290
|
+
let lastJ;
|
|
292
291
|
while (true) {
|
|
292
|
+
const elapsedBeforeMs = Date.now() - startedAt;
|
|
293
|
+
// The first observation always happens, even when the budget is
|
|
294
|
+
// already spent. A later poll is never started after the deadline:
|
|
295
|
+
// the loop reports the structured timeout from the last observed
|
|
296
|
+
// state instead of issuing a request the budget cannot cover.
|
|
297
|
+
if (lastJ !== undefined && elapsedBeforeMs >= timeout) {
|
|
298
|
+
const bs = lastJ.baseStatus ?? {};
|
|
299
|
+
const def = bs.def ?? {};
|
|
300
|
+
const gs = lastJ.globalState ?? {};
|
|
301
|
+
return {
|
|
302
|
+
success: false,
|
|
303
|
+
jobId,
|
|
304
|
+
state: bs.state ?? "unknown",
|
|
305
|
+
type: def.type ?? "unknown",
|
|
306
|
+
elapsedMs: elapsedBeforeMs,
|
|
307
|
+
pollCount,
|
|
308
|
+
timedOut: true,
|
|
309
|
+
progress: {
|
|
310
|
+
done: gs.done ?? 0,
|
|
311
|
+
failed: gs.failed ?? 0,
|
|
312
|
+
running: gs.running ?? 0,
|
|
313
|
+
total: gs.total ?? null,
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
}
|
|
293
317
|
pollCount += 1;
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
const
|
|
299
|
-
const remainingMs = timeout - elapsedBefore;
|
|
318
|
+
// Requests issued while budget remains are bounded by the remaining
|
|
319
|
+
// time; a spent budget still issues exactly one transport attempt
|
|
320
|
+
// (no retries, client requestTimeoutMs cap) so the first observation
|
|
321
|
+
// reaches the server instead of failing before any attempt.
|
|
322
|
+
const remainingMs = timeout - elapsedBeforeMs;
|
|
300
323
|
let j;
|
|
301
324
|
try {
|
|
302
325
|
j = await this.client.get(`/public/api/projects/${projectEnc}/jobs/${jobEnc}/`, remainingMs > 0
|
|
303
326
|
? { timeoutMs: remainingMs, }
|
|
304
|
-
:
|
|
327
|
+
: { noRetry: true, });
|
|
305
328
|
}
|
|
306
329
|
catch (error) {
|
|
307
330
|
// The poll budget ran out mid-request: report the documented
|
|
@@ -325,6 +348,7 @@ export class JobsResource extends BaseResource {
|
|
|
325
348
|
},
|
|
326
349
|
};
|
|
327
350
|
}
|
|
351
|
+
lastJ = j;
|
|
328
352
|
const bs = j.baseStatus ?? {};
|
|
329
353
|
const def = bs.def ?? {};
|
|
330
354
|
const gs = j.globalState ?? {};
|
|
@@ -387,24 +411,10 @@ export class JobsResource extends BaseResource {
|
|
|
387
411
|
...(removed !== undefined ? { removed, } : {}),
|
|
388
412
|
};
|
|
389
413
|
}
|
|
390
|
-
// Timeout —
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
jobId,
|
|
395
|
-
state,
|
|
396
|
-
type: def.type ?? "unknown",
|
|
397
|
-
elapsedMs,
|
|
398
|
-
pollCount,
|
|
399
|
-
timedOut: true,
|
|
400
|
-
progress: {
|
|
401
|
-
done: gs.done ?? 0,
|
|
402
|
-
failed: gs.failed ?? 0,
|
|
403
|
-
running: gs.running ?? 0,
|
|
404
|
-
total: gs.total ?? null,
|
|
405
|
-
},
|
|
406
|
-
};
|
|
407
|
-
}
|
|
414
|
+
// Timeout — the guard at the top of the loop returns the failure
|
|
415
|
+
// result from this observation without issuing another request.
|
|
416
|
+
if (elapsedMs >= timeout)
|
|
417
|
+
continue;
|
|
408
418
|
const nextDelayMs = computeNextPollDelayMs({
|
|
409
419
|
pollCount,
|
|
410
420
|
baseIntervalMs,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { ClientValidationError, DataikuError, } from "../errors.js";
|
|
2
2
|
import { MacroDefinitionSchema, MacroRunStartSchema, MacroStateSchema, MacroSummaryArraySchema, MacroWaitResultSchema, } from "../schemas.js";
|
|
3
|
-
import { computeNextPollDelayMs, isRequestDeadlineError, } from "../utils/polling.js";
|
|
3
|
+
import { computeNextPollDelayMs, DEFAULT_POLL_INTERVAL_MS, DEFAULT_TIMEOUT_MS, isRequestDeadlineError, } from "../utils/polling.js";
|
|
4
4
|
import { BaseResource, requireNonEmpty, } from "./base.js";
|
|
5
|
-
const DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
6
|
-
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
7
5
|
/** Hard floor for the result download cap; keeps a caller typo from hanging the read. */
|
|
8
6
|
const MIN_RESULT_MAX_BYTES = 1;
|
|
9
7
|
const MAX_RESULT_MAX_BYTES = 2 * 1024 * 1024 * 1024;
|
|
@@ -121,7 +119,7 @@ export class MacrosResource extends BaseResource {
|
|
|
121
119
|
const maxBytes = macroResultMaxBytes(opts?.maxBytes);
|
|
122
120
|
const raw = await this.client.getTextLimited(`${this.base(runnableType, opts?.projectKey)}/result/${encodeURIComponent(runId)}`, maxBytes);
|
|
123
121
|
if (raw.truncated) {
|
|
124
|
-
throw new
|
|
122
|
+
throw new ClientValidationError(`Macro result exceeded ${String(maxBytes)} bytes; retry with a larger maxBytes.`, "validation_failed");
|
|
125
123
|
}
|
|
126
124
|
const text = raw.text;
|
|
127
125
|
const trimmed = text.trim();
|