dataiku-sdk 3.1.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.
Files changed (149) hide show
  1. package/README.md +253 -38
  2. package/dist/build-metadata.json +1 -1
  3. package/dist/packages/types/src/index.d.ts +102 -0
  4. package/dist/packages/types/src/index.js +76 -0
  5. package/dist/src/auth.js +1 -1
  6. package/dist/src/cli/coerce.js +11 -2
  7. package/dist/src/cli/commands/analysis.js +4 -3
  8. package/dist/src/cli/commands/api-service.js +5 -3
  9. package/dist/src/cli/commands/app.js +61 -18
  10. package/dist/src/cli/commands/bundle.js +3 -2
  11. package/dist/src/cli/commands/code-env.js +23 -16
  12. package/dist/src/cli/commands/connection.d.ts +9 -0
  13. package/dist/src/cli/commands/connection.js +267 -1
  14. package/dist/src/cli/commands/dashboard.js +7 -6
  15. package/dist/src/cli/commands/data-collection.d.ts +2 -0
  16. package/dist/src/cli/commands/data-collection.js +164 -0
  17. package/dist/src/cli/commands/data-quality.js +9 -8
  18. package/dist/src/cli/commands/dataset.js +170 -40
  19. package/dist/src/cli/commands/doctor.js +4 -2
  20. package/dist/src/cli/commands/flow-zone.js +9 -8
  21. package/dist/src/cli/commands/folder.js +9 -8
  22. package/dist/src/cli/commands/future.js +4 -3
  23. package/dist/src/cli/commands/group.d.ts +2 -0
  24. package/dist/src/cli/commands/group.js +109 -0
  25. package/dist/src/cli/commands/index.js +151 -78
  26. package/dist/src/cli/commands/insight.js +8 -7
  27. package/dist/src/cli/commands/job.js +4 -3
  28. package/dist/src/cli/commands/knowledge-bank.d.ts +2 -0
  29. package/dist/src/cli/commands/knowledge-bank.js +80 -0
  30. package/dist/src/cli/commands/llm.d.ts +2 -0
  31. package/dist/src/cli/commands/llm.js +93 -0
  32. package/dist/src/cli/commands/macro.d.ts +2 -0
  33. package/dist/src/cli/commands/macro.js +221 -0
  34. package/dist/src/cli/commands/meaning.js +5 -4
  35. package/dist/src/cli/commands/ml-task.js +21 -8
  36. package/dist/src/cli/commands/model-evaluation-store.js +4 -3
  37. package/dist/src/cli/commands/notebook.js +17 -12
  38. package/dist/src/cli/commands/plugin.d.ts +2 -0
  39. package/dist/src/cli/commands/plugin.js +799 -0
  40. package/dist/src/cli/commands/project-folder.d.ts +2 -0
  41. package/dist/src/cli/commands/project-folder.js +197 -0
  42. package/dist/src/cli/commands/project-git.js +14 -54
  43. package/dist/src/cli/commands/project-library.js +7 -6
  44. package/dist/src/cli/commands/project.js +55 -8
  45. package/dist/src/cli/commands/recipe.js +50 -14
  46. package/dist/src/cli/commands/saved-model.d.ts +5 -0
  47. package/dist/src/cli/commands/saved-model.js +392 -4
  48. package/dist/src/cli/commands/scenario.js +147 -9
  49. package/dist/src/cli/commands/sql.js +3 -2
  50. package/dist/src/cli/commands/statistics.js +7 -6
  51. package/dist/src/cli/commands/user.d.ts +8 -0
  52. package/dist/src/cli/commands/user.js +296 -0
  53. package/dist/src/cli/commands/variable.js +2 -1
  54. package/dist/src/cli/commands/webapp.js +2 -1
  55. package/dist/src/cli/commands/wiki.js +7 -6
  56. package/dist/src/cli/contract.d.ts +2 -3
  57. package/dist/src/cli/contract.js +1167 -163
  58. package/dist/src/cli/flags.d.ts +4 -0
  59. package/dist/src/cli/flags.js +50 -2
  60. package/dist/src/cli/helpers/app-successor.d.ts +19 -4
  61. package/dist/src/cli/helpers/app-successor.js +90 -30
  62. package/dist/src/cli/helpers/cleanup.js +3 -1
  63. package/dist/src/cli/helpers/flow-zone.js +1 -2
  64. package/dist/src/cli/output.d.ts +1 -1
  65. package/dist/src/cli/output.js +23 -10
  66. package/dist/src/cli/usage.d.ts +1 -0
  67. package/dist/src/cli/usage.js +47 -1
  68. package/dist/src/cli.js +225 -95
  69. package/dist/src/client.d.ts +86 -6
  70. package/dist/src/client.js +263 -50
  71. package/dist/src/errors.d.ts +3 -0
  72. package/dist/src/errors.js +4 -0
  73. package/dist/src/index.d.ts +16 -7
  74. package/dist/src/index.js +11 -2
  75. package/dist/src/resources/analyses.js +1 -8
  76. package/dist/src/resources/applications.d.ts +8 -6
  77. package/dist/src/resources/applications.js +21 -21
  78. package/dist/src/resources/base.d.ts +4 -0
  79. package/dist/src/resources/base.js +15 -0
  80. package/dist/src/resources/bundles.d.ts +9 -4
  81. package/dist/src/resources/bundles.js +10 -5
  82. package/dist/src/resources/connections.d.ts +78 -1
  83. package/dist/src/resources/connections.js +132 -1
  84. package/dist/src/resources/data-collections.d.ts +118 -0
  85. package/dist/src/resources/data-collections.js +49 -0
  86. package/dist/src/resources/datasets.d.ts +69 -0
  87. package/dist/src/resources/datasets.js +99 -1
  88. package/dist/src/resources/folders.js +2 -1
  89. package/dist/src/resources/futures.d.ts +4 -1
  90. package/dist/src/resources/futures.js +38 -6
  91. package/dist/src/resources/groups.d.ts +47 -0
  92. package/dist/src/resources/groups.js +56 -0
  93. package/dist/src/resources/jobs.d.ts +8 -13
  94. package/dist/src/resources/jobs.js +41 -16
  95. package/dist/src/resources/knowledge-banks.d.ts +58 -0
  96. package/dist/src/resources/knowledge-banks.js +61 -0
  97. package/dist/src/resources/llms.d.ts +92 -0
  98. package/dist/src/resources/llms.js +62 -0
  99. package/dist/src/resources/macros.d.ts +121 -0
  100. package/dist/src/resources/macros.js +231 -0
  101. package/dist/src/resources/ml-tasks.d.ts +37 -2
  102. package/dist/src/resources/ml-tasks.js +100 -20
  103. package/dist/src/resources/model-evaluation-stores.js +1 -8
  104. package/dist/src/resources/notebooks.d.ts +43 -7
  105. package/dist/src/resources/notebooks.js +53 -13
  106. package/dist/src/resources/plugins.d.ts +265 -0
  107. package/dist/src/resources/plugins.js +458 -0
  108. package/dist/src/resources/project-folders.d.ts +71 -0
  109. package/dist/src/resources/project-folders.js +57 -0
  110. package/dist/src/resources/project-git.d.ts +6 -0
  111. package/dist/src/resources/project-git.js +69 -42
  112. package/dist/src/resources/project-library.d.ts +0 -1
  113. package/dist/src/resources/project-library.js +1 -17
  114. package/dist/src/resources/projects.d.ts +19 -3
  115. package/dist/src/resources/projects.js +30 -18
  116. package/dist/src/resources/recipes.d.ts +15 -1
  117. package/dist/src/resources/recipes.js +73 -6
  118. package/dist/src/resources/saved-models.d.ts +134 -1
  119. package/dist/src/resources/saved-models.js +214 -6
  120. package/dist/src/resources/scenarios.d.ts +105 -0
  121. package/dist/src/resources/scenarios.js +232 -106
  122. package/dist/src/resources/sql.js +5 -1
  123. package/dist/src/resources/users.d.ts +129 -0
  124. package/dist/src/resources/users.js +128 -0
  125. package/dist/src/resources/webapps.d.ts +15 -2
  126. package/dist/src/resources/webapps.js +18 -4
  127. package/dist/src/schemas.d.ts +2 -2
  128. package/dist/src/schemas.js +1 -1
  129. package/dist/src/skill.d.ts +13 -4
  130. package/dist/src/skill.js +75 -24
  131. package/dist/src/utils/deep-merge.d.ts +1 -1
  132. package/dist/src/utils/polling.d.ts +20 -0
  133. package/dist/src/utils/polling.js +27 -0
  134. package/dist/src/utils/response-file.d.ts +2 -0
  135. package/dist/src/utils/response-file.js +34 -0
  136. package/dist/src/utils/secret-sanitize.d.ts +54 -0
  137. package/dist/src/utils/secret-sanitize.js +101 -0
  138. package/package.json +8 -5
  139. package/packages/types/dist/index.d.ts +102 -0
  140. package/packages/types/dist/index.js +76 -0
  141. package/plugin.json +1 -1
  142. package/skills/dataiku-dss/SKILL.md +47 -225
  143. package/skills/dataiku-dss/references/app-releases.md +28 -0
  144. package/skills/dataiku-dss/references/authentication.md +39 -0
  145. package/skills/dataiku-dss/references/coding.md +8 -0
  146. package/skills/dataiku-dss/references/discovery.md +30 -0
  147. package/skills/dataiku-dss/references/flow-maps.md +12 -0
  148. package/skills/dataiku-dss/references/mutations.md +33 -0
  149. package/skills/dataiku-dss/references/troubleshooting.md +29 -0
