@lightdash/cli 2.504.2 → 2.505.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.
@@ -4,5 +4,5 @@ export type AgentOptions = {
4
4
  verbose: boolean;
5
5
  };
6
6
  export declare const resolveAgentProject: (project?: string) => Promise<string>;
7
- export declare const getAgentAccess: (projectUuid: string) => Promise<AiAccessForUser>;
7
+ export declare const getAgentAccess: (projectUuid: string, signal?: AbortSignal | null) => Promise<AiAccessForUser>;
8
8
  //# sourceMappingURL=agentAccess.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agentAccess.d.ts","sourceRoot":"","sources":["../../src/handlers/agentAccess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKzE,MAAM,MAAM,YAAY,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,mBAAmB,aAClB,MAAM,KACjB,OAAO,CAAC,MAAM,CAShB,CAAC;AAEF,eAAO,MAAM,cAAc,gBAAiB,MAAM,KAAG,OAAO,CAAC,eAAe,CAKtE,CAAC"}
1
+ {"version":3,"file":"agentAccess.d.ts","sourceRoot":"","sources":["../../src/handlers/agentAccess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKzE,MAAM,MAAM,YAAY,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,mBAAmB,aAClB,MAAM,KACjB,OAAO,CAAC,MAAM,CAShB,CAAC;AAEF,eAAO,MAAM,cAAc,gBACV,MAAM,WACX,WAAW,GAAG,IAAI,KAC3B,OAAO,CAAC,eAAe,CAMpB,CAAC"}
@@ -15,9 +15,10 @@ const resolveAgentProject = async (project) => {
15
15
  return config.context.project;
16
16
  };
17
17
  exports.resolveAgentProject = resolveAgentProject;
18
- const getAgentAccess = (projectUuid) => (0, apiClient_1.lightdashApi)({
18
+ const getAgentAccess = (projectUuid, signal = null) => (0, apiClient_1.lightdashApi)({
19
19
  method: 'GET',
20
20
  url: `/api/v2/projects/${projectUuid}/ai-access/me`,
21
21
  body: undefined,
22
+ ...(signal ? { signal } : {}),
22
23
  });
23
24
  exports.getAgentAccess = getAgentAccess;
@@ -1 +1 @@
1
- {"version":3,"file":"agentAccess.mock.d.ts","sourceRoot":"","sources":["../../src/handlers/agentAccess.mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,eAAe,EACvB,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,gBAAgB,yCAAyC,CAAC;AACvE,eAAO,MAAM,eAAe,6GAA4F,CAAC;AACzH,eAAO,MAAM,WAAW,EAAE,eAmBzB,CAAC;AACF,eAAO,MAAM,oBAAoB,EAAE,eAKlC,CAAC"}
1
+ {"version":3,"file":"agentAccess.mock.d.ts","sourceRoot":"","sources":["../../src/handlers/agentAccess.mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,eAAe,EACvB,MAAM,mBAAmB,CAAC;AAE3B,eAAO,MAAM,gBAAgB,yCAAyC,CAAC;AACvE,eAAO,MAAM,eAAe,6GAA4F,CAAC;AACzH,eAAO,MAAM,WAAW,EAAE,eAoBzB,CAAC;AACF,eAAO,MAAM,oBAAoB,EAAE,eAMlC,CAAC"}
@@ -7,6 +7,7 @@ exports.agentConnectUrl = `https://example.com/agent/connect?project=${exports.a
7
7
  exports.agentAccess = {
8
8
  projectUuid: exports.agentProjectUuid,
9
9
  expiresAt: null,
10
+ principalName: null,
10
11
  requirementSource: 'organization',
11
12
  source: 'agent_sign_in',
12
13
  identity: null,
@@ -26,6 +27,7 @@ exports.agentAccess = {
26
27
  exports.connectedAgentAccess = {
27
28
  ...exports.agentAccess,
28
29
  identity: 'connected_person',
30
+ principalName: 'charlie@acme.com',
29
31
  enabled: true,
30
32
  refusal: null,
31
33
  };
@@ -1 +1 @@
1
- {"version":3,"file":"agentConnect.d.ts","sourceRoot":"","sources":["../../src/handlers/agentConnect.ts"],"names":[],"mappings":"AASA,OAAO,EAGH,KAAK,YAAY,EACpB,MAAM,eAAe,CAAC;AAGvB,KAAK,mBAAmB,GAAG,YAAY,GAAG;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAyCF,eAAO,MAAM,mBAAmB,YACnB,mBAAmB,KAC7B,OAAO,CAAC,IAAI,CAgJd,CAAC"}
1
+ {"version":3,"file":"agentConnect.d.ts","sourceRoot":"","sources":["../../src/handlers/agentConnect.ts"],"names":[],"mappings":"AAWA,OAAO,EAGH,KAAK,YAAY,EACpB,MAAM,eAAe,CAAC;AAGvB,KAAK,mBAAmB,GAAG,YAAY,GAAG;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA6BF,eAAO,MAAM,mBAAmB,YACnB,mBAAmB,KAC7B,OAAO,CAAC,IAAI,CA2Pd,CAAC"}
@@ -20,40 +20,16 @@ const getFailureReason = (error) => {
20
20
  return 'The sign-in did not complete. Try again.';
21
21
  }
22
22
  };
23
- const pollForConnection = async (projectUuid) => {
24
- const deadline = Date.now() + 120_000;
25
- const poll = async () => {
26
- await new Promise((resolve) => {
27
- setTimeout(resolve, Math.min(3000, deadline - Date.now()));
28
- });
29
- const remaining = deadline - Date.now();
30
- if (remaining <= 0)
31
- return false;
32
- let timer;
33
- try {
34
- const access = await Promise.race([
35
- (0, agentAccess_1.getAgentAccess)(projectUuid),
36
- new Promise((resolve) => {
37
- timer = setTimeout(() => resolve(undefined), remaining);
38
- }),
39
- ]);
40
- if (access === undefined)
41
- return false;
42
- if (access.refusal === null)
43
- return true;
44
- }
45
- finally {
46
- clearTimeout(timer);
47
- }
48
- return poll();
49
- };
50
- return poll();
23
+ const formatRemaining = (milliseconds) => {
24
+ const seconds = Math.max(0, Math.ceil(milliseconds / 1000));
25
+ return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`;
51
26
  };
27
+ const isConnected = (access) => access.refusal === null && access.identity === 'connected_person';
52
28
  const agentConnectHandler = async (options) => {
53
29
  globalState_1.default.setVerbose(options.verbose);
54
30
  const projectUuid = await (0, agentAccess_1.resolveAgentProject)(options.project);
55
31
  const access = await (0, agentAccess_1.getAgentAccess)(projectUuid);
56
- if (access.refusal === null && access.identity === 'connected_person') {
32
+ if (isConnected(access)) {
57
33
  console.error('Agent already connected');
58
34
  return;
59
35
  }
@@ -84,12 +60,14 @@ const agentConnectHandler = async (options) => {
84
60
  process.env.LIGHTDASH_OAUTH_PORT))) {
85
61
  throw new common_1.ParameterError('OAuth port must be a number between 1 and 65535');
86
62
  }
63
+ const requests = new AbortController();
64
+ let stopped = false;
87
65
  let resolveCallback;
88
66
  let rejectCallback;
89
67
  const callback = new Promise((resolve, reject) => {
90
68
  resolveCallback = resolve;
91
69
  rejectCallback = reject;
92
- }).then(() => ({ status: 'connected' }), (error) => ({ status: 'failed', code: error.message }));
70
+ });
93
71
  const server = http.createServer((req, res) => {
94
72
  const url = new URL(req.url ?? '/', 'http://localhost');
95
73
  if (req.method !== 'GET' || url.pathname !== '/done') {
@@ -114,7 +92,11 @@ const agentConnectHandler = async (options) => {
114
92
  resolveCallback();
115
93
  }
116
94
  });
117
- let timer;
95
+ let timer = null;
96
+ let pollTimer = null;
97
+ let countdownTimer = null;
98
+ let browserTimer = null;
99
+ let spinner = null;
118
100
  try {
119
101
  await new Promise((resolve, reject) => {
120
102
  server.once('error', reject);
@@ -129,33 +111,134 @@ const agentConnectHandler = async (options) => {
129
111
  const connectUrl = new URL(access.refusal.connectUrl);
130
112
  connectUrl.searchParams.set('redirect', redirect);
131
113
  connectUrl.searchParams.set('entryPoint', common_1.AgentIdentityConnectEntryPoint.CLI);
114
+ const interactive = process.stderr.isTTY === true &&
115
+ !globalState_1.default.isNonInteractive() &&
116
+ (!process.env.CI || process.env.CI === 'false');
117
+ const deadline = Date.now() + timeout * 1000;
118
+ const expiry = new Promise((resolve) => {
119
+ timer = setTimeout(() => resolve({ status: 'timeout' }), timeout * 1000);
120
+ });
132
121
  const result = Promise.race([
133
- callback,
122
+ callback.then(async () => {
123
+ try {
124
+ const currentAccess = await (0, agentAccess_1.getAgentAccess)(projectUuid, requests.signal);
125
+ return isConnected(currentAccess)
126
+ ? { status: 'connected', access: currentAccess }
127
+ : { status: 'user_not_connected' };
128
+ }
129
+ catch {
130
+ if (!stopped)
131
+ globalState_1.default.debug('> Could not refresh agent access after approval');
132
+ return expiry;
133
+ }
134
+ }, (error) => ({
135
+ status: 'failed',
136
+ code: error.message,
137
+ })),
138
+ expiry,
134
139
  new Promise((resolve) => {
135
- timer = setTimeout(() => resolve({ status: 'timeout' }), timeout * 1000);
140
+ let polling = false;
141
+ pollTimer = setInterval(async () => {
142
+ if (polling || stopped || Date.now() >= deadline)
143
+ return;
144
+ polling = true;
145
+ try {
146
+ const currentAccess = await (0, agentAccess_1.getAgentAccess)(projectUuid, requests.signal);
147
+ if (!stopped && isConnected(currentAccess)) {
148
+ resolve({
149
+ status: 'connected',
150
+ access: currentAccess,
151
+ });
152
+ }
153
+ }
154
+ catch {
155
+ if (!stopped)
156
+ globalState_1.default.debug('> Could not poll agent access; retrying');
157
+ }
158
+ finally {
159
+ polling = false;
160
+ }
161
+ }, 3000);
136
162
  }),
137
163
  ]);
138
- console.error(`\n${styles.title('🔐 Agent connection')}`);
139
- console.error('Opening browser for authentication...');
140
- console.error("If the browser doesn't open automatically, please visit:");
141
- console.error(`${styles.secondary(connectUrl.href)}\n`);
142
- await (0, oauth_1.openBrowser)(connectUrl.href);
164
+ console.error('Your agent needs to sign in to Snowflake as you, once.');
165
+ console.error(`\n Open: ${connectUrl.href}`);
166
+ const opened = await Promise.race([
167
+ (0, oauth_1.openBrowser)(connectUrl.href).catch(() => false),
168
+ new Promise((resolve) => {
169
+ browserTimer = setTimeout(() => resolve(false), 1500);
170
+ }),
171
+ result.then(() => false),
172
+ ]);
173
+ if (browserTimer)
174
+ clearTimeout(browserTimer);
175
+ console.error(opened
176
+ ? ' Opened in your browser.'
177
+ : ' Open this link in a browser to approve.');
178
+ const waiting = 'Waiting for you to approve in the browser…';
179
+ if (interactive) {
180
+ console.error('');
181
+ const waitingText = () => `${waiting} (link expires in ${formatRemaining(deadline - Date.now())})`;
182
+ spinner = globalState_1.default.startSpinner({
183
+ text: waitingText(),
184
+ stream: process.stderr,
185
+ isEnabled: true,
186
+ });
187
+ countdownTimer = setInterval(() => {
188
+ if (spinner)
189
+ spinner.text = waitingText();
190
+ }, 1000);
191
+ }
192
+ else {
193
+ const expiresAt = new Date(deadline).toLocaleTimeString('en-GB', {
194
+ hour: '2-digit',
195
+ minute: '2-digit',
196
+ });
197
+ console.error(` Link expires in ${formatRemaining(deadline - Date.now())} (at ${expiresAt}).\n`);
198
+ console.error(waiting);
199
+ }
143
200
  const outcome = await result;
144
- if (outcome.status === 'failed') {
145
- console.error(`Agent connection failed: ${getFailureReason(outcome.code)}`);
146
- process.exitCode = 1;
201
+ if (outcome.status === 'connected') {
202
+ const connectedAccess = outcome.access;
203
+ const principal = connectedAccess.principalName ?? 'you';
204
+ const until = connectedAccess.expiresAt
205
+ ? ` until ${new Date(connectedAccess.expiresAt).toLocaleDateString('en-GB', {
206
+ day: 'numeric',
207
+ month: 'short',
208
+ year: 'numeric',
209
+ })}`
210
+ : '';
211
+ const connected = `${interactive ? styles.success('Connected.') : 'Connected.'} Agents now run as ${interactive ? styles.bold(principal) : principal} in an agent session${until}.`;
212
+ if (spinner)
213
+ spinner.succeed(connected);
214
+ else
215
+ console.error(connected);
216
+ console.error('Run your last command again.');
147
217
  return;
148
218
  }
149
- if (outcome.status === 'connected' ||
150
- (await pollForConnection(projectUuid))) {
151
- console.error('Agent connected');
152
- return;
219
+ spinner?.stop();
220
+ if (outcome.status === 'user_not_connected') {
221
+ console.error('You approved in the browser, but this Lightdash user is still not connected. Check the browser is signed in to Lightdash as the same user, then run `lightdash agent connect` again.');
222
+ }
223
+ else {
224
+ console.error(outcome.status === 'failed'
225
+ ? `Connection failed: ${getFailureReason(outcome.code)} Run \`lightdash agent connect\` to try again.`
226
+ : 'The link expired before you approved it. Run `lightdash agent connect` to get a new link.');
153
227
  }
154
- console.error('Agent connection did not complete. Run `lightdash agent status` after you approve in the browser.');
155
228
  process.exitCode = 1;
156
229
  }
157
230
  finally {
158
- clearTimeout(timer);
231
+ stopped = true;
232
+ requests.abort();
233
+ if (timer)
234
+ clearTimeout(timer);
235
+ if (pollTimer)
236
+ clearInterval(pollTimer);
237
+ if (countdownTimer)
238
+ clearInterval(countdownTimer);
239
+ if (browserTimer)
240
+ clearTimeout(browserTimer);
241
+ spinner?.stop();
159
242
  await new Promise((resolve) => {
160
243
  server.close(() => resolve());
161
244
  server.closeAllConnections();
@@ -4,13 +4,14 @@ type LightdashApiProps = {
4
4
  method: 'GET' | 'POST' | 'PATCH' | 'DELETE' | 'PUT';
5
5
  url: string;
6
6
  body: BodyInit | undefined;
7
+ signal?: AbortSignal;
7
8
  };
8
9
  type LightdashRawApiProps = LightdashApiProps & {
9
10
  headers?: Record<string, string>;
10
11
  };
11
12
  export declare const setGzipEnabled: (enabled: boolean) => void;
12
- export declare const lightdashRawApi: ({ method, url, body, headers: requestHeaders, }: LightdashRawApiProps) => Promise<Response>;
13
- export declare const lightdashApi: <T extends ApiResponse['results']>({ method, url, body, }: LightdashApiProps) => Promise<T>;
13
+ export declare const lightdashRawApi: ({ method, url, body, headers: requestHeaders, signal, }: LightdashRawApiProps) => Promise<Response>;
14
+ export declare const lightdashApi: <T extends ApiResponse['results']>({ method, url, body, signal, }: LightdashApiProps) => Promise<T>;
14
15
  export declare const getUserContext: () => Promise<LightdashUserWithAbilityRules>;
15
16
  export type ContentAsCodeUploadPermissions = {
16
17
  charts: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/handlers/dbt/apiClient.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,WAAW,EAIX,WAAW,EAEX,KAAK,6BAA6B,EAGrC,MAAM,mBAAmB,CAAC;AAC3B,OAAc,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS5D,KAAK,iBAAiB,GAAG;IACrB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF,KAAK,oBAAoB,GAAG,iBAAiB,GAAG;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAKF,eAAO,MAAM,cAAc,YAAa,OAAO,SAE9C,CAAC;AAqCF,eAAO,MAAM,eAAe,oDAKzB,oBAAoB,KAAG,OAAO,CAAC,QAAQ,CA8BzC,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,CAAC,SAAS,WAAW,CAAC,SAAS,CAAC,0BAIhE,iBAAiB,KAAG,OAAO,CAAC,CAAC,CAgD/B,CAAC;AAEF,eAAO,MAAM,cAAc,QACb,OAAO,CAAC,6BAA6B,CAKzC,CAAC;AAEX,MAAM,MAAM,8BAA8B,GAAG;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,iCAAiC,gBAC7B,MAAM,KACpB,OAAO,CAAC,8BAA8B,CAiGxC,CAAC;AAEF,eAAO,MAAM,8BAA8B,wBAClB,MAAM,GAAG,SAAS,eAC1B,WAAW,KACzB,OAAO,CAAC,IAAI,CA+Gd,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,IAAI,CA2B1D,CAAC"}
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../src/handlers/dbt/apiClient.ts"],"names":[],"mappings":"AACA,OAAO,EAGH,WAAW,EAIX,WAAW,EAEX,KAAK,6BAA6B,EAGrC,MAAM,mBAAmB,CAAC;AAC3B,OAAc,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS5D,KAAK,iBAAiB,GAAG;IACrB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;CACxB,CAAC;AAEF,KAAK,oBAAoB,GAAG,iBAAiB,GAAG;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,CAAC;AAKF,eAAO,MAAM,cAAc,YAAa,OAAO,SAE9C,CAAC;AAkDF,eAAO,MAAM,eAAe,4DAMzB,oBAAoB,KAAG,OAAO,CAAC,QAAQ,CAmCzC,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,CAAC,SAAS,WAAW,CAAC,SAAS,CAAC,kCAKhE,iBAAiB,KAAG,OAAO,CAAC,CAAC,CAiD/B,CAAC;AAEF,eAAO,MAAM,cAAc,QACb,OAAO,CAAC,6BAA6B,CAKzC,CAAC;AAEX,MAAM,MAAM,8BAA8B,GAAG;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,iCAAiC,gBAC7B,MAAM,KACpB,OAAO,CAAC,8BAA8B,CAiGxC,CAAC;AAEF,eAAO,MAAM,8BAA8B,wBAClB,MAAM,GAAG,SAAS,eAC1B,WAAW,KACzB,OAAO,CAAC,IAAI,CA+Gd,CAAC;AAEF,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,IAAI,CA2B1D,CAAC"}
@@ -38,10 +38,16 @@ const fetchWithTimeout = async (fullUrl, init) => {
38
38
  const controller = new AbortController();
39
39
  const timer = setTimeout(() => controller.abort(), timeoutMs);
40
40
  try {
41
- return await (0, node_fetch_1.default)(fullUrl, { ...init, signal: controller.signal });
41
+ return await (0, node_fetch_1.default)(fullUrl, {
42
+ ...init,
43
+ signal: init.signal
44
+ ? AbortSignal.any([init.signal, controller.signal])
45
+ : controller.signal,
46
+ });
42
47
  }
43
48
  catch (error) {
44
- if (error.name === 'AbortError') {
49
+ if (controller.signal.aborted &&
50
+ error.name === 'AbortError') {
45
51
  throw new Error(`Request to ${fullUrl} timed out after ${timeoutMs}ms`);
46
52
  }
47
53
  throw error;
@@ -50,7 +56,7 @@ const fetchWithTimeout = async (fullUrl, init) => {
50
56
  clearTimeout(timer);
51
57
  }
52
58
  };
53
- const lightdashRawApi = async ({ method, url, body, headers: requestHeaders = {}, }) => {
59
+ const lightdashRawApi = async ({ method, url, body, headers: requestHeaders = {}, signal, }) => {
54
60
  const config = await (0, config_1.getConfig)();
55
61
  if (!(config.context?.apiKey && config.context.serverUrl)) {
56
62
  throw new common_1.AuthorizationError(`Not logged in. Run 'lightdash login --help'`);
@@ -61,7 +67,12 @@ const lightdashRawApi = async ({ method, url, body, headers: requestHeaders = {}
61
67
  };
62
68
  const fullUrl = new url_1.URL(url, config.context.serverUrl).href;
63
69
  globalState_1.default.debug(`> Making HTTP ${method} request to: ${fullUrl}`);
64
- const response = await fetchWithTimeout(fullUrl, { method, headers, body });
70
+ const response = await fetchWithTimeout(fullUrl, {
71
+ method,
72
+ headers,
73
+ body,
74
+ signal,
75
+ });
65
76
  globalState_1.default.debug(`> HTTP request returned status: ${response.status}`);
66
77
  if (!response.ok) {
67
78
  const contentType = response.headers.get('content-type');
@@ -75,7 +86,7 @@ const lightdashRawApi = async ({ method, url, body, headers: requestHeaders = {}
75
86
  return response;
76
87
  };
77
88
  exports.lightdashRawApi = lightdashRawApi;
78
- const lightdashApi = async ({ method, url, body, }) => {
89
+ const lightdashApi = async ({ method, url, body, signal, }) => {
79
90
  const headers = {};
80
91
  let requestBody = body;
81
92
  if (gzipEnabled &&
@@ -98,6 +109,7 @@ const lightdashApi = async ({ method, url, body, }) => {
98
109
  url,
99
110
  body: requestBody,
100
111
  headers,
112
+ signal,
101
113
  })
102
114
  .then((r) => r.json())
103
115
  .then((d) => {
@@ -1,2 +1,2 @@
1
- export declare const openBrowser: (url: string) => Promise<void>;
1
+ export declare const openBrowser: (url: string) => Promise<boolean>;
2
2
  //# sourceMappingURL=oauth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/handlers/login/oauth.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,WAAW,QAAe,MAAM,KAAG,OAAO,CAAC,IAAI,CAc3D,CAAC"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/handlers/login/oauth.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,WAAW,QAAe,MAAM,KAAG,OAAO,CAAC,OAAO,CAgB9D,CAAC"}
@@ -19,9 +19,11 @@ const openBrowser = async (url) => {
19
19
  else {
20
20
  await execAsync(`xdg-open "${url}"`);
21
21
  }
22
+ return true;
22
23
  }
23
24
  catch (error) {
24
25
  globalState_1.default.debug(`> Could not open browser automatically: ${error}`);
26
+ return false;
25
27
  }
26
28
  };
27
29
  exports.openBrowser = openBrowser;
package/dist/index.js CHANGED
@@ -162,7 +162,7 @@ agentProgram
162
162
  .description('Connects your agent to the warehouse using browser sign-in')
163
163
  .option('--project <project uuid or slug>', 'Specify the project', parseProjectArgument)
164
164
  .option('--oauth-port <port>', 'Port for the local callback server (default: LIGHTDASH_OAUTH_PORT or a random available port)', parseOAuthPortArgument)
165
- .option('--timeout <seconds>', 'Seconds to wait for the browser callback before polling for another 120 seconds', Number, 180)
165
+ .option('--timeout <seconds>', 'Seconds the connect link stays valid while the CLI waits for approval', Number, 180)
166
166
  .option('--verbose', undefined, false)
167
167
  .addHelpText('after', `
168
168
  ${styles.bold('Examples:')}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "2.504.2",
3
+ "version": "2.505.0",
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.504.2",
26
- "@lightdash/warehouses": "2.504.2",
25
+ "@lightdash/common": "2.505.0",
26
+ "@lightdash/warehouses": "2.505.0",
27
27
  "@sidvind/better-ajv-errors": "7.0.0",
28
28
  "@types/columnify": "1.5.1",
29
29
  "ajv": "8.18.0",