dataiku-sdk 1.0.0 → 2.0.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 (43) hide show
  1. package/README.md +64 -10
  2. package/bin/dss.js +67 -78
  3. package/dist/build-metadata.json +1 -0
  4. package/dist/src/cli/commands/api-service.js +5 -4
  5. package/dist/src/cli/commands/app.js +45 -12
  6. package/dist/src/cli/commands/bundle.js +5 -4
  7. package/dist/src/cli/commands/data-quality.js +42 -0
  8. package/dist/src/cli/commands/dataset.d.ts +23 -0
  9. package/dist/src/cli/commands/dataset.js +187 -6
  10. package/dist/src/cli/commands/job.js +15 -2
  11. package/dist/src/cli/commands/project-library.js +4 -4
  12. package/dist/src/cli/commands/project.js +116 -12
  13. package/dist/src/cli/contract.d.ts +1 -0
  14. package/dist/src/cli/contract.js +194 -15
  15. package/dist/src/cli/doctor.d.ts +12 -2
  16. package/dist/src/cli/doctor.js +44 -13
  17. package/dist/src/cli/flags.js +2 -0
  18. package/dist/src/cli/helpers/app-successor.d.ts +15 -3
  19. package/dist/src/cli/helpers/app-successor.js +155 -15
  20. package/dist/src/cli/helpers/cleanup.js +30 -1
  21. package/dist/src/cli/output.d.ts +3 -1
  22. package/dist/src/cli/output.js +11 -6
  23. package/dist/src/cli/types.d.ts +2 -0
  24. package/dist/src/cli/version.d.ts +47 -4
  25. package/dist/src/cli/version.js +176 -9
  26. package/dist/src/cli.js +55 -14
  27. package/dist/src/client.d.ts +28 -1
  28. package/dist/src/client.js +34 -7
  29. package/dist/src/errors.d.ts +1 -1
  30. package/dist/src/index.d.ts +3 -2
  31. package/dist/src/index.js +1 -0
  32. package/dist/src/resources/datasets.d.ts +43 -0
  33. package/dist/src/resources/datasets.js +199 -28
  34. package/dist/src/resources/folders.js +6 -8
  35. package/dist/src/resources/projects.d.ts +36 -3
  36. package/dist/src/resources/projects.js +122 -20
  37. package/dist/src/skill.js +1 -18
  38. package/dist/src/utils/project-archive.d.ts +32 -0
  39. package/dist/src/utils/project-archive.js +623 -0
  40. package/dist/src/utils/stable-hash.js +1 -2
  41. package/package.json +10 -10
  42. package/plugin.json +1 -1
  43. package/skills/dataiku-dss/SKILL.md +27 -35
package/dist/src/cli.js CHANGED
@@ -32,19 +32,28 @@ import { canonicalDssUrl, } from "./utils/dss-url.js";
32
32
  // ---------------------------------------------------------------------------
33
33
  // Auth commands (run before client creation)
34
34
  // ---------------------------------------------------------------------------
35
- function findUnboundAppCleanup(entries) {
35
+ function findUnboundLifecycleCleanup(entries) {
36
36
  for (const [index, entry,] of entries.entries()) {
37
37
  const parsed = parseArgs(entry.cleanup.argv);
38
38
  const [resource, action,] = parsed.positional;
39
- if (resource !== "app" || action !== "delete-instance")
39
+ if (resource === "app" && action === "delete-instance") {
40
+ if (parsed.flags["unconfirmed-creation"] === true)
41
+ continue;
42
+ const expected = parsed.flags["expect-project-incarnation"];
43
+ if (typeof expected !== "string")
44
+ return { index, resource, action, reason: "missing", };
45
+ if (!/^[0-9a-f]{64}$/.test(expected))
46
+ return { index, resource, action, reason: "invalid", };
40
47
  continue;
41
- if (parsed.flags["unconfirmed-creation"] === true)
48
+ }
49
+ if (resource === "project" && action === "delete") {
50
+ const expected = parsed.flags["expect-project-incarnation"];
51
+ if (typeof expected !== "string")
52
+ return { index, resource, action, reason: "missing", };
53
+ if (!/^[0-9a-f]{64}$/.test(expected))
54
+ return { index, resource, action, reason: "invalid", };
42
55
  continue;
43
- const expected = parsed.flags["expect-project-incarnation"];
44
- if (typeof expected !== "string")
45
- return { index, reason: "missing", };
46
- if (!/^[0-9a-f]{64}$/.test(expected))
47
- return { index, reason: "invalid", };
56
+ }
48
57
  }
49
58
  return undefined;
50
59
  }
@@ -119,9 +128,10 @@ async function runCleanup(flags) {
119
128
  };
120
129
  }
