dataiku-sdk 3.2.0 → 3.3.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 +149 -46
- package/dist/build-metadata.json +1 -1
- package/dist/packages/types/src/index.d.ts +102 -0
- package/dist/packages/types/src/index.js +76 -0
- package/dist/src/cli/commands/app.js +57 -15
- package/dist/src/cli/commands/bundle.js +1 -1
- package/dist/src/cli/commands/code-env.js +13 -7
- package/dist/src/cli/commands/connection.d.ts +9 -0
- package/dist/src/cli/commands/connection.js +267 -1
- package/dist/src/cli/commands/data-collection.d.ts +2 -0
- package/dist/src/cli/commands/data-collection.js +164 -0
- package/dist/src/cli/commands/dataset.js +161 -32
- package/dist/src/cli/commands/future.js +2 -2
- package/dist/src/cli/commands/group.d.ts +2 -0
- package/dist/src/cli/commands/group.js +109 -0
- package/dist/src/cli/commands/index.js +151 -78
- package/dist/src/cli/commands/knowledge-bank.d.ts +2 -0
- package/dist/src/cli/commands/knowledge-bank.js +80 -0
- package/dist/src/cli/commands/llm.d.ts +2 -0
- package/dist/src/cli/commands/llm.js +93 -0
- package/dist/src/cli/commands/macro.d.ts +2 -0
- package/dist/src/cli/commands/macro.js +221 -0
- package/dist/src/cli/commands/ml-task.js +18 -6
- package/dist/src/cli/commands/notebook.js +6 -2
- package/dist/src/cli/commands/plugin.d.ts +2 -0
- package/dist/src/cli/commands/plugin.js +799 -0
- package/dist/src/cli/commands/project-folder.d.ts +2 -0
- package/dist/src/cli/commands/project-folder.js +197 -0
- package/dist/src/cli/commands/project-git.js +14 -54
- package/dist/src/cli/commands/project.js +52 -6
- package/dist/src/cli/commands/recipe.js +36 -1
- package/dist/src/cli/commands/saved-model.d.ts +5 -0
- package/dist/src/cli/commands/saved-model.js +388 -1
- package/dist/src/cli/commands/scenario.js +138 -1
- package/dist/src/cli/commands/user.d.ts +8 -0
- package/dist/src/cli/commands/user.js +296 -0
- package/dist/src/cli/contract.d.ts +1 -2
- package/dist/src/cli/contract.js +1089 -103
- package/dist/src/cli/flags.js +30 -1
- package/dist/src/cli/helpers/app-successor.d.ts +19 -4
- package/dist/src/cli/helpers/app-successor.js +90 -30
- package/dist/src/cli/helpers/cleanup.js +3 -1
- package/dist/src/cli/helpers/flow-zone.js +1 -2
- package/dist/src/cli/output.d.ts +1 -1
- package/dist/src/cli/output.js +23 -10
- package/dist/src/cli/usage.d.ts +1 -0
- package/dist/src/cli/usage.js +47 -1
- package/dist/src/cli.js +147 -41
- package/dist/src/client.d.ts +83 -5
- package/dist/src/client.js +185 -29
- package/dist/src/errors.d.ts +3 -0
- package/dist/src/errors.js +2 -0
- package/dist/src/index.d.ts +16 -7
- package/dist/src/index.js +11 -2
- package/dist/src/resources/analyses.js +1 -8
- package/dist/src/resources/applications.d.ts +8 -6
- package/dist/src/resources/applications.js +21 -21
- package/dist/src/resources/base.d.ts +4 -0
- package/dist/src/resources/base.js +15 -0
- package/dist/src/resources/bundles.d.ts +9 -4
- package/dist/src/resources/bundles.js +10 -5
- package/dist/src/resources/connections.d.ts +78 -1
- package/dist/src/resources/connections.js +132 -1
- package/dist/src/resources/data-collections.d.ts +118 -0
- package/dist/src/resources/data-collections.js +49 -0
- package/dist/src/resources/datasets.d.ts +69 -0
- package/dist/src/resources/datasets.js +99 -1
- package/dist/src/resources/futures.d.ts +4 -1
- package/dist/src/resources/futures.js +38 -6
- package/dist/src/resources/groups.d.ts +47 -0
- package/dist/src/resources/groups.js +56 -0
- package/dist/src/resources/jobs.d.ts +8 -13
- package/dist/src/resources/jobs.js +41 -16
- package/dist/src/resources/knowledge-banks.d.ts +58 -0
- package/dist/src/resources/knowledge-banks.js +61 -0
- package/dist/src/resources/llms.d.ts +92 -0
- package/dist/src/resources/llms.js +62 -0
- package/dist/src/resources/macros.d.ts +121 -0
- package/dist/src/resources/macros.js +231 -0
- package/dist/src/resources/ml-tasks.d.ts +37 -2
- package/dist/src/resources/ml-tasks.js +100 -20
- package/dist/src/resources/model-evaluation-stores.js +1 -8
- package/dist/src/resources/notebooks.d.ts +43 -7
- package/dist/src/resources/notebooks.js +53 -13
- package/dist/src/resources/plugins.d.ts +265 -0
- package/dist/src/resources/plugins.js +458 -0
- package/dist/src/resources/project-folders.d.ts +71 -0
- package/dist/src/resources/project-folders.js +57 -0
- package/dist/src/resources/project-git.d.ts +6 -0
- package/dist/src/resources/project-git.js +69 -42
- package/dist/src/resources/project-library.d.ts +0 -1
- package/dist/src/resources/project-library.js +1 -17
- package/dist/src/resources/projects.d.ts +19 -1
- package/dist/src/resources/projects.js +27 -1
- package/dist/src/resources/recipes.d.ts +15 -1
- package/dist/src/resources/recipes.js +73 -6
- package/dist/src/resources/saved-models.d.ts +134 -1
- package/dist/src/resources/saved-models.js +214 -6
- package/dist/src/resources/scenarios.d.ts +105 -0
- package/dist/src/resources/scenarios.js +232 -106
- package/dist/src/resources/sql.js +5 -1
- package/dist/src/resources/users.d.ts +129 -0
- package/dist/src/resources/users.js +128 -0
- package/dist/src/resources/webapps.d.ts +15 -2
- package/dist/src/resources/webapps.js +18 -4
- package/dist/src/schemas.d.ts +2 -2
- package/dist/src/schemas.js +1 -1
- package/dist/src/utils/deep-merge.d.ts +1 -1
- package/dist/src/utils/polling.d.ts +20 -0
- package/dist/src/utils/polling.js +27 -0
- package/dist/src/utils/response-file.js +1 -1
- package/dist/src/utils/secret-sanitize.d.ts +54 -0
- package/dist/src/utils/secret-sanitize.js +101 -0
- package/package.json +6 -5
- package/packages/types/dist/index.d.ts +102 -0
- package/packages/types/dist/index.js +76 -0
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +7 -5
- package/skills/dataiku-dss/references/app-releases.md +8 -7
- package/skills/dataiku-dss/references/discovery.md +4 -4
package/dist/src/cli.js
CHANGED
|
@@ -3,28 +3,26 @@ import * as fs from "node:fs/promises";
|
|
|
3
3
|
import { homedir, } from "node:os";
|
|
4
4
|
import { resolve, } from "node:path";
|
|
5
5
|
import { num, unknownJsonInput, } from "./cli/coerce.js";
|
|
6
|
+
import { commands, } from "./cli/commands/index.js";
|
|
6
7
|
import { dataikuEnvironmentEnabled, loadEnvFile, } from "./cli/env.js";
|
|
7
8
|
import { executionMode, FLAG_ALIASES, isNegativeNumberToken, parseArgs, SHORT_FLAGS, VALUE_FLAGS, } from "./cli/flags.js";
|
|
8
9
|
import { cleanupLedgerEntry, } from "./cli/helpers/cleanup.js";
|
|
9
10
|
import { commandFailureExitCode, CommandResultFailure, flushCliWarnings, isFailedWaitResult, planResult, projectResultFields, setOutputFieldProjection, writeCommandResult, } from "./cli/output.js";
|
|
10
11
|
import { currentCommandContext, resolveCredentials, resolveLoginCredentials, } from "./cli/runtime.js";
|
|
11
|
-
import { COMMANDS_RUN_HINT, missingActionError, noCommandError, requireArgs, unknownActionError, unknownResourceError, UsageError, } from "./cli/usage.js";
|
|
12
|
+
import { COMMANDS_RUN_HINT, inferRequiresProject, missingActionError, noCommandError, requireArgs, RESOURCE_NAMES, unknownActionError, unknownResourceError, UsageError, } from "./cli/usage.js";
|
|
12
13
|
import { cliVersionResult, } from "./cli/version.js";
|
|
13
14
|
import { getCredentialsPath, } from "./config.js";
|
|
14
15
|
import { canonicalStatusText, ClientValidationError, DataikuError, dataikuErrorCode, } from "./errors.js";
|
|
15
16
|
import { appendCleanupLedgerEntry, findCleanupLedgerBindingViolation, preflightCleanupLedgerPath, readCleanupLedger, reserveCleanupLedgerDssUrl, } from "./utils/cleanup-ledger.js";
|
|
16
17
|
import { canonicalDssUrl, } from "./utils/dss-url.js";
|
|
17
|
-
|
|
18
|
+
import { sanitizeSecrets, } from "./utils/secret-sanitize.js";
|
|
18
19
|
let contract;
|
|
19
20
|
let commandRuntimeLoad;
|
|
20
|
-
//
|
|
21
|
+
// Command definitions are resource-lazy; full contract metadata loads only
|
|
22
|
+
// after a valid action is selected or explicit discovery is requested.
|
|
21
23
|
function loadCommandRuntime() {
|
|
22
|
-
return commandRuntimeLoad ??=
|
|
23
|
-
|
|
24
|
-
import("./cli/contract.js"),
|
|
25
|
-
]).then(([commandModule, contractModule,]) => {
|
|
26
|
-
commands = commandModule.commands;
|
|
27
|
-
contract = contractModule;
|
|
24
|
+
return commandRuntimeLoad ??= import("./cli/contract.js").then((module) => {
|
|
25
|
+
contract = module;
|
|
28
26
|
});
|
|
29
27
|
}
|
|
30
28
|
// ---------------------------------------------------------------------------
|
|
@@ -279,6 +277,8 @@ const META_COMMAND_RESOURCES = {
|
|
|
279
277
|
};
|
|
280
278
|
const commandRegistryCache = new Map();
|
|
281
279
|
function cachedCommandRegistry(resource) {
|
|
280
|
+
if (!contract)
|
|
281
|
+
return undefined;
|
|
282
282
|
if (!commandRegistryCache.has(resource)) {
|
|
283
283
|
commandRegistryCache.set(resource, contract.buildCommandRegistry(resource)[resource]);
|
|
284
284
|
}
|
|
@@ -415,11 +415,21 @@ const batchDryRunClientHandler = {
|
|
|
415
415
|
throw new BatchDryRunValidationComplete();
|
|
416
416
|
},
|
|
417
417
|
};
|
|
418
|
-
const
|
|
418
|
+
const batchDryRunResource = new Proxy(batchDryRunClientTarget, batchDryRunClientHandler);
|
|
419
|
+
let batchDryRunClient;
|
|
419
420
|
async function validateDryRunHandlerPreconditions(handler, args, flags) {
|
|
420
421
|
const readsFromStdin = flags["stdin"] === true || flags["sql"] === "-";
|
|
421
422
|
if (readsFromStdin)
|
|
422
423
|
return;
|
|
424
|
+
if (!batchDryRunClient) {
|
|
425
|
+
const { DataikuClient, } = await import("./client.js");
|
|
426
|
+
batchDryRunClient = new Proxy(new DataikuClient({
|
|
427
|
+
url: "http://dry-run.invalid",
|
|
428
|
+
apiKey: "dry-run-validation",
|
|
429
|
+
}), {
|
|
430
|
+
get: (_target, property) => property === "then" ? undefined : batchDryRunResource,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
423
433
|
try {
|
|
424
434
|
await handler(batchDryRunClient, args, flags);
|
|
425
435
|
}
|
|
@@ -760,9 +770,8 @@ function batchPlan(flags) {
|
|
|
760
770
|
});
|
|
761
771
|
}
|
|
762
772
|
async function runMetaCommand(resource, action, flags) {
|
|
763
|
-
if (resource !== "version")
|
|
764
|
-
await loadCommandRuntime();
|
|
765
773
|
if (resource === "doctor") {
|
|
774
|
+
await loadCommandRuntime();
|
|
766
775
|
if (action !== undefined && action !== "run") {
|
|
767
776
|
throw unknownActionError("doctor", action, ["run",]);
|
|
768
777
|
}
|
|
@@ -772,6 +781,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
772
781
|
return { action: "run", result, exitCode, };
|
|
773
782
|
}
|
|
774
783
|
if (resource === "auth") {
|
|
784
|
+
await loadCommandRuntime();
|
|
775
785
|
const validActions = Object.keys(contract.AUTH_ACTIONS);
|
|
776
786
|
if (!action) {
|
|
777
787
|
throw missingActionError("auth", validActions, "dss auth login --url URL --api-key KEY");
|
|
@@ -787,6 +797,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
787
797
|
return { action, result: await authMeta.handler(flags), exitCode: 0, };
|
|
788
798
|
}
|
|
789
799
|
if (resource === "install-skill") {
|
|
800
|
+
await loadCommandRuntime();
|
|
790
801
|
if (action !== undefined && action !== "run") {
|
|
791
802
|
throw unknownActionError("install-skill", action, ["run",]);
|
|
792
803
|
}
|
|
@@ -794,6 +805,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
794
805
|
return { action: "run", result: await runInstallSkill(flags), exitCode: 0, };
|
|
795
806
|
}
|
|
796
807
|
if (resource === "agent") {
|
|
808
|
+
await loadCommandRuntime();
|
|
797
809
|
if (!action)
|
|
798
810
|
throw missingActionError("agent", ["contract",], contract.AGENT_CONTRACT_USAGE);
|
|
799
811
|
currentCommandContext.action = action;
|
|
@@ -802,6 +814,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
802
814
|
return { action, result: contract.buildAgentContract(), exitCode: 0, };
|
|
803
815
|
}
|
|
804
816
|
if (resource === "commands") {
|
|
817
|
+
await loadCommandRuntime();
|
|
805
818
|
if (!action)
|
|
806
819
|
throw missingActionError("commands", ["run",], contract.COMMANDS_USAGE);
|
|
807
820
|
currentCommandContext.action = action;
|
|
@@ -809,24 +822,28 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
809
822
|
throw unknownActionError("commands", action, ["run",]);
|
|
810
823
|
validateSupportedCommandFlags("commands", "run", flags);
|
|
811
824
|
const selectors = commandRegistrySelectors(flags);
|
|
812
|
-
const
|
|
825
|
+
const outputPath = flags["output"];
|
|
826
|
+
if (selectors.length === 0 && typeof outputPath !== "string") {
|
|
827
|
+
return { action, result: contract.commandActionSummary(), exitCode: 0, };
|
|
828
|
+
}
|
|
829
|
+
const registry = selectors.length === 0 ? contract.buildCommandRegistry() : {};
|
|
813
830
|
for (const selector of selectors) {
|
|
814
831
|
const selectorParts = selector.split(".");
|
|
815
832
|
if (selectorParts.some((part) => part.length === 0)) {
|
|
816
833
|
throw new UsageError(`Invalid --fields selector: ${selector}. Expected RESOURCE or RESOURCE.ACTION[.FIELD...].`, "usage_error", contract.COMMANDS_USAGE, { selector, });
|
|
817
834
|
}
|
|
818
835
|
const [selectedResource, selectedAction,] = selectorParts;
|
|
819
|
-
const resourceActions =
|
|
836
|
+
const resourceActions = cachedCommandRegistry(selectedResource);
|
|
820
837
|
if (!resourceActions)
|
|
821
838
|
throw unknownResourceError(selectedResource);
|
|
839
|
+
registry[selectedResource] = resourceActions;
|
|
822
840
|
if (selectedAction && !resourceActions[selectedAction]) {
|
|
823
841
|
throw unknownActionError(selectedResource, selectedAction, Object.keys(resourceActions));
|
|
824
842
|
}
|
|
825
843
|
}
|
|
826
|
-
const outputPath = flags["output"];
|
|
827
844
|
const selectedRegistry = selectors.length === 0
|
|
828
845
|
? registry
|
|
829
|
-
: projectResultFields(registry, selectors);
|
|
846
|
+
: projectResultFields(registry, selectors, () => Object.keys(contract.commandActionSummary()).sort());
|
|
830
847
|
if (typeof outputPath === "string") {
|
|
831
848
|
const exported = selectedRegistry;
|
|
832
849
|
await fs.writeFile(outputPath, `${JSON.stringify(exported)}\n`, "utf-8");
|
|
@@ -834,7 +851,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
834
851
|
}
|
|
835
852
|
return {
|
|
836
853
|
action,
|
|
837
|
-
result:
|
|
854
|
+
result: selectedRegistry,
|
|
838
855
|
exitCode: 0,
|
|
839
856
|
};
|
|
840
857
|
}
|
|
@@ -846,6 +863,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
846
863
|
return { action: "run", result: cliVersionResult(), exitCode: 0, };
|
|
847
864
|
}
|
|
848
865
|
if (resource === "cleanup") {
|
|
866
|
+
await loadCommandRuntime();
|
|
849
867
|
if (action !== undefined && action !== "run") {
|
|
850
868
|
throw unknownActionError("cleanup", action, ["run",]);
|
|
851
869
|
}
|
|
@@ -857,6 +875,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
857
875
|
return { action: "run", result, exitCode, };
|
|
858
876
|
}
|
|
859
877
|
if (resource === "fixtures") {
|
|
878
|
+
await loadCommandRuntime();
|
|
860
879
|
if (action !== undefined && action !== "run") {
|
|
861
880
|
throw unknownActionError("fixtures", action, ["run",]);
|
|
862
881
|
}
|
|
@@ -865,6 +884,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
865
884
|
return { action: "run", result: await runFixtures(flags), exitCode: 0, };
|
|
866
885
|
}
|
|
867
886
|
if (resource === "batch") {
|
|
887
|
+
await loadCommandRuntime();
|
|
868
888
|
if (action !== undefined && action !== "run") {
|
|
869
889
|
throw unknownActionError("batch", action, ["run",]);
|
|
870
890
|
}
|
|
@@ -1181,27 +1201,12 @@ function summarizeCleanupFailures(failures) {
|
|
|
1181
1201
|
: [];
|
|
1182
1202
|
}));
|
|
1183
1203
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
return next && !next.startsWith("-") ? next : undefined;
|
|
1191
|
-
}
|
|
1192
|
-
if (arg.startsWith(`${longFlag}=`))
|
|
1193
|
-
return arg.slice(longFlag.length + 1);
|
|
1194
|
-
}
|
|
1195
|
-
return undefined;
|
|
1196
|
-
}
|
|
1197
|
-
function commandIsProjectScoped(resource, action) {
|
|
1198
|
-
if (!resource)
|
|
1199
|
-
return false;
|
|
1200
|
-
const usage = commands[resource]?.[action ?? ""]?.usage ?? "";
|
|
1201
|
-
return contract.inferRequiresProject(resource, action ?? "", usage);
|
|
1202
|
-
}
|
|
1203
|
-
function rawCommandContext() {
|
|
1204
|
-
const argv = process.argv.slice(2);
|
|
1204
|
+
/**
|
|
1205
|
+
* Positional arguments scanned with the same flag grammar as `parseArgs`, so
|
|
1206
|
+
* error reporting can recover the invoked resource/action without depending
|
|
1207
|
+
* on the command registry being loaded.
|
|
1208
|
+
*/
|
|
1209
|
+
function rawPositionals(argv) {
|
|
1205
1210
|
const positionals = [];
|
|
1206
1211
|
for (let index = 0; index < argv.length; index++) {
|
|
1207
1212
|
const arg = argv[index];
|
|
@@ -1224,6 +1229,30 @@ function rawCommandContext() {
|
|
|
1224
1229
|
}
|
|
1225
1230
|
positionals.push(arg);
|
|
1226
1231
|
}
|
|
1232
|
+
return positionals;
|
|
1233
|
+
}
|
|
1234
|
+
function rawFlagValue(argv, flagName) {
|
|
1235
|
+
const longFlag = `--${flagName}`;
|
|
1236
|
+
for (let index = 0; index < argv.length; index++) {
|
|
1237
|
+
const arg = argv[index];
|
|
1238
|
+
if (arg === longFlag) {
|
|
1239
|
+
const next = argv[index + 1];
|
|
1240
|
+
return next && !next.startsWith("-") ? next : undefined;
|
|
1241
|
+
}
|
|
1242
|
+
if (arg.startsWith(`${longFlag}=`))
|
|
1243
|
+
return arg.slice(longFlag.length + 1);
|
|
1244
|
+
}
|
|
1245
|
+
return undefined;
|
|
1246
|
+
}
|
|
1247
|
+
function commandIsProjectScoped(resource, action) {
|
|
1248
|
+
if (!resource)
|
|
1249
|
+
return false;
|
|
1250
|
+
const usage = commands[resource]?.[action ?? ""]?.usage ?? "";
|
|
1251
|
+
return inferRequiresProject(resource, action ?? "", usage);
|
|
1252
|
+
}
|
|
1253
|
+
function rawCommandContext() {
|
|
1254
|
+
const argv = process.argv.slice(2);
|
|
1255
|
+
const positionals = rawPositionals(argv);
|
|
1227
1256
|
const resource = currentCommandContext.resource ?? positionals[0];
|
|
1228
1257
|
const action = currentCommandContext.action ?? positionals[1];
|
|
1229
1258
|
const explicitProjectKey = rawFlagValue(argv, "project-key") ?? rawFlagValue(argv, "project");
|
|
@@ -1274,6 +1303,67 @@ function requestIdFromBody(body) {
|
|
|
1274
1303
|
}
|
|
1275
1304
|
return undefined;
|
|
1276
1305
|
}
|
|
1306
|
+
/** DSS diagnostic fields, in the resource layer's read order (detailedMessage → message → errorMessage). */
|
|
1307
|
+
const DSS_DIAGNOSTIC_MESSAGE_FIELDS = ["detailedMessage", "message", "errorMessage",];
|
|
1308
|
+
const MAX_DSS_DIAGNOSTIC_LENGTH = 300;
|
|
1309
|
+
/**
|
|
1310
|
+
* Credential material for redacting a server echo in a receipt: resolved
|
|
1311
|
+
* through the same resolver every command uses (flag → env → saved), so the
|
|
1312
|
+
* report path never grows a second credential-precedence convention.
|
|
1313
|
+
*/
|
|
1314
|
+
function cliSecretValues() {
|
|
1315
|
+
try {
|
|
1316
|
+
const { apiKey, } = resolveCredentials(parseArgs(process.argv.slice(2)).flags);
|
|
1317
|
+
return apiKey ? [apiKey,] : [];
|
|
1318
|
+
}
|
|
1319
|
+
catch {
|
|
1320
|
+
return [];
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Bounded, sanitized server diagnostic preserved on an ambiguous mutation
|
|
1325
|
+
* envelope (`dssMessage`/`dssErrorType`, next to the existing `dssCategory`):
|
|
1326
|
+
* the DSS error text and Java error type the response body carried, so the
|
|
1327
|
+
* receipt explains why the server failed while the mutation outcome stays
|
|
1328
|
+
* unknown. Whitespace collapses to one line, credential material is redacted,
|
|
1329
|
+
* long text truncates, and the raw body/stack never pass through.
|
|
1330
|
+
*/
|
|
1331
|
+
function dssDiagnosticDetails(err) {
|
|
1332
|
+
try {
|
|
1333
|
+
const parsed = JSON.parse(err.body);
|
|
1334
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
1335
|
+
return {};
|
|
1336
|
+
const record = parsed;
|
|
1337
|
+
let secrets;
|
|
1338
|
+
const diagnostic = (value) => {
|
|
1339
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
1340
|
+
return undefined;
|
|
1341
|
+
secrets ??= cliSecretValues();
|
|
1342
|
+
const sanitized = sanitizeSecrets(value.replace(/\s+/g, " ").trim(), {
|
|
1343
|
+
sensitiveKeys: {},
|
|
1344
|
+
secrets,
|
|
1345
|
+
redactUrlUserinfo: true,
|
|
1346
|
+
});
|
|
1347
|
+
return sanitized.length > MAX_DSS_DIAGNOSTIC_LENGTH
|
|
1348
|
+
? `${sanitized.slice(0, MAX_DSS_DIAGNOSTIC_LENGTH)}…`
|
|
1349
|
+
: sanitized;
|
|
1350
|
+
};
|
|
1351
|
+
let message;
|
|
1352
|
+
for (const field of DSS_DIAGNOSTIC_MESSAGE_FIELDS) {
|
|
1353
|
+
message = diagnostic(record[field]);
|
|
1354
|
+
if (message !== undefined)
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
const errorType = diagnostic(record["errorType"]);
|
|
1358
|
+
return {
|
|
1359
|
+
...(message !== undefined ? { dssMessage: message, } : {}),
|
|
1360
|
+
...(errorType !== undefined ? { dssErrorType: errorType, } : {}),
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
catch {
|
|
1364
|
+
return {};
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1277
1367
|
const MISSING_PROJECT_KEY_ERROR_PREFIX = "projectKey is required";
|
|
1278
1368
|
function isAmbiguousMutationFailure(err, context) {
|
|
1279
1369
|
if (!(err instanceof DataikuError))
|
|
@@ -1384,6 +1474,8 @@ function buildErrorReport(err) {
|
|
|
1384
1474
|
requestId: err.requestId ?? requestIdFromBody(err.body),
|
|
1385
1475
|
details: {
|
|
1386
1476
|
dssCategory: err.category,
|
|
1477
|
+
...(err.bodyTruncated ? { bodyTruncated: true, } : {}),
|
|
1478
|
+
...dssDiagnosticDetails(err),
|
|
1387
1479
|
statusText: canonicalStatusText(err.status),
|
|
1388
1480
|
idempotency: "none",
|
|
1389
1481
|
...(err.retry ? { retry: err.retry, } : {}),
|
|
@@ -1417,6 +1509,7 @@ function buildErrorReport(err) {
|
|
|
1417
1509
|
requestId: err.requestId ?? requestIdFromBody(err.body),
|
|
1418
1510
|
details: {
|
|
1419
1511
|
dssCategory: err.category,
|
|
1512
|
+
...(err.bodyTruncated ? { bodyTruncated: true, } : {}),
|
|
1420
1513
|
statusText: canonicalStatusText(err.status),
|
|
1421
1514
|
body: safeBody,
|
|
1422
1515
|
...(err.retry ? { retry: err.retry, } : {}),
|
|
@@ -1451,6 +1544,14 @@ function writeErrorReport(err) {
|
|
|
1451
1544
|
flushCliWarnings();
|
|
1452
1545
|
process.stdout.write(`${JSON.stringify(buildErrorReport(err))}\n`);
|
|
1453
1546
|
}
|
|
1547
|
+
/** Only ambiguous mutation failures require full contract metadata. */
|
|
1548
|
+
function errorReportNeedsCommandRuntime(err) {
|
|
1549
|
+
if (contract || !(err instanceof DataikuError))
|
|
1550
|
+
return false;
|
|
1551
|
+
const method = err.retry?.method.toUpperCase();
|
|
1552
|
+
return !!method && method !== "GET" && method !== "HEAD"
|
|
1553
|
+
&& (err.status === 0 || err.status >= 500);
|
|
1554
|
+
}
|
|
1454
1555
|
// ---------------------------------------------------------------------------
|
|
1455
1556
|
// Main
|
|
1456
1557
|
// ---------------------------------------------------------------------------
|
|
@@ -1489,7 +1590,8 @@ async function main() {
|
|
|
1489
1590
|
process.exitCode = metaCommand.exitCode;
|
|
1490
1591
|
return;
|
|
1491
1592
|
}
|
|
1492
|
-
|
|
1593
|
+
// Resource and action recovery require only this resource's definitions.
|
|
1594
|
+
if (!RESOURCE_NAMES.includes(resource))
|
|
1493
1595
|
throw unknownResourceError(resource);
|
|
1494
1596
|
const resourceActions = commands[resource];
|
|
1495
1597
|
if (positional.length === 1) {
|
|
@@ -1500,8 +1602,12 @@ async function main() {
|
|
|
1500
1602
|
const actionMeta = resourceActions[action];
|
|
1501
1603
|
if (!actionMeta)
|
|
1502
1604
|
throw unknownActionError(resource, action, Object.keys(resourceActions));
|
|
1605
|
+
await loadCommandRuntime();
|
|
1503
1606
|
validateSupportedCommandFlags(resource, action, flags);
|
|
1504
1607
|
const args = positional.slice(2);
|
|
1608
|
+
// Command-local validation runs for live, --plan, and --dry-run alike, so a
|
|
1609
|
+
// bad identifier is a usage error before any plan is built or request made.
|
|
1610
|
+
actionMeta.validate?.(args, flags);
|
|
1505
1611
|
if (executionMode(flags).plan) {
|
|
1506
1612
|
const plan = contract.buildMutationPlan(resource, action, actionMeta, args, flags);
|
|
1507
1613
|
writeCommandResult(plan);
|
|
@@ -1515,7 +1621,6 @@ async function main() {
|
|
|
1515
1621
|
writeCommandResult(result);
|
|
1516
1622
|
return;
|
|
1517
1623
|
}
|
|
1518
|
-
actionMeta.validate?.(args, flags);
|
|
1519
1624
|
const { url, apiKey, projectKey, tlsRejectUnauthorized, caCertPath, } = resolveCredentials(flags);
|
|
1520
1625
|
currentCommandContext.projectKey = projectKey;
|
|
1521
1626
|
if (!url) {
|
|
@@ -1547,7 +1652,8 @@ async function main() {
|
|
|
1547
1652
|
writeCommandResult(result);
|
|
1548
1653
|
}
|
|
1549
1654
|
main().catch(async (err) => {
|
|
1550
|
-
|
|
1655
|
+
if (errorReportNeedsCommandRuntime(err))
|
|
1656
|
+
await loadCommandRuntime();
|
|
1551
1657
|
writeErrorReport(err);
|
|
1552
1658
|
process.exitCode = errorExitCode(err);
|
|
1553
1659
|
});
|
package/dist/src/client.d.ts
CHANGED
|
@@ -8,19 +8,26 @@ import { CodeEnvsResource } from "./resources/code-envs.js";
|
|
|
8
8
|
import { ConnectionsResource } from "./resources/connections.js";
|
|
9
9
|
import { ContinuousActivitiesResource } from "./resources/continuous-activities.js";
|
|
10
10
|
import { DashboardsResource } from "./resources/dashboards.js";
|
|
11
|
+
import { DataCollectionsResource } from "./resources/data-collections.js";
|
|
11
12
|
import { DataQualityResource } from "./resources/data-quality.js";
|
|
12
13
|
import { DatasetsResource } from "./resources/datasets.js";
|
|
13
14
|
import { DiscussionsResource } from "./resources/discussions.js";
|
|
14
15
|
import { FlowZonesResource } from "./resources/flow-zones.js";
|
|
15
16
|
import { FoldersResource } from "./resources/folders.js";
|
|
16
17
|
import { FuturesResource } from "./resources/futures.js";
|
|
18
|
+
import { GroupsResource } from "./resources/groups.js";
|
|
17
19
|
import { InsightsResource } from "./resources/insights.js";
|
|
18
20
|
import { JobsResource } from "./resources/jobs.js";
|
|
21
|
+
import { KnowledgeBanksResource } from "./resources/knowledge-banks.js";
|
|
22
|
+
import { LlmsResource } from "./resources/llms.js";
|
|
23
|
+
import { MacrosResource } from "./resources/macros.js";
|
|
19
24
|
import { MeaningsResource } from "./resources/meanings.js";
|
|
20
25
|
import { MetricsResource } from "./resources/metrics.js";
|
|
21
26
|
import { MlTasksResource } from "./resources/ml-tasks.js";
|
|
22
27
|
import { ModelEvaluationStoresResource } from "./resources/model-evaluation-stores.js";
|
|
23
28
|
import { NotebooksResource } from "./resources/notebooks.js";
|
|
29
|
+
import { PluginsResource } from "./resources/plugins.js";
|
|
30
|
+
import { ProjectFoldersResource } from "./resources/project-folders.js";
|
|
24
31
|
import { ProjectGitResource } from "./resources/project-git.js";
|
|
25
32
|
import { ProjectLibraryResource } from "./resources/project-library.js";
|
|
26
33
|
import { ProjectsResource } from "./resources/projects.js";
|
|
@@ -30,10 +37,43 @@ import { ScenariosResource } from "./resources/scenarios.js";
|
|
|
30
37
|
import { SqlResource } from "./resources/sql.js";
|
|
31
38
|
import { StatisticsResource } from "./resources/statistics.js";
|
|
32
39
|
import { StreamingEndpointsResource } from "./resources/streaming-endpoints.js";
|
|
40
|
+
import { UsersResource } from "./resources/users.js";
|
|
33
41
|
import { VariablesResource } from "./resources/variables.js";
|
|
34
42
|
import { WebappsResource } from "./resources/webapps.js";
|
|
35
43
|
import { WikiResource } from "./resources/wiki.js";
|
|
36
44
|
import { WorkspacesResource } from "./resources/workspaces.js";
|
|
45
|
+
/** One part of a {@link DataikuClient.uploadForm} multipart/form-data body. */
|
|
46
|
+
export interface UploadFormPart {
|
|
47
|
+
/** Form field name. */
|
|
48
|
+
name: string;
|
|
49
|
+
/** Text field value. Mutually exclusive with `blob`/`fileName` file parts. */
|
|
50
|
+
value?: string;
|
|
51
|
+
/** File content. Omit (or null) together with `fileName` for a zero-byte file part. */
|
|
52
|
+
blob?: Blob | null;
|
|
53
|
+
/** Filename for file parts. */
|
|
54
|
+
fileName?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Multipart part modes for {@link DataikuClient.uploadForm}:
|
|
58
|
+
* - `value`: a form text field;
|
|
59
|
+
* - neither `blob` nor `fileName`: a filename-less, zero-length field part —
|
|
60
|
+
* the official Python client's files={"file": (None, None)} shape required
|
|
61
|
+
* by the managed-folder MLflow import (a Blob would add `filename=`, even
|
|
62
|
+
* when empty);
|
|
63
|
+
* - `blob` (optionally with `fileName`): a file part.
|
|
64
|
+
*/
|
|
65
|
+
/** Per-call overrides for {@link DataikuClient.get}. */
|
|
66
|
+
export interface DataikuGetOptions {
|
|
67
|
+
/**
|
|
68
|
+
* TOTAL duration budget in milliseconds for this call, measured from call
|
|
69
|
+
* start: it bounds every retry attempt's fetch, the backoff sleeps between
|
|
70
|
+
* attempts, and the response body read. When the budget is exhausted the
|
|
71
|
+
* request is aborted and a timeout DataikuError is thrown. The client-level
|
|
72
|
+
* requestTimeoutMs still caps each attempt and buffered body read; this
|
|
73
|
+
* budget may shorten those limits but never extends them.
|
|
74
|
+
*/
|
|
75
|
+
timeoutMs?: number;
|
|
76
|
+
}
|
|
37
77
|
export interface DataikuClientTraceEvent {
|
|
38
78
|
type: "trace";
|
|
39
79
|
phase: "request" | "response" | "error";
|
|
@@ -72,9 +112,9 @@ export interface DataikuClientConfig {
|
|
|
72
112
|
/** Max retry attempts for idempotent requests (default 4, capped at 10) */
|
|
73
113
|
retryMaxAttempts?: number;
|
|
74
114
|
/**
|
|
75
|
-
* Maximum bytes
|
|
76
|
-
*
|
|
77
|
-
*
|
|
115
|
+
* Maximum bytes retained from a single response body by text/JSON consumers
|
|
116
|
+
* (default 50 MiB). Oversized successful responses are rejected. Error
|
|
117
|
+
* responses retain a bounded prefix with DataikuError.bodyTruncated=true.
|
|
78
118
|
*/
|
|
79
119
|
maxResponseBodyBytes?: number;
|
|
80
120
|
/** Emit HTTP request/response trace events. Defaults to JSONL on stderr when verbose is true. */
|
|
@@ -139,6 +179,14 @@ export declare class DataikuClient {
|
|
|
139
179
|
private mlTasksResource?;
|
|
140
180
|
private savedModelsResource?;
|
|
141
181
|
private modelEvaluationStoresResource?;
|
|
182
|
+
private projectFoldersResource?;
|
|
183
|
+
private dataCollectionsResource?;
|
|
184
|
+
private llmsResource?;
|
|
185
|
+
private knowledgeBanksResource?;
|
|
186
|
+
private macrosResource?;
|
|
187
|
+
private pluginsResource?;
|
|
188
|
+
private usersResource?;
|
|
189
|
+
private groupsResource?;
|
|
142
190
|
get projects(): ProjectsResource;
|
|
143
191
|
get datasets(): DatasetsResource;
|
|
144
192
|
get dashboards(): DashboardsResource;
|
|
@@ -175,6 +223,14 @@ export declare class DataikuClient {
|
|
|
175
223
|
get mlTasks(): MlTasksResource;
|
|
176
224
|
get savedModels(): SavedModelsResource;
|
|
177
225
|
get modelEvaluationStores(): ModelEvaluationStoresResource;
|
|
226
|
+
get projectFolders(): ProjectFoldersResource;
|
|
227
|
+
get dataCollections(): DataCollectionsResource;
|
|
228
|
+
get llms(): LlmsResource;
|
|
229
|
+
get knowledgeBanks(): KnowledgeBanksResource;
|
|
230
|
+
get macros(): MacrosResource;
|
|
231
|
+
get plugins(): PluginsResource;
|
|
232
|
+
get users(): UsersResource;
|
|
233
|
+
get groups(): GroupsResource;
|
|
178
234
|
constructor(config?: DataikuClientConfig);
|
|
179
235
|
/**
|
|
180
236
|
* Canonical request base URL: the exact prefix every HTTP verb concatenates
|
|
@@ -189,7 +245,7 @@ export declare class DataikuClient {
|
|
|
189
245
|
*/
|
|
190
246
|
getMaxResponseBodyBytes(): number;
|
|
191
247
|
resolveProjectKey(paramValue?: string): string;
|
|
192
|
-
get<T = unknown>(path: string): Promise<T>;
|
|
248
|
+
get<T = unknown>(path: string, options?: DataikuGetOptions): Promise<T>;
|
|
193
249
|
/**
|
|
194
250
|
* GET returning the parsed JSON body plus selected response metadata
|
|
195
251
|
* (documented DSS version headers, server date, request id). Authorization
|
|
@@ -239,10 +295,32 @@ export declare class DataikuClient {
|
|
|
239
295
|
* {@link getText} (byte cap `maxResponseBodyBytes`, request deadline).
|
|
240
296
|
*/
|
|
241
297
|
postText(path: string, body?: unknown): Promise<string>;
|
|
298
|
+
/** Send raw file contents through the shared authenticated transport. */
|
|
299
|
+
postRawBody(path: string, body: string | Uint8Array): Promise<void>;
|
|
300
|
+
/** Git endpoints require Basic API-key authentication, unlike the bearer API. */
|
|
301
|
+
requestGit(method: string, path: string, body?: unknown, deadlineAt?: number): Promise<Response>;
|
|
242
302
|
postStream(path: string, body?: unknown): Promise<Response>;
|
|
243
303
|
put<T = unknown>(path: string, body: unknown): Promise<T>;
|
|
244
304
|
del(path: string): Promise<void>;
|
|
245
305
|
putVoid(path: string, body: unknown): Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* PUT without a request body. A few DSS endpoints (bundle export) reject
|
|
308
|
+
* an empty JSON object body with 400 validation, and the official Python
|
|
309
|
+
* client sends no body at all for them.
|
|
310
|
+
*/
|
|
311
|
+
putVoidNoBody(path: string): Promise<void>;
|
|
312
|
+
/**
|
|
313
|
+
* POST a multipart/form-data body built from explicit parts, with optional
|
|
314
|
+
* query parameters appended to the path, returning the parsed JSON body.
|
|
315
|
+
*
|
|
316
|
+
* A part with `value` becomes a form text field; a part with `blob`
|
|
317
|
+
* (or a `fileName` with no blob) becomes a file part — a `fileName` without
|
|
318
|
+
* blob yields a zero-byte file part, which some DSS import endpoints
|
|
319
|
+
* (e.g. saved-model MLflow version import) require for metadata-only parts.
|
|
320
|
+
* The `Content-Type` header is left to the runtime so the multipart
|
|
321
|
+
* boundary is set correctly.
|
|
322
|
+
*/
|
|
323
|
+
uploadForm<T = unknown>(path: string, parts: UploadFormPart[], query?: URLSearchParams): Promise<T>;
|
|
246
324
|
private uploadResponse;
|
|
247
325
|
upload(path: string, filePath: string, fileName?: string): Promise<void>;
|
|
248
326
|
uploadJson<T>(path: string, filePath: string, fileName?: string): Promise<T>;
|
|
@@ -271,7 +349,7 @@ export declare class DataikuClient {
|
|
|
271
349
|
private requestIdFromHeaders;
|
|
272
350
|
private parseJsonResponse;
|
|
273
351
|
/**
|
|
274
|
-
* Read at most `maxBytes` of a
|
|
352
|
+
* Read at most `maxBytes` of a response body as UTF-8 text.
|
|
275
353
|
*
|
|
276
354
|
* The body is consumed with the request deadline still active (measured
|
|
277
355
|
* from the first read): a stalled body throws a DataikuError instead of
|