dataiku-sdk 2.0.0 → 3.1.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.
Files changed (80) hide show
  1. package/LICENSE +107 -17
  2. package/README.md +144 -17
  3. package/dist/build-metadata.json +1 -1
  4. package/dist/packages/types/src/index.d.ts +39 -4
  5. package/dist/packages/types/src/index.js +31 -2
  6. package/dist/src/cli/commands/api-service.js +62 -16
  7. package/dist/src/cli/commands/bundle.js +49 -15
  8. package/dist/src/cli/commands/code-env.js +210 -49
  9. package/dist/src/cli/commands/code.d.ts +19 -0
  10. package/dist/src/cli/commands/code.js +87 -15
  11. package/dist/src/cli/commands/dataset.js +8 -3
  12. package/dist/src/cli/commands/flow-zone.js +33 -5
  13. package/dist/src/cli/commands/notebook.js +72 -41
  14. package/dist/src/cli/commands/project-git.js +8 -5
  15. package/dist/src/cli/commands/project-library.d.ts +21 -0
  16. package/dist/src/cli/commands/project-library.js +121 -50
  17. package/dist/src/cli/commands/project.js +16 -2
  18. package/dist/src/cli/commands/recipe.js +37 -12
  19. package/dist/src/cli/commands/sql.d.ts +10 -0
  20. package/dist/src/cli/commands/sql.js +39 -17
  21. package/dist/src/cli/commands/webapp.js +67 -13
  22. package/dist/src/cli/contract.d.ts +15 -0
  23. package/dist/src/cli/contract.js +870 -107
  24. package/dist/src/cli/env.d.ts +9 -0
  25. package/dist/src/cli/env.js +20 -2
  26. package/dist/src/cli/flags.js +9 -0
  27. package/dist/src/cli/helpers/cleanup.js +104 -3
  28. package/dist/src/cli/helpers/flow-zone.d.ts +3 -0
  29. package/dist/src/cli/helpers/flow-zone.js +33 -3
  30. package/dist/src/cli/helpers/recipe.d.ts +20 -0
  31. package/dist/src/cli/helpers/recipe.js +158 -3
  32. package/dist/src/cli/output.d.ts +2 -0
  33. package/dist/src/cli/output.js +33 -6
  34. package/dist/src/cli/runtime.d.ts +35 -1
  35. package/dist/src/cli/runtime.js +125 -18
  36. package/dist/src/cli/types.d.ts +7 -0
  37. package/dist/src/cli.js +135 -28
  38. package/dist/src/client.d.ts +60 -0
  39. package/dist/src/client.js +237 -42
  40. package/dist/src/errors.d.ts +8 -2
  41. package/dist/src/errors.js +40 -0
  42. package/dist/src/index.d.ts +4 -3
  43. package/dist/src/index.js +2 -1
  44. package/dist/src/resources/api-services.d.ts +48 -6
  45. package/dist/src/resources/api-services.js +54 -8
  46. package/dist/src/resources/bundles.d.ts +51 -6
  47. package/dist/src/resources/bundles.js +39 -9
  48. package/dist/src/resources/code-envs.d.ts +25 -3
  49. package/dist/src/resources/code-envs.js +104 -2
  50. package/dist/src/resources/datasets.d.ts +20 -0
  51. package/dist/src/resources/datasets.js +232 -52
  52. package/dist/src/resources/jobs.d.ts +35 -10
  53. package/dist/src/resources/jobs.js +92 -17
  54. package/dist/src/resources/notebooks.d.ts +77 -7
  55. package/dist/src/resources/notebooks.js +143 -19
  56. package/dist/src/resources/project-git.d.ts +12 -0
  57. package/dist/src/resources/project-git.js +39 -8
  58. package/dist/src/resources/project-library.d.ts +122 -7
  59. package/dist/src/resources/project-library.js +494 -25
  60. package/dist/src/resources/projects.d.ts +5 -2
  61. package/dist/src/resources/projects.js +18 -2
  62. package/dist/src/resources/scenarios.d.ts +30 -0
  63. package/dist/src/resources/scenarios.js +73 -27
  64. package/dist/src/resources/sql.d.ts +6 -0
  65. package/dist/src/resources/sql.js +22 -2
  66. package/dist/src/resources/webapps.d.ts +35 -4
  67. package/dist/src/resources/webapps.js +54 -5
  68. package/dist/src/schemas.d.ts +2 -2
  69. package/dist/src/schemas.js +1 -1
  70. package/dist/src/skill.d.ts +9 -0
  71. package/dist/src/skill.js +37 -4
  72. package/dist/src/utils/flow-analysis.d.ts +53 -0
  73. package/dist/src/utils/flow-analysis.js +382 -0
  74. package/dist/src/utils/project-archive.d.ts +41 -2
  75. package/dist/src/utils/project-archive.js +159 -16
  76. package/package.json +5 -5
  77. package/packages/types/dist/index.d.ts +39 -4
  78. package/packages/types/dist/index.js +31 -2
  79. package/plugin.json +2 -2
  80. package/skills/dataiku-dss/SKILL.md +75 -48
@@ -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, } from "./errors.js";
6
+ import { classifyDataikuError, ClientValidationError, DataikuError, NON_JSON_RESPONSE_MARKER, } 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";
@@ -47,6 +47,14 @@ const MAX_RETRY_ATTEMPTS_CAP = 10;
47
47
  const BASE_DELAY_MS = 2_000;
48
48
  const MAX_BACKOFF_DELAY_MS = 30_000;
49
49
  const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
50
+ /**
51
+ * Default cap on bytes buffered from a single response body by the text/JSON
52
+ * consumers (getText, postText, parseJsonResponse). Bodies larger than this
53
+ * are rejected with a DataikuError after the stream is cancelled; raw
54
+ * streaming methods (stream, postStream) are unaffected.
55
+ */
56
+ const DEFAULT_MAX_BUFFERED_BODY_BYTES = 50 * 1024 * 1024;
57
+ const RESPONSE_TOO_LARGE_STATUS_TEXT = "Response Too Large";
50
58
  /* ------------------------------------------------------------------ */
51
59
  /* Helpers */
52
60
  /* ------------------------------------------------------------------ */
@@ -105,6 +113,43 @@ function trimToUtf8Boundary(bytes) {
105
113
  return bytes;
106
114
  return continuation + 1 < expected ? bytes.subarray(0, i) : bytes;
107
115
  }
