dataiku-sdk 0.10.0 → 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 (133) 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 +127 -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/bundles.js +2 -2
  111. package/dist/src/resources/continuous-activities.js +1 -0
  112. package/dist/src/resources/data-quality.js +5 -3
  113. package/dist/src/resources/datasets.d.ts +3 -0
  114. package/dist/src/resources/datasets.js +3 -0
  115. package/dist/src/resources/flow-zones.d.ts +2 -2
  116. package/dist/src/resources/flow-zones.js +4 -1
  117. package/dist/src/resources/meanings.d.ts +2 -0
  118. package/dist/src/resources/meanings.js +4 -0
  119. package/dist/src/resources/notebooks.d.ts +5 -7
  120. package/dist/src/resources/notebooks.js +10 -7
  121. package/dist/src/resources/projects.d.ts +1 -1
  122. package/dist/src/resources/projects.js +2 -2
  123. package/dist/src/resources/recipes.d.ts +3 -3
  124. package/dist/src/resources/recipes.js +50 -7
  125. package/dist/src/resources/scenarios.js +67 -26
  126. package/dist/src/resources/statistics.js +9 -0
  127. package/dist/src/schemas.d.ts +2 -2
  128. package/dist/src/schemas.js +1 -1
  129. package/dist/src/skill.js +2 -2
  130. package/dist/src/utils/sanitize.js +2 -1
  131. package/package.json +1 -1
  132. package/packages/types/dist/index.d.ts +15 -2
  133. package/packages/types/dist/index.js +9 -1
