@lightdash/cli 2.504.2 → 2.505.1
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.
- package/dist/.tsbuildinfo.build +1 -1
- package/dist/handlers/agentAccess.d.ts +1 -1
- package/dist/handlers/agentAccess.d.ts.map +1 -1
- package/dist/handlers/agentAccess.js +2 -1
- package/dist/handlers/agentAccess.mock.d.ts.map +1 -1
- package/dist/handlers/agentAccess.mock.js +2 -0
- package/dist/handlers/agentConnect.d.ts.map +1 -1
- package/dist/handlers/agentConnect.js +130 -47
- package/dist/handlers/dbt/apiClient.d.ts +3 -2
- package/dist/handlers/dbt/apiClient.d.ts.map +1 -1
- package/dist/handlers/dbt/apiClient.js +17 -5
- package/dist/handlers/login/oauth.d.ts +1 -1
- package/dist/handlers/login/oauth.d.ts.map +1 -1
- package/dist/handlers/login/oauth.js +2 -0
- package/dist/index.js +1 -1
- package/package.json +3 -3
|
@@ -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,
|
|
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,
|
|
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":"
|
|
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
|
|
24
|
-
const
|
|
25
|
-
|
|
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
|
|
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
|
-
})
|
|
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
|
-
|
|
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(
|
|
139
|
-
console.error(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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 === '
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
console.error('
|
|
152
|
-
|
|
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
|
-
|
|
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;
|
|
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, {
|
|
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 (
|
|
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, {
|
|
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<
|
|
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,
|
|
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
|
|
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.
|
|
3
|
+
"version": "2.505.1",
|
|
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.
|
|
26
|
-
"@lightdash/warehouses": "2.
|
|
25
|
+
"@lightdash/common": "2.505.1",
|
|
26
|
+
"@lightdash/warehouses": "2.505.1",
|
|
27
27
|
"@sidvind/better-ajv-errors": "7.0.0",
|
|
28
28
|
"@types/columnify": "1.5.1",
|
|
29
29
|
"ajv": "8.18.0",
|