116
+ /**
117
+ * Drop leading UTF-8 continuation bytes. A UTF-8 character never *starts*
118
+ * with a continuation byte, so any leading continuation bytes are the remains
119
+ * of a character split by a byte cut at the start of the retained range.
120
+ * Dropping them keeps the decoded text free of replacement characters.
121
+ */
122
+ function trimFromUtf8BoundaryStart(bytes) {
123
+ let i = 0;
124
+ while (i < bytes.length && (bytes[i] & 0xC0) === 0x80) {
125
+ i++;
126
+ }
127
+ return i > 0 ? bytes.subarray(i) : bytes;
128
+ }
129
+ function buildBodyReadTimeoutError(timeoutMs) {
130
+ return new DataikuError(0, "Request Timeout", `Request timed out after ${timeoutMs}ms while reading the response body.`);
131
+ }
132
+ /**
133
+ * Read the next chunk of a response body under a hard deadline.
134
+ * When `remainingMs` elapses, the stream is cancelled and the caller's
135
+ * promise rejects with a DataikuError, so a stalled body cannot hang the
136
+ * buffered consumers after headers already arrived.
137
+ */
138
+ async function readChunkWithDeadline(reader, remainingMs, timeoutMs) {
139
+ const { promise, resolve, reject, } = Promise.withResolvers();
140
+ const timer = setTimeout(() => {
141
+ void reader.cancel(buildBodyReadTimeoutError(timeoutMs)).catch(() => { });
142
+ reject(buildBodyReadTimeoutError(timeoutMs));
143
+ }, remainingMs);
144
+ reader.read().then((result) => {
145
+ clearTimeout(timer);
146
+ resolve(result);
147
+ }, (error) => {
148
+ clearTimeout(timer);
149
+ reject(error);
150
+ });
151
+ return promise;
152
+ }
108
153
  function buildRetryMetadata(method, enabled, maxAttempts, attempts, delaysMs, timedOut) {
109
154
  return {
110
155
  method,
@@ -161,6 +206,7 @@ export class DataikuClient {
161
206
  apiKey;
162
207
  defaultProjectKey;
163
208
  requestTimeoutMs;
209
+ maxResponseBodyBytes;
164
210
  retryMaxAttempts;
165
211
  verbose;
166
212
  tlsOptions;
@@ -326,6 +372,7 @@ export class DataikuClient {
326
372
  this.apiKey = apiKey;
327
373
  this.defaultProjectKey = config?.projectKey?.trim() || undefined;
328
374
  this.requestTimeoutMs = config?.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
375
+ this.maxResponseBodyBytes = config?.maxResponseBodyBytes ?? DEFAULT_MAX_BUFFERED_BODY_BYTES;
329
376
  const rawMax = config?.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS;
330
377
  this.retryMaxAttempts = Math.min(Math.max(1, rawMax), MAX_RETRY_ATTEMPTS_CAP);
331
378
  this.verbose = config?.verbose === true;
@@ -344,6 +391,13 @@ export class DataikuClient {
344
391
  getRequestTimeoutMs() {
345
392
  return this.requestTimeoutMs;
346
393
  }
394
+ /**
395
+ * The configured maximum number of bytes buffered from a single response
396
+ * body by the text/JSON consumer methods (default 50 MiB).
397
+ */
398
+ getMaxResponseBodyBytes() {
399
+ return this.maxResponseBodyBytes;
400
+ }
347
401
  /* ---- public: project key resolution ---- */
348
402
  resolveProjectKey(paramValue) {
349
403
  const pk = paramValue?.trim();
@@ -374,56 +428,50 @@ export class DataikuClient {
374
428
  const data = await this.parseJsonResponse(res);
375
429
  return { data, meta: this.responseMeta(res.headers), };
376
430
  }
431
+ /**
432
+ * GET returning the entire text body. The body is buffered with a hard
433
+ * byte cap (`maxResponseBodyBytes`, default 50 MiB) and read under the
434
+ * request deadline: a response exceeding the cap throws a DataikuError
435
+ * instead of being silently truncated, and a stalled body times out.
436
+ */
377
437
  async getText(path) {
378
438
  const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
379
439
  method: "GET",
380
440
  headers: this.getAnyHeaders(),
381
441
  });
382
- return res.text();
442
+ const { text, truncated, } = await this.readBoundedBodyText(res, this.maxResponseBodyBytes);
443
+ if (truncated)
444
+ throw this.buildResponseTooLargeError(res, this.maxResponseBodyBytes);
445
+ return text;
383
446
  }
447
+ /**
448
+ * GET returning at most the first `maxBytes` bytes of a text body.
449
+ * When the response exceeds the cap the stream is cancelled, only the
450
+ * collected prefix is returned and `truncated` is true. The read runs
451
+ * under the request deadline: a stalled body throws a DataikuError.
452
+ */
384
453
  async getTextLimited(path, maxBytes) {
385
454
  const limit = Math.max(0, Math.floor(maxBytes));
386
455
  const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
387
456
  method: "GET",
388
457
  headers: this.getAnyHeaders(),
389
458
  });
390
- if (!res.body)
391
- return { text: "", truncated: false, };
392
- const reader = res.body.getReader();
393
- const chunks = [];
394
- let bytesRead = 0;
395
- let truncated = false;
396
- try {
397
- while (bytesRead < limit) {
398
- const { done, value, } = await reader.read();
399
- if (done)
400
- break;
401
- const room = limit - bytesRead;
402
- if (value.byteLength > room) {
403
- chunks.push(value.slice(0, room));
404
- bytesRead += room;
405
- truncated = true;
406
- break;
407
- }
408
- chunks.push(value);
409
- bytesRead += value.byteLength;
410
- }
411
- if (!truncated && bytesRead >= limit) {
412
- // Buffer filled exactly on a chunk boundary; peek whether more data remains.
413
- const { done, } = await reader.read();
414
- if (!done)
415
- truncated = true;
416
- }
417
- }
418
- finally {
419
- await reader.cancel();
420
- }
421
- const collected = concatBytes(chunks, bytesRead);
422
- // On truncation, drop any trailing partial UTF-8 character so the decoded
423
- // text never re-encodes beyond the byte cap (a stream-flush would otherwise
424
- // emit a 3-byte replacement char for a split multibyte sequence).
425
- const usable = truncated ? trimToUtf8Boundary(collected) : collected;
426
- return { text: new TextDecoder().decode(usable), truncated, };
459
+ return this.readBoundedBodyText(res, limit);
460
+ }
461
+ /**
462
+ * GET returning at most the last `maxBytes` bytes of a text body.
463
+ * When the response exceeds the cap, earlier bytes are discarded, only
464
+ * the tail is kept and `truncated` is true — so callers that need the end
465
+ * of a large document (e.g. job logs) stay bounded without losing the most
466
+ * recent content. The read runs under the request deadline.
467
+ */
468
+ async getTextTailLimited(path, maxBytes) {
469
+ const limit = Math.max(0, Math.floor(maxBytes));
470
+ const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
471
+ method: "GET",
472
+ headers: this.getAnyHeaders(),
473
+ });
474
+ return this.readBodyTextTail(res, limit);
427
475
  }
