dataiku-sdk 3.4.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 +3 -3
- 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 +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 +27 -50
- 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 +13 -23
- 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 +156 -253
- 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/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.js +7 -6
- 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/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 +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.js +2 -4
- 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 +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/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 +4 -4
- package/plugin.json +1 -1
- package/skills/dataiku-dss/SKILL.md +2 -3
- package/skills/dataiku-dss/references/authentication.md +3 -3
- package/skills/dataiku-dss/references/coding.md +1 -1
- package/dist/src/utils/pagination.d.ts +0 -8
- package/dist/src/utils/pagination.js +0 -23
package/dist/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { homedir, } from "node:os";
|
|
|
4
4
|
import { resolve, } from "node:path";
|
|
5
5
|
import { num, unknownJsonInput, } from "./cli/coerce.js";
|
|
6
6
|
import { commands, } from "./cli/commands/index.js";
|
|
7
|
-
import {
|
|
7
|
+
import { ambientProjectKey, loadEnvFile, } from "./cli/env.js";
|
|
8
8
|
import { executionMode, FLAG_ALIASES, isNegativeNumberToken, parseArgs, SHORT_FLAGS, VALUE_FLAGS, } from "./cli/flags.js";
|
|
9
9
|
import { cleanupLedgerEntry, } from "./cli/helpers/cleanup.js";
|
|
10
10
|
import { commandFailureExitCode, CommandResultFailure, flushCliWarnings, isFailedWaitResult, planResult, projectResultFields, setOutputFieldProjection, writeCommandResult, } from "./cli/output.js";
|
|
@@ -334,32 +334,11 @@ function validateSupportedCommandFlags(resource, action, flags) {
|
|
|
334
334
|
? "Remove --dry-run; use --plan to preview the mutation instead."
|
|
335
335
|
: `Remove --dry-run; ${resource} ${action} has no dry-run mode.`);
|
|
336
336
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
for (const char of usage) {
|
|
342
|
-
if (char === "[") {
|
|
343
|
-
optionalDepth++;
|
|
344
|
-
if (optionalDepth === 1)
|
|
345
|
-
stripped += " ";
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
if (char === "]" && optionalDepth > 0) {
|
|
349
|
-
optionalDepth--;
|
|
350
|
-
if (optionalDepth === 0)
|
|
351
|
-
stripped += " ";
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
if (optionalDepth === 0)
|
|
355
|
-
stripped += char;
|
|
337
|
+
// Registry commands reject --plan in buildMutationPlan; meta commands never reach it.
|
|
338
|
+
if (META_COMMAND_RESOURCES[resource] === true && executionMode(flags).plan
|
|
339
|
+
&& !entry.flags.some((flag) => flag.name === "plan")) {
|
|
340
|
+
throw new UsageError(`--plan is only supported for mutating commands; ${resource} ${action} has no plan mode.`, "usage_error", `Remove --plan; ${resource} ${action} has no plan mode.`);
|
|
356
341
|
}
|
|
357
|
-
return stripped;
|
|
358
|
-
}
|
|
359
|
-
function requiredPositionalCount(usage) {
|
|
360
|
-
const requiredUsage = stripOptionalUsageGroupsForValidation(usage);
|
|
361
|
-
const positionalTokens = [...requiredUsage.matchAll(/<[^>]+>/g),];
|
|
362
|
-
return positionalTokens.length;
|
|
363
342
|
}
|
|
364
343
|
function flagIsProvided(flags, name, allowEmpty = false) {
|
|
365
344
|
const value = flags[name];
|
|
@@ -370,7 +349,7 @@ function flagIsProvided(flags, name, allowEmpty = false) {
|
|
|
370
349
|
return allowEmpty || value.length > 0;
|
|
371
350
|
}
|
|
372
351
|
function validateRequiredCommandInputs(resource, action, args, flags, entry) {
|
|
373
|
-
const argCount =
|
|
352
|
+
const argCount = entry.positionalArguments.filter((positional) => positional.required).length;
|
|
374
353
|
const allowEmptyFlags = {};
|
|
375
354
|
for (const flag of entry.flags) {
|
|
376
355
|
if (flag.allowEmptyValue === true)
|
|
@@ -776,6 +755,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
776
755
|
throw unknownActionError("doctor", action, ["run",]);
|
|
777
756
|
}
|
|
778
757
|
currentCommandContext.action = action ?? "run";
|
|
758
|
+
validateSupportedCommandFlags("doctor", "run", flags);
|
|
779
759
|
const { runDoctor, } = await import("./cli/doctor.js");
|
|
780
760
|
const { result, exitCode, } = await runDoctor(flags);
|
|
781
761
|
return { action: "run", result, exitCode, };
|
|
@@ -791,6 +771,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
791
771
|
if (!authMeta) {
|
|
792
772
|
throw unknownActionError("auth", action, validActions, "auth only supports 'login'. To check credentials/connectivity, run 'dss doctor'.");
|
|
793
773
|
}
|
|
774
|
+
validateSupportedCommandFlags("auth", action, flags);
|
|
794
775
|
if (executionMode(flags).plan) {
|
|
795
776
|
return { action, result: authLoginPlan(flags), exitCode: 0, };
|
|
796
777
|
}
|
|
@@ -802,6 +783,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
802
783
|
throw unknownActionError("install-skill", action, ["run",]);
|
|
803
784
|
}
|
|
804
785
|
currentCommandContext.action = action ?? "run";
|
|
786
|
+
validateSupportedCommandFlags("install-skill", "run", flags);
|
|
805
787
|
return { action: "run", result: await runInstallSkill(flags), exitCode: 0, };
|
|
806
788
|
}
|
|
807
789
|
if (resource === "agent") {
|
|
@@ -811,6 +793,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
811
793
|
currentCommandContext.action = action;
|
|
812
794
|
if (action !== "contract")
|
|
813
795
|
throw unknownActionError("agent", action, ["contract",]);
|
|
796
|
+
validateSupportedCommandFlags("agent", "contract", flags);
|
|
814
797
|
return { action, result: contract.buildAgentContract(), exitCode: 0, };
|
|
815
798
|
}
|
|
816
799
|
if (resource === "commands") {
|
|
@@ -856,10 +839,12 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
856
839
|
};
|
|
857
840
|
}
|
|
858
841
|
if (resource === "version") {
|
|
842
|
+
await loadCommandRuntime();
|
|
859
843
|
if (action !== undefined && action !== "run") {
|
|
860
844
|
throw unknownActionError("version", action, ["run",]);
|
|
861
845
|
}
|
|
862
846
|
currentCommandContext.action = action ?? "run";
|
|
847
|
+
validateSupportedCommandFlags("version", "run", flags);
|
|
863
848
|
return { action: "run", result: cliVersionResult(), exitCode: 0, };
|
|
864
849
|
}
|
|
865
850
|
if (resource === "cleanup") {
|
|
@@ -868,6 +853,10 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
868
853
|
throw unknownActionError("cleanup", action, ["run",]);
|
|
869
854
|
}
|
|
870
855
|
currentCommandContext.action = action ?? "run";
|
|
856
|
+
validateSupportedCommandFlags("cleanup", "run", flags);
|
|
857
|
+
if (flags["apply"] === true && executionMode(flags).dryRun) {
|
|
858
|
+
throw new UsageError("--dry-run and --apply are mutually exclusive.", "usage_error");
|
|
859
|
+
}
|
|
871
860
|
if (executionMode(flags).plan) {
|
|
872
861
|
return { action: "run", result: cleanupPlan(flags), exitCode: 0, };
|
|
873
862
|
}
|
|
@@ -880,6 +869,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
880
869
|
throw unknownActionError("fixtures", action, ["run",]);
|
|
881
870
|
}
|
|
882
871
|
currentCommandContext.action = action ?? "run";
|
|
872
|
+
validateSupportedCommandFlags("fixtures", "run", flags);
|
|
883
873
|
const { runFixtures, } = await import("./cli/doctor.js");
|
|
884
874
|
return { action: "run", result: await runFixtures(flags), exitCode: 0, };
|
|
885
875
|
}
|
|
@@ -889,6 +879,7 @@ async function runMetaCommand(resource, action, flags) {
|
|
|
889
879
|
throw unknownActionError("batch", action, ["run",]);
|
|
890
880
|
}
|
|
891
881
|
currentCommandContext.action = action ?? "run";
|
|
882
|
+
validateSupportedCommandFlags("batch", "run", flags);
|
|
892
883
|
if (executionMode(flags).plan) {
|
|
893
884
|
return { action: "run", result: batchPlan(flags), exitCode: 0, };
|
|
894
885
|
}
|
|
@@ -993,9 +984,7 @@ async function runBatch(flags) {
|
|
|
993
984
|
if (executionMode(flags).dryRun) {
|
|
994
985
|
const batchProjectKey = typeof flags["project-key"] === "string"
|
|
995
986
|
? flags["project-key"]
|
|
996
|
-
:
|
|
997
|
-
? process.env.DATAIKU_PROJECT_KEY
|
|
998
|
-
: undefined;
|
|
987
|
+
: ambientProjectKey();
|
|
999
988
|
const planned = await Promise.all(steps.map(async (argv, index) => {
|
|
1000
989
|
const context = batchStepCommandContext(argv);
|
|
1001
990
|
Object.assign(currentCommandContext, { ...context, projectKey: batchProjectKey, });
|
|
@@ -1018,7 +1007,8 @@ async function runBatch(flags) {
|
|
|
1018
1007
|
};
|
|
1019
1008
|
}
|
|
1020
1009
|
catch (error) {
|
|
1021
|
-
|
|
1010
|
+
// Steps validate concurrently; the shared context may belong to a sibling.
|
|
1011
|
+
const envelope = buildErrorReport(error, { ...context, projectKey: batchProjectKey, });
|
|
1022
1012
|
return {
|
|
1023
1013
|
index,
|
|
1024
1014
|
args: redactArgv(argv),
|
|
@@ -1037,9 +1027,7 @@ async function runBatch(flags) {
|
|
|
1037
1027
|
validateBatchStepModes(steps);
|
|
1038
1028
|
let projectKey = typeof flags["project-key"] === "string"
|
|
1039
1029
|
? flags["project-key"]
|
|
1040
|
-
:
|
|
1041
|
-
? process.env.DATAIKU_PROJECT_KEY
|
|
1042
|
-
: undefined;
|
|
1030
|
+
: ambientProjectKey();
|
|
1043
1031
|
let client;
|
|
1044
1032
|
const needsClient = steps.some((argv) => batchStepNeedsClient(argv));
|
|
1045
1033
|
if (needsClient) {
|
|
@@ -1247,8 +1235,7 @@ function rawFlagValue(argv, flagName) {
|
|
|
1247
1235
|
function commandIsProjectScoped(resource, action) {
|
|
1248
1236
|
if (!resource)
|
|
1249
1237
|
return false;
|
|
1250
|
-
|
|
1251
|
-
return inferRequiresProject(resource, action ?? "", usage);
|
|
1238
|
+
return inferRequiresProject(resource, action ?? "");
|
|
1252
1239
|
}
|
|
1253
1240
|
function rawCommandContext() {
|
|
1254
1241
|
const argv = process.argv.slice(2);
|
|
@@ -1256,15 +1243,13 @@ function rawCommandContext() {
|
|
|
1256
1243
|
const resource = currentCommandContext.resource ?? positionals[0];
|
|
1257
1244
|
const action = currentCommandContext.action ?? positionals[1];
|
|
1258
1245
|
const explicitProjectKey = rawFlagValue(argv, "project-key") ?? rawFlagValue(argv, "project");
|
|
1259
|
-
const
|
|
1260
|
-
? process.env.DATAIKU_PROJECT_KEY
|
|
1261
|
-
: undefined;
|
|
1246
|
+
const environmentProjectKey = ambientProjectKey();
|
|
1262
1247
|
return {
|
|
1263
1248
|
resource,
|
|
1264
1249
|
action,
|
|
1265
1250
|
projectKey: explicitProjectKey
|
|
1266
1251
|
?? (commandIsProjectScoped(resource, action)
|
|
1267
|
-
? currentCommandContext.projectKey ??
|
|
1252
|
+
? currentCommandContext.projectKey ?? environmentProjectKey
|
|
1268
1253
|
: undefined),
|
|
1269
1254
|
};
|
|
1270
1255
|
}
|
|
@@ -1364,7 +1349,6 @@ function dssDiagnosticDetails(err) {
|
|
|
1364
1349
|
return {};
|
|
1365
1350
|
}
|
|
1366
1351
|
}
|
|
1367
|
-
const MISSING_PROJECT_KEY_ERROR_PREFIX = "projectKey is required";
|
|
1368
1352
|
function isAmbiguousMutationFailure(err, context) {
|
|
1369
1353
|
if (!(err instanceof DataikuError))
|
|
1370
1354
|
return false;
|
|
@@ -1399,9 +1383,11 @@ function boundedFailureResult(result) {
|
|
|
1399
1383
|
function errorExitCode(err) {
|
|
1400
1384
|
if (err instanceof CommandResultFailure)
|
|
1401
1385
|
return err.exitCode;
|
|
1402
|
-
if (err instanceof ClientValidationError
|
|
1386
|
+
if (err instanceof ClientValidationError
|
|
1387
|
+
&& (err.code === "assertion_failed" || err.code === "long_running_failure"))
|
|
1403
1388
|
return 4;
|
|
1404
|
-
if (err instanceof ClientValidationError
|
|
1389
|
+
if (err instanceof ClientValidationError
|
|
1390
|
+
&& (err.code === "ambiguous_outcome" || err.code === "internal_error"))
|
|
1405
1391
|
return 2;
|
|
1406
1392
|
if (err instanceof UsageError || err instanceof ClientValidationError)
|
|
1407
1393
|
return 1;
|
|
@@ -1409,15 +1395,14 @@ function errorExitCode(err) {
|
|
|
1409
1395
|
return 2;
|
|
1410
1396
|
if (err instanceof DataikuError)
|
|
1411
1397
|
return err.category === "transient" ? 3 : 2;
|
|
1412
|
-
if (err instanceof Error && err.message.startsWith(MISSING_PROJECT_KEY_ERROR_PREFIX))
|
|
1413
|
-
return 1;
|
|
1414
1398
|
return 2;
|
|
1415
1399
|
}
|
|
1416
|
-
function buildErrorReport(err) {
|
|
1417
|
-
const context = rawCommandContext();
|
|
1400
|
+
function buildErrorReport(err, contextOverride) {
|
|
1401
|
+
const context = contextOverride ?? rawCommandContext();
|
|
1418
1402
|
const exitCode = errorExitCode(err);
|
|
1419
1403
|
if (err instanceof ClientValidationError
|
|
1420
|
-
&& (err.code === "ambiguous_outcome" || err.code === "assertion_failed"
|
|
1404
|
+
&& (err.code === "ambiguous_outcome" || err.code === "assertion_failed"
|
|
1405
|
+
|| err.code === "long_running_failure")) {
|
|
1421
1406
|
return {
|
|
1422
1407
|
type: "error",
|
|
1423
1408
|
ok: false,
|
|
@@ -1439,7 +1424,9 @@ function buildErrorReport(err) {
|
|
|
1439
1424
|
code: err.code,
|
|
1440
1425
|
category: err.code === "target_absence_unverifiable"
|
|
1441
1426
|
? "permission_or_environment"
|
|
1442
|
-
: "
|
|
1427
|
+
: err.code === "internal_error"
|
|
1428
|
+
? "internal"
|
|
1429
|
+
: "usage",
|
|
1443
1430
|
exitCode,
|
|
1444
1431
|
...(err.code === "target_absence_unverifiable" ? { retryable: false, } : {}),
|
|
1445
1432
|
...(err.hint ? { hint: err.hint, } : {}),
|
|
@@ -1517,18 +1504,6 @@ function buildErrorReport(err) {
|
|
|
1517
1504
|
...context,
|
|
1518
1505
|
};
|
|
1519
1506
|
}
|
|
1520
|
-
if (err instanceof Error && err.message.startsWith(MISSING_PROJECT_KEY_ERROR_PREFIX)) {
|
|
1521
|
-
return {
|
|
1522
|
-
type: "error",
|
|
1523
|
-
ok: false,
|
|
1524
|
-
error: err.message,
|
|
1525
|
-
code: "missing_required_flag",
|
|
1526
|
-
category: "usage",
|
|
1527
|
-
exitCode,
|
|
1528
|
-
hint: "Pass --project-key or set DATAIKU_PROJECT_KEY.",
|
|
1529
|
-
...context,
|
|
1530
|
-
};
|
|
1531
|
-
}
|
|
1532
1507
|
const message = err instanceof Error ? err.message : String(err);
|
|
1533
1508
|
return {
|
|
1534
1509
|
type: "error",
|
|
@@ -1579,9 +1554,7 @@ async function main() {
|
|
|
1579
1554
|
action: positional[1],
|
|
1580
1555
|
projectKey: typeof flags["project-key"] === "string"
|
|
1581
1556
|
? flags["project-key"]
|
|
1582
|
-
:
|
|
1583
|
-
? process.env.DATAIKU_PROJECT_KEY
|
|
1584
|
-
: undefined,
|
|
1557
|
+
: ambientProjectKey(),
|
|
1585
1558
|
});
|
|
1586
1559
|
const metaCommand = await runMetaCommand(resource, positional[1], flags);
|
|
1587
1560
|
if (metaCommand) {
|
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,7 +465,7 @@ 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) {
|
|
@@ -810,8 +812,7 @@ export class DataikuClient {
|
|
|
810
812
|
return JSON.parse(text);
|
|
811
813
|
}
|
|
812
814
|
catch {
|
|
813
|
-
|
|
814
|
-
throw new DataikuError(res.status, res.statusText || "Invalid JSON response", `${NON_JSON_RESPONSE_MARKER}: ${summary}`, undefined, this.requestIdFromHeaders(res.headers));
|
|
815
|
+
throw new DataikuError(res.status, res.statusText || "Invalid JSON response", nonJsonResponseBody(text), undefined, this.requestIdFromHeaders(res.headers));
|
|
815
816
|
}
|
|
816
817
|
}
|
|
817
818
|
/* ---- private: bounded response body reading ---- */
|
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") {
|
|
@@ -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. */
|
|
@@ -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
|
}
|