@lightdash/cli 2.603.2 → 2.603.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/handlers/preview.ts"],"names":[],"mappings":"AACA,OAAO,EACH,+BAA+B,EAUlC,MAAM,mBAAmB,CAAC;AAoB3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAalD,KAAK,qBAAqB,GAAG,iBAAiB,GAAG;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,kBAAkB,EAAE,+BAA+B,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,wBAAwB,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAoBF,KAAK,yBAAyB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC;AA2GF,eAAO,MAAM,cAAc,oBACN,qBAAqB,KACvC,OAAO,CAAC,IAAI,CAoTd,CAAC;AAkKF,eAAO,MAAM,mBAAmB,oBACX,qBAAqB,KACvC,OAAO,CAAC,IAAI,CA2Qd,CAAC;AAEF,eAAO,MAAM,kBAAkB,YAClB,yBAAyB,KACnC,OAAO,CAAC,IAAI,CA2Cd,CAAC"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/handlers/preview.ts"],"names":[],"mappings":"AACA,OAAO,EACH,+BAA+B,EAUlC,MAAM,mBAAmB,CAAC;AAoB3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAalD,KAAK,qBAAqB,GAAG,iBAAiB,GAAG;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,kBAAkB,EAAE,+BAA+B,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,wBAAwB,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAoBF,KAAK,yBAAyB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC;AA2QF,eAAO,MAAM,cAAc,oBACN,qBAAqB,KACvC,OAAO,CAAC,IAAI,CAwWd,CAAC;AAEF,eAAO,MAAM,mBAAmB,oBACX,qBAAqB,KACvC,OAAO,CAAC,IAAI,CA2Qd,CAAC;AAEF,eAAO,MAAM,kBAAkB,YAClB,yBAAyB,KACnC,OAAO,CAAC,IAAI,CA2Cd,CAAC"}
@@ -104,6 +104,108 @@ const getPreviewProject = async (name) => {
104
104
  });
105
105
  return projects.find((project) => project.type === common_1.ProjectType.PREVIEW && project.name === name);
106
106
  };
