dataiku-sdk 0.10.1 → 0.11.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 (132) hide show
  1. package/dist/packages/types/src/index.d.ts +15 -2
  2. package/dist/packages/types/src/index.js +9 -1
  3. package/dist/src/cli/coerce.d.ts +36 -0
  4. package/dist/src/cli/coerce.js +239 -0
  5. package/dist/src/cli/commands/api-deployer.d.ts +2 -0
  6. package/dist/src/cli/commands/api-deployer.js +170 -0
  7. package/dist/src/cli/commands/api-service.d.ts +2 -0
  8. package/dist/src/cli/commands/api-service.js +102 -0
  9. package/dist/src/cli/commands/app.d.ts +2 -0
  10. package/dist/src/cli/commands/app.js +78 -0
  11. package/dist/src/cli/commands/bundle.d.ts +2 -0
  12. package/dist/src/cli/commands/bundle.js +107 -0
  13. package/dist/src/cli/commands/business-app.d.ts +2 -0
  14. package/dist/src/cli/commands/business-app.js +76 -0
  15. package/dist/src/cli/commands/code-env.d.ts +2 -0
  16. package/dist/src/cli/commands/code-env.js +255 -0
  17. package/dist/src/cli/commands/code.d.ts +2 -0
  18. package/dist/src/cli/commands/code.js +63 -0
  19. package/dist/src/cli/commands/connection.d.ts +2 -0
  20. package/dist/src/cli/commands/connection.js +54 -0
  21. package/dist/src/cli/commands/continuous-activity.d.ts +2 -0
  22. package/dist/src/cli/commands/continuous-activity.js +38 -0
  23. package/dist/src/cli/commands/dashboard.d.ts +2 -0
  24. package/dist/src/cli/commands/dashboard.js +99 -0
  25. package/dist/src/cli/commands/data-quality.d.ts +2 -0
  26. package/dist/src/cli/commands/data-quality.js +235 -0
  27. package/dist/src/cli/commands/dataset.d.ts +2 -0
  28. package/dist/src/cli/commands/dataset.js +288 -0
  29. package/dist/src/cli/commands/discussion.d.ts +2 -0
  30. package/dist/src/cli/commands/discussion.js +47 -0
  31. package/dist/src/cli/commands/doctor.d.ts +2 -0
  32. package/dist/src/cli/commands/doctor.js +9 -0
  33. package/dist/src/cli/commands/flow-zone.d.ts +2 -0
  34. package/dist/src/cli/commands/flow-zone.js +282 -0
  35. package/dist/src/cli/commands/folder.d.ts +2 -0
  36. package/dist/src/cli/commands/folder.js +202 -0
  37. package/dist/src/cli/commands/future.d.ts +2 -0
  38. package/dist/src/cli/commands/future.js +57 -0
  39. package/dist/src/cli/commands/index.d.ts +2 -0
  40. package/dist/src/cli/commands/index.js +70 -0
  41. package/dist/src/cli/commands/insight.d.ts +2 -0
  42. package/dist/src/cli/commands/insight.js +156 -0
  43. package/dist/src/cli/commands/job.d.ts +2 -0
  44. package/dist/src/cli/commands/job.js +406 -0
  45. package/dist/src/cli/commands/meaning.d.ts +2 -0
  46. package/dist/src/cli/commands/meaning.js +115 -0
  47. package/dist/src/cli/commands/metrics.d.ts +2 -0
  48. package/dist/src/cli/commands/metrics.js +39 -0
  49. package/dist/src/cli/commands/notebook.d.ts +2 -0
  50. package/dist/src/cli/commands/notebook.js +242 -0
  51. package/dist/src/cli/commands/project-deployer.d.ts +2 -0
  52. package/dist/src/cli/commands/project-deployer.js +118 -0
  53. package/dist/src/cli/commands/project-library.d.ts +2 -0
  54. package/dist/src/cli/commands/project-library.js +197 -0
  55. package/dist/src/cli/commands/project.d.ts +2 -0
  56. package/dist/src/cli/commands/project.js +132 -0
  57. package/dist/src/cli/commands/recipe.d.ts +2 -0
  58. package/dist/src/cli/commands/recipe.js +632 -0
  59. package/dist/src/cli/commands/scenario.d.ts +2 -0
  60. package/dist/src/cli/commands/scenario.js +190 -0
  61. package/dist/src/cli/commands/sql.d.ts +2 -0
  62. package/dist/src/cli/commands/sql.js +109 -0
  63. package/dist/src/cli/commands/statistics.d.ts +2 -0
  64. package/dist/src/cli/commands/statistics.js +165 -0
  65. package/dist/src/cli/commands/streaming-endpoint.d.ts +2 -0
  66. package/dist/src/cli/commands/streaming-endpoint.js +50 -0
  67. package/dist/src/cli/commands/variable.d.ts +2 -0
  68. package/dist/src/cli/commands/variable.js +49 -0
  69. package/dist/src/cli/commands/webapp.d.ts +2 -0
  70. package/dist/src/cli/commands/webapp.js +67 -0
  71. package/dist/src/cli/commands/wiki.d.ts +2 -0
  72. package/dist/src/cli/commands/wiki.js +123 -0
  73. package/dist/src/cli/commands/workspace.d.ts +2 -0
  74. package/dist/src/cli/commands/workspace.js +68 -0
  75. package/dist/src/cli/contract.d.ts +104 -0
  76. package/dist/src/cli/contract.js +2031 -0
  77. package/dist/src/cli/doctor.d.ts +104 -0
  78. package/dist/src/cli/doctor.js +356 -0
  79. package/dist/src/cli/env.d.ts +2 -0
  80. package/dist/src/cli/env.js +37 -0
  81. package/dist/src/cli/flags.d.ts +16 -0
  82. package/dist/src/cli/flags.js +255 -0
  83. package/dist/src/cli/helpers/cleanup.d.ts +3 -0
  84. package/dist/src/cli/helpers/cleanup.js +158 -0
  85. package/dist/src/cli/helpers/dataset.d.ts +2 -0
  86. package/dist/src/cli/helpers/dataset.js +17 -0
  87. package/dist/src/cli/helpers/flow-zone.d.ts +69 -0
  88. package/dist/src/cli/helpers/flow-zone.js +420 -0
  89. package/dist/src/cli/helpers/recipe.d.ts +11 -0
  90. package/dist/src/cli/helpers/recipe.js +83 -0
  91. package/dist/src/cli/output.d.ts +38 -0
  92. package/dist/src/cli/output.js +159 -0
  93. package/dist/src/cli/runtime.d.ts +15 -0
  94. package/dist/src/cli/runtime.js +59 -0
  95. package/dist/src/cli/types.d.ts +25 -0
  96. package/dist/src/cli/types.js +1 -0
  97. package/dist/src/cli/usage.d.ts +16 -0
  98. package/dist/src/cli/usage.js +80 -0
  99. package/dist/src/cli/version.d.ts +14 -0
  100. package/dist/src/cli/version.js +63 -0
  101. package/dist/src/cli.js +671 -8254
  102. package/dist/src/client.d.ts +1 -1
  103. package/dist/src/client.js +14 -13
  104. package/dist/src/errors.d.ts +6 -0
  105. package/dist/src/errors.js +102 -4
  106. package/dist/src/index.d.ts +3 -3
  107. package/dist/src/index.js +2 -2
  108. package/dist/src/resources/applications.d.ts +1 -1
  109. package/dist/src/resources/applications.js +27 -1
  110. package/dist/src/resources/continuous-activities.js +1 -0
  111. package/dist/src/resources/data-quality.js +5 -3
  112. package/dist/src/resources/datasets.d.ts +3 -0
  113. package/dist/src/resources/datasets.js +3 -0
  114. package/dist/src/resources/flow-zones.d.ts +2 -2
  115. package/dist/src/resources/flow-zones.js +4 -1
  116. package/dist/src/resources/meanings.d.ts +2 -0
  117. package/dist/src/resources/meanings.js +4 -0
  118. package/dist/src/resources/notebooks.d.ts +5 -7
  119. package/dist/src/resources/notebooks.js +10 -7
  120. package/dist/src/resources/projects.d.ts +1 -1
  121. package/dist/src/resources/projects.js +2 -2
  122. package/dist/src/resources/recipes.d.ts +3 -3
  123. package/dist/src/resources/recipes.js +50 -7
  124. package/dist/src/resources/scenarios.js +67 -26
  125. package/dist/src/resources/statistics.js +9 -0
  126. package/dist/src/schemas.d.ts +2 -2
  127. package/dist/src/schemas.js +1 -1
  128. package/dist/src/skill.js +2 -2
  129. package/dist/src/utils/sanitize.js +2 -1
  130. package/package.json +1 -1
  131. package/packages/types/dist/index.d.ts +15 -2
  132. package/packages/types/dist/index.js +9 -1