428
476
  /**
429
477
  * POST with optional transient retry. Only opt in when repeating the request
@@ -442,13 +490,20 @@ export class DataikuClient {
442
490
  }, retryMaxAttempts);
443
491
  return this.parseJsonResponse(res);
444
492
  }
493
+ /**
494
+ * POST returning the text body, under the same bounded buffering rules as
495
+ * {@link getText} (byte cap `maxResponseBodyBytes`, request deadline).
496
+ */
445
497
  async postText(path, body) {
446
498
  const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
447
499
  method: "POST",
448
500
  headers: this.getHeaders(),
449
501
  body: body !== undefined ? JSON.stringify(body) : undefined,
450
502
  });
451
- return res.text();
503
+ const { text, truncated, } = await this.readBoundedBodyText(res, this.maxResponseBodyBytes);
504
+ if (truncated)
505
+ throw this.buildResponseTooLargeError(res, this.maxResponseBodyBytes);
506
+ return text;
452
507
  }
453
508
  async postStream(path, body) {
454
509
  return this.fetchWithRetry(`${this.baseUrl}${path}`, {
@@ -571,7 +626,9 @@ export class DataikuClient {
571
626
  return undefined;
572
627
  }
573
628
  async parseJsonResponse(res) {
574
- const text = await res.text();
629
+ const { text, truncated, } = await this.readBoundedBodyText(res, this.maxResponseBodyBytes);
630
+ if (truncated)
631
+ throw this.buildResponseTooLargeError(res, this.maxResponseBodyBytes);
575
632
  // SAFETY: Empty 2xx responses from DSS are surfaced to callers as undefined
576
633
  // cast to T. This keeps existing call sites stable, but callers that rely on
577
634
  // an object shape must guard explicitly before dereferencing the result.
@@ -582,9 +639,147 @@ export class DataikuClient {
582
639
  }
583
640
  catch {
584
641
  const summary = text.length > 300 ? `${text.slice(0, 300)}…` : text;
585
- throw new DataikuError(res.status, res.statusText || "Invalid JSON response", `Expected JSON response body but got non-JSON content: ${summary}`, undefined, this.requestIdFromHeaders(res.headers));
642
+ throw new DataikuError(res.status, res.statusText || "Invalid JSON response", `${NON_JSON_RESPONSE_MARKER}: ${summary}`, undefined, this.requestIdFromHeaders(res.headers));
586
643
  }
587
644
  }
645
+ /* ---- private: bounded response body reading ---- */
646
+ /**
647
+ * Read at most `maxBytes` of a 2xx response body as UTF-8 text.
648
+ *
649
+ * The body is consumed with the request deadline still active (measured
650
+ * from the first read): a stalled body throws a DataikuError instead of
651
+ * hanging. When the stream yields more than the cap, the reader cancels the
652
+ * body and returns the collected prefix with `truncated: true`; truncated
653
+ * text is trimmed to a UTF-8 character boundary so it never decodes beyond
654
+ * the byte cap.
655
+ */
656
+ async readBoundedBodyText(res, maxBytes) {
657
+ const limit = Math.max(0, Math.floor(maxBytes));
658
+ if (!res.body)
659
+ return { text: "", truncated: false, };
660
+ const reader = res.body.getReader();
661
+ const chunks = [];
662
+ let bytesRead = 0;
663
+ let truncated = false;
664
+ const startedAt = Date.now();
665
+ try {
666
+ while (bytesRead < limit) {
667
+ const remainingMs = this.requestTimeoutMs - (Date.now() - startedAt);
668
+ if (remainingMs <= 0)
669
+ throw buildBodyReadTimeoutError(this.requestTimeoutMs);
670
+ const { done, value, } = await readChunkWithDeadline(reader, remainingMs, this.requestTimeoutMs);
671
+ if (done)
672
+ break;
673
+ const room = limit - bytesRead;
674
+ if (value.byteLength > room) {
675
+ chunks.push(value.slice(0, room));
676
+ bytesRead += room;
677
+ truncated = true;
678
+ break;
679
+ }
680
+ chunks.push(value);
681
+ bytesRead += value.byteLength;
682
+ }
683
+ if (!truncated && bytesRead >= limit) {
684
+ // Buffer filled exactly on a chunk boundary; peek whether more data remains.
685
+ const remainingMs = this.requestTimeoutMs - (Date.now() - startedAt);
686
+ if (remainingMs <= 0)
687
+ throw buildBodyReadTimeoutError(this.requestTimeoutMs);
688
+ const { done, } = await readChunkWithDeadline(reader, remainingMs, this.requestTimeoutMs);
689
+ if (!done)
690
+ truncated = true;
691
+ }
692
+ }
693
+ finally {
694
+ void reader.cancel().catch(() => { });
695
+ }
696
+ const collected = concatBytes(chunks, bytesRead);
697
+ // On truncation, drop any trailing partial UTF-8 character so the decoded
698
+ // text never re-encodes beyond the byte cap (a stream-flush would otherwise
699
+ // emit a 3-byte replacement char for a split multibyte sequence).
700
+ const usable = truncated ? trimToUtf8Boundary(collected) : collected;
701
+ return { text: new TextDecoder().decode(usable), truncated, };
702
+ }
703
+ /**
704
+ * Read a 2xx response body keeping only the last `maxBytes` bytes.
705
+ * Earlier bytes are discarded as the stream advances, so memory stays
706
+ * bounded by the cap plus one chunk even for arbitrarily large bodies.
707
+ * Returns `truncated: true` when bytes had to be dropped. Bytes that fall
708
+ * in the middle of a UTF-8 character are dropped from both ends so the
709
+ * decoded text never contains a replacement character.
710
+ */
711
+ async readBodyTextTail(res, maxBytes) {
712
+ const limit = Math.max(0, Math.floor(maxBytes));
713
+ if (!res.body)
714
+ return { text: "", truncated: false, };
715
+ const reader = res.body.getReader();
716
+ const ring = new Uint8Array(limit);
717
+ let writeOffset = 0;
718
+ let retainedBytes = 0;
719
+ let truncated = false;
720
+ const startedAt = Date.now();
721
+ try {
722
+ while (true) {
723
+ const remainingMs = this.requestTimeoutMs - (Date.now() - startedAt);
724
+ if (remainingMs <= 0)
725
+ throw buildBodyReadTimeoutError(this.requestTimeoutMs);
726
+ const { done, value, } = await readChunkWithDeadline(reader, remainingMs, this.requestTimeoutMs);
727
+ if (done)
728
+ break;
729
+ if (limit === 0) {
730
+ truncated = value.byteLength > 0;
731
+ if (truncated)
732
+ break;
733
+ continue;
734
+ }
735
+ if (value.byteLength >= limit) {
736
+ ring.set(value.subarray(value.byteLength - limit));
737
+ truncated = truncated || retainedBytes > 0 || value.byteLength > limit;
738
+ retainedBytes = limit;
739
+ writeOffset = 0;
740
+ continue;
741
+ }
742
+ const firstLength = Math.min(value.byteLength, limit - writeOffset);
743
+ ring.set(value.subarray(0, firstLength), writeOffset);
744
+ const remainingLength = value.byteLength - firstLength;
745
+ if (remainingLength > 0) {
746
+ ring.set(value.subarray(firstLength));
747
+ }
748
+ writeOffset = (writeOffset + value.byteLength) % limit;
749
+ truncated = truncated || retainedBytes + value.byteLength > limit;
750
+ retainedBytes = Math.min(limit, retainedBytes + value.byteLength);
751
+ }
752
+ }
753
+ finally {
754
+ void reader.cancel().catch(() => { });
755
+ }
756
+ let collected;
757
+ if (retainedBytes === 0) {
758
+ collected = new Uint8Array(0);
759
+ }
760
+ else if (retainedBytes < limit) {
761
+ collected = ring.slice(0, retainedBytes);
762
+ }
763
+ else if (writeOffset === 0) {
764
+ collected = ring;
765
+ }
766
+ else {
767
+ collected = new Uint8Array(retainedBytes);
768
+ const suffixLength = limit - writeOffset;
769
+ collected.set(ring.subarray(writeOffset));
770
+ collected.set(ring.subarray(0, writeOffset), suffixLength);
771
+ }
772
+ // A byte cut inside a multi-byte sequence can leave continuation bytes at
773
+ // the start (and possibly the end) of the tail; drop both so the decoded
774
+ // text never starts or ends with a U+FFFD replacement character.
775
+ const usable = truncated
776
+ ? trimToUtf8Boundary(trimFromUtf8BoundaryStart(collected))
777
+ : collected;
778
+ return { text: new TextDecoder().decode(usable), truncated, };
779
+ }
780
+ buildResponseTooLargeError(res, limit) {
781
+ return new DataikuError(res.status, RESPONSE_TOO_LARGE_STATUS_TEXT, `Response body exceeded the ${limit}-byte limit; the body was cancelled after ${limit} bytes.`, undefined, this.requestIdFromHeaders(res.headers));
782
+ }
588
783
  /* ---- private: retry loop ---- */
589
784
  async fetchWithRetry(url, init, retryMaxAttempts) {
590
785
  const method = (init.method ?? "GET").toUpperCase();
@@ -1,5 +1,5 @@
1
- export type DataikuErrorCategory = "not_found" | "forbidden" | "validation" | "transient" | "unknown";
2
- export type StableErrorCode = "usage_error" | "unknown_flag" | "missing_required_arg" | "missing_required_flag" | "invalid_flag_value" | "conflicting_input_sources" | "invalid_enum" | "not_found" | "permission_denied" | "target_absence_unverifiable" | "validation_failed" | "transient" | "long_running_failure" | "command_result_failure" | "assertion_failed" | "ambiguous_outcome" | "internal_error";
1
+ export type DataikuErrorCategory = "not_found" | "forbidden" | "validation" | "transient" | "unexpected_response" | "unknown";
2
+ export type StableErrorCode = "usage_error" | "unknown_flag" | "missing_required_arg" | "missing_required_flag" | "invalid_flag_value" | "conflicting_input_sources" | "invalid_enum" | "not_found" | "permission_denied" | "target_absence_unverifiable" | "validation_failed" | "transient" | "long_running_failure" | "command_result_failure" | "assertion_failed" | "ambiguous_outcome" | "unexpected_response" | "internal_error";
3
3
  export declare function dataikuErrorCode(category: DataikuErrorCategory): StableErrorCode;
4
4
  export interface DataikuErrorTaxonomy {
5
5
  category: DataikuErrorCategory;
@@ -26,6 +26,12 @@ export declare class ClientValidationError extends Error {
26
26
  readonly details?: Record<string, unknown>;
27
27
  constructor(message: string, code?: StableErrorCode, hint?: string, details?: Record<string, unknown>);
28
28
  }
29
+ /**
30
+ * Message prefix the client stamps on a 2xx body that is not JSON. The
31
+ * classifier recognizes exactly this prefix, so the parse-failure path and the
32
+ * taxonomy stay in sync as one contract.
33
+ */
34
+ export declare const NON_JSON_RESPONSE_MARKER = "Expected JSON response body but got non-JSON content";
29
35
  export declare function classifyDataikuError(status: number, body: string): DataikuErrorTaxonomy;
30
36
  export declare class DataikuError extends Error {
31
37
  status: number;
@@ -8,6 +8,8 @@ export function dataikuErrorCode(category) {
8
8
  return "validation_failed";
9
9
  case "transient":
10
10
  return "transient";
11
+ case "unexpected_response":
12
+ return "unexpected_response";
11
13
  case "unknown":
12
14
  return "internal_error";
13
15
  }
@@ -17,11 +19,21 @@ const CANONICAL_STATUS_TEXT = {
17
19
  401: "Unauthorized",
18
20
  403: "Forbidden",
19
21
  404: "Not Found",
22
+ 405: "Method Not Allowed",
23
+ 406: "Not Acceptable",
20
24
  408: "Request Timeout",
21
25
  409: "Conflict",
26
+ 410: "Gone",
27
+ 412: "Precondition Failed",
28
+ 413: "Payload Too Large",
29
+ 415: "Unsupported Media Type",
30
+ 416: "Range Not Satisfiable",
31
+ 418: "I'm a Teapot",
22
32
  422: "Unprocessable Entity",
23
33
  425: "Too Early",
34
+ 426: "Upgrade Required",
24
35
  429: "Too Many Requests",
36
+ 451: "Unavailable For Legal Reasons",
25
37
  500: "Internal Server Error",
26
38
  501: "Not Implemented",
27
39
  502: "Bad Gateway",
@@ -43,6 +55,12 @@ export class ClientValidationError extends Error {
43
55
  this.details = details;
44
56
  }
45
57
  }
58
+ /**
59
+ * Message prefix the client stamps on a 2xx body that is not JSON. The
60
+ * classifier recognizes exactly this prefix, so the parse-failure path and the
61
+ * taxonomy stay in sync as one contract.
62
+ */
63
+ export const NON_JSON_RESPONSE_MARKER = "Expected JSON response body but got non-JSON content";
46
64
  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.";
47
65
  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.";
48
66
  const MAX_ERROR_SUMMARY_LENGTH = 200;
@@ -141,6 +159,18 @@ export function classifyDataikuError(status, body) {
141
159
  retryHint: "Network/transport failure. Retry with backoff and verify DSS URL reachability.",
142
160
  };
143
161
  }
162
+ // A 2xx response carrying a non-JSON body is a response-contract violation,
163
+ // not a transport fault: HTTP succeeded, but an intermediary (proxy, SSO or
164
+ // login page, HTML gateway) answered in place of the DSS API. Only the client's
165
+ // own parse-failure marker produces this prefix.
166
+ if (status >= 200 && status < 300
167
+ && lowerBody.startsWith(NON_JSON_RESPONSE_MARKER.toLowerCase())) {
168
+ return {
169
+ category: "unexpected_response",
170
+ retryable: false,
171
+ 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.",
172
+ };
173
+ }
144
174
  const isSqlInputConnectionMismatch = (status === 400 || status >= 500)
145
175
  && lowerBody.includes("s3 dataset")
146
176
  && lowerBody.includes("athena connection");
@@ -280,6 +310,16 @@ export function classifyDataikuError(status, body) {
280
310
  retryHint: "Retry with exponential backoff. If it persists, check DSS availability and upstream proxies.",
281
311
  };
282
312
  }
313
+ // Any remaining HTTP error status is an API-contract mismatch: the endpoint,
314
+ // resource, or DSS feature/version does not support this request. It is
315
+ // non-retryable — retrying unchanged cannot succeed.
316
+ if (status >= 400) {
317
+ return {
318
+ category: "unexpected_response",
319
+ retryable: false,
320
+ retryHint: "The DSS API rejected the request with an unrecognized HTTP status. Verify the endpoint, resource, and DSS feature/version availability; do not retry unchanged.",
321
+ };
322
+ }
283
323
  return {
284
324
  category: "unknown",
285
325
  retryable: false,
@@ -18,7 +18,7 @@ export { type FlowZoneItemInput, FlowZonesResource, } from "./resources/flow-zon
18
18
  export { FoldersResource, } from "./resources/folders.js";
19
19
  export { FuturesResource, } from "./resources/futures.js";
20
20
  export { InsightsResource, } from "./resources/insights.js";
21
- export { computeNextPollDelayMs, type JobBuildAndWaitOptions, type JobBuildOptions, type JobBuildTarget, type JobBuildTargetType, type JobLogFilter, type JobLogProgress, type JobLogSummary, JobsResource, parseJobLogProgress, } from "./resources/jobs.js";
21
+ export { computeNextPollDelayMs, type JobBuildAndWaitOptions, type JobBuildOptions, type JobBuildTarget, type JobBuildTargetType, type JobLogFilter, type JobLogProgress, type JobLogSummary, type JobLogUnavailableReason, JobsResource, type JobWaitOutcome, parseJobLogProgress, } from "./resources/jobs.js";
22
22
  export { MeaningsResource, } from "./resources/meanings.js";
23
23
  export { MetricsResource, } from "./resources/metrics.js";
24
24
  export * from "./resources/ml-tasks.js";
@@ -37,10 +37,11 @@ export { VariablesResource, } from "./resources/variables.js";
37
37
  export { WebappsResource, } from "./resources/webapps.js";
38
38
  export { WikiResource, } from "./resources/wiki.js";
39
39
  export { WorkspacesResource, } from "./resources/workspaces.js";
40
- export { BuildModeSchema, CodeEnvActionResultSchema, CodeEnvCreateOptionsSchema, CodeEnvDetailsSchema, CodeEnvPackageListSchema, CodeEnvSetPackagesOptionsSchema, CodeEnvSummaryArraySchema, CodeEnvSummarySchema, CodeEnvUpdatePackagesOptionsSchema, CodeEnvUsageArraySchema, CodeEnvWaitOptionsSchema, ConnectionSummarySchema, DashboardDetailsSchema, DashboardSummaryArraySchema, DashboardSummarySchema, DataQualityComputeResultSchema, DataQualityProjectStatusSchema, DataQualityRuleArraySchema, DataQualityRuleResultArraySchema, DataQualityRuleResultSchema, DataQualityRuleSchema, DataQualityRulesSchema, DataQualityStatusByPartitionSchema, DataQualityStatusSchema, DataQualityTimelineEntrySchema, DataQualityTimelineSchema, DatasetCreateOptionsSchema, DatasetDetailsSchema, DatasetSchemaSchema, DatasetSummaryArraySchema, DatasetSummarySchema, FlowMapOptionsSchema, FlowZoneArraySchema, FlowZoneCreateOptionsSchema, FlowZoneItemSchema, FlowZoneObjectTypeSchema, FlowZonePositionSchema, FlowZoneSchema, FlowZoneUpdateOptionsSchema, FolderCreateOptionsSchema, FolderDetailsSchema, FolderItemArraySchema, FolderItemSchema, FolderSummaryArraySchema, FolderSummarySchema, FutureStateSchema, FutureWaitResultSchema, InsightDetailsSchema, InsightSummaryArraySchema, InsightSummarySchema, JobSummaryArraySchema, JobSummarySchema, JobWaitResultSchema, JupyterCellSchema, JupyterNotebookContentSchema, JupyterNotebookSummaryArraySchema, JupyterNotebookSummarySchema, NotebookSessionArraySchema, NotebookSessionSchema, parseSchema, ProjectDetailsSchema, ProjectGitActionResultSchema, ProjectGitDiffResultSchema, ProjectGitFutureResponseSchema, ProjectGitFutureStateSchema, ProjectGitLibrariesSchema, ProjectGitLibrarySchema, ProjectGitLogResultSchema, ProjectGitRemoteSchema, ProjectGitStatusSchema, ProjectGitTagSchema, ProjectGitTagsSchema, ProjectMetadataSchema, ProjectSummaryArraySchema, ProjectSummarySchema, ProjectVariablesSchema, RecipeCreateOptionsSchema, RecipeCreateResultSchema, RecipeDetailsSchema, RecipeSummaryArraySchema, RecipeSummarySchema, safeParseSchema, ScenarioDetailsSchema, ScenarioStatusSchema, ScenarioStepRunSchema, ScenarioSummaryArraySchema, ScenarioSummarySchema, ScenarioWaitResultSchema, SqlNotebookCellSchema, SqlNotebookContentSchema, SqlNotebookSummaryArraySchema, SqlNotebookSummarySchema, SqlQueryResponseSchema, SqlQueryResultSchema, SqlQuerySchemaSchema, WikiArticleDataArraySchema, WikiArticleDataSchema, WikiArticleMetadataSchema, WikiSettingsSchema, WikiTaxonomyNodeSchema, } from "./schemas.js";
40
+ export { BuildModeSchema, CodeEnvActionResultSchema, CodeEnvCreateOptionsSchema, CodeEnvDetailsSchema, CodeEnvGetLogOptionsSchema, CodeEnvLogResultSchema, CodeEnvLogSummaryArraySchema, CodeEnvLogSummarySchema, CodeEnvPackageListSchema, CodeEnvSetPackagesOptionsSchema, CodeEnvSummaryArraySchema, CodeEnvSummarySchema, CodeEnvUpdateImagesOptionsSchema, CodeEnvUpdatePackagesOptionsSchema, CodeEnvUsageArraySchema, CodeEnvVersionForProjectSchema, CodeEnvWaitOptionsSchema, ConnectionSummarySchema, DashboardDetailsSchema, DashboardSummaryArraySchema, DashboardSummarySchema, DataQualityComputeResultSchema, DataQualityProjectStatusSchema, DataQualityRuleArraySchema, DataQualityRuleResultArraySchema, DataQualityRuleResultSchema, DataQualityRuleSchema, DataQualityRulesSchema, DataQualityStatusByPartitionSchema, DataQualityStatusSchema, DataQualityTimelineEntrySchema, DataQualityTimelineSchema, DatasetCreateOptionsSchema, DatasetDetailsSchema, DatasetSchemaSchema, DatasetSummaryArraySchema, DatasetSummarySchema, FlowMapOptionsSchema, FlowZoneArraySchema, FlowZoneCreateOptionsSchema, FlowZoneItemSchema, FlowZoneObjectTypeSchema, FlowZonePositionSchema, FlowZoneSchema, FlowZoneUpdateOptionsSchema, FolderCreateOptionsSchema, FolderDetailsSchema, FolderItemArraySchema, FolderItemSchema, FolderSummaryArraySchema, FolderSummarySchema, FutureStateSchema, FutureWaitResultSchema, InsightDetailsSchema, InsightSummaryArraySchema, InsightSummarySchema, JobSummaryArraySchema, JobSummarySchema, JobWaitResultSchema, JupyterCellSchema, JupyterNotebookContentSchema, JupyterNotebookSummaryArraySchema, JupyterNotebookSummarySchema, NotebookSessionArraySchema, NotebookSessionSchema, parseSchema, ProjectDetailsSchema, ProjectGitActionResultSchema, ProjectGitDiffResultSchema, ProjectGitFutureResponseSchema, ProjectGitFutureStateSchema, ProjectGitLibrariesSchema, ProjectGitLibrarySchema, ProjectGitLogResultSchema, ProjectGitRemoteSchema, ProjectGitStatusSchema, ProjectGitTagSchema, ProjectGitTagsSchema, ProjectMetadataSchema, ProjectSummaryArraySchema, ProjectSummarySchema, ProjectVariablesSchema, RecipeCreateOptionsSchema, RecipeCreateResultSchema, RecipeDetailsSchema, RecipeSummaryArraySchema, RecipeSummarySchema, safeParseSchema, ScenarioDetailsSchema, ScenarioStatusSchema, ScenarioStepRunSchema, ScenarioSummaryArraySchema, ScenarioSummarySchema, ScenarioWaitResultSchema, SqlNotebookCellSchema, SqlNotebookContentSchema, SqlNotebookHistorySchema, SqlNotebookSummaryArraySchema, SqlNotebookSummarySchema, SqlQueryResponseSchema, SqlQueryResultSchema, SqlQuerySchemaSchema, WikiArticleDataArraySchema, WikiArticleDataSchema, WikiArticleMetadataSchema, WikiSettingsSchema, WikiTaxonomyNodeSchema, } from "./schemas.js";
41
41
  export type { SafeParseResult, } from "./schemas.js";
42
- export type { BuildMode, CodeEnvActionResult, CodeEnvCreateOptions, CodeEnvDetails, CodeEnvPackageList, CodeEnvSetPackagesOptions, CodeEnvSummary, CodeEnvUpdatePackagesOptions, CodeEnvUsage, 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, NotebookSession, ProjectDetails, ProjectGitActionResult, ProjectGitDiffResult, ProjectGitFutureResponse, ProjectGitFutureState, ProjectGitLibraries, ProjectGitLibrary, ProjectGitLogResult, ProjectGitRemote, ProjectGitStatus, ProjectGitTag, ProjectGitTags, ProjectMetadata, ProjectSummary, ProjectVariables, RecipeCreateOptions, RecipeCreateResult, RecipeDetails, RecipeSummary, ScenarioDetails, ScenarioStatus, ScenarioStepRun, ScenarioSummary, ScenarioWaitResult, SqlNotebookCell, SqlNotebookContent, SqlNotebookSummary, SqlQueryResponse, SqlQueryResult, SqlQuerySchema, WikiArticleData, WikiArticleMetadata, WikiSettings, WikiTaxonomyNode, } from "./schemas.js";
42
+ 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, NotebookSession, ProjectDetails, ProjectGitActionResult, ProjectGitDiffResult, ProjectGitFutureResponse, ProjectGitFutureState, ProjectGitLibraries, ProjectGitLibrary, ProjectGitLogResult, ProjectGitRemote, ProjectGitStatus, ProjectGitTag, ProjectGitTags, ProjectMetadata, ProjectSummary, ProjectVariables, RecipeCreateOptions, RecipeCreateResult, RecipeDetails, RecipeSummary, ScenarioDetails, ScenarioStatus, ScenarioStepRun, ScenarioSummary, ScenarioWaitResult, SqlNotebookCell, SqlNotebookContent, SqlNotebookSummary, SqlQueryResponse, SqlQueryResult, SqlQuerySchema, WikiArticleData, WikiArticleMetadata, WikiSettings, WikiTaxonomyNode, } from "./schemas.js";
43
43
  export { deepMerge, } from "./utils/deep-merge.js";
44
+ export { type AnalyzedFlowMap, type AnalyzedFlowNode, analyzeFlowMap, type FlowMapComponent, type FlowMapDiagnostic, type FlowMapRendering, type FlowMapZone, type FlowRenderFormat, flowTopologyFingerprint, renderFlowMap, } from "./utils/flow-analysis.js";
44
45
  export { type NormalizedFlowEdge, type NormalizedFlowMap, type NormalizedFlowNode, normalizeFlowGraph, } from "./utils/flow-map.js";
45
46
  export * from "./utils/project-archive.js";
46
47
  export { sanitizeFileName, } from "./utils/sanitize.js";
package/dist/src/index.js CHANGED
@@ -42,9 +42,10 @@ export { WebappsResource, } from "./resources/webapps.js";
42
42
  export { WikiResource, } from "./resources/wiki.js";
43
43
  export { WorkspacesResource, } from "./resources/workspaces.js";
44
44
  // Schemas (TypeBox schema objects for runtime validation)
45
- export { BuildModeSchema, CodeEnvActionResultSchema, CodeEnvCreateOptionsSchema, CodeEnvDetailsSchema, CodeEnvPackageListSchema, CodeEnvSetPackagesOptionsSchema, CodeEnvSummaryArraySchema, CodeEnvSummarySchema, CodeEnvUpdatePackagesOptionsSchema, CodeEnvUsageArraySchema, CodeEnvWaitOptionsSchema, ConnectionSummarySchema, DashboardDetailsSchema, DashboardSummaryArraySchema, DashboardSummarySchema, DataQualityComputeResultSchema, DataQualityProjectStatusSchema, DataQualityRuleArraySchema, DataQualityRuleResultArraySchema, DataQualityRuleResultSchema, DataQualityRuleSchema, DataQualityRulesSchema, DataQualityStatusByPartitionSchema, DataQualityStatusSchema, DataQualityTimelineEntrySchema, DataQualityTimelineSchema, DatasetCreateOptionsSchema, DatasetDetailsSchema, DatasetSchemaSchema, DatasetSummaryArraySchema, DatasetSummarySchema, FlowMapOptionsSchema, FlowZoneArraySchema, FlowZoneCreateOptionsSchema, FlowZoneItemSchema, FlowZoneObjectTypeSchema, FlowZonePositionSchema, FlowZoneSchema, FlowZoneUpdateOptionsSchema, FolderCreateOptionsSchema, FolderDetailsSchema, FolderItemArraySchema, FolderItemSchema, FolderSummaryArraySchema, FolderSummarySchema, FutureStateSchema, FutureWaitResultSchema, InsightDetailsSchema, InsightSummaryArraySchema, InsightSummarySchema, JobSummaryArraySchema, JobSummarySchema, JobWaitResultSchema, JupyterCellSchema, JupyterNotebookContentSchema, JupyterNotebookSummaryArraySchema, JupyterNotebookSummarySchema, NotebookSessionArraySchema, NotebookSessionSchema, parseSchema, ProjectDetailsSchema, ProjectGitActionResultSchema, ProjectGitDiffResultSchema, ProjectGitFutureResponseSchema, ProjectGitFutureStateSchema, ProjectGitLibrariesSchema, ProjectGitLibrarySchema, ProjectGitLogResultSchema, ProjectGitRemoteSchema, ProjectGitStatusSchema, ProjectGitTagSchema, ProjectGitTagsSchema, ProjectMetadataSchema, ProjectSummaryArraySchema, ProjectSummarySchema, ProjectVariablesSchema, RecipeCreateOptionsSchema, RecipeCreateResultSchema, RecipeDetailsSchema, RecipeSummaryArraySchema, RecipeSummarySchema, safeParseSchema, ScenarioDetailsSchema, ScenarioStatusSchema, ScenarioStepRunSchema, ScenarioSummaryArraySchema, ScenarioSummarySchema, ScenarioWaitResultSchema, SqlNotebookCellSchema, SqlNotebookContentSchema, SqlNotebookSummaryArraySchema, SqlNotebookSummarySchema, SqlQueryResponseSchema, SqlQueryResultSchema, SqlQuerySchemaSchema, WikiArticleDataArraySchema, WikiArticleDataSchema, WikiArticleMetadataSchema, WikiSettingsSchema, WikiTaxonomyNodeSchema, } from "./schemas.js";
45
+ export { BuildModeSchema, CodeEnvActionResultSchema, CodeEnvCreateOptionsSchema, CodeEnvDetailsSchema, CodeEnvGetLogOptionsSchema, CodeEnvLogResultSchema, CodeEnvLogSummaryArraySchema, CodeEnvLogSummarySchema, CodeEnvPackageListSchema, CodeEnvSetPackagesOptionsSchema, CodeEnvSummaryArraySchema, CodeEnvSummarySchema, CodeEnvUpdateImagesOptionsSchema, CodeEnvUpdatePackagesOptionsSchema, CodeEnvUsageArraySchema, CodeEnvVersionForProjectSchema, CodeEnvWaitOptionsSchema, ConnectionSummarySchema, DashboardDetailsSchema, DashboardSummaryArraySchema, DashboardSummarySchema, DataQualityComputeResultSchema, DataQualityProjectStatusSchema, DataQualityRuleArraySchema, DataQualityRuleResultArraySchema, DataQualityRuleResultSchema, DataQualityRuleSchema, DataQualityRulesSchema, DataQualityStatusByPartitionSchema, DataQualityStatusSchema, DataQualityTimelineEntrySchema, DataQualityTimelineSchema, DatasetCreateOptionsSchema, DatasetDetailsSchema, DatasetSchemaSchema, DatasetSummaryArraySchema, DatasetSummarySchema, FlowMapOptionsSchema, FlowZoneArraySchema, FlowZoneCreateOptionsSchema, FlowZoneItemSchema, FlowZoneObjectTypeSchema, FlowZonePositionSchema, FlowZoneSchema, FlowZoneUpdateOptionsSchema, FolderCreateOptionsSchema, FolderDetailsSchema, FolderItemArraySchema, FolderItemSchema, FolderSummaryArraySchema, FolderSummarySchema, FutureStateSchema, FutureWaitResultSchema, InsightDetailsSchema, InsightSummaryArraySchema, InsightSummarySchema, JobSummaryArraySchema, JobSummarySchema, JobWaitResultSchema, JupyterCellSchema, JupyterNotebookContentSchema, JupyterNotebookSummaryArraySchema, JupyterNotebookSummarySchema, NotebookSessionArraySchema, NotebookSessionSchema, parseSchema, ProjectDetailsSchema, ProjectGitActionResultSchema, ProjectGitDiffResultSchema, ProjectGitFutureResponseSchema, ProjectGitFutureStateSchema, ProjectGitLibrariesSchema, ProjectGitLibrarySchema, ProjectGitLogResultSchema, ProjectGitRemoteSchema, ProjectGitStatusSchema, ProjectGitTagSchema, ProjectGitTagsSchema, ProjectMetadataSchema, ProjectSummaryArraySchema, ProjectSummarySchema, ProjectVariablesSchema, RecipeCreateOptionsSchema, RecipeCreateResultSchema, RecipeDetailsSchema, RecipeSummaryArraySchema, RecipeSummarySchema, safeParseSchema, ScenarioDetailsSchema, ScenarioStatusSchema, ScenarioStepRunSchema, ScenarioSummaryArraySchema, ScenarioSummarySchema, ScenarioWaitResultSchema, SqlNotebookCellSchema, SqlNotebookContentSchema, SqlNotebookHistorySchema, SqlNotebookSummaryArraySchema, SqlNotebookSummarySchema, SqlQueryResponseSchema, SqlQueryResultSchema, SqlQuerySchemaSchema, WikiArticleDataArraySchema, WikiArticleDataSchema, WikiArticleMetadataSchema, WikiSettingsSchema, WikiTaxonomyNodeSchema, } from "./schemas.js";
46
46
  // Utilities
47
47
  export { deepMerge, } from "./utils/deep-merge.js";
48
+ export { analyzeFlowMap, flowTopologyFingerprint, renderFlowMap, } from "./utils/flow-analysis.js";
48
49
  export { normalizeFlowGraph, } from "./utils/flow-map.js";
49
50
  export * from "./utils/project-archive.js";
50
51
  export { sanitizeFileName, } from "./utils/sanitize.js";
@@ -9,6 +9,32 @@ export interface ApiServicePackageListItem extends Record<string, unknown> {
9
9
  packageId?: string;
10
10
  serviceId?: string;
11
11
  }
12
+ /**
13
+ * 64-hex SHA-256 hash of the service settings as last fetched, used as a
14
+ * non-atomic stale-read guard: the write is refused when the settings already
15
+ * differ at the verification read. DSS exposes no conditional write, so a
16
+ * writer committing between that read and the PUT is still not detected.
17
+ */
18
+ export interface ApiServiceSaveOptions {
19
+ expectHash?: string;
20
+ }
21
+ /** Optional, documented parameters of the package-generation endpoint. */
22
+ export interface ApiServiceCreatePackageOptions {
23
+ releaseNotes?: string;
24
+ }
25
+ /**
26
+ * Optional, documented parameter of the package-publish endpoint: the id of
27
+ * the published service on the API Deployer where the package is deployed
28
+ * (defaults to the service's own id server-side).
29
+ */
30
+ export interface ApiServicePublishOptions {
31
+ publishedServiceId?: string;
32
+ }
33
+ export interface ApiServicePackageListItem extends Record<string, unknown> {
34
+ id?: string;
35
+ packageId?: string;
36
+ serviceId?: string;
37
+ }
12
38
  export type ApiServiceActionResult = Record<string, unknown> | undefined;
13
39
  export declare class ApiServicesResource extends BaseResource {
14
40
  /** List API services in a project. */
@@ -17,24 +43,40 @@ export declare class ApiServicesResource extends BaseResource {
17
43
  create(serviceId: string, projectKey?: string): Promise<ApiServiceActionResult>;
18
44
  /** Get API service settings, including endpoint definitions. */
19
45
  getSettings(serviceId: string, projectKey?: string): Promise<Record<string, unknown>>;
20
- /** Save API service settings. */
21
- saveSettings(serviceId: string, body: Record<string, unknown>, projectKey?: string): Promise<ApiServiceActionResult>;
46
+ /**
47
+ * Save API service settings with explicit replacement semantics: the body
48
+ * is the complete settings object (fetched via get-settings) and is PUT
49
+ * as-is. With `expectHash` armed, the settings are read first and their
50
+ * stable hash must match, or the write is refused before any PUT.
51
+ */
52
+ saveSettings(serviceId: string, body: Record<string, unknown>, projectKey?: string, options?: ApiServiceSaveOptions): Promise<ApiServiceActionResult>;
22
53
  /** Add a standard prediction endpoint backed by a saved model. */
23
54
  addPredictionEndpoint(serviceId: string, endpointId: string, savedModelId: string, projectKey?: string): Promise<ApiServiceActionResult>;
24
55
  /** List deployable packages for an API service. */
25
56
  listPackages(serviceId: string, projectKey?: string): Promise<ApiServicePackageListItem[]>;
26
57
  /** Get an API service package summary. */
27
58
  getPackageSummary(serviceId: string, packageId: string, projectKey?: string): Promise<Record<string, unknown>>;
28
- /** Create a deployable package from the current service state. */
29
- createPackage(serviceId: string, packageId: string, projectKey?: string): Promise<{
59
+ /**
60
+ * Create a deployable package from the current service state. The
61
+ * documented optional `releaseNotes` parameter is forwarded as the
62
+ * `releaseNotes` query parameter when provided.
63
+ */
64
+ createPackage(serviceId: string, packageId: string, projectKey?: string, options?: ApiServiceCreatePackageOptions): Promise<{
30
65
  message: string;
31
66
  }>;
32
67
  /** Delete an API service package. */
33
68
  deletePackage(serviceId: string, packageId: string, projectKey?: string): Promise<void>;
34
69
  /** Download an API service package archive. */
35
70
  downloadPackageArchive(serviceId: string, packageId: string, projectKey?: string): Promise<Response>;
36
- /** Publish an API service package to the API Deployer. */
37
- publishPackage(serviceId: string, packageId: string, projectKey?: string): Promise<ApiServiceActionResult>;
71
+ /**
72
+ * Publish an API service package to the API Deployer. The documented
73
+ * optional `publishedServiceId` parameter selects the published service
74
+ * the package is deployed to (a new published service is created when no
75
+ * match exists; when omitted, the server falls back to the service's own
76
+ * id). It is forwarded as the `publishedServiceId` query parameter when
77
+ * provided.
78
+ */
79
+ publishPackage(serviceId: string, packageId: string, projectKey?: string, options?: ApiServicePublishOptions): Promise<ApiServiceActionResult>;
38
80
  private servicePath;
39
81
  private packagePath;
40
82
  }