@slates/cli 1.0.0-rc.2 → 1.0.0-rc.4
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/package.json +4 -3
- package/src/commands/auth.ts +10 -5
- package/src/commands/test.ts +2 -0
- package/src/lib/integration.ts +45 -29
- package/src/lib/oauth.ts +6 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slates/cli",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@inquirer/prompts": "^7.4.0",
|
|
28
|
-
"@slates/client": "1.0.0-rc.
|
|
29
|
-
"@slates/
|
|
28
|
+
"@slates/client": "1.0.0-rc.6",
|
|
29
|
+
"@slates/oauth-microsoft": "1.0.0-rc.1",
|
|
30
|
+
"@slates/profiles": "1.0.0-rc.4",
|
|
30
31
|
"sade": "^1.8.1"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
package/src/commands/auth.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { confirm, select } from '@inquirer/prompts';
|
|
2
|
+
import { normalizeMicrosoftRedirectUriForIntegration } from '@slates/oauth-microsoft';
|
|
2
3
|
import { SlatesOAuthCredentialRecord, SlatesStoredAuth } from '@slates/profiles';
|
|
3
4
|
import {
|
|
4
5
|
chooseAuthMethod,
|
|
@@ -6,7 +7,7 @@ import {
|
|
|
6
7
|
createIntegrationClientContext,
|
|
7
8
|
openIntegrationStore
|
|
8
9
|
} from '../lib/context';
|
|
9
|
-
import { chooseScopes, createOAuthCallbackListener,
|
|
10
|
+
import { chooseScopes, createOAuthCallbackListener, printBrowserUrl } from '../lib/oauth';
|
|
10
11
|
import {
|
|
11
12
|
parseJsonObject,
|
|
12
13
|
parseList,
|
|
@@ -263,7 +264,11 @@ let runAuthSetup = async (opts: AuthSetupOptions): Promise<SlatesStoredAuth> =>
|
|
|
263
264
|
|
|
264
265
|
if (authMethod.type === 'auth.oauth') {
|
|
265
266
|
let callback = await createOAuthCallbackListener();
|
|
266
|
-
|
|
267
|
+
let redirectUri = normalizeMicrosoftRedirectUriForIntegration(
|
|
268
|
+
opts.integration,
|
|
269
|
+
callback.redirectUri
|
|
270
|
+
);
|
|
271
|
+
console.log(`OAuth redirect URL: ${redirectUri}`);
|
|
267
272
|
|
|
268
273
|
let resolvedOAuthCredentials = await chooseOAuthCredentialsForSetup({
|
|
269
274
|
store,
|
|
@@ -282,7 +287,7 @@ let runAuthSetup = async (opts: AuthSetupOptions): Promise<SlatesStoredAuth> =>
|
|
|
282
287
|
|
|
283
288
|
let authorizationUrl = await client.getAuthorizationUrl({
|
|
284
289
|
authenticationMethodId: authMethod.id,
|
|
285
|
-
redirectUri
|
|
290
|
+
redirectUri,
|
|
286
291
|
state: callback.state,
|
|
287
292
|
input: authInput,
|
|
288
293
|
clientId,
|
|
@@ -293,7 +298,7 @@ let runAuthSetup = async (opts: AuthSetupOptions): Promise<SlatesStoredAuth> =>
|
|
|
293
298
|
callbackState = authorizationUrl.callbackState ?? null;
|
|
294
299
|
finalInput = authorizationUrl.input ?? authInput;
|
|
295
300
|
|
|
296
|
-
|
|
301
|
+
printBrowserUrl(authorizationUrl.authorizationUrl);
|
|
297
302
|
let callbackResult = await callback.wait();
|
|
298
303
|
if (callbackResult.state !== callback.state) {
|
|
299
304
|
throw new Error('OAuth state mismatch.');
|
|
@@ -303,7 +308,7 @@ let runAuthSetup = async (opts: AuthSetupOptions): Promise<SlatesStoredAuth> =>
|
|
|
303
308
|
authenticationMethodId: authMethod.id,
|
|
304
309
|
code: callbackResult.code,
|
|
305
310
|
state: callbackResult.state,
|
|
306
|
-
redirectUri
|
|
311
|
+
redirectUri,
|
|
307
312
|
input: finalInput,
|
|
308
313
|
clientId,
|
|
309
314
|
clientSecret,
|
package/src/commands/test.ts
CHANGED
|
@@ -47,6 +47,7 @@ export let runVitestWithProfile = async (opts: WithProfile & { vitestArgs: strin
|
|
|
47
47
|
{
|
|
48
48
|
integration: integration.relativeDir,
|
|
49
49
|
profileId: profile.id,
|
|
50
|
+
rootDir: store.rootDir,
|
|
50
51
|
storePath: store.storePath,
|
|
51
52
|
cliDir: store.dirPath
|
|
52
53
|
},
|
|
@@ -64,6 +65,7 @@ export let runVitestWithProfile = async (opts: WithProfile & { vitestArgs: strin
|
|
|
64
65
|
SLATES_INTEGRATION: integration.relativeDir,
|
|
65
66
|
SLATES_PROFILE_ID: profile.id,
|
|
66
67
|
SLATES_CLI_DIR: store.dirPath,
|
|
68
|
+
SLATES_STORE_ROOT_DIR: store.rootDir,
|
|
67
69
|
SLATES_STORE_PATH: store.storePath,
|
|
68
70
|
SLATES_TEST_CONTEXT_PATH: contextPath
|
|
69
71
|
}
|
package/src/lib/integration.ts
CHANGED
|
@@ -36,17 +36,24 @@ let isWithinRoot = (rootDir: string, targetPath: string) => {
|
|
|
36
36
|
|
|
37
37
|
let resolveIntegrationDir = async (input: string, cwd: string) => {
|
|
38
38
|
let rootDir = resolveSlatesCliRoot(cwd);
|
|
39
|
-
let
|
|
39
|
+
let integrationRoots = [
|
|
40
|
+
path.join(rootDir, 'integrations'),
|
|
41
|
+
path.join(rootDir, 'test-integrations')
|
|
42
|
+
];
|
|
43
|
+
|
|
40
44
|
if (!input.includes(path.sep) && !input.includes('/')) {
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
for (let root of integrationRoots) {
|
|
46
|
+
let namedPath = path.join(root, input);
|
|
47
|
+
if (await pathExists(path.join(namedPath, 'package.json'))) {
|
|
48
|
+
return { rootDir, dirPath: namedPath };
|
|
49
|
+
}
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
let candidate = path.resolve(cwd, input);
|
|
47
54
|
if (!(await pathExists(path.join(candidate, 'package.json')))) {
|
|
48
55
|
throw new Error(
|
|
49
|
-
`Could not resolve integration "${input}". Pass an integration name from \`integrations/\` or a relative path to an integration directory.`
|
|
56
|
+
`Could not resolve integration "${input}". Pass an integration name from \`integrations/\` or \`test-integrations/\`, or a relative path to an integration directory.`
|
|
50
57
|
);
|
|
51
58
|
}
|
|
52
59
|
|
|
@@ -103,32 +110,41 @@ export let resolveIntegration = async (
|
|
|
103
110
|
export let listWorkspaceIntegrations = async (opts: { cwd?: string } = {}) => {
|
|
104
111
|
let cwd = opts.cwd ?? process.cwd();
|
|
105
112
|
let rootDir = resolveSlatesCliRoot(cwd);
|
|
106
|
-
let
|
|
113
|
+
let integrationRoots = [
|
|
114
|
+
path.join(rootDir, 'integrations'),
|
|
115
|
+
path.join(rootDir, 'test-integrations')
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
let integrations: WorkspaceIntegrationSummary[] = [];
|
|
119
|
+
|
|
120
|
+
for (let integrationsDir of integrationRoots) {
|
|
121
|
+
if (!(await pathExists(integrationsDir))) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
107
124
|
|
|
108
|
-
|
|
109
|
-
|
|
125
|
+
let entries = await readdir(integrationsDir, { withFileTypes: true });
|
|
126
|
+
let chunk = await Promise.all(
|
|
127
|
+
entries
|
|
128
|
+
.filter(entry => entry.isDirectory())
|
|
129
|
+
.map(async entry => {
|
|
130
|
+
let dirPath = path.join(integrationsDir, entry.name);
|
|
131
|
+
if (!(await pathExists(path.join(dirPath, 'package.json')))) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
rootDir,
|
|
137
|
+
dirPath,
|
|
138
|
+
relativeDir: toPosixPath(path.relative(rootDir, dirPath)),
|
|
139
|
+
name: entry.name
|
|
140
|
+
} satisfies WorkspaceIntegrationSummary;
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
integrations.push(
|
|
145
|
+
...chunk.filter((integration): integration is WorkspaceIntegrationSummary => integration !== null)
|
|
146
|
+
);
|
|
110
147
|
}
|
|
111
148
|
|
|
112
|
-
|
|
113
|
-
let integrations = await Promise.all(
|
|
114
|
-
entries
|
|
115
|
-
.filter(entry => entry.isDirectory())
|
|
116
|
-
.map(async entry => {
|
|
117
|
-
let dirPath = path.join(integrationsDir, entry.name);
|
|
118
|
-
if (!(await pathExists(path.join(dirPath, 'package.json')))) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
rootDir,
|
|
124
|
-
dirPath,
|
|
125
|
-
relativeDir: toPosixPath(path.relative(rootDir, dirPath)),
|
|
126
|
-
name: entry.name
|
|
127
|
-
} satisfies WorkspaceIntegrationSummary;
|
|
128
|
-
})
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
return integrations
|
|
132
|
-
.filter((integration): integration is WorkspaceIntegrationSummary => integration !== null)
|
|
133
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
149
|
+
return integrations.sort((a, b) => a.relativeDir.localeCompare(b.relativeDir));
|
|
134
150
|
};
|
package/src/lib/oauth.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { checkbox } from '@inquirer/prompts';
|
|
2
|
-
import { execFile } from 'child_process';
|
|
3
2
|
import { randomUUID } from 'crypto';
|
|
4
3
|
import { createServer } from 'http';
|
|
5
|
-
import { promisify } from 'util';
|
|
6
4
|
|
|
7
|
-
let execFileAsync = promisify(execFile);
|
|
8
5
|
let DEFAULT_OAUTH_CALLBACK_PORT = 45873;
|
|
9
6
|
|
|
10
7
|
export let chooseScopes = async (
|
|
@@ -21,27 +18,16 @@ export let chooseScopes = async (
|
|
|
21
18
|
choices: authMethod.scopes.map((scope: any) => ({
|
|
22
19
|
name: `${scope.title} (${scope.id})`,
|
|
23
20
|
value: scope.id,
|
|
24
|
-
checked:
|
|
21
|
+
checked:
|
|
22
|
+
initialScopes.length > 0
|
|
23
|
+
? initialScopes.includes(scope.id)
|
|
24
|
+
: scope.defaultChecked ?? true
|
|
25
25
|
}))
|
|
26
26
|
})) as string[];
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
export let
|
|
30
|
-
|
|
31
|
-
if (process.platform === 'darwin') {
|
|
32
|
-
await execFileAsync('open', [url]);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (process.platform === 'win32') {
|
|
37
|
-
await execFileAsync('cmd', ['/c', 'start', '', url]);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
await execFileAsync('xdg-open', [url]);
|
|
42
|
-
} catch {
|
|
43
|
-
console.log(`Open this URL in your browser:\n${url}`);
|
|
44
|
-
}
|
|
29
|
+
export let printBrowserUrl = (url: string) => {
|
|
30
|
+
console.log(`Open this URL in your browser:\n${url}`);
|
|
45
31
|
};
|
|
46
32
|
|
|
47
33
|
export let createOAuthCallbackListener = async () => {
|