@@ -138,7 +138,7 @@ export declare class DataikuClient {
138
138
  get workspaces(): WorkspacesResource;
139
139
  get metrics(): MetricsResource;
140
140
  get meanings(): MeaningsResource;
141
- constructor(config: DataikuClientConfig);
141
+ constructor(config?: DataikuClientConfig);
142
142
  getRequestTimeoutMs(): number;
143
143
  resolveProjectKey(paramValue?: string): string;
144
144
  get<T = unknown>(path: string): Promise<T>;
@@ -270,22 +270,23 @@ export class DataikuClient {
270
270
  return (this.meaningsResource ??= new MeaningsResource(this));
271
271
  }
272
272
  constructor(config) {
273
- const url = config.url?.trim();
274
- if (!url)
275
- throw new Error("DataikuClientConfig.url is required and must not be empty");
276
- const apiKey = config.apiKey?.trim();
277
- if (!apiKey)
278
- throw new Error("DataikuClientConfig.apiKey is required and must not be empty");
273
+ const envUrl = process.env["DATAIKU_URL"]?.trim();
274
+ const envApiKey = process.env["DATAIKU_API_KEY"]?.trim();
275
+ const url = config?.url?.trim() || envUrl;
276
+ const apiKey = config?.apiKey?.trim() || envApiKey;
277
+ if (!url || !apiKey) {
278
+ throw new Error("Dataiku URL and API key are required: pass {url, apiKey} or set DATAIKU_URL/DATAIKU_API_KEY");
279
+ }
279
280
  this.baseUrl = url.replace(/\/+$/, "");
280
281
  this.apiKey = apiKey;
281
- this.defaultProjectKey = config.projectKey?.trim() || undefined;
282
- this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
283
- const rawMax = config.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS;
282
+ this.defaultProjectKey = config?.projectKey?.trim() || undefined;
283
+ this.requestTimeoutMs = config?.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
284
+ const rawMax = config?.retryMaxAttempts ?? DEFAULT_RETRY_MAX_ATTEMPTS;
284
285
  this.retryMaxAttempts = Math.min(Math.max(1, rawMax), MAX_RETRY_ATTEMPTS_CAP);
285
- this.verbose = config.verbose === true;
286
- this.tlsOptions = buildFetchTlsOptions(config);
287
- this.onTrace = config.onTrace ?? defaultTrace;
288
- this.onValidationWarning = config.onValidationWarning ?? defaultValidationWarning;
286
+ this.verbose = config?.verbose === true;
287
+ this.tlsOptions = config ? buildFetchTlsOptions(config) : undefined;
288
+ this.onTrace = config?.onTrace ?? defaultTrace;
289
+ this.onValidationWarning = config?.onValidationWarning ?? defaultValidationWarning;
289
290
  }
290
291
  getRequestTimeoutMs() {
291
292
  return this.requestTimeoutMs;
@@ -15,6 +15,12 @@ export interface DataikuRetryMetadata {
15
15
  delaysMs: number[];
16
16
  timedOut: boolean;
17
17
  }
18
+ export declare class ClientValidationError extends Error {
19
+ readonly code: StableErrorCode;
20
+ readonly hint?: string;
21
+ readonly details?: Record<string, unknown>;
22
+ constructor(message: string, code?: StableErrorCode, hint?: string, details?: Record<string, unknown>);
23
+ }
18
24
  export declare function classifyDataikuError(status: number, body: string): DataikuErrorTaxonomy;
19
25
  export declare class DataikuError extends Error {
20
26
  status: number;
@@ -12,8 +12,71 @@ export function dataikuErrorCode(category) {
12
12
  return "internal_error";
13
13
  }
14
14
  }
15
+ export class ClientValidationError extends Error {
16
+ code;
17
+ hint;
18
+ details;
19
+ constructor(message, code = "validation_failed", hint, details) {
20
+ super(message);
21
+ this.name = "ClientValidationError";
22
+ this.code = code;
23
+ this.hint = hint;
24
+ this.details = details;
25
+ }
26
+ }
15
27
  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.";
16
28
  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.";
29
+ const MAX_ERROR_SUMMARY_LENGTH = 200;
30
+ function isHtmlResponseBody(body) {
31
+ const lowerTrimmed = body.trimStart().slice(0, 500).toLowerCase();
32
+ return lowerTrimmed.startsWith("<")
33
+ || lowerTrimmed.includes("<!doctype html")
34
+ || lowerTrimmed.includes("<html")
35
+ || lowerTrimmed.includes("<body")
36
+ || lowerTrimmed.includes("<title");
37
+ }
38
+ function stripServerFilesystemPaths(text) {
39
+ return text
40
+ .replace(/\b[A-Za-z]:\\[^\s"'`<>),\]}]+/g, "[server path]")
41
+ .replace(/(^|[\s("'`[{])\/(?=[^\s"'`<>),\]}]*\/)(?!(?:public|dip|api|backend|auth|login|projects?|datasets?|recipes?|scenarios?|folders?)(?:\/|$))[^\s"'`<>),\]}]+/g, "$1[server path]");
42
+ }
43
+ function decodeHtmlEntities(text) {
44
+ return text
45
+ .replace(/&nbsp;/gi, " ")
46
+ .replace(/&amp;/gi, "&")
47
+ .replace(/&lt;/gi, "<")
48
+ .replace(/&gt;/gi, ">")
49
+ .replace(/&quot;/gi, '"')
50
+ .replace(/&#39;/g, "'")
51
+ .replace(/&apos;/gi, "'");
52
+ }
53
+ function firstHtmlTextLine(body) {
54
+ const text = decodeHtmlEntities(body
55
+ .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, " ")
56
+ .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, " ")
57
+ .replace(/<[^>]+>/g, "\n"));
58
+ return text
59
+ .split(/\r?\n/g)
60
+ .map((line) => line.trim())
61
+ .find((line) => line.length > 0);
62
+ }
63
+ function conciseErrorSummary(text) {
64
+ const sanitized = stripServerFilesystemPaths(text);
65
+ return sanitized.length > MAX_ERROR_SUMMARY_LENGTH
66
+ ? `${sanitized.slice(0, MAX_ERROR_SUMMARY_LENGTH)}…`
67
+ : sanitized;
68
+ }
69
+ function summarizeHtmlErrorBody(body) {
70
+ const textLine = firstHtmlTextLine(body);
71
+ if (!textLine)
72
+ return "HTML error page from DSS";
73
+ return `HTML error page from DSS: ${conciseErrorSummary(textLine)}`;
74
+ }
75
+ function summarizeErrorText(text) {
76
+ if (isHtmlResponseBody(text))
77
+ return summarizeHtmlErrorBody(text);
78
+ return conciseErrorSummary(text);
79
+ }
17
80
  function isCertificateTrustFailure(lowerBody) {
18
81
  return lowerBody.includes("unable to verify the first certificate")
19
82
  || lowerBody.includes("unable to get local issuer certificate")
@@ -69,6 +132,15 @@ export function classifyDataikuError(status, body) {
69
132
  retryHint: "SQL recipes require SQL/Athena-backed input datasets. Use a SQL-compatible input, associate the S3 dataset with Athena, or create a Python recipe for file/S3 inputs.",
70
133
  };
71
134
  }
135
+ const isLicenseDenied = status >= 400
136
+ && lowerBody.includes("license does not allow");
137
+ if (isLicenseDenied) {
138
+ return {
139
+ category: "forbidden",
140
+ retryable: false,
141
+ retryHint: "DSS license or enabled features do not allow this operation. Contact a DSS administrator; do not retry unchanged.",
142
+ };
143
+ }
72
144
  const isMissingDatasetRootPath = status === 500
73
145
  && lowerBody.includes("root path of the dataset")
74
146
  && lowerBody.includes("does not exist");
@@ -79,10 +151,36 @@ export function classifyDataikuError(status, body) {
79
151
  retryHint: "Dataset files are missing on storage. Build/materialize the dataset or upstream recipes before preview/download.",
80
152
  };
81
153
  }
154
+ const isReadDirectoryAsFile = status >= 500
155
+ && lowerBody.includes("cannot read directory as file");
156
+ if (isReadDirectoryAsFile) {
157
+ return {
158
+ category: "validation",
159
+ retryable: false,
160
+ retryHint: "The path refers to a directory, not a file. List its contents instead of reading it as a file; do not retry unchanged.",
161
+ };
162
+ }
163
+ const apostropheNormalizedBody = lowerBody.replace(/\\u0027|\u2019/g, "'");
164
+ const isServerObjectMissingContraction = status >= 500
165
+ && apostropheNormalizedBody.includes("doesn't exist");
166
+ if (isServerObjectMissingContraction) {
167
+ return {
168
+ category: "not_found",
169
+ retryable: false,
170
+ retryHint: "Requested object was not found. Verify the identifier before retrying.",
171
+ };
172
+ }
173
+ const hasServerMissingObjectToken = lowerBody.includes("package")
174
+ || lowerBody.includes("directory");
175
+ const hasServerMissingObjectLanguage = lowerBody.includes("does not exist")
176
+ || lowerBody.includes("not found");
177
+ const isServerFilesystemNotFoundLike = status >= 500
178
+ && (lowerBody.includes("not a file")
179
+ || (hasServerMissingObjectToken && hasServerMissingObjectLanguage));
82
180
  const isServerNotFoundLike = status >= 500
83
181
  && (lowerBody.includes("not found") || lowerBody.includes("does not exist"))
84
182
  && ["dataset", "recipe", "scenario", "project", "folder",].some((token) => lowerBody.includes(token));
85
- if (isServerNotFoundLike) {
183
+ if (isServerFilesystemNotFoundLike || isServerNotFoundLike) {
86
184
  return {
87
185
  category: "not_found",
88
186
  retryable: false,
@@ -133,7 +231,7 @@ export function classifyDataikuError(status, body) {
133
231
  retryHint: BUSINESS_APPS_API_UNAVAILABLE_HINT,
134
232
  };
135
233
  }
136
- const isHtmlGatewayResponse = lowerBody.includes("<!doctype html>");
234
+ const isHtmlGatewayResponse = isHtmlResponseBody(body);
137
235
  return {
138
236
  category: "not_found",
139
237
  retryable: false,
@@ -195,14 +293,14 @@ export class DataikuError extends Error {
195
293
  try {
196
294
  const parsed = JSON.parse(body);
197
295
  if (parsed.message)
198
- return String(parsed.message);
296
+ return summarizeErrorText(String(parsed.message));
199
297
  }
200
298
  catch {
201
299
  // not JSON — use raw body
202
300
  }
203
301
  if (!body)
204
302
  return "(empty response body)";
205
- return body.length > 200 ? `${body.slice(0, 200)}…` : body;
303
+ return summarizeErrorText(body);
206
304
  }
207
305
  static formatRetryMetadata(retry) {
208
306
  if (!retry)
@@ -1,7 +1,7 @@
1
1
  export { DataikuClient, type DataikuClientConfig, type DataikuClientTraceEvent, } from "./client.js";
2
2
  export { type CredentialValidationOptions, type CredentialValidationResult, validateCredentials, } from "./auth.js";
3
3
  export { type DssCredentials, getConfigDir, getCredentialsPath, loadCredentials, saveCredentials, } from "./config.js";
4
- export { DataikuError, type DataikuErrorCategory, type DataikuErrorTaxonomy, type DataikuRetryMetadata, } from "./errors.js";
4
+ export { ClientValidationError, DataikuError, type DataikuErrorCategory, type DataikuErrorTaxonomy, type DataikuRetryMetadata, } from "./errors.js";
5
5
  export { ApiDeployerResource, } from "./resources/api-deployer.js";
6
6
  export { ApiServicesResource, } from "./resources/api-services.js";
7
7
  export { ApplicationsResource, } from "./resources/applications.js";
@@ -32,9 +32,9 @@ export { VariablesResource, } from "./resources/variables.js";
32
32
  export { WebappsResource, } from "./resources/webapps.js";
33
33
  export { WikiResource, } from "./resources/wiki.js";
34
34
  export { WorkspacesResource, } from "./resources/workspaces.js";
35
- 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, ProjectMetadataSchema, ProjectSummaryArraySchema, ProjectSummarySchema, ProjectVariablesSchema, RecipeCreateOptionsSchema, RecipeCreateResultSchema, RecipeDetailsSchema, RecipeSummaryArraySchema, RecipeSummarySchema, safeParseSchema, ScenarioDetailsSchema, ScenarioStatusSchema, ScenarioSummaryArraySchema, ScenarioSummarySchema, ScenarioWaitResultSchema, SqlNotebookCellSchema, SqlNotebookContentSchema, SqlNotebookSummaryArraySchema, SqlNotebookSummarySchema, SqlQueryResponseSchema, SqlQueryResultSchema, SqlQuerySchemaSchema, WikiArticleDataArraySchema, WikiArticleDataSchema, WikiArticleMetadataSchema, WikiSettingsSchema, WikiTaxonomyNodeSchema, } from "./schemas.js";
35
+ 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, 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";
36
36
  export type { SafeParseResult, } from "./schemas.js";
37
- 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, ProjectMetadata, ProjectSummary, ProjectVariables, RecipeCreateOptions, RecipeCreateResult, RecipeDetails, RecipeSummary, ScenarioDetails, ScenarioStatus, ScenarioSummary, ScenarioWaitResult, SqlNotebookCell, SqlNotebookContent, SqlNotebookSummary, SqlQueryResponse, SqlQueryResult, SqlQuerySchema, WikiArticleData, WikiArticleMetadata, WikiSettings, WikiTaxonomyNode, } from "./schemas.js";
37
+ 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, 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";
38
38
  export { deepMerge, } from "./utils/deep-merge.js";
39
39
  export { type NormalizedFlowEdge, type NormalizedFlowMap, type NormalizedFlowNode, normalizeFlowGraph, } from "./utils/flow-map.js";
40
40
  export { sanitizeFileName, } from "./utils/sanitize.js";
package/dist/src/index.js CHANGED
@@ -4,7 +4,7 @@ export { DataikuClient, } from "./client.js";
4
4
  export { validateCredentials, } from "./auth.js";
5
5
  export { getConfigDir, getCredentialsPath, loadCredentials, saveCredentials, } from "./config.js";
6
6
  // Errors
7
- export { DataikuError, } from "./errors.js";
7
+ export { ClientValidationError, DataikuError, } from "./errors.js";
8
8
  // Resources (for advanced use / extension)
9
9
  export { ApiDeployerResource, } from "./resources/api-deployer.js";
10
10
  export { ApiServicesResource, } from "./resources/api-services.js";
@@ -37,7 +37,7 @@ export { WebappsResource, } from "./resources/webapps.js";
37
37
  export { WikiResource, } from "./resources/wiki.js";
38
38
  export { WorkspacesResource, } from "./resources/workspaces.js";
39
39
  // Schemas (TypeBox schema objects for runtime validation)
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, ProjectMetadataSchema, ProjectSummaryArraySchema, ProjectSummarySchema, ProjectVariablesSchema, RecipeCreateOptionsSchema, RecipeCreateResultSchema, RecipeDetailsSchema, RecipeSummaryArraySchema, RecipeSummarySchema, safeParseSchema, ScenarioDetailsSchema, ScenarioStatusSchema, ScenarioSummaryArraySchema, ScenarioSummarySchema, ScenarioWaitResultSchema, SqlNotebookCellSchema, SqlNotebookContentSchema, SqlNotebookSummaryArraySchema, SqlNotebookSummarySchema, SqlQueryResponseSchema, SqlQueryResultSchema, SqlQuerySchemaSchema, WikiArticleDataArraySchema, WikiArticleDataSchema, WikiArticleMetadataSchema, WikiSettingsSchema, WikiTaxonomyNodeSchema, } from "./schemas.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, 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";
41
41
  // Utilities
42
42
  export { deepMerge, } from "./utils/deep-merge.js";
43
43
  export { normalizeFlowGraph, } from "./utils/flow-map.js";
@@ -31,7 +31,7 @@ export declare class ApplicationsResource extends BaseResource {
31
31
  createInstance(appId: string, body: Record<string, unknown>): Promise<AppInstanceRef>;
32
32
  /** Get the manifest for an app instance project. */
33
33
  getInstanceManifest(projectKey?: string): Promise<Record<string, unknown>>;
34
- /** Save the manifest for an app instance project. */
34
+ /** Save the manifest for a Dataiku App template project (rejects classic app-instance projects). */
35
35
  saveInstanceManifest(manifest: Record<string, unknown>, projectKey?: string): Promise<void>;
36
36
  /** Delete an app instance project. */
37
37
  deleteInstance(projectKey?: string): Promise<void>;
@@ -1,3 +1,4 @@
1
+ import { ClientValidationError, DataikuError, } from "../errors.js";
1
2
  import { BaseResource, } from "./base.js";
2
3
  export class ApplicationsResource extends BaseResource {
3
4
  /** List all Dataiku Apps. */
@@ -20,12 +21,37 @@ export class ApplicationsResource extends BaseResource {
20
21
  async getInstanceManifest(projectKey) {
21
22
  return this.client.get(`/public/api/projects/${this.enc(projectKey)}/app-manifest`);
22
23
  }
23
- /** Save the manifest for an app instance project. */
24
+ /** Save the manifest for a Dataiku App template project (rejects classic app-instance projects). */
24
25
  async saveInstanceManifest(manifest, projectKey) {
26
+ const currentManifest = await this.getInstanceManifest(projectKey);
27
+ if (currentManifest.projectAppType === "APP_INSTANCE") {
28
+ throw new ClientValidationError("Classic Dataiku App instance manifests cannot be saved through the app-manifest endpoint; only Dataiku App template project manifests can be updated.", "validation_failed", "Save against the Dataiku App template project instead; existing classic app-instance manifests are read-only through this endpoint.", { projectAppType: "APP_INSTANCE", projectKey: this.resolveProjectKey(projectKey), });
29
+ }
25
30
  await this.client.putVoid(`/public/api/projects/${this.enc(projectKey)}/app-manifest`, manifest);
26
31
  }
27
32
  /** Delete an app instance project. */
28
33
  async deleteInstance(projectKey) {
34
+ let manifest;
35
+ try {
36
+ manifest = await this.getInstanceManifest(projectKey);
37
+ }
38
+ catch (error) {
39
+ // DSS answers the app-manifest probe with 400 "neither an app template nor an app
40
+ // instance" for ordinary projects; treat only that as "not an app instance". Rethrow
41
+ // everything else (404 not-found, transient, permission) so real failures are not masked.
42
+ if (error instanceof DataikuError && error.status === 400) {
43
+ manifest = undefined;
44
+ }
45
+ else {
46
+ throw error;
47
+ }
48
+ }
49
+ if (manifest?.projectAppType !== "APP_INSTANCE") {
50
+ throw new ClientValidationError("Only classic Dataiku App instance projects can be deleted through app delete-instance.", "validation_failed", "Use `dss app delete-instance` only for projects whose app manifest has projectAppType=APP_INSTANCE; use `dss project delete` for ordinary projects.", {
51
+ projectAppType: manifest?.projectAppType ?? null,
52
+ projectKey: this.resolveProjectKey(projectKey),
53
+ });
54
+ }
29
55
  await this.client.del(`/public/api/projects/${this.enc(projectKey)}`);
30
56
  }
31
57
  /** List all Business Apps. */
@@ -14,6 +14,7 @@ export class ContinuousActivitiesResource extends BaseResource {
14
14
  }
15
15
  /** Stop a continuous recipe activity. */
16
16
  async stop(recipeId, projectKey) {
17
+ await this.getStatus(recipeId, projectKey);
17
18
  await this.client.postText(`${this.activityPath(recipeId, projectKey)}/stop`);
18
19
  }
19
20
  activityPath(recipeId, projectKey) {
@@ -1,3 +1,4 @@
1
+ import { DataikuError, } from "../errors.js";
1
2
  import { DataQualityComputeResultSchema, DataQualityProjectStatusSchema, DataQualityRuleArraySchema, DataQualityRuleResultArraySchema, DataQualityRuleSchema, DataQualityRulesSchema, DataQualityStatusByPartitionSchema, DataQualityStatusSchema, DataQualityTimelineSchema, } from "../schemas.js";
2
3
  import { deepMerge, } from "../utils/deep-merge.js";
3
4
  import { BaseResource, } from "./base.js";
@@ -49,13 +50,14 @@ export class DataQualityResource extends BaseResource {
49
50
  async getRule(datasetName, ruleId, projectKey) {
50
51
  const rules = await this.listRules(datasetName, projectKey);
51
52
  const rule = rules.find((candidate) => candidate.id === ruleId);
52
- if (!rule)
53
- throw new Error(`Data quality rule not found: ${ruleId}`);
53
+ if (!rule) {
54
+ throw new DataikuError(404, "Not Found", JSON.stringify({ message: `Data quality rule not found: ${ruleId}`, }));
55
+ }
54
56
  return rule;
55
57
  }
56
58
  async status(datasetName, projectKey) {
57
59
  const pk = this.resolveProjectKey(projectKey);
58
- const raw = await this.client.get(`${datasetPath(pk, datasetName)}/status`);
60
+ const raw = await this.client.get(`${datasetPath(pk, datasetName)}/status-by-partition`);
59
61
  return this.client.safeParse(DataQualityStatusSchema, raw, "dataQuality.status");
60
62
  }
61
63
  async statusByPartition(datasetName, opts = {}) {
@@ -8,6 +8,9 @@ export interface DatasetBuildValidationResult {
8
8
  path: string | null;
9
9
  formatType: string | null;
10
10
  warnings: string[];
11
+ validationScope: "configuration";
12
+ materializationChecked: false;
13
+ note: string;
11
14
  }
12
15
  export interface DatasetSchemaColumnInput {
13
16
  name: string;
@@ -530,6 +530,9 @@ export class DatasetsResource extends BaseResource {
530
530
  path,
531
531
  formatType,
532
532
  warnings,
533
+ validationScope: "configuration",
534
+ materializationChecked: false,
535
+ note: "Validates build configuration only; it does not verify storage file existence or materialized data.",
533
536
  };
534
537
  }
535
538
  /** Clone dataset settings, preserving connection/storage, format, and schema fields. */
@@ -20,6 +20,6 @@ export declare class FlowZonesResource extends BaseResource {
20
20
  moveItems(zoneId: string, items: FlowZoneItemInput[], projectKey?: string): Promise<FlowZone>;
21
21
  /** Move a single item into a flow zone. */
22
22
  moveItem(zoneId: string, item: FlowZoneItemInput, projectKey?: string): Promise<FlowZone>;
23
- /** Get the graph for a single flow zone. */
24
- graph(zoneId: string, projectKey?: string): Promise<unknown>;
23
+ /** Get the full flow graph, or the graph for a single non-default flow zone. */
24
+ graph(zoneId?: string, projectKey?: string): Promise<unknown>;
25
25
  }
@@ -54,8 +54,11 @@ export class FlowZonesResource extends BaseResource {
54
54
  async moveItem(zoneId, item, projectKey) {
55
55
  return this.moveItems(zoneId, [item,], projectKey);
56
56
  }
57
- /** Get the graph for a single flow zone. */
57
+ /** Get the full flow graph, or the graph for a single non-default flow zone. */
58
58
  async graph(zoneId, projectKey) {
59
+ if (zoneId === undefined || zoneId === "default") {
60
+ return this.client.get(`/public/api/projects/${this.enc(projectKey)}/flow/graph/`);
61
+ }
59
62
  return this.client.get(`/public/api/projects/${this.enc(projectKey)}/flow/zones/${encodeURIComponent(zoneId)}/graph`);
60
63
  }
61
64
  }
@@ -37,5 +37,7 @@ export declare class MeaningsResource extends BaseResource {
37
37
  create(id: string, label: string, type: MeaningType, body?: MeaningCreateBody): Promise<string>;
38
38
  /** Replace a user-defined meaning definition. */
39
39
  update(meaningId: string, body: MeaningDefinition): Promise<MeaningDefinition>;
40
+ /** Delete a user-defined meaning definition. */
41
+ delete(meaningId: string): Promise<void>;
40
42
  private meaningPath;
41
43
  }
@@ -27,6 +27,10 @@ export class MeaningsResource extends BaseResource {
27
27
  async update(meaningId, body) {
28
28
  return this.client.put(this.meaningPath(meaningId), body);
29
29
  }
30
+ /** Delete a user-defined meaning definition. */
31
+ async delete(meaningId) {
32
+ await this.client.del(this.meaningPath(meaningId));
33
+ }
30
34
  meaningPath(meaningId) {
31
35
  return `/public/api/meanings/${encodeURIComponent(meaningId)}`;
32
36
  }
@@ -5,15 +5,11 @@ export declare class NotebooksResource extends BaseResource {
5
5
  listJupyter(projectKey?: string): Promise<JupyterNotebookSummary[]>;
6
6
  /** Get the full content of a Jupyter notebook. */
7
7
  getJupyter(name: string, projectKey?: string): Promise<JupyterNotebookContent>;
8
+ /** Create a Jupyter notebook. */
9
+ createJupyter(name: string, content: JupyterNotebookContent, projectKey?: string): Promise<void>;
8
10
  /** Save (overwrite) a Jupyter notebook's content. */
9
11
  saveJupyter(name: string, content: JupyterNotebookContent, projectKey?: string): Promise<void>;
10
- /**
11
- * Delete a Jupyter notebook.
12
- *
13
- * The SDK intentionally does not expose notebook creation as a first-class
14
- * resource method yet; integration tests create disposable notebooks through
15
- * the documented project-level create endpoint.
16
- */
12
+ /** Delete a Jupyter notebook. */
17
13
  deleteJupyter(name: string, projectKey?: string): Promise<void>;
18
14
  /**
19
15
  * Clear all cell outputs from a Jupyter notebook.
@@ -36,6 +32,8 @@ export declare class NotebooksResource extends BaseResource {
36
32
  listSql(projectKey?: string): Promise<SqlNotebookSummary[]>;
37
33
  /** Get the full content of a SQL notebook. */
38
34
  getSql(id: string, projectKey?: string): Promise<SqlNotebookContent>;
35
+ /** Create a SQL notebook. */
36
+ createSql(id: string, content: SqlNotebookContent, projectKey?: string): Promise<void>;
39
37
  /** Save (overwrite) a SQL notebook's content. */
40
38
  saveSql(id: string, content: SqlNotebookContent, projectKey?: string): Promise<void>;
41
39
  /** Delete a SQL notebook. */
@@ -13,18 +13,17 @@ export class NotebooksResource extends BaseResource {
13
13
  const raw = await this.client.get(`/public/api/projects/${this.enc(projectKey)}/jupyter-notebooks/${nameEnc}`);
14
14
  return this.client.safeParse(JupyterNotebookContentSchema, raw, "notebooks.getJupyter");
15
15
  }
16
+ /** Create a Jupyter notebook. */
17
+ async createJupyter(name, content, projectKey) {
18
+ const nameEnc = encodeURIComponent(name);
19
+ await this.client.post(`/public/api/projects/${this.enc(projectKey)}/jupyter-notebooks/${nameEnc}`, content);
20
+ }
16
21
  /** Save (overwrite) a Jupyter notebook's content. */
17
22
  async saveJupyter(name, content, projectKey) {
18
23
  const nameEnc = encodeURIComponent(name);
19
24
  await this.client.putVoid(`/public/api/projects/${this.enc(projectKey)}/jupyter-notebooks/${nameEnc}`, content);
20
25
  }
21
- /**
22
- * Delete a Jupyter notebook.
23
- *
24
- * The SDK intentionally does not expose notebook creation as a first-class
25
- * resource method yet; integration tests create disposable notebooks through
26
- * the documented project-level create endpoint.
27
- */
26
+ /** Delete a Jupyter notebook. */
28
27
  async deleteJupyter(name, projectKey) {
29
28
  const nameEnc = encodeURIComponent(name);
30
29
  await this.client.del(`/public/api/projects/${this.enc(projectKey)}/jupyter-notebooks/${nameEnc}`);
@@ -74,6 +73,10 @@ export class NotebooksResource extends BaseResource {
74
73
  const raw = await this.client.get(`/public/api/projects/${this.enc(projectKey)}/sql-notebooks/${idEnc}`);
75
74
  return this.client.safeParse(SqlNotebookContentSchema, raw, "notebooks.getSql");
76
75
  }
76
+ /** Create a SQL notebook. */
77
+ async createSql(id, content, projectKey) {
78
+ await this.client.post(`/public/api/projects/${this.enc(projectKey)}/sql-notebooks/`, { ...content, id, projectKey: this.resolveProjectKey(projectKey), });
79
+ }
77
80
  /** Save (overwrite) a SQL notebook's content. */
78
81
  async saveSql(id, content, projectKey) {
79
82
  const idEnc = encodeURIComponent(id);
@@ -69,7 +69,7 @@ export declare class ProjectsResource extends BaseResource {
69
69
  private postStream;
70
70
  private uploadJson;
71
71
  /** Create a new project. */
72
- createProject(projectKey: string, name: string, ownerLogin?: string, settings?: ProjectLifecycleSettings | null): Promise<string>;
72
+ createProject(projectKey: string, name: string, ownerLogin: string, settings?: ProjectLifecycleSettings | null): Promise<Record<string, unknown>>;
73
73
  /** Delete a project using the lifecycle endpoint. */
74
74
  deleteProject(projectKey: string, dropData?: boolean): Promise<void>;
75
75
  /** Duplicate a project. */
@@ -130,10 +130,10 @@ export class ProjectsResource extends BaseResource {
130
130
  }
131
131
  /** Create a new project. */
132
132
  async createProject(projectKey, name, ownerLogin, settings) {
133
- return this.client.postText("/public/api/projects/", {
133
+ return this.client.post("/public/api/projects/", {
134
134
  projectKey,
135
135
  name,
136
- owner: ownerLogin ?? null,
136
+ owner: ownerLogin,
137
137
  settings: settings ?? null,
138
138
  description: null,
139
139
  permissions: [],
@@ -103,10 +103,10 @@ export declare class RecipesResource extends BaseResource {
103
103
  /** Clone recipe graph/settings and optionally clone a dataset output. */
104
104
  clone(sourceName: string, opts: RecipeCloneOptions): Promise<RecipeCloneResult>;
105
105
  /**
106
- * Download a recipe code payload to a local file.
106
+ * Download a recipe code payload to a local file.
107
107
 
108
- * Returns the path to the written file.
109
- */
108
+ * Returns the path to the written file.
109
+ */
110
110
  downloadCode(recipeName: string, opts?: {
111
111
  outputPath?: string;
112
112
  projectKey?: string;
@@ -147,6 +147,20 @@ function rewriteSqlTableReferences(payload, rewrites) {
147
147
  }
148
148
  return next;
149
149
  }
150
+ function rewritePayloadText(payload, rewrites) {
151
+ const entries = Object
152
+ .entries(rewrites)
153
+ .filter(([from,]) => from.length > 0)
154
+ .sort(([left,], [right,]) => right.length - left.length);
155
+ if (entries.length === 0)
156
+ return payload;
157
+ const replacements = new Map(entries);
158
+ const alternatives = entries
159
+ .map(([from,]) => escapedRegExp(from))
160
+ .join("|");
161
+ const pattern = new RegExp(String.raw `(?<![A-Za-z0-9_$])(${alternatives})(?![A-Za-z0-9_$])`, "g");
162
+ return payload.replace(pattern, (match) => replacements.get(match) ?? match);
163
+ }
150
164
  function rewritePayload(payload, rewrites, payloadTextRewrites = {}, recipeType) {
151
165
  if (payload === undefined
152
166
  || (Object.keys(rewrites).length === 0 && Object.keys(payloadTextRewrites).length === 0)) {
@@ -162,10 +176,7 @@ function rewritePayload(payload, rewrites, payloadTextRewrites = {}, recipeType)
162
176
  if (isSqlRecipeType(recipeType)) {
163
177
  next = rewriteSqlTableReferences(next, rewrites);
164
178
  }
165
- for (const [from, to,] of Object.entries(payloadTextRewrites)) {
166
- if (from.length > 0)
167
- next = next.split(from).join(to);
168
- }
179
+ next = rewritePayloadText(next, payloadTextRewrites);
169
180
  return next;
170
181
  }
171
182
  function cloneRecipeDefinition(recipe, targetName, projectKey, rewrites) {
@@ -553,6 +564,37 @@ export class RecipesResource extends BaseResource {
553
564
  await provisionOutputDatasets();
554
565
  await createRecipe();
555
566
  }
567
+ // For sync recipes (a 1:1 copy) DSS does not propagate schema on build, so a
568
+ // schemaless dataset output silently builds to an empty dataset. Copy the
569
+ // single input's schema onto any schemaless dataset output so the build
570
+ // materializes rows (mirrors the DSS UI, which sets the sync output schema).
571
+ let syncOutputSchemaPropagated;
572
+ if (type.toLowerCase() === "sync" && !outputFolder) {
573
+ const inputRefs = recipeInputItems({ inputs, }).map((item) => item.ref);
574
+ const outputDatasetRefs = recipeOutputItems({ outputs, })
575
+ .filter((item) => item.type !== "MANAGED_FOLDER")
576
+ .map((item) => item.ref);
577
+ if (inputRefs.length === 1 && outputDatasetRefs.length > 0) {
578
+ const inputSchema = await this.client.datasets
579
+ .schema(inputRefs[0], pk)
580
+ .catch(() => undefined);
581
+ const inputColumns = inputSchema?.columns;
582
+ if (inputColumns && inputColumns.length > 0) {
583
+ const propagated = [];
584
+ for (const ref of outputDatasetRefs) {
585
+ const current = await this.client.datasets
586
+ .schema(ref, pk)
587
+ .catch(() => undefined);
588
+ if (current && current.columns.length === 0) {
589
+ await this.client.datasets.updateSchema(ref, inputColumns, pk);
590
+ propagated.push(ref);
591
+ }
592
+ }
593
+ if (propagated.length > 0)
594
+ syncOutputSchemaPropagated = propagated;
595
+ }
596
+ }
597
+ }
556
598
  // For join recipes: configure join conditions after creation
557
599
  let joinConfigured = false;
558
600
  const joinCols = typeof opts.joinOn === "string" ? [opts.joinOn,] : asStringArray(opts.joinOn);
@@ -627,6 +669,7 @@ export class RecipesResource extends BaseResource {
627
669
  createdDatasets,
628
670
  joinConfigured,
629
671
  outputProvisioningFallbackUsed: usedOutputProvisioningFallback,
672
+ ...(syncOutputSchemaPropagated ? { syncOutputSchemaPropagated, } : {}),
630
673
  ...(outputFolder ? { outputFolder, } : {}),
631
674
  ...(temporaryOutputDataset ? { temporaryOutputDataset, } : {}),
632
675
  ...(temporaryOutputDatasetDeleted !== undefined ? { temporaryOutputDatasetDeleted, } : {}),
@@ -719,10 +762,10 @@ export class RecipesResource extends BaseResource {
719
762
  };
720
763
  }
721
764
  /**
722
- * Download a recipe code payload to a local file.
765
+ * Download a recipe code payload to a local file.
723
766
 
724
- * Returns the path to the written file.
725
- */
767
+ * Returns the path to the written file.
768
+ */
726
769
  async downloadCode(recipeName, opts) {
727
770
  const result = await this.get(recipeName, {
728
771
  includePayload: true,