107
+ const withCurrentSettings = (credentials, current) => {
108
+ if (!current || current.type !== credentials.type)
109
+ return credentials;
110
+ const defined = Object.fromEntries(Object.entries(credentials).filter(([, value]) => value !== undefined));
111
+ return { ...current, ...defined };
112
+ };
113
+ const resolveSourceConnection = async (project, sourceOption, upstreamProjectUuid) => {
114
+ if (project.connectionRoute !== 'multi') {
115
+ return { sourceUuid: undefined, connection: { kind: 'primary' } };
116
+ }
117
+ const sourceUuid = await (0, sourceSelection_1.resolveProjectSourceUuid)(project.projectUuid, sourceOption, upstreamProjectUuid);
118
+ if (!sourceUuid)
119
+ return { sourceUuid, connection: { kind: 'primary' } };
120
+ let bindings;
121
+ try {
122
+ bindings = await (0, apiClient_1.lightdashApi)({
123
+ method: 'GET',
124
+ url: `/api/v1/projects/${project.projectUuid}/warehouse-connections/dbt-sources/bindings`,
125
+ body: undefined,
126
+ });
127
+ }
128
+ catch {
129
+ return { sourceUuid, connection: { kind: 'unknown', sourceUuid } };
130
+ }
131
+ const boundConnectionUuid = bindings.sources.find((item) => item.projectDbtSourceUuid === sourceUuid)?.warehouseConnectionUuid ?? null;
132
+ if (boundConnectionUuid === null) {
133
+ return { sourceUuid, connection: { kind: 'primary' } };
134
+ }
135
+ const boundConnection = bindings.connections.find((item) => item.warehouseConnectionUuid === boundConnectionUuid);
136
+ if (!boundConnection) {
137
+ return { sourceUuid, connection: { kind: 'unknown', sourceUuid } };
138
+ }
139
+ return {
140
+ sourceUuid,
141
+ connection: boundConnection.isOriginal
142
+ ? { kind: 'primary' }
143
+ : { kind: 'extra', connection: boundConnection },
144
+ };
145
+ };
146
+ // Credentials resolved locally (AWS SSO, Snowflake SSO) expire, so a re-run
147
+ // with the same name pushes freshly resolved ones into the existing preview.
148
+ const refreshPreviewWarehouseCredentials = async (projectUuid, options, upstreamProjectUuid) => {
149
+ const source = (0, warehouseConnection_1.getWarehouseCredentialsSource)(options);
150
+ if (source.source === 'organization') {
151
+ globalState_1.default.debug(`> Preview uses organization warehouse credentials "${source.name}", nothing to refresh`);
152
+ return;
153
+ }
154
+ if (source.source === 'none') {
155
+ globalState_1.default.debug('> Skipping warehouse credentials refresh (--no-warehouse-credentials)');
156
+ return;
157
+ }
158
+ const loaded = await (0, createProject_1.loadWarehouseCredentialsFromProfiles)({
159
+ projectDir: options.projectDir,
160
+ profilesDir: options.profilesDir,
161
+ target: options.target,
162
+ profile: options.profile,
163
+ startOfWeek: options.startOfWeek,
164
+ assumeYes: options.assumeYes,
165
+ targetPath: options.targetPath,
166
+ });
167
+ if (!loaded) {
168
+ console.error(styles.warning('Keeping the warehouse credentials already stored on the preview.'));
169
+ return;
170
+ }
171
+ const project = await (0, refresh_1.getProject)(projectUuid);
172
+ const { connection: sourceConnection } = await resolveSourceConnection(project, options.source, upstreamProjectUuid);
173
+ if (sourceConnection.kind === 'unknown') {
174
+ console.error(styles.warning(`Could not read which connection source ${options.source ?? sourceConnection.sourceUuid} uses; keeping the warehouse credentials already stored on the preview.`));
175
+ return;
176
+ }
177
+ const connection = sourceConnection.kind === 'extra'
178
+ ? sourceConnection.connection
179
+ : undefined;
180
+ const spinner = globalState_1.default.startSpinner(connection
181
+ ? ` Refreshing warehouse credentials for "${connection.name}"...`
182
+ : ' Refreshing warehouse credentials...');
183
+ try {
184
+ if (connection) {
185
+ const current = await (0, apiClient_1.lightdashApi)({
186
+ method: 'GET',
187
+ url: `/api/v1/projects/${projectUuid}/warehouse-connections/${connection.warehouseConnectionUuid}`,
188
+ body: undefined,
189
+ });
190
+ const body = {
191
+ warehouseConnection: withCurrentSettings(loaded.credentials, current.warehouseConnection),
192
+ };
193
+ await (0, apiClient_1.lightdashApi)({
194
+ method: 'PATCH',
195
+ url: `/api/v1/projects/${projectUuid}/warehouse-connections/${connection.warehouseConnectionUuid}`,
196
+ body: JSON.stringify(body),
197
+ });
198
+ }
199
+ else {
200
+ await (0, warehouseConnection_1.updateProjectWarehouseConnection)(project, loaded.credentials, 'Refreshing warehouse credentials');
201
+ }
202
+ spinner.succeed(' Warehouse credentials refreshed');
203
+ }
204
+ catch (e) {
205
+ spinner.fail();
206
+ throw e;
207
+ }
208
+ };
107
209
  const previewHandler = async (originalOptions) => {
108
210
  (0, credentials_1.refuseAgentConnection)();
109
211
  const options = { ...originalOptions };
@@ -144,10 +246,11 @@ const previewHandler = async (originalOptions) => {
144
246
  options.combineManifestProjectUuid = config.context?.project;
145
247
  // Validate upstream project before attempting to copy permissions or content
146
248
  let upstreamProjectValid = false;
249
+ let upstreamProject;
147
250
  if (config.context?.project) {
148
251
  try {
149
252
  globalState_1.default.debug(`> Validating upstream project: ${config.context.project}`);
150
- const upstreamProject = await (0, apiClient_1.lightdashApi)({
253
+ upstreamProject = await (0, apiClient_1.lightdashApi)({
151
254
  method: 'GET',
152
255
  url: `/api/v1/projects/${config.context.project}`,
153
256
  body: undefined,
@@ -179,16 +282,29 @@ const previewHandler = async (originalOptions) => {
179
282
  else if (upstreamProjectValid) {
180
283
  console.error(`\n${styles.success('✔')} Copying charts and dashboards from "${config.context?.projectName || 'source project'}"`);
181
284
  }
285
+ const upstreamProjectUuid = config.context?.project && upstreamProjectValid
286
+ ? config.context.project
287
+ : undefined;
288
+ const upstreamSourceConnection = upstreamProject &&
289
+ upstreamProjectUuid &&
290
+ projectTypeConfig.warehouseCredentials !== false &&
291
+ (0, warehouseConnection_1.getWarehouseCredentialsSource)({
292
+ ...options,
293
+ warehouseCredentials: projectTypeConfig.warehouseCredentials,
294
+ }).source === 'profiles'
295
+ ? (await resolveSourceConnection(upstreamProject, options.source, upstreamProjectUuid)).connection
296
+ : { kind: 'primary' };
297
+ const keepsUpstreamPrimary = upstreamSourceConnection.kind !== 'primary';
182
298
  try {
183
299
  const results = await (0, createProject_1.createProject)({
184
300
  ...options,
185
301
  name,
186
302
  type: common_1.ProjectType.PREVIEW,
187
- upstreamProjectUuid: config.context?.project && upstreamProjectValid
188
- ? config.context.project
189
- : undefined,
303
+ upstreamProjectUuid,
190
304
  copyContent: !options.skipCopyContent && upstreamProjectValid,
191
- warehouseCredentials: projectTypeConfig.warehouseCredentials,
305
+ warehouseCredentials: keepsUpstreamPrimary
306
+ ? false
307
+ : projectTypeConfig.warehouseCredentials,
192
308
  expiresIn: options.expiresIn
193
309
  ? parseInt(options.expiresIn, 10)
194
310
  : undefined,
@@ -212,11 +328,6 @@ const previewHandler = async (originalOptions) => {
212
328
  }
213
329
  return;
214
330
  }
215
- if (options.disableTimestampConversion === undefined) {
216
- options.disableTimestampConversion =
217
- (0, timestampConversion_1.getDisableTimestampConversionFromProject)(project.warehouseConnection);
218
- globalState_1.default.debug(`> Using disable-timestamp-conversion=${String(options.disableTimestampConversion ?? false)} from preview project settings`);
219
- }
220
331
  const previewStartTime = Date.now();
221
332
  await analytics_1.LightdashAnalytics.track({
222
333
  event: 'preview.started',
@@ -226,6 +337,24 @@ const previewHandler = async (originalOptions) => {
226
337
  },
227
338
  });
228
339
  try {
340
+ if (keepsUpstreamPrimary) {
341
+ await refreshPreviewWarehouseCredentials(project.projectUuid, {
342
+ ...options,
343
+ warehouseCredentials: projectTypeConfig.warehouseCredentials,
344
+ }, upstreamProjectUuid);
345
+ }
346
+ const previewSource = upstreamProjectUuid
347
+ ? await resolveSourceConnection(await (0, refresh_1.getProject)(project.projectUuid), options.source, upstreamProjectUuid)
348
+ : undefined;
349
+ if (options.disableTimestampConversion === undefined &&
350
+ previewSource?.connection.kind === 'extra') {
351
+ options.disableTimestampConversion = (await (0, timestampConversion_1.getProjectDeploySettings)(undefined, project.projectUuid, previewSource.sourceUuid)).disableTimestampConversion;
352
+ }
353
+ else if (options.disableTimestampConversion === undefined) {
354
+ options.disableTimestampConversion =
355
+ (0, timestampConversion_1.getDisableTimestampConversionFromProject)(project.warehouseConnection);
356
+ globalState_1.default.debug(`> Using disable-timestamp-conversion=${String(options.disableTimestampConversion ?? false)} from preview project settings`);
357
+ }
229
358
  const { explores, isProjectComplete } = await (0, compile_1.compileProject)(options);
230
359
  await (0, deploy_1.deploy)(explores, {
231
360
  ...options,
@@ -320,108 +449,6 @@ const previewHandler = async (originalOptions) => {
320
449
  await cleanupProject(executionId, project.projectUuid, previewStartTime);
321
450
  };
322
451
  exports.previewHandler = previewHandler;
323
- const withCurrentSettings = (credentials, current) => {
324
- if (!current || current.type !== credentials.type)
325
- return credentials;
326
- const defined = Object.fromEntries(Object.entries(credentials).filter(([, value]) => value !== undefined));
327
- return { ...current, ...defined };
328
- };
329
- const resolveSourceConnection = async (project, sourceOption, upstreamProjectUuid) => {
330
- if (project.connectionRoute !== 'multi') {
331
- return { sourceUuid: undefined, connection: { kind: 'primary' } };
332
- }
333
- const sourceUuid = await (0, sourceSelection_1.resolveProjectSourceUuid)(project.projectUuid, sourceOption, upstreamProjectUuid);
334
- if (!sourceUuid)
335
- return { sourceUuid, connection: { kind: 'primary' } };
336
- let bindings;
337
- try {
338
- bindings = await (0, apiClient_1.lightdashApi)({
339
- method: 'GET',
340
- url: `/api/v1/projects/${project.projectUuid}/warehouse-connections/dbt-sources/bindings`,
341
- body: undefined,
342
- });
343
- }
344
- catch {
345
- return { sourceUuid, connection: { kind: 'unknown', sourceUuid } };
346
- }
347
- const boundConnectionUuid = bindings.sources.find((item) => item.projectDbtSourceUuid === sourceUuid)?.warehouseConnectionUuid ?? null;
348
- if (boundConnectionUuid === null) {
349
- return { sourceUuid, connection: { kind: 'primary' } };
350
- }
351
- const boundConnection = bindings.connections.find((item) => item.warehouseConnectionUuid === boundConnectionUuid);
352
- if (!boundConnection) {
353
- return { sourceUuid, connection: { kind: 'unknown', sourceUuid } };
354
- }
355
- return {
356
- sourceUuid,
357
- connection: boundConnection.isOriginal
358
- ? { kind: 'primary' }
359
- : { kind: 'extra', connection: boundConnection },
360
- };
361
- };
362
- // Credentials resolved locally (AWS SSO, Snowflake SSO) expire, so a re-run
363
- // with the same name pushes freshly resolved ones into the existing preview.
364
- const refreshPreviewWarehouseCredentials = async (projectUuid, options, upstreamProjectUuid) => {
365
- const source = (0, warehouseConnection_1.getWarehouseCredentialsSource)(options);
366
- if (source.source === 'organization') {
367
- globalState_1.default.debug(`> Preview uses organization warehouse credentials "${source.name}", nothing to refresh`);
368
- return;
369
- }
370
- if (source.source === 'none') {
371
- globalState_1.default.debug('> Skipping warehouse credentials refresh (--no-warehouse-credentials)');
372
- return;
373
- }
374
- const loaded = await (0, createProject_1.loadWarehouseCredentialsFromProfiles)({
375
- projectDir: options.projectDir,
376
- profilesDir: options.profilesDir,
377
- target: options.target,
378
- profile: options.profile,
379
- startOfWeek: options.startOfWeek,
380
- assumeYes: options.assumeYes,
381
- targetPath: options.targetPath,
382
- });
383
- if (!loaded) {
384
- console.error(styles.warning('Keeping the warehouse credentials already stored on the preview.'));
385
- return;
386
- }
387
- const project = await (0, refresh_1.getProject)(projectUuid);
388
- const { connection: sourceConnection } = await resolveSourceConnection(project, options.source, upstreamProjectUuid);
389
- if (sourceConnection.kind === 'unknown') {
390
- console.error(styles.warning(`Could not read which connection source ${options.source ?? sourceConnection.sourceUuid} uses; keeping the warehouse credentials already stored on the preview.`));
391
- return;
392
- }
393
- const connection = sourceConnection.kind === 'extra'
394
- ? sourceConnection.connection
395
- : undefined;
396
- const spinner = globalState_1.default.startSpinner(connection
397
- ? ` Refreshing warehouse credentials for "${connection.name}"...`
398
- : ' Refreshing warehouse credentials...');
399
- try {
400
- if (connection) {
401
- const current = await (0, apiClient_1.lightdashApi)({
402
- method: 'GET',
403
- url: `/api/v1/projects/${projectUuid}/warehouse-connections/${connection.warehouseConnectionUuid}`,
404
- body: undefined,
405
- });
406
- const body = {
407
- warehouseConnection: withCurrentSettings(loaded.credentials, current.warehouseConnection),
408
- };
409
- await (0, apiClient_1.lightdashApi)({
410
- method: 'PATCH',
411
- url: `/api/v1/projects/${projectUuid}/warehouse-connections/${connection.warehouseConnectionUuid}`,
412
- body: JSON.stringify(body),
413
- });
414
- }
415
- else {
416
- await (0, warehouseConnection_1.updateProjectWarehouseConnection)(project, loaded.credentials, 'Refreshing warehouse credentials');
417
- }
418
- spinner.succeed(' Warehouse credentials refreshed');
419
- }
420
- catch (e) {
421
- spinner.fail();
422
- throw e;
423
- }
424
- };
425
452
  const startPreviewHandler = async (originalOptions) => {
426
453
  (0, credentials_1.refuseAgentConnection)();
427
454
  const options = { ...originalOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "2.603.2",
3
+ "version": "2.603.3",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,8 +22,8 @@
22
22
  "@actions/core": "1.11.1",
23
23
  "@aws-sdk/credential-providers": "3.995.0",
24
24
  "@casl/ability": "6.8.0",
25
- "@lightdash/common": "2.603.2",
26
- "@lightdash/warehouses": "2.603.2",
25
+ "@lightdash/common": "2.603.3",
26
+ "@lightdash/warehouses": "2.603.3",
27
27
  "@sidvind/better-ajv-errors": "7.0.0",
28
28
  "@types/columnify": "1.5.1",
29
29
  "ajv": "8.18.0",