@@ -0,0 +1,118 @@
1
+ import { BaseResource } from "./base.js";
2
+ /**
3
+ * Data collections are instance-level curated groupings of DSS objects
4
+ * (datasets, saved models, agents, fine-tuned models, agent tools, semantic
5
+ * models) shared across projects.
6
+ *
7
+ * @see https://doc.dataiku.com/dss/api/15/rest/ (Data Collections section)
8
+ */
9
+ export type DataCollectionObjectReferenceType = "DATASET" | "SAVED_MODEL" | "FINE_TUNED_MODEL" | "AGENT" | "AGENT_TOOL" | "SEMANTIC_MODEL" | (string & {});
10
+ export interface DataCollectionPermission extends Record<string, unknown> {
11
+ /** Name of the user this permission applies to (exclusive with group). */
12
+ user?: string;
13
+ /** Name of the group this permission applies to (exclusive with user). */
14
+ group?: string;
15
+ /** true if the permission grants administrator access. */
16
+ admin?: boolean;
17
+ /** true if the permission grants contributor access. */
18
+ write?: boolean;
19
+ /** true if the permission grants member access. */
20
+ read?: boolean;
21
+ }
22
+ export interface DataCollectionSummary extends Record<string, unknown> {
23
+ /** Name of the collection. */
24
+ displayName?: string;
25
+ /** Color of the collection (#RRGBB syntax). */
26
+ color?: string | null;
27
+ /** The description of the collection (markdown). */
28
+ description?: string | null;
29
+ /** List of tags of the collection. */
30
+ tags?: string[] | null;
31
+ /** Id of the collection. */
32
+ id?: string;
33
+ /** Number of objects in the collection. */
34
+ itemCount?: number;
35
+ /** Number of datasets in the collection. */
36
+ datasetsCount?: number;
37
+ /** Number of saved models in the collection, excluding agents and fine tuned models. */
38
+ savedModelsCount?: number;
39
+ /** Number of fine tuned models in the collection. */
40
+ fineTunedModelsCount?: number;
41
+ /** Number of agents in the collection. */
42
+ agentsCount?: number;
43
+ /** Number of agent tools in the collection. */
44
+ agentToolsCount?: number;
45
+ /** Number of semantic models in the collection. */
46
+ semanticModelsCount?: number;
47
+ /** Timestamp of the last collection modification. */
48
+ lastModifiedOn?: number;
49
+ }
50
+ export interface DataCollectionSettings extends Record<string, unknown> {
51
+ /** Id of the collection. */
52
+ id?: string;
53
+ /** Name of the collection. */
54
+ displayName: string;
55
+ /** Color of the collection (#RRGGBB syntax). */
56
+ color?: string | null;
57
+ /** The description of the collection (markdown). */
58
+ description?: string | null;
59
+ /** List of tags of the collection. */
60
+ tags?: string[] | null;
61
+ /** List of permissions of the collection (READER, CONTRIBUTOR or ADMIN). */
62
+ permissions?: DataCollectionPermission[] | null;
63
+ }
64
+ export interface DataCollectionCreateRequest extends Omit<DataCollectionSettings, "id"> {
65
+ /**
66
+ * Id of the Collection (a random id is generated if not provided).
67
+ * Must match the [A-Za-z0-9]{8} server-side format when provided.
68
+ */
69
+ id?: string;
70
+ }
71
+ /**
72
+ * An object inside a collection: a reference to a DSS object hosted by a
73
+ * project. The documented shape covers datasets; `type` accepts the other
74
+ * collection member kinds the instance may report.
75
+ */
76
+ export interface DataCollectionObject extends Record<string, unknown> {
77
+ /** The type of this object (e.g. "DATASET"). */
78
+ type: DataCollectionObjectReferenceType;
79
+ /** The key of the project hosting the object. */
80
+ projectKey: string;
81
+ /** The id (name) of the object in its project. */
82
+ id: string;
83
+ }
84
+ export declare class DataCollectionsResource extends BaseResource {
85
+ /** List the collections on which the API key has READ privilege. */
86
+ list(): Promise<DataCollectionSummary[]>;
87
+ /**
88
+ * Create a collection. The creating user is added as an administrator.
89
+ * Requires the mayCreateDataCollections global permission. DSS returns
90
+ * `{ msg, id }`; the created id is surfaced to the caller.
91
+ */
92
+ create(body: DataCollectionCreateRequest): Promise<{
93
+ msg?: string;
94
+ id?: string;
95
+ }>;
96
+ /**
97
+ * Get the settings of a collection. Requires READ on the collection; the
98
+ * permissions array is omitted unless the caller is an ADMIN.
99
+ */
100
+ get(dataCollectionId: string): Promise<DataCollectionSettings>;
101
+ /**
102
+ * Update the settings of a collection. Only set a settings object obtained
103
+ * through {@link get}. Requires ADMIN on the collection.
104
+ */
105
+ update(dataCollectionId: string, settings: DataCollectionSettings): Promise<DataCollectionSettings>;
106
+ /** Permanently delete a collection. Requires ADMIN on the collection. */
107
+ delete(dataCollectionId: string): Promise<void>;
108
+ /** List the objects in a collection. Requires READ on the collection. */
109
+ listObjects(dataCollectionId: string): Promise<DataCollectionObject[]>;
110
+ /**
111
+ * Add an object to a collection. Requires WRITE (Contributor) on the
112
+ * collection, the mayPublishToDataCollections global group permission, and
113
+ * publishToDataCollections on the project hosting the object (if relevant).
114
+ */
115
+ addObject(dataCollectionId: string, object: DataCollectionObject): Promise<void>;
116
+ /** Remove a dataset from a collection. Requires WRITE on the collection. */
117
+ removeDataset(dataCollectionId: string, projectKey: string, datasetName: string): Promise<void>;
118
+ }
@@ -0,0 +1,49 @@
1
+ import { BaseResource, } from "./base.js";
2
+ export class DataCollectionsResource extends BaseResource {
3
+ /** List the collections on which the API key has READ privilege. */
4
+ async list() {
5
+ return this.client.get("/public/api/data-collections/");
6
+ }
7
+ /**
8
+ * Create a collection. The creating user is added as an administrator.
9
+ * Requires the mayCreateDataCollections global permission. DSS returns
10
+ * `{ msg, id }`; the created id is surfaced to the caller.
11
+ */
12
+ async create(body) {
13
+ return this.client.post("/public/api/data-collections/", body);
14
+ }
15
+ /**
16
+ * Get the settings of a collection. Requires READ on the collection; the
17
+ * permissions array is omitted unless the caller is an ADMIN.
18
+ */
19
+ async get(dataCollectionId) {
20
+ return this.client.get(`/public/api/data-collections/${encodeURIComponent(dataCollectionId)}`);
21
+ }
22
+ /**
23
+ * Update the settings of a collection. Only set a settings object obtained
24
+ * through {@link get}. Requires ADMIN on the collection.
25
+ */
26
+ async update(dataCollectionId, settings) {
27
+ return this.client.put(`/public/api/data-collections/${encodeURIComponent(dataCollectionId)}`, settings);
28
+ }
29
+ /** Permanently delete a collection. Requires ADMIN on the collection. */
30
+ async delete(dataCollectionId) {
31
+ await this.client.del(`/public/api/data-collections/${encodeURIComponent(dataCollectionId)}`);
32
+ }
33
+ /** List the objects in a collection. Requires READ on the collection. */
34
+ async listObjects(dataCollectionId) {
35
+ return this.client.get(`/public/api/data-collections/${encodeURIComponent(dataCollectionId)}/objects`);
36
+ }
37
+ /**
38
+ * Add an object to a collection. Requires WRITE (Contributor) on the
39
+ * collection, the mayPublishToDataCollections global group permission, and
40
+ * publishToDataCollections on the project hosting the object (if relevant).
41
+ */
42
+ async addObject(dataCollectionId, object) {
43
+ await this.client.post(`/public/api/data-collections/${encodeURIComponent(dataCollectionId)}/objects`, object);
44
+ }
45
+ /** Remove a dataset from a collection. Requires WRITE on the collection. */
46
+ async removeDataset(dataCollectionId, projectKey, datasetName) {
47
+ await this.client.del(`/public/api/data-collections/${encodeURIComponent(dataCollectionId)}/objects/dataset/${encodeURIComponent(projectKey)}/${encodeURIComponent(datasetName)}`);
48
+ }
49
+ }
@@ -17,6 +17,37 @@ export interface DatasetSchemaColumnInput {
17
17
  type: string;
18
18
  comment?: string;
19
19
  }