121
130
  // Lifecycle binding is as load-bearing as server binding. Validate the whole
122
- // reversed plan before step one so a later legacy app entry cannot leave an
123
- // earlier cleanup applied and then fail on project-key reuse protection.
124
- const lifecycleViolation = findUnboundAppCleanup(ordered);
131
+ // reversed plan before step one so a later legacy app or project entry
132
+ // cannot leave an earlier cleanup applied and then fail on project-key
133
+ // reuse protection.
134
+ const lifecycleViolation = findUnboundLifecycleCleanup(ordered);
125
135
  if (lifecycleViolation) {
126
136
  return {
127
137
  result: {
@@ -129,8 +139,8 @@ async function runCleanup(flags) {
129
139
  steps,
130
140
  lifecycleError: {
131
141
  entryIndex: lifecycleViolation.index,
132
- resource: "app",
133
- action: "delete-instance",
142
+ resource: lifecycleViolation.resource,
143
+ action: lifecycleViolation.action,
134
144
  reason: lifecycleViolation.reason,
135
145
  },
136
146
  },
@@ -147,6 +157,11 @@ async function runCleanup(flags) {
147
157
  || !commands[resource]?.[action]) {
148
158
  throw new UsageError(`Invalid cleanup argv: ${entry.cleanup.argv.join(" ")}`);
149
159
  }
160
+ if (resource === "project"
161
+ && action === "delete"
162
+ && typeof parsed.flags["expect-project-incarnation"] !== "string") {
163
+ throw new UsageError("Project cleanup entry is not bound to a project incarnation. Refusing deletion after possible project-key reuse.", "validation_failed", "Capture a new cleanup entry from the current CLI. Legacy entries cannot safely delete projects.");
164
+ }
150
165
  if (resource === "app"
151
166
  && action === "delete-instance"
152
167
  && parsed.flags["unconfirmed-creation"] !== true
@@ -1194,6 +1209,8 @@ const MISSING_PROJECT_KEY_ERROR_PREFIX = "projectKey is required";
1194
1209
  function errorExitCode(err) {
1195
1210
  if (err instanceof CommandResultFailure)
1196
1211
  return err.exitCode;
1212
+ if (err instanceof ClientValidationError && err.code === "ambiguous_outcome")
1213
+ return 2;
1197
1214
  if (err instanceof UsageError || err instanceof ClientValidationError)
1198
1215
  return 1;
1199
1216
  if (err instanceof DataikuError)
@@ -1205,14 +1222,30 @@ function errorExitCode(err) {
1205
1222
  function buildErrorReport(err) {
1206
1223
  const context = rawCommandContext();
1207
1224
  const exitCode = errorExitCode(err);
1225
+ if (err instanceof ClientValidationError && err.code === "ambiguous_outcome") {
1226
+ return {
1227
+ type: "error",
1228
+ ok: false,
1229
+ error: err.message,
1230
+ code: err.code,
1231
+ category: "dss",
1232
+ exitCode,
1233
+ ...(err.hint ? { hint: err.hint, } : {}),
1234
+ ...(err.details ? { details: err.details, } : {}),
1235
+ ...context,
1236
+ };
1237
+ }
1208
1238
  if (err instanceof UsageError || err instanceof ClientValidationError) {
1209
1239
  return {
1210
1240
  type: "error",
1211
1241
  ok: false,
1212
1242
  error: err.message,
1213
1243
  code: err.code,
1214
- category: "usage",
1244
+ category: err.code === "target_absence_unverifiable"
1245
+ ? "permission_or_environment"
1246
+ : "usage",
1215
1247
  exitCode,
1248
+ ...(err.code === "target_absence_unverifiable" ? { retryable: false, } : {}),
1216
1249
  ...(err.hint ? { hint: err.hint, } : {}),
1217
1250
  ...(err.details ? { details: err.details, } : {}),
1218
1251
  ...context,
@@ -1346,6 +1379,14 @@ async function main() {
1346
1379
  writeCommandResult(plan);
1347
1380
  return;
1348
1381
  }
1382
+ if (actionMeta.localHandler) {
1383
+ const result = await actionMeta.localHandler(args, flags);
1384
+ const failureExitCode = commandFailureExitCode(result);
1385
+ if (failureExitCode !== undefined)
1386
+ throw new CommandResultFailure(result, failureExitCode);
1387
+ writeCommandResult(result);
1388
+ return;
1389
+ }
1349
1390
  const { url, apiKey, projectKey, tlsRejectUnauthorized, caCertPath, } = resolveCredentials(flags);
1350
1391
  currentCommandContext.projectKey = projectKey;
1351
1392
  if (!url) {
@@ -45,6 +45,21 @@ export interface DataikuClientTraceEvent {
45
45
  elapsedMs?: number;
46
46
  detail?: string;
47
47
  }
48
+ /**
49
+ * Selected response metadata captured alongside a public API response body.
50
+ * A fixed whitelist of non-sensitive headers: authorization data is never
51
+ * returned. Null means the header was absent.
52
+ */
53
+ export interface DataikuClientResponseMeta {
54
+ /** `DSS-Version` — version of the DSS backend answering the request. */
55
+ dssVersion: string | null;
56
+ /** `DSS-API-Version` — version of the API server handling the request. */
57
+ dssApiVersion: string | null;
58
+ /** `Date` — origin server timestamp, when present. */
59
+ date: string | null;
60
+ /** Server-provided request id, when present. */
61
+ requestId: string | null;
62
+ }
48
63
  export interface DataikuClientConfig {
49
64
  /** DSS base URL (e.g. https://dss.example.com) */
50
65
  url: string;
@@ -163,6 +178,15 @@ export declare class DataikuClient {
163
178
  getRequestTimeoutMs(): number;
164
179
  resolveProjectKey(paramValue?: string): string;
165
180
  get<T = unknown>(path: string): Promise<T>;
181
+ /**
182
+ * GET returning the parsed JSON body plus selected response metadata
183
+ * (documented DSS version headers, server date, request id). Authorization
184
+ * headers are never included.
185
+ */
186
+ getWithMetadata<T = unknown>(path: string): Promise<{
187
+ data: T;
188
+ meta: DataikuClientResponseMeta;
189
+ }>;
166
190
  getText(path: string): Promise<string>;
167
191
  getTextLimited(path: string, maxBytes: number): Promise<{
168
192
  text: string;
@@ -180,10 +204,13 @@ export declare class DataikuClient {
180
204
  put<T = unknown>(path: string, body: unknown): Promise<T>;
181
205
  del(path: string): Promise<void>;
182
206
  putVoid(path: string, body: unknown): Promise<void>;
183
- upload(path: string, filePath: string): Promise<void>;
207
+ private uploadResponse;
208
+ upload(path: string, filePath: string, fileName?: string): Promise<void>;
209
+ uploadJson<T>(path: string, filePath: string, fileName?: string): Promise<T>;
184
210
  stream(path: string): Promise<Response>;
185
211
  private getHeaders;
186
212
  private getAnyHeaders;
213
+ private responseMeta;
187
214
  private logTrace;
188
215
  /**
189
216
  * Validate raw data against a TypeBox schema, throwing on structural mismatch.
@@ -1,4 +1,5 @@
1
1
  import { readFileSync, } from "node:fs";
2
+ import { basename, } from "node:path";
2
3
  import { getCACertificates, } from "node:tls";
3
4
  import { Value, } from "@sinclair/typebox/value";
4
5
  import { safeParseSchema, } from "./schemas.js";
@@ -360,6 +361,19 @@ export class DataikuClient {
360
361
  });
361
362
  return this.parseJsonResponse(res);
362
363
  }
364
+ /**
365
+ * GET returning the parsed JSON body plus selected response metadata
366
+ * (documented DSS version headers, server date, request id). Authorization
367
+ * headers are never included.
368
+ */
369
+ async getWithMetadata(path) {
370
+ const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
371
+ method: "GET",
372
+ headers: this.getHeaders(),
373
+ });
374
+ const data = await this.parseJsonResponse(res);
375
+ return { data, meta: this.responseMeta(res.headers), };
376
+ }
363
377
  async getText(path) {
364
378
  const res = await this.fetchWithRetry(`${this.baseUrl}${path}`, {
365
379
  method: "GET",
@@ -464,19 +478,23 @@ export class DataikuClient {
464
478
  body: JSON.stringify(body),
465
479
  });
466
480
  }
467
- async upload(path, filePath) {
468
- const { openAsBlob, } = await import("node:fs");
469
- const { basename, } = await import("node:path");
470
- const fileBlob = await openAsBlob(filePath);
471
- const fileName = basename(filePath);
481
+ async uploadResponse(path, filePath, fileName) {
482
+ const fileBlob = Bun.file(filePath);
472
483
  const formData = new FormData();
473
- formData.append("file", fileBlob, fileName);
474
- await this.fetchWithRetry(`${this.baseUrl}${path}`, {
484
+ formData.append("file", fileBlob, fileName ?? basename(filePath));
485
+ return this.fetchWithRetry(`${this.baseUrl}${path}`, {
475
486
  method: "POST",
476
487
  headers: { Authorization: `Bearer ${this.apiKey}`, },
477
488
  body: formData,
478
489
  });
479
490
  }
491
+ async upload(path, filePath, fileName) {
492
+ await this.uploadResponse(path, filePath, fileName);
493
+ }
494
+ async uploadJson(path, filePath, fileName) {
495
+ const response = await this.uploadResponse(path, filePath, fileName);
496
+ return this.parseJsonResponse(response);
497
+ }
480
498
  async stream(path) {
481
499
  return this.fetchWithRetry(`${this.baseUrl}${path}`, {
482
500
  method: "GET",
@@ -497,6 +515,15 @@ export class DataikuClient {
497
515
  Accept: "*/*",
498
516
  };
499
517
  }
518
+ responseMeta(headers) {
519
+ // Fixed non-sensitive whitelist. `Headers.get` is case-insensitive.
520
+ return {
521
+ dssVersion: headers.get("dss-version"),
522
+ dssApiVersion: headers.get("dss-api-version"),
523
+ date: headers.get("date"),
524
+ requestId: this.requestIdFromHeaders(headers) ?? null,
525
+ };
526
+ }
500
527
  logTrace(event) {
501
528
  if (this.verbose)
502
529
  this.onTrace({ type: "trace", ...event, });
@@ -1,5 +1,5 @@
1
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" | "validation_failed" | "transient" | "long_running_failure" | "command_result_failure" | "assertion_failed" | "ambiguous_outcome" | "internal_error";
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";
3
3
  export declare function dataikuErrorCode(category: DataikuErrorCategory): StableErrorCode;
4
4
  export interface DataikuErrorTaxonomy {
5
5
  category: DataikuErrorCategory;
@@ -12,7 +12,7 @@ export { type ConnectionSchemaListOptions, ConnectionsResource, type ConnectionT
12
12
  export { ContinuousActivitiesResource, } from "./resources/continuous-activities.js";
13
13
  export { DashboardsResource, } from "./resources/dashboards.js";
14
14
  export { DataQualityResource, } from "./resources/data-quality.js";
15
- export { type DatasetBuildValidationResult, type DatasetCloneOptions, type DatasetCloneResult, type DatasetSchemaColumnInput, DatasetsResource, } from "./resources/datasets.js";
15
+ export { type DatasetBuildValidationResult, type DatasetCloneOptions, type DatasetCloneResult, type DatasetSchemaColumnInput, DatasetsResource, type UploadDatasetFileOptions, type UploadDatasetFileResult, type UploadedFileMetadata, } from "./resources/datasets.js";
16
16
  export { DiscussionsResource, } from "./resources/discussions.js";
17
17
  export { type FlowZoneItemInput, FlowZonesResource, } from "./resources/flow-zones.js";
18
18
  export { FoldersResource, } from "./resources/folders.js";
@@ -26,7 +26,7 @@ export * from "./resources/model-evaluation-stores.js";
26
26
  export { NotebooksResource, } from "./resources/notebooks.js";
27
27
  export * from "./resources/project-git.js";
28
28
  export { ProjectLibraryResource, } from "./resources/project-library.js";
29
- export { type FlowMapResult, ProjectsResource, } from "./resources/projects.js";
29
+ export { type FlowMapResult, type ProjectImportProcessResult, type ProjectImportResult, type ProjectImportSettings, type ProjectImportUploadResult, ProjectsResource, } from "./resources/projects.js";
30
30
  export { type RecipeCloneOptions, type RecipeCloneResult, type RecipeGraphReference, type RecipeGraphValidationResult, type RecipeRunOptions, type RecipeRunOutput, type RecipeRunResult, RecipesResource, } from "./resources/recipes.js";
31
31
  export * from "./resources/saved-models.js";
32
32
  export { normalizeScenarioUpdateData, SCENARIO_CANONICAL_EDITABLE_FIELDS, type ScenarioFieldChange, type ScenarioFieldMismatch, type ScenarioScriptRunResult, ScenariosResource, type ScenarioUpdateNormalization, type ScenarioUpdatePreview, scenarioUpdatePreview, type ScenarioUpdateResult, } from "./resources/scenarios.js";
@@ -42,5 +42,6 @@ export type { SafeParseResult, } from "./schemas.js";
42
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";
43
43
  export { deepMerge, } from "./utils/deep-merge.js";
44
44
  export { type NormalizedFlowEdge, type NormalizedFlowMap, type NormalizedFlowNode, normalizeFlowGraph, } from "./utils/flow-map.js";
45
+ export * from "./utils/project-archive.js";
45
46
  export { sanitizeFileName, } from "./utils/sanitize.js";
46
47
  export { validateStreamColumns, } from "./resources/datasets.js";
package/dist/src/index.js CHANGED
@@ -46,6 +46,7 @@ export { BuildModeSchema, CodeEnvActionResultSchema, CodeEnvCreateOptionsSchema,
46
46
  // Utilities
47
47
  export { deepMerge, } from "./utils/deep-merge.js";
48
48
  export { normalizeFlowGraph, } from "./utils/flow-map.js";
49
+ export * from "./utils/project-archive.js";
49
50
  export { sanitizeFileName, } from "./utils/sanitize.js";
50
51
  // Stream validation
51
52
  export { validateStreamColumns, } from "./resources/datasets.js";
@@ -32,6 +32,25 @@ export interface DatasetCloneResult {
32
32
  created: Record<string, unknown>;
33
33
  settings: Record<string, unknown>;
34
34
  }
35
+ export interface UploadedFileMetadata {
36
+ filename: string;
37
+ path?: string;
38
+ length?: number;
39
+ mime?: string;
40
+ weird?: boolean;
41
+ [key: string]: unknown;
42
+ }
43
+ export interface UploadDatasetFileOptions {
44
+ projectKey?: string;
45
+ fileName: string;
46
+ }
47
+ export interface UploadDatasetFileResult {
48
+ datasetName: string;
49
+ projectKey: string;
50
+ fileName: string;
51
+ bytes: number;
52
+ after: UploadedFileMetadata;
53
+ }
35
54
  /**
36
55
  * Compare streamed TSV header columns against a known dataset schema.
37
56
  * Returns an array of warning strings (empty if all columns match).
@@ -49,6 +68,11 @@ export declare class DatasetsResource extends BaseResource {
49
68
  schema(datasetName: string, projectKey?: string): Promise<DatasetSchema>;
50
69
  /** Replace dataset schema columns directly through the schema endpoint. */
51
70
  updateSchema(datasetName: string, columns: DatasetSchemaColumnInput[], projectKey?: string): Promise<void>;
71
+ /**
72
+ * Get the raw dataset schema object exactly as the DSS schema endpoint
73
+ * returns it, without schema validation — used for deterministic comparison.
74
+ */
75
+ getSchemaObject(datasetName: string, projectKey?: string): Promise<unknown>;
52
76
  /**
53
77
  * Preview dataset rows as structured data: column names plus row arrays,
54
78
  * mirroring the sql query shape ({ columns, rows, rowCount }). Streams TSV
@@ -70,6 +94,21 @@ export declare class DatasetsResource extends BaseResource {
70
94
  }>;
71
95
  rows: string[][];
72
96
  rowCount: number;
97
+ truncated: boolean;
98
+ limit: number;
99
+ }>;
100
+ /**
101
+ * Count dataset rows by streaming the TSV data endpoint and stopping as soon
102
+ * as `expected + 1` rows have been seen, so a mismatched dataset is never
103
+ * fully scanned. Returns the observed count together with `exact` (false when
104
+ * the probe cap was reached, i.e. the count is a lower bound) and whether the
105
+ * count satisfies the assertion.
106
+ */
107
+ assertRowCount(datasetName: string, expected: number, projectKey?: string): Promise<{
108
+ expected: number;
109
+ count: number;
110
+ exact: boolean;
111
+ satisfied: boolean;
73
112
  }>;
74
113
  /** Get dataset metadata (tags, custom fields, checklists). */
75
114
  metadata(datasetName: string, projectKey?: string): Promise<Record<string, unknown>>;
@@ -102,6 +141,10 @@ export declare class DatasetsResource extends BaseResource {
102
141
  create(opts: DatasetCreateOptions): Promise<Record<string, unknown>>;
103
142
  /** Validate common build blockers before running a dataset build. */
104
143
  validateBuildSettings(datasetName: string, projectKey?: string): Promise<DatasetBuildValidationResult>;
144
+ /** List files stored by an UploadedFiles dataset. */
145
+ listUploadedFiles(datasetName: string, projectKey?: string): Promise<UploadedFileMetadata[]>;
146
+ /** Add a new file to an UploadedFiles dataset and verify its byte length. */
147
+ uploadDatasetFile(datasetName: string, localPath: string, opts: UploadDatasetFileOptions): Promise<UploadDatasetFileResult>;
105
148
  /** Clone dataset settings, preserving connection/storage, format, and schema fields. */
106
149
  clone(sourceName: string, targetName: string, opts?: DatasetCloneOptions): Promise<DatasetCloneResult>;
107
150
  /** Update a dataset by deep-merging a patch into the current definition. */