@@ -0,0 +1,104 @@
1
+ import { DataikuClient } from "../client.js";
2
+ export interface DoctorCheck {
3
+ name: string;
4
+ ok: boolean;
5
+ message: string;
6
+ details?: Record<string, unknown>;
7
+ }
8
+ export type PermissionStatus = "yes" | "no" | "unknown";
9
+ export type DoctorPermissionKey = "canListProjects" | "canReadProject" | "canMutateProject" | "canCreateFolder" | "canRunJobs" | "canCreateScenario" | "canSaveJupyter" | "canMutateConnection";
10
+ export type DoctorPermissions = Record<DoctorPermissionKey, PermissionStatus>;
11
+ export interface DoctorFixtures {
12
+ defaultDataset: string | null;
13
+ defaultRecipe: string | null;
14
+ defaultScenario: string | null;
15
+ defaultFlowZone: string | null;
16
+ defaultManagedFolder: string | null;
17
+ defaultJupyterNotebook: string | null;
18
+ }
19
+ export interface FixtureReject {
20
+ id?: string;
21
+ name?: string;
22
+ type?: string;
23
+ reason: string;
24
+ }
25
+ export interface FixtureDiscoveryResult {
26
+ projectKey: string;
27
+ allowTypes: string[];
28
+ fixtures: DoctorFixtures;
29
+ safeDataset: Record<string, unknown> | null;
30
+ safeManagedFolder: Record<string, unknown> | null;
31
+ safeJupyterNotebook: Record<string, unknown> | null;
32
+ unsafe: {
33
+ datasets: FixtureReject[];
34
+ managedFolders: FixtureReject[];
35
+ jupyterNotebooks: FixtureReject[];
36
+ };
37
+ }
38
+ export interface DoctorEnvironment {
39
+ projectKey?: string;
40
+ dssVersion?: string;
41
+ instanceTime?: string;
42
+ integrationFlags: {
43
+ mutating: boolean;
44
+ adminMutating: boolean;
45
+ variables: boolean;
46
+ sqlLive: boolean;
47
+ bundles: boolean;
48
+ apiServices: boolean;
49
+ };
50
+ }
51
+ export interface DoctorResult {
52
+ ok: boolean;
53
+ checks: DoctorCheck[];
54
+ context: {
55
+ hasUrl: boolean;
56
+ hasApiKey: boolean;
57
+ projectKey?: string;
58
+ tlsVerify: "strict" | "disabled";
59
+ caCert: "default" | "custom";
60
+ };
61
+ permissions?: DoctorPermissions;
62
+ permissionDetails?: Partial<Record<DoctorPermissionKey, Record<string, unknown>>>;
63
+ fixtures?: DoctorFixtures;
64
+ environment?: DoctorEnvironment;
65
+ }
66
+ export declare function errorDetails(error: unknown): Record<string, unknown>;
67
+ export declare function firstStringField(items: unknown[] | undefined, fields: string[]): string | null;
68
+ export declare function integrationFlag(name: string): boolean;
69
+ export declare function doctorEnvironment(projectKey?: string): DoctorEnvironment;
70
+ export declare function permissionStatusForError(error: unknown): PermissionStatus;
71
+ export declare function probeDoctorPermission(probe: () => Promise<unknown>): Promise<{
72
+ status: PermissionStatus;
73
+ details?: Record<string, unknown>;
74
+ }>;
75
+ export declare function probeReadOnlyPrerequisiteForMutation(probe: () => Promise<unknown>, readAction: string): Promise<{
76
+ status: PermissionStatus;
77
+ details?: Record<string, unknown>;
78
+ }>;
79
+ export declare function missingProjectPermission(): {
80
+ status: PermissionStatus;
81
+ details: Record<string, unknown>;
82
+ };
83
+ export declare function recordsFromUnknownArray(items: unknown[]): Array<Record<string, unknown>>;
84
+ export declare function doctorFixturesFromLists(datasets: unknown[], recipes: unknown[], scenarios: unknown[], flowZones: unknown[], folders: unknown[], jupyterNotebooks: unknown[]): DoctorFixtures;
85
+ export declare function discoverDoctorFixtures(client: DataikuClient, projectKey: string): Promise<DoctorFixtures>;
86
+ export declare const DEFAULT_FIXTURE_ALLOW_TYPES: string[];
87
+ export declare function fixtureAllowTypes(flags: Record<string, string | boolean>): string[];
88
+ export declare function isAllowedFixtureType(type: string | undefined, allowTypes: string[]): boolean;
89
+ export declare function fixtureReject(record: Record<string, unknown>, reason: string): FixtureReject;
90
+ export declare function firstSafeTypedFixture(items: unknown[], allowTypes: string[]): {
91
+ safe: Record<string, unknown> | null;
92
+ unsafe: FixtureReject[];
93
+ };
94
+ export declare function firstSafeJupyterNotebook(items: unknown[]): {
95
+ safe: Record<string, unknown> | null;
96
+ unsafe: FixtureReject[];
97
+ };
98
+ export declare function discoverFixtureReport(client: DataikuClient, projectKey: string, flags: Record<string, string | boolean>): Promise<FixtureDiscoveryResult>;
99
+ export declare function doctorCapabilities(client: DataikuClient, projectKey: string | undefined, accessibleProjects: unknown[] | undefined, flags: Record<string, string | boolean>): Promise<Pick<DoctorResult, "permissions" | "permissionDetails" | "fixtures" | "environment">>;
100
+ export declare function runDoctor(flags: Record<string, string | boolean>): Promise<{
101
+ result: DoctorResult;
102
+ exitCode: number;
103
+ }>;
104
+ export declare function runFixtures(flags: Record<string, string | boolean>): Promise<FixtureDiscoveryResult>;
@@ -0,0 +1,356 @@
1
+ import { DataikuClient, } from "../client.js";
2
+ import { DataikuError, } from "../errors.js";
3
+ import { num, splitCsvFlag, stringField, } from "./coerce.js";
4
+ import { currentCommandContext, resolveCredentials, } from "./runtime.js";
5
+ import { UsageError, } from "./usage.js";
6
+ export function errorDetails(error) {
7
+ if (error instanceof DataikuError) {
8
+ return {
9
+ category: error.category,
10
+ retryable: error.retryable,
11
+ status: error.status,
12
+ statusText: error.statusText,
13
+ };
14
+ }
15
+ return { message: error instanceof Error ? error.message : String(error), };
16
+ }
17
+ export function firstStringField(items, fields) {
18
+ for (const item of items ?? []) {
19
+ if (item === null || typeof item !== "object" || Array.isArray(item))
20
+ continue;
21
+ const record = item;
22
+ for (const field of fields) {
23
+ const value = record[field];
24
+ if (typeof value === "string" && value.trim().length > 0)
25
+ return value;
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ export function integrationFlag(name) {
31
+ const value = process.env[name];
32
+ return value === "1" || value?.toLowerCase() === "true";
33
+ }
34
+ export function doctorEnvironment(projectKey) {
35
+ return {
36
+ ...(projectKey ? { projectKey, } : {}),
37
+ integrationFlags: {
38
+ mutating: integrationFlag("RUN_DATAIKU_INTEGRATION_MUTATING"),
39
+ adminMutating: integrationFlag("RUN_DATAIKU_ADMIN_MUTATING"),
40
+ variables: integrationFlag("RUN_DATAIKU_INTEGRATION_VARIABLES"),
41
+ sqlLive: integrationFlag("RUN_DATAIKU_SQL_LIVE"),
42
+ bundles: integrationFlag("RUN_DATAIKU_INTEGRATION_BUNDLES"),
43
+ apiServices: integrationFlag("RUN_DATAIKU_INTEGRATION_API_SERVICES"),
44
+ },
45
+ };
46
+ }
47
+ export function permissionStatusForError(error) {
48
+ if (error instanceof DataikuError) {
49
+ if (error.status === 401 || error.status === 403 || error.status === 404)
50
+ return "no";
51
+ if (error.status === 0 || error.status >= 500 || error.category === "transient")
52
+ return "unknown";
53
+ if (error.category === "forbidden" || error.category === "not_found")
54
+ return "no";
55
+ return "unknown";
56
+ }
57
+ return "unknown";
58
+ }
59
+ export async function probeDoctorPermission(probe) {
60
+ try {
61
+ await probe();
62
+ return { status: "yes", };
63
+ }
64
+ catch (error) {
65
+ return { status: permissionStatusForError(error), details: errorDetails(error), };
66
+ }
67
+ }
68
+ export async function probeReadOnlyPrerequisiteForMutation(probe, readAction) {
69
+ const readProbe = await probeDoctorPermission(probe);
70
+ if (readProbe.status !== "yes")
71
+ return readProbe;
72
+ return {
73
+ status: "unknown",
74
+ details: {
75
+ reason: "mutation capability was not verified because doctor capabilities are read-only",
76
+ readAction,
77
+ readStatus: "yes",
78
+ },
79
+ };
80
+ }
81
+ export function missingProjectPermission() {
82
+ return {
83
+ status: "unknown",
84
+ details: { reason: "projectKey is required for this probe", },
85
+ };
86
+ }
87
+ export function recordsFromUnknownArray(items) {
88
+ return items.filter((item) => item !== null && typeof item === "object" && !Array.isArray(item));
89
+ }
90
+ export function doctorFixturesFromLists(datasets, recipes, scenarios, flowZones, folders, jupyterNotebooks) {
91
+ return {
92
+ defaultDataset: firstStringField(datasets, ["name",]),
93
+ defaultRecipe: firstStringField(recipes, ["name",]),
94
+ defaultScenario: firstStringField(scenarios, ["id",]),
95
+ defaultFlowZone: firstStringField(flowZones, ["id",]),
96
+ defaultManagedFolder: firstStringField(folders, ["id",]),
97
+ defaultJupyterNotebook: firstStringField(jupyterNotebooks, ["name",]),
98
+ };
99
+ }
100
+ export async function discoverDoctorFixtures(client, projectKey) {
101
+ const [datasets, recipes, scenarios, flowZones, folders, jupyterNotebooks,] = await Promise.all([
102
+ client.datasets.list(projectKey),
103
+ client.recipes.list(projectKey),
104
+ client.scenarios.list(projectKey),
105
+ client.flowZones.list(projectKey),
106
+ client.folders.list(projectKey),
107
+ client.notebooks.listJupyter(projectKey),
108
+ ]);
109
+ return doctorFixturesFromLists(datasets, recipes, scenarios, flowZones, folders, jupyterNotebooks);
110
+ }
111
+ export const DEFAULT_FIXTURE_ALLOW_TYPES = ["Filesystem", "Inline",];
112
+ export function fixtureAllowTypes(flags) {
113
+ const configured = splitCsvFlag(flags["allow-types"]);
114
+ return configured.length > 0 ? configured : DEFAULT_FIXTURE_ALLOW_TYPES;
115
+ }
116
+ export function isAllowedFixtureType(type, allowTypes) {
117
+ if (!type)
118
+ return false;
119
+ const normalized = type.trim().toLowerCase();
120
+ return allowTypes.some((allowed) => allowed.trim().toLowerCase() === normalized);
121
+ }
122
+ export function fixtureReject(record, reason) {
123
+ return {
124
+ ...(stringField(record, ["id",]) ? { id: stringField(record, ["id",]), } : {}),
125
+ ...(stringField(record, ["name",]) ? { name: stringField(record, ["name",]), } : {}),
126
+ ...(stringField(record, ["type",]) ? { type: stringField(record, ["type",]), } : {}),
127
+ reason,
128
+ };
129
+ }
130
+ export function firstSafeTypedFixture(items, allowTypes) {
131
+ const unsafe = [];
132
+ for (const record of recordsFromUnknownArray(items)) {
133
+ const type = stringField(record, ["type",]);
134
+ if (isAllowedFixtureType(type, allowTypes))
135
+ return { safe: record, unsafe, };
136
+ unsafe.push(fixtureReject(record, `type=${type ?? "missing"}`));
137
+ }
138
+ return { safe: null, unsafe, };
139
+ }
140
+ export function firstSafeJupyterNotebook(items) {
141
+ const unsafe = [];
142
+ for (const record of recordsFromUnknownArray(items)) {
143
+ const name = stringField(record, ["name",]);
144
+ if (name && !name.startsWith("_"))
145
+ return { safe: record, unsafe, };
146
+ unsafe.push(fixtureReject(record, name ? "name starts with _" : "missing name"));
147
+ }
148
+ return { safe: null, unsafe, };
149
+ }
150
+ export async function discoverFixtureReport(client, projectKey, flags) {
151
+ const allowTypes = fixtureAllowTypes(flags);
152
+ const [datasets, recipes, scenarios, flowZones, folders, jupyterNotebooks,] = await Promise.all([
153
+ client.datasets.list(projectKey),
154
+ client.recipes.list(projectKey),
155
+ client.scenarios.list(projectKey),
156
+ client.flowZones.list(projectKey),
157
+ client.folders.list(projectKey),
158
+ client.notebooks.listJupyter(projectKey),
159
+ ]);
160
+ const dataset = firstSafeTypedFixture(datasets, allowTypes);
161
+ const folder = firstSafeTypedFixture(folders, allowTypes);
162
+ const notebook = firstSafeJupyterNotebook(jupyterNotebooks);
163
+ return {
164
+ projectKey,
165
+ allowTypes,
166
+ fixtures: doctorFixturesFromLists(datasets, recipes, scenarios, flowZones, folders, jupyterNotebooks),
167
+ safeDataset: dataset.safe,
168
+ safeManagedFolder: folder.safe,
169
+ safeJupyterNotebook: notebook.safe,
170
+ unsafe: {
171
+ datasets: dataset.unsafe,
172
+ managedFolders: folder.unsafe,
173
+ jupyterNotebooks: notebook.unsafe,
174
+ },
175
+ };
176
+ }
177
+ export async function doctorCapabilities(client, projectKey, accessibleProjects, flags) {
178
+ const probeProjectKey = projectKey ?? firstStringField(accessibleProjects, ["projectKey",])
179
+ ?? undefined;
180
+ const probes = {
181
+ canListProjects: () => probeDoctorPermission(async () => accessibleProjects ?? await client.projects.list()),
182
+ canReadProject: () => probeProjectKey
183
+ ? probeDoctorPermission(() => client.projects.get(probeProjectKey))
184
+ : Promise.resolve(missingProjectPermission()),
185
+ canMutateProject: () => probeProjectKey
186
+ ? probeReadOnlyPrerequisiteForMutation(() => client.variables.get(probeProjectKey), "variables.get")
187
+ : Promise.resolve(missingProjectPermission()),
188
+ canCreateFolder: () => probeProjectKey
189
+ ? probeReadOnlyPrerequisiteForMutation(() => client.folders.list(probeProjectKey), "folders.list")
190
+ : Promise.resolve(missingProjectPermission()),
191
+ canRunJobs: () => probeProjectKey
192
+ ? probeReadOnlyPrerequisiteForMutation(() => client.jobs.list(probeProjectKey), "jobs.list")
193
+ : Promise.resolve(missingProjectPermission()),
194
+ canCreateScenario: () => probeProjectKey
195
+ ? probeReadOnlyPrerequisiteForMutation(() => client.scenarios.list(probeProjectKey), "scenarios.list")
196
+ : Promise.resolve(missingProjectPermission()),
197
+ canSaveJupyter: () => probeProjectKey
198
+ ? probeReadOnlyPrerequisiteForMutation(() => client.notebooks.listJupyter(probeProjectKey), "notebooks.listJupyter")
199
+ : Promise.resolve(missingProjectPermission()),
200
+ canMutateConnection: () => probeReadOnlyPrerequisiteForMutation(() => client.connections.list(), "connections.list"),
201
+ };
202
+ const permissions = {};
203
+ const permissionDetails = {};
204
+ for (const key of Object.keys(probes)) {
205
+ const probe = await probes[key]();
206
+ permissions[key] = probe.status;
207
+ if (probe.details)
208
+ permissionDetails[key] = probe.details;
209
+ }
210
+ const capabilityResult = {
211
+ permissions,
212
+ ...(Object.keys(permissionDetails).length > 0 ? { permissionDetails, } : {}),
213
+ environment: doctorEnvironment(projectKey),
214
+ };
215
+ if (flags["fast"] !== true && probeProjectKey) {
216
+ try {
217
+ capabilityResult.fixtures = await discoverDoctorFixtures(client, probeProjectKey);
218
+ }
219
+ catch (error) {
220
+ capabilityResult.fixtures = {
221
+ defaultDataset: null,
222
+ defaultRecipe: null,
223
+ defaultScenario: null,
224
+ defaultFlowZone: null,
225
+ defaultManagedFolder: null,
226
+ defaultJupyterNotebook: null,
227
+ };
228
+ capabilityResult.permissionDetails = {
229
+ ...capabilityResult.permissionDetails,
230
+ canReadProject: {
231
+ ...capabilityResult.permissionDetails?.canReadProject,
232
+ fixtureDiscovery: errorDetails(error),
233
+ },
234
+ };
235
+ }
236
+ }
237
+ return capabilityResult;
238
+ }
239
+ export async function runDoctor(flags) {
240
+ const { url, apiKey, projectKey, tlsRejectUnauthorized, caCertPath, } = resolveCredentials(flags);
241
+ const checks = [];
242
+ const context = {
243
+ hasUrl: url.trim().length > 0,
244
+ hasApiKey: apiKey.trim().length > 0,
245
+ ...(projectKey ? { projectKey, } : {}),
246
+ tlsVerify: tlsRejectUnauthorized === false ? "disabled" : "strict",
247
+ caCert: caCertPath ? "custom" : "default",
248
+ };
249
+ const credentialsOk = context.hasUrl && context.hasApiKey;
250
+ checks.push({
251
+ name: "credentials_present",
252
+ ok: credentialsOk,
253
+ message: credentialsOk
254
+ ? "Dataiku URL and API key are configured."
255
+ : "Missing Dataiku URL and/or API key. Set DATAIKU_URL/DATAIKU_API_KEY or pass --url/--api-key.",
256
+ });
257
+ let accessibleProjects;
258
+ if (credentialsOk) {
259
+ const requestTimeoutMs = num(flags["request-timeout"]);
260
+ const retryMaxAttempts = num(flags["retries"]);
261
+ const client = new DataikuClient({
262
+ url,
263
+ apiKey,
264
+ projectKey,
265
+ verbose: flags["verbose"] === true,
266
+ requestTimeoutMs,
267
+ retryMaxAttempts,
268
+ tlsRejectUnauthorized,
269
+ caCertPath,
270
+ });
271
+ try {
272
+ const projects = await client.projects.list();
273
+ accessibleProjects = projects;
274
+ checks.push({
275
+ name: "connectivity",
276
+ ok: true,
277
+ message: "Connected to DSS and listed accessible projects.",
278
+ details: { projectCount: projects.length, },
279
+ });
280
+ }
281
+ catch (error) {
282
+ checks.push({
283
+ name: "connectivity",
284
+ ok: false,
285
+ message: "Could not list accessible projects.",
286
+ details: errorDetails(error),
287
+ });
288
+ }
289
+ if (projectKey) {
290
+ try {
291
+ const project = await client.projects.get(projectKey);
292
+ checks.push({
293
+ name: "default_project",
294
+ ok: true,
295
+ message: `Project ${projectKey} is accessible.`,
296
+ details: {
297
+ projectKey,
298
+ name: typeof project.name === "string" ? project.name : undefined,
299
+ },
300
+ });
301
+ }
302
+ catch (error) {
303
+ checks.push({
304
+ name: "default_project",
305
+ ok: false,
306
+ message: `Project ${projectKey} is not accessible.`,
307
+ details: errorDetails(error),
308
+ });
309
+ }
310
+ }
311
+ }
312
+ const result = { ok: checks.every((check) => check.ok), checks, context, };
313
+ if (flags["capabilities"] === true && credentialsOk) {
314
+ const requestTimeoutMs = num(flags["request-timeout"]);
315
+ const retryMaxAttempts = num(flags["retries"]) ?? 1;
316
+ const client = new DataikuClient({
317
+ url,
318
+ apiKey,
319
+ projectKey,
320
+ verbose: flags["verbose"] === true,
321
+ requestTimeoutMs,
322
+ retryMaxAttempts,
323
+ tlsRejectUnauthorized,
324
+ caCertPath,
325
+ });
326
+ result.environment = doctorEnvironment(projectKey);
327
+ Object.assign(result, await doctorCapabilities(client, projectKey, accessibleProjects, flags));
328
+ }
329
+ return { result, exitCode: result.ok ? 0 : 2, };
330
+ }
331
+ export async function runFixtures(flags) {
332
+ const { url, apiKey, projectKey, tlsRejectUnauthorized, caCertPath, } = resolveCredentials(flags);
333
+ if (!url) {
334
+ throw new UsageError("Missing Dataiku URL. Set DATAIKU_URL or pass --url.", "missing_required_flag");
335
+ }
336
+ if (!apiKey) {
337
+ throw new UsageError("Missing API key. Set DATAIKU_API_KEY or pass --api-key.", "missing_required_flag");
338
+ }
339
+ if (!projectKey) {
340
+ throw new UsageError("Missing project key. Set DATAIKU_PROJECT_KEY or pass --project-key.", "missing_required_flag");
341
+ }
342
+ currentCommandContext.projectKey = projectKey;
343
+ const requestTimeoutMs = num(flags["request-timeout"]);
344
+ const retryMaxAttempts = num(flags["retries"]) ?? 1;
345
+ const client = new DataikuClient({
346
+ url,
347
+ apiKey,
348
+ projectKey,
349
+ verbose: flags["verbose"] === true,
350
+ requestTimeoutMs,
351
+ retryMaxAttempts,
352
+ tlsRejectUnauthorized,
353
+ caCertPath,
354
+ });
355
+ return discoverFixtureReport(client, projectKey, flags);
356
+ }
@@ -0,0 +1,2 @@
1
+ export declare function dataikuEnvironmentEnabled(): boolean;
2
+ export declare function loadEnvFile(): void;
@@ -0,0 +1,37 @@
1
+ import { readFileSync, } from "node:fs";
2
+ import { dirname, resolve, } from "node:path";
3
+ import { fileURLToPath, } from "node:url";
4
+ export function dataikuEnvironmentEnabled() {
5
+ return process.env.DATAIKU_DISABLE_ENV !== "1";
6
+ }
7
+ export function loadEnvFile() {
8
+ if (!dataikuEnvironmentEnabled())
9
+ return;
10
+ // The invocation cwd takes precedence over the CLI install/root directory, so a
11
+ // project-local .env where `dss` is invoked overrides defaults shipped beside the
12
+ // CLI. First writer wins below, so cwd must be listed first.
13
+ const dirs = [
14
+ process.cwd(),
15
+ resolve(dirname(fileURLToPath(import.meta.url)), "..", ".."),
16
+ ];
17
+ for (const dir of dirs) {
18
+ try {
19
+ const content = readFileSync(resolve(dir, ".env"), "utf-8");
20
+ for (const line of content.split("\n")) {
21
+ const trimmed = line.trim();
22
+ if (!trimmed || trimmed.startsWith("#"))
23
+ continue;
24
+ const eq = trimmed.indexOf("=");
25
+ if (eq === -1)
26
+ continue;
27
+ const key = trimmed.slice(0, eq).trim();
28
+ const val = trimmed.slice(eq + 1).trim().replace(/^['"]|['"]$/g, "");
29
+ if (!process.env[key])
30
+ process.env[key] = val;
31
+ }
32
+ }
33
+ catch {
34
+ // no .env file — fine
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,16 @@
1
+ export declare const BOOLEAN_FLAGS: Set<string>;
2
+ export declare const SHORT_FLAGS: Record<string, string>;
3
+ /** Long-flag aliases: these are normalized to the canonical name in parseArgs. */
4
+ export declare const FLAG_ALIASES: Record<string, string>;
5
+ export declare const VALUE_FLAGS: Set<string>;
6
+ export declare const REPEATABLE_VALUE_FLAGS: Set<string>;
7
+ export declare const KNOWN_LONG_FLAGS: Set<string>;
8
+ export declare function normalizeLongFlag(rawFlagName: string): string;
9
+ export declare function isNegativeNumberToken(value: string): boolean;
10
+ export declare function requireFlagValue(flagLabel: string, next: string | undefined): string;
11
+ export declare function setParsedFlagValue(flags: Record<string, string | boolean>, flagName: string, value: string): void;
12
+ export interface ParsedArgs {
13
+ positional: string[];
14
+ flags: Record<string, string | boolean>;
15
+ }
16
+ export declare function parseArgs(argv: string[]): ParsedArgs;