20
+ /** Options for creating a managed dataset through the dedicated endpoint. */
21
+ export interface DatasetManagedCreateOptions {
22
+ /** Name of the new dataset (unique in the project). */
23
+ name: string;
24
+ /** Connection where the dataset is stored. */
25
+ connection: string;
26
+ /** When the connection accepts several dataset types, the type to use. */
27
+ typeOptionId?: string;
28
+ /** Optional identifier of a file format option (e.g. CSV_EXCEL_GZIP, PARQUET_HIVE). */
29
+ formatOptionId?: string;
30
+ /**
31
+ * Partitioning option id. Use {@link DatasetManagedCreateOptions.copyPartitioningFrom}
32
+ * to build one from an existing dataset or folder reference.
33
+ */
34
+ partitioningOptionId?: string;
35
+ /**
36
+ * Copy partitioning from an existing dataset or folder instead of passing a
37
+ * raw `partitioningOptionId`. `type` defaults to `DATASET` and may be
38
+ * `FOLDER`.
39
+ */
40
+ copyPartitioningFrom?: {
41
+ ref: string;
42
+ type?: "DATASET" | "FOLDER";
43
+ };
44
+ }
45
+ /** Result of creating a managed dataset (the endpoint answers 204 with no body). */
46
+ export interface DatasetManagedCreateResult {
47
+ datasetName: string;
48
+ projectKey: string;
49
+ creationSettings: Record<string, unknown>;
50
+ }
20
51
  export interface DatasetCloneOptions {
21
52
  projectKey?: string;
22
53
  path?: string;
@@ -120,6 +151,44 @@ export declare class DatasetsResource extends BaseResource {
120
151
  }>;
121
152
  /** Get dataset metadata (tags, custom fields, checklists). */
122
153
  metadata(datasetName: string, projectKey?: string): Promise<Record<string, unknown>>;
154
+ /**
155
+ * Replace dataset metadata with the given object (faithful PUT per the DSS
156
+ * API contract: the caller GETs the metadata, edits it, and PUTs the full
157
+ * object back — no partial merge is applied client-side). `label`,
158
+ * `description`, `tags`, and `custom` are the documented writable fields;
159
+ * any additional server-provided metadata fields present in the object are
160
+ * preserved verbatim.
161
+ */
162
+ updateMetadata(datasetName: string, metadata: Record<string, unknown>, projectKey?: string): Promise<Record<string, unknown>>;
163
+ /**
164
+ * Create a managed dataset through the dedicated
165
+ * `POST /projects/{projectKey}/datasets/managed` endpoint. DSS handles the
166
+ * format/storage details: you select the name, the connection, and optional
167
+ * type/format/partitioning options. The endpoint answers `204` with no
168
+ * body; the returned settings echo what was sent.
169
+ */
170
+ createManaged(opts: DatasetManagedCreateOptions, projectKey?: string): Promise<DatasetManagedCreateResult>;
171
+ /**
172
+ * Get the full info object for a dataset (type, parameters, last build
173
+ * information, schema, etc.). The server returns a complex opaque object;
174
+ * it is surfaced without validation.
175
+ */
176
+ info(datasetName: string, projectKey?: string): Promise<Record<string, unknown>>;
177
+ /**
178
+ * Get the full column lineage (auto-computed and manual) of a column in
179
+ * this dataset. Relations with datasets from both local and foreign
180
+ * projects are included.
181
+ *
182
+ * Route per the official Python client:
183
+ * `GET /projects/{projectKey}/datasets/{datasetName}/column-lineage`
184
+ * with query `columnName` (required) and `maxDatasetCount` (optional,
185
+ * positive integer — the docs page renders a merged project-scoped path,
186
+ * but DSS's own client and route registry use this per-dataset form).
187
+ */
188
+ getColumnLineage(datasetName: string, column: string, opts?: {
189
+ maxDatasetCount?: number;
190
+ projectKey?: string;
191
+ }): Promise<unknown>;
123
192
  /**
124
193
  * Download dataset rows as a gzipped (or .csv) file, capped at `limit` rows
125
194
  * (default 100k). Returns the written path, the number of data rows written,
@@ -712,6 +712,104 @@ export class DatasetsResource extends BaseResource {
712
712
  const dsEnc = encodeURIComponent(datasetName);
713
713
  return this.client.get(`/public/api/projects/${this.enc(projectKey)}/datasets/${dsEnc}/metadata`);
714
714
  }
715
+ /**
716
+ * Replace dataset metadata with the given object (faithful PUT per the DSS
717
+ * API contract: the caller GETs the metadata, edits it, and PUTs the full
718
+ * object back — no partial merge is applied client-side). `label`,
719
+ * `description`, `tags`, and `custom` are the documented writable fields;
720
+ * any additional server-provided metadata fields present in the object are
721
+ * preserved verbatim.
722
+ */
723
+ async updateMetadata(datasetName, metadata, projectKey) {
724
+ if (metadata === null || Array.isArray(metadata)) {
725
+ throw new ClientValidationError("metadata must be a JSON object.");
726
+ }
727
+ const dsEnc = encodeURIComponent(datasetName);
728
+ return this.client.put(`/public/api/projects/${this.enc(projectKey)}/datasets/${dsEnc}/metadata`, metadata);
729
+ }
730
+ /**
731
+ * Create a managed dataset through the dedicated
732
+ * `POST /projects/{projectKey}/datasets/managed` endpoint. DSS handles the
733
+ * format/storage details: you select the name, the connection, and optional
734
+ * type/format/partitioning options. The endpoint answers `204` with no
735
+ * body; the returned settings echo what was sent.
736
+ */
737
+ async createManaged(opts, projectKey) {
738
+ const name = typeof opts.name === "string" ? opts.name.trim() : "";
739
+ if (name === "") {
740
+ throw new ClientValidationError("name must be a non-empty dataset name.");
741
+ }
742
+ const connection = typeof opts.connection === "string" ? opts.connection.trim() : "";
743
+ if (connection === "") {
744
+ throw new ClientValidationError("connection must be a non-empty connection name.");
745
+ }
746
+ if (opts.partitioningOptionId !== undefined && opts.copyPartitioningFrom !== undefined) {
747
+ throw new ClientValidationError("Pass either partitioningOptionId or copyPartitioningFrom, not both.");
748
+ }
749
+ if (opts.copyPartitioningFrom !== undefined
750
+ && (typeof opts.copyPartitioningFrom.ref !== "string"
751
+ || opts.copyPartitioningFrom.ref.trim() === "")) {
752
+ throw new ClientValidationError("copyPartitioningFrom.ref must be a non-empty dataset or folder name.");
753
+ }
754
+ const pk = this.resolveProjectKey(projectKey);
755
+ const creationSettings = { connectionId: connection, };
756
+ if (opts.typeOptionId !== undefined)
757
+ creationSettings.typeOptionId = opts.typeOptionId;
758
+ if (opts.formatOptionId !== undefined || opts.partitioningOptionId !== undefined
759
+ || opts.copyPartitioningFrom !== undefined) {
760
+ const specificSettings = {};
761
+ if (opts.formatOptionId !== undefined) {
762
+ specificSettings.formatOptionId = opts.formatOptionId;
763
+ }
764
+ if (opts.partitioningOptionId !== undefined) {
765
+ specificSettings.partitioningOptionId = opts.partitioningOptionId;
766
+ }
767
+ else if (opts.copyPartitioningFrom !== undefined) {
768
+ const code = opts.copyPartitioningFrom.type === "FOLDER" ? "folder" : "dataset";
769
+ specificSettings.partitioningOptionId = `copy:${code}:${opts.copyPartitioningFrom.ref.trim()}`;
770
+ }
771
+ creationSettings.specificSettings = specificSettings;
772
+ }
773
+ await this.client.post(`/public/api/projects/${encodeURIComponent(pk)}/datasets/managed`, { name, creationSettings, });
774
+ return { datasetName: name, projectKey: pk, creationSettings, };
775
+ }
776
+ /**
777
+ * Get the full info object for a dataset (type, parameters, last build
778
+ * information, schema, etc.). The server returns a complex opaque object;
779
+ * it is surfaced without validation.
780
+ */
781
+ async info(datasetName, projectKey) {
782
+ const dsEnc = encodeURIComponent(datasetName);
783
+ return this.client.get(`/public/api/projects/${this.enc(projectKey)}/datasets/${dsEnc}/info`);
784
+ }
785
+ /**
786
+ * Get the full column lineage (auto-computed and manual) of a column in
787
+ * this dataset. Relations with datasets from both local and foreign
788
+ * projects are included.
789
+ *
790
+ * Route per the official Python client:
791
+ * `GET /projects/{projectKey}/datasets/{datasetName}/column-lineage`
792
+ * with query `columnName` (required) and `maxDatasetCount` (optional,
793
+ * positive integer — the docs page renders a merged project-scoped path,
794
+ * but DSS's own client and route registry use this per-dataset form).
795
+ */
796
+ async getColumnLineage(datasetName, column, opts = {}) {
797
+ const trimmed = typeof column === "string" ? column.trim() : "";
798
+ if (trimmed === "") {
799
+ throw new ClientValidationError("column must be a non-empty column name.");
800
+ }
801
+ const maxDatasetCount = opts.maxDatasetCount;
802
+ if (maxDatasetCount !== undefined
803
+ && (!Number.isSafeInteger(maxDatasetCount) || maxDatasetCount <= 0)) {
804
+ throw new ClientValidationError("maxDatasetCount must be a positive integer.");
805
+ }
806
+ const dsEnc = encodeURIComponent(datasetName);
807
+ const params = [`columnName=${encodeURIComponent(trimmed)}`,];
808
+ if (maxDatasetCount !== undefined) {
809
+ params.push(`maxDatasetCount=${encodeURIComponent(String(maxDatasetCount))}`);
810
+ }
811
+ return this.client.get(`/public/api/projects/${this.enc(opts?.projectKey)}/datasets/${dsEnc}/column-lineage?${params.join("&")}`);
812
+ }
715
813
  /**
716
814
  * Download dataset rows as a gzipped (or .csv) file, capped at `limit` rows
717
815
  * (default 100k). Returns the written path, the number of data rows written,
@@ -746,7 +844,7 @@ export class DatasetsResource extends BaseResource {
746
844
  : undefined;
747
845
  const shouldGzip = filePath.endsWith(".gz");
748
846
  const stats = { rows: 0, truncated: false, };
749
- const nodeStream = Readable.fromWeb(res.body);
847
+ const nodeStream = Readable.from(res.body, { objectMode: false, });
750
848
  const csvTransform = tsvToCsvTransform(limit, stats, onHeader, opts?.rawData !== true);
751
849
  fs.mkdirSync(nodePath.dirname(filePath), { recursive: true, });
752
850
  const fileOut = fs.createWriteStream(filePath);
@@ -1,6 +1,7 @@
1
1
  import * as nodePath from "node:path";
2
2
  import { FolderDetailsSchema, FolderItemArraySchema, FolderSummaryArraySchema, } from "../schemas.js";
3
3
  import { deepMerge, } from "../utils/deep-merge.js";
4
+ import { writeResponseToFile, } from "../utils/response-file.js";
4
5
  import { sanitizeFileName, } from "../utils/sanitize.js";
5
6
  import { BaseResource, } from "./base.js";
6
7
  import { resolveAdminManagedStorageConnection, } from "./connections.js";
@@ -73,7 +74,7 @@ export class FoldersResource extends BaseResource {
73
74
  throw new Error("folders.download response did not include a body");
74
75
  const dest = opts?.localPath
75
76
  ?? nodePath.resolve(process.cwd(), inferDownloadFileName(normalizedPath));
76
- await Bun.write(dest, new Response(res.body), { createPath: false, });
77
+ await writeResponseToFile(dest, res);
77
78
  return dest;
78
79
  }
79
80
  upload(folderId, path, localPath, projectKey) {
@@ -5,10 +5,13 @@ export interface FutureWaitOptions {
5
5
  timeoutMs?: number;
6
6
  }
7
7
  export declare class FuturesResource extends BaseResource {
8
- get(futureId: string): Promise<FutureState>;
8
+ get(futureId: string, opts?: {
9
+ timeoutMs?: number;
10
+ }): Promise<FutureState>;
9
11
  peek(futureId: string): Promise<FutureState>;
10
12
  state(futureId: string, opts?: {
11
13
  peek?: boolean;
14
+ timeoutMs?: number;
12
15
  }): Promise<FutureState>;
13
16
  abort(futureId: string): Promise<void>;
14
17
  wait(futureId: string, opts?: FutureWaitOptions): Promise<FutureWaitResult>;
@@ -1,4 +1,5 @@
1
1
  import { FutureStateSchema, FutureWaitResultSchema, } from "../schemas.js";
2
+ import { computeNextPollDelayMs, isRequestDeadlineError, } from "../utils/polling.js";
2
3
  import { BaseResource, } from "./base.js";
3
4
  const DEFAULT_POLL_INTERVAL_MS = 2_000;
4
5
  const DEFAULT_TIMEOUT_MS = 120_000;
@@ -23,8 +24,8 @@ function waitState(state) {
23
24
  return "RUNNING";
24
25
  }
25
26
  export class FuturesResource extends BaseResource {
26
- async get(futureId) {
27
- return this.state(futureId, { peek: false, });
27
+ async get(futureId, opts = {}) {
28
+ return this.state(futureId, { peek: false, timeoutMs: opts.timeoutMs, });
28
29
  }
29
30
  async peek(futureId) {
30
31
  return this.state(futureId, { peek: true, });
@@ -32,14 +33,18 @@ export class FuturesResource extends BaseResource {
32
33
  async state(futureId, opts = {}) {
33
34
  const params = new URLSearchParams();
34
35
  params.set("peek", String(opts.peek === true));
35
- const raw = await this.client.get(`/public/api/futures/${encodeURIComponent(futureId)}?${params.toString()}`);
36
+ const raw = await this.client.get(`/public/api/futures/${encodeURIComponent(futureId)}?${params.toString()}`, { timeoutMs: opts.timeoutMs, });
36
37
  return this.client.safeParse(FutureStateSchema, raw, "futures.state");
37
38
  }
38
39
  async abort(futureId) {
39
40
  await this.client.del(`/public/api/futures/${encodeURIComponent(futureId)}`);
40
41
  }
41
42
  async wait(futureId, opts = {}) {
42
- const baseIntervalMs = Math.max(1, opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
43
+ // Adaptive backoff is the default; an explicit pollIntervalMs is an
44
+ // exact contract the caller chose, so it is never adapted.
45
+ const explicitIntervalMs = opts.pollIntervalMs;
46
+ const baseIntervalMs = Math.max(1, explicitIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
47
+ const adaptiveEnabled = explicitIntervalMs === undefined;
43
48
  // A caller's budget is never rounded up to a whole poll interval: a 5ms
44
49
  // wait must answer in about 5ms. One state observation always happens
45
50
  // regardless, because the poll precedes the deadline check.
@@ -48,7 +53,29 @@ export class FuturesResource extends BaseResource {
48
53
  let pollCount = 0;
49
54
  while (true) {
50
55
  pollCount += 1;
51
- const state = await this.get(futureId);
56
+ // One state observation always happens, even when the budget is
57
+ // already spent (the poll precedes the deadline check); only the
58
+ // requests issued while budget remains are bounded by the remaining
59
+ // time, so a stalled status endpoint can never defeat the deadline.
60
+ const remainingMs = timeoutMs - (Date.now() - startedAt);
61
+ let state;
62
+ try {
63
+ state = await this.get(futureId, remainingMs > 0 ? { timeoutMs: remainingMs, } : undefined);
64
+ }
65
+ catch (error) {
66
+ // The poll budget ran out mid-request: report the structured
67
+ // timeout instead of letting the transport deadline error escape.
68
+ if (!isRequestDeadlineError(error, startedAt + timeoutMs))
69
+ throw error;
70
+ return this.client.safeParse(FutureWaitResultSchema, {
71
+ futureId,
72
+ state: "RUNNING",
73
+ elapsedMs: Date.now() - startedAt,
74
+ pollCount,
75
+ success: false,
76
+ timedOut: true,
77
+ }, "futures.wait");
78
+ }
52
79
  const elapsedMs = Date.now() - startedAt;
53
80
  const status = waitState(state);
54
81
  if (isFinished(state)) {
@@ -85,7 +112,12 @@ export class FuturesResource extends BaseResource {
85
112
  }
86
113
  // Only the remaining budget is slept: a longer sleep would report an
87
114
  // elapsed time the caller never authorized.
88
- await sleep(Math.min(baseIntervalMs, timeoutMs - elapsedMs));
115
+ const nextDelayMs = computeNextPollDelayMs({
116
+ pollCount,
117
+ baseIntervalMs,
118
+ adaptiveEnabled,
119
+ });
120
+ await sleep(Math.min(nextDelayMs, timeoutMs - elapsedMs));
89
121
  }
90
122
  }
91
123
  }
@@ -0,0 +1,47 @@
1
+ import { BaseResource } from "./base.js";
2
+ /**
3
+ * A DSS group as returned by the admin Security endpoints. The documented
4
+ * attributes below are stable; DSS may return undocumented extra attributes
5
+ * (per the API docs they must not be modified on update), so they are preserved
6
+ * under `Record<string, unknown>` and are never stripped by this SDK.
7
+ */
8
+ export interface DssGroup extends Record<string, unknown> {
9
+ name?: string;
10
+ description?: string;
11
+ /** Whether this group gives administrative rights on DSS. */
12
+ admin?: boolean;
13
+ sourceType?: string;
14
+ }
15
+ /**
16
+ * Body of `POST /admin/groups` (create) and the editable subset of the PUT
17
+ * body. DSS requires `name` on create; `admin` and `description` are optional.
18
+ */
19
+ export interface GroupCreateRequest extends Record<string, unknown> {
20
+ name: string;
21
+ description?: string;
22
+ admin?: boolean;
23
+ }
24
+ export declare class GroupsResource extends BaseResource {
25
+ /** Retrieves the list of DSS groups (Admin required). */
26
+ list(): Promise<DssGroup[]>;
27
+ /**
28
+ * Retrieves a Group object describing a DSS user group, used for access
29
+ * control on connections and projects (Admin required).
30
+ */
31
+ get(groupName: string): Promise<DssGroup>;
32
+ /**
33
+ * Creates a group (Admin required). DSS answers with
34
+ * `{msg: "Created group <name>"}`; the raw server record is returned as-is.
35
+ */
36
+ create(body: GroupCreateRequest): Promise<Record<string, unknown>>;
37
+ /**
38
+ * Updates a group (Admin required). Per the docs the body MUST have been
39
+ * obtained from a prior GET at the same URL; undocumented attributes should
40
+ * be passed through unmodified. DSS answers with `{msg: "Edited group ..."}`.
41
+ */
42
+ update(groupName: string, body: DssGroup): Promise<Record<string, unknown>>;
43
+ /** Deletes a DSS users group (Admin required). */
44
+ delete(groupName: string): Promise<{
45
+ deleted: string;
46
+ }>;
47
+ }
@@ -0,0 +1,56 @@
1
+ import { ClientValidationError, } from "../errors.js";
2
+ import { BaseResource, requireArrayResponse, requireNonEmpty, } from "./base.js";
3
+ function validateGroupBody(body, method) {
4
+ if (body === null || body === undefined || typeof body !== "object" || Array.isArray(body)) {
5
+ throw new ClientValidationError(`${method}: body must be a Group object.`);
6
+ }
7
+ const record = body;
8
+ if (record.admin !== undefined && typeof record.admin !== "boolean") {
9
+ throw new ClientValidationError(`${method}: admin must be a boolean.`);
10
+ }
11
+ return record;
12
+ }
13
+ export class GroupsResource extends BaseResource {
14
+ /** Retrieves the list of DSS groups (Admin required). */
15
+ async list() {
16
+ const raw = await this.client.get("/public/api/admin/groups");
17
+ return requireArrayResponse(raw, "groups.list");
18
+ }
19
+ /**
20
+ * Retrieves a Group object describing a DSS user group, used for access
21
+ * control on connections and projects (Admin required).
22
+ */
23
+ async get(groupName) {
24
+ const enc = requireNonEmpty(groupName, "groupName").trim();
25
+ return this.client.get(`/public/api/admin/groups/${encodeURIComponent(enc)}`);
26
+ }
27
+ /**
28
+ * Creates a group (Admin required). DSS answers with
29
+ * `{msg: "Created group <name>"}`; the raw server record is returned as-is.
30
+ */
31
+ async create(body) {
32
+ if (body === null || body === undefined || typeof body !== "object" || Array.isArray(body)
33
+ || typeof body.name !== "string"
34
+ || body.name.trim().length === 0) {
35
+ throw new ClientValidationError("groups.create: body.name is required.");
36
+ }
37
+ validateGroupBody(body, "groups.create");
38
+ return this.client.post("/public/api/admin/groups", body);
39
+ }
40
+ /**
41
+ * Updates a group (Admin required). Per the docs the body MUST have been
42
+ * obtained from a prior GET at the same URL; undocumented attributes should
43
+ * be passed through unmodified. DSS answers with `{msg: "Edited group ..."}`.
44
+ */
45
+ async update(groupName, body) {
46
+ const enc = requireNonEmpty(groupName, "groupName").trim();
47
+ const validated = validateGroupBody(body, "groups.update");
48
+ return this.client.put(`/public/api/admin/groups/${encodeURIComponent(enc)}`, validated);
49
+ }
50
+ /** Deletes a DSS users group (Admin required). */
51
+ async delete(groupName) {
52
+ const enc = requireNonEmpty(groupName, "groupName").trim();
53
+ await this.client.del(`/public/api/admin/groups/${encodeURIComponent(enc)}`);
54
+ return { deleted: enc, };
55
+ }
56
+ }
@@ -1,6 +1,13 @@
1
1
  import type { BuildMode, JobSummary, JobWaitResult } from "../schemas.js";
2
2
  import { BaseResource } from "./base.js";
3
- export type JobBuildTargetType = "DATASET" | "MANAGED_FOLDER";
3
+ /**
4
+ * Buildable target kinds. DATASET and MANAGED_FOLDER are user-selectable;
5
+ * MODEL_EVALUATION_STORE appears as a recipe output role and is a valid job
6
+ * target per the official client (recipe.run object_type_map maps
7
+ * COMPUTABLE_MODEL_EVALUATION_STORE to MODEL_EVALUATION_STORE before
8
+ * JobDefinition.with_output).
9
+ */
10
+ export type JobBuildTargetType = "DATASET" | "MANAGED_FOLDER" | "MODEL_EVALUATION_STORE";
4
11
  export type JobLogFilter = "stdout" | "stderr" | "user" | "errors";
5
12
  export interface JobLogProgress {
6
13
  lastProgressLine?: string;
@@ -46,17 +53,6 @@ export interface JobBuildAndWaitOptions extends JobBuildOptions {
46
53
  logId?: string;
47
54
  summary?: boolean;
48
55
  }
49
- interface ComputeNextPollDelayMsOptions {
50
- pollCount: number;
51
- baseIntervalMs: number;
52
- adaptiveEnabled: boolean;
53
- }
54
- /**
55
- * Compute the next poll delay.
56
- * When adaptive polling is enabled, the interval doubles every 3 polls,
57
- * capped at MAX_POLL_INTERVAL_MS (or baseIntervalMs if it's larger).
58
- */
59
- export declare function computeNextPollDelayMs({ pollCount, baseIntervalMs, adaptiveEnabled, }: ComputeNextPollDelayMsOptions): number;
60
56
  export declare function parseJobLogProgress(log: string, elapsedMs?: number): JobLogProgress | undefined;
61
57
  export declare class JobsResource extends BaseResource {
62
58
  /** List jobs in a project. */
@@ -146,4 +142,3 @@ export declare class JobsResource extends BaseResource {
146
142
  /** Request a job abort. */
147
143
  abort(jobId: string, projectKey?: string): Promise<void>;
148
144
  }
149
- export {};