@slates/cli 1.0.0-rc.4 → 1.0.0-rc.5
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 -4
- package/src/cli.ts +206 -176
- package/src/commands/auth.test.ts +36 -0
- package/src/commands/auth.ts +36 -4
- package/src/lib/context.ts +9 -2
- package/src/lib/oauth.ts +25 -1
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.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@inquirer/prompts": "^7.4.0",
|
|
28
|
-
"@slates/client": "1.0.0-rc.
|
|
29
|
-
"@slates/oauth-microsoft": "1.0.0-rc.
|
|
30
|
-
"@slates/profiles": "1.0.0-rc.
|
|
28
|
+
"@slates/client": "1.0.0-rc.7",
|
|
29
|
+
"@slates/oauth-microsoft": "1.0.0-rc.2",
|
|
30
|
+
"@slates/profiles": "1.0.0-rc.5",
|
|
31
31
|
"sade": "^1.8.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
package/src/cli.ts
CHANGED
|
@@ -59,203 +59,233 @@ if (isGlobalTestCommand) {
|
|
|
59
59
|
|
|
60
60
|
cli.parse([process.argv[0] ?? 'bun', process.argv[1] ?? 'slates', ...argv]);
|
|
61
61
|
} else {
|
|
62
|
+
cli
|
|
63
|
+
.command('profiles add')
|
|
64
|
+
.option('--name', 'Profile name')
|
|
65
|
+
.option('--entry', 'Local slate entry file')
|
|
66
|
+
.option('--export-name', 'Named export for the local slate provider')
|
|
67
|
+
.option('--default', 'Use this profile as the default')
|
|
68
|
+
.action(opts =>
|
|
69
|
+
printResult(() =>
|
|
70
|
+
addProfile({
|
|
71
|
+
integration: integration!,
|
|
72
|
+
name: opts.name,
|
|
73
|
+
entry: opts.entry,
|
|
74
|
+
exportName: opts.exportName,
|
|
75
|
+
useAsDefault: Boolean(opts.default)
|
|
76
|
+
})
|
|
77
|
+
)
|
|
78
|
+
);
|
|
62
79
|
|
|
63
|
-
cli
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
.option('--entry', 'Local slate entry file')
|
|
67
|
-
.option('--export-name', 'Named export for the local slate provider')
|
|
68
|
-
.option('--default', 'Use this profile as the default')
|
|
69
|
-
.action(opts =>
|
|
70
|
-
printResult(() =>
|
|
71
|
-
addProfile({
|
|
72
|
-
integration: integration!,
|
|
73
|
-
name: opts.name,
|
|
74
|
-
entry: opts.entry,
|
|
75
|
-
exportName: opts.exportName,
|
|
76
|
-
useAsDefault: Boolean(opts.default)
|
|
77
|
-
})
|
|
78
|
-
)
|
|
79
|
-
);
|
|
80
|
+
cli
|
|
81
|
+
.command('profiles list')
|
|
82
|
+
.action(() => printResult(() => listProfiles({ integration: integration! })));
|
|
80
83
|
|
|
81
|
-
cli
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
cli
|
|
85
|
+
.command('profiles get [profile]')
|
|
86
|
+
.action((profile: string | undefined) =>
|
|
87
|
+
printResult(() => getProfile({ integration: integration!, profile }))
|
|
88
|
+
);
|
|
84
89
|
|
|
85
|
-
cli
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
cli
|
|
91
|
+
.command('profiles use [profile]')
|
|
92
|
+
.action((profile: string | undefined) =>
|
|
93
|
+
printResult(() => useProfile({ integration: integration!, profile }))
|
|
94
|
+
);
|
|
90
95
|
|
|
91
|
-
cli
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
cli
|
|
97
|
+
.command('profiles remove [profile]')
|
|
98
|
+
.action((profile: string | undefined) =>
|
|
99
|
+
printResult(() => removeProfile({ integration: integration!, profile }))
|
|
100
|
+
);
|
|
96
101
|
|
|
97
|
-
cli
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
cli
|
|
103
|
+
.command('setup')
|
|
104
|
+
.option('--name', 'Profile name')
|
|
105
|
+
.option('--export-name', 'Named export for the local slate provider')
|
|
106
|
+
.action(opts =>
|
|
107
|
+
printResult(() =>
|
|
108
|
+
setupIntegration({
|
|
109
|
+
integration: integration!,
|
|
110
|
+
name: opts.name,
|
|
111
|
+
exportName: opts.exportName
|
|
112
|
+
})
|
|
113
|
+
)
|
|
114
|
+
);
|
|
102
115
|
|
|
103
|
-
cli
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
)
|
|
115
|
-
);
|
|
116
|
+
cli
|
|
117
|
+
.command('tools list')
|
|
118
|
+
.option('--profile', 'Profile ID or name')
|
|
119
|
+
.action(opts =>
|
|
120
|
+
printResult(() =>
|
|
121
|
+
listTools({
|
|
122
|
+
integration: integration!,
|
|
123
|
+
profile: opts.profile
|
|
124
|
+
})
|
|
125
|
+
)
|
|
126
|
+
);
|
|
116
127
|
|
|
117
|
-
cli
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
128
|
+
cli
|
|
129
|
+
.command('tools get [toolId]')
|
|
130
|
+
.option('--profile', 'Profile ID or name')
|
|
131
|
+
.action((toolId: string | undefined, opts) =>
|
|
132
|
+
printResult(() =>
|
|
133
|
+
getTool({
|
|
134
|
+
integration: integration!,
|
|
135
|
+
profile: opts.profile,
|
|
136
|
+
toolId
|
|
137
|
+
})
|
|
138
|
+
)
|
|
139
|
+
);
|
|
121
140
|
|
|
122
|
-
cli
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
printResult(async () => {
|
|
134
|
-
let tool = await getTool({ integration: integration!, profile: opts.profile, toolId });
|
|
135
|
-
return tool.inputSchema;
|
|
136
|
-
})
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
cli
|
|
140
|
-
.command('tools call [toolId]')
|
|
141
|
-
.option('--profile', 'Profile ID or name')
|
|
142
|
-
.option('--input', 'JSON input object')
|
|
143
|
-
.option('--auth-method-id', 'Preferred auth method ID')
|
|
144
|
-
.action((toolId: string | undefined, opts) =>
|
|
145
|
-
printResult(() =>
|
|
146
|
-
callTool({
|
|
147
|
-
integration: integration!,
|
|
148
|
-
profile: opts.profile,
|
|
149
|
-
toolId,
|
|
150
|
-
input: opts.input,
|
|
151
|
-
authMethodId: opts.authMethodId
|
|
141
|
+
cli
|
|
142
|
+
.command('tools schema [toolId]')
|
|
143
|
+
.option('--profile', 'Profile ID or name')
|
|
144
|
+
.action((toolId: string | undefined, opts) =>
|
|
145
|
+
printResult(async () => {
|
|
146
|
+
let tool = await getTool({
|
|
147
|
+
integration: integration!,
|
|
148
|
+
profile: opts.profile,
|
|
149
|
+
toolId
|
|
150
|
+
});
|
|
151
|
+
return tool.inputSchema;
|
|
152
152
|
})
|
|
153
|
-
)
|
|
154
|
-
);
|
|
153
|
+
);
|
|
155
154
|
|
|
156
|
-
cli
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
cli
|
|
156
|
+
.command('tools call [toolId]')
|
|
157
|
+
.option('--profile', 'Profile ID or name')
|
|
158
|
+
.option('--input', 'JSON input object')
|
|
159
|
+
.option('--auth-method-id', 'Preferred auth method ID')
|
|
160
|
+
.action((toolId: string | undefined, opts) =>
|
|
161
|
+
printResult(() =>
|
|
162
|
+
callTool({
|
|
163
|
+
integration: integration!,
|
|
164
|
+
profile: opts.profile,
|
|
165
|
+
toolId,
|
|
166
|
+
input: opts.input,
|
|
167
|
+
authMethodId: opts.authMethodId
|
|
168
|
+
})
|
|
169
|
+
)
|
|
170
|
+
);
|
|
160
171
|
|
|
161
|
-
cli
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
172
|
+
cli
|
|
173
|
+
.command('auth list')
|
|
174
|
+
.option('--profile', 'Profile ID or name')
|
|
175
|
+
.action(opts =>
|
|
176
|
+
printResult(() => listAuth({ integration: integration!, profile: opts.profile }))
|
|
177
|
+
);
|
|
167
178
|
|
|
168
|
-
cli
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
.action((authMethodId: string | undefined, opts) =>
|
|
177
|
-
printResult(() =>
|
|
178
|
-
setupAuth({
|
|
179
|
-
integration: integration!,
|
|
180
|
-
profile: opts.profile,
|
|
181
|
-
authMethodId,
|
|
182
|
-
input: opts.input,
|
|
183
|
-
oauthCredential: opts.oauthCredential,
|
|
184
|
-
clientId: opts.clientId,
|
|
185
|
-
clientSecret: opts.clientSecret,
|
|
186
|
-
scopes: opts.scopes
|
|
187
|
-
})
|
|
188
|
-
)
|
|
189
|
-
);
|
|
179
|
+
cli
|
|
180
|
+
.command('auth get [authMethodId]')
|
|
181
|
+
.option('--profile', 'Profile ID or name')
|
|
182
|
+
.action((authMethodId: string | undefined, opts) =>
|
|
183
|
+
printResult(() =>
|
|
184
|
+
getAuth({ integration: integration!, profile: opts.profile, authMethodId })
|
|
185
|
+
)
|
|
186
|
+
);
|
|
190
187
|
|
|
191
|
-
cli
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
188
|
+
cli
|
|
189
|
+
.command('auth setup [authMethodId]')
|
|
190
|
+
.option('--profile', 'Profile ID or name')
|
|
191
|
+
.option('--input', 'JSON auth input object')
|
|
192
|
+
.option('--oauth-credential', 'OAuth credential ID or name')
|
|
193
|
+
.option('--client-id', 'OAuth client ID')
|
|
194
|
+
.option('--client-secret', 'OAuth client secret')
|
|
195
|
+
.option('--scopes', 'Comma-separated OAuth scopes')
|
|
196
|
+
.action((authMethodId: string | undefined, opts) =>
|
|
197
|
+
printResult(() =>
|
|
198
|
+
setupAuth({
|
|
199
|
+
integration: integration!,
|
|
200
|
+
profile: opts.profile,
|
|
201
|
+
authMethodId,
|
|
202
|
+
input: opts.input,
|
|
203
|
+
oauthCredential: opts.oauthCredential,
|
|
204
|
+
clientId: opts.clientId,
|
|
205
|
+
clientSecret: opts.clientSecret,
|
|
206
|
+
scopes: opts.scopes
|
|
207
|
+
})
|
|
208
|
+
)
|
|
209
|
+
);
|
|
196
210
|
|
|
197
|
-
cli
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
.action((authMethodId: string | undefined, opts) =>
|
|
203
|
-
printResult(() =>
|
|
204
|
-
addOAuthCredentials({
|
|
205
|
-
integration: integration!,
|
|
206
|
-
authMethodId,
|
|
207
|
-
name: opts.name,
|
|
208
|
-
clientId: opts.clientId,
|
|
209
|
-
clientSecret: opts.clientSecret
|
|
210
|
-
})
|
|
211
|
-
)
|
|
212
|
-
);
|
|
211
|
+
cli
|
|
212
|
+
.command('auth credentials list [authMethodId]')
|
|
213
|
+
.action((authMethodId: string | undefined) =>
|
|
214
|
+
printResult(() => listOAuthCredentials({ integration: integration!, authMethodId }))
|
|
215
|
+
);
|
|
213
216
|
|
|
214
|
-
cli
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
cli
|
|
218
|
+
.command('auth credentials add [authMethodId]')
|
|
219
|
+
.option('--name', 'Credential name')
|
|
220
|
+
.option('--client-id', 'OAuth client ID')
|
|
221
|
+
.option('--client-secret', 'OAuth client secret')
|
|
222
|
+
.action((authMethodId: string | undefined, opts) =>
|
|
223
|
+
printResult(() =>
|
|
224
|
+
addOAuthCredentials({
|
|
225
|
+
integration: integration!,
|
|
226
|
+
authMethodId,
|
|
227
|
+
name: opts.name,
|
|
228
|
+
clientId: opts.clientId,
|
|
229
|
+
clientSecret: opts.clientSecret
|
|
230
|
+
})
|
|
231
|
+
)
|
|
232
|
+
);
|
|
220
233
|
|
|
221
|
-
cli
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
234
|
+
cli
|
|
235
|
+
.command('auth refresh [authMethodId]')
|
|
236
|
+
.option('--profile', 'Profile ID or name')
|
|
237
|
+
.action((authMethodId: string | undefined, opts) =>
|
|
238
|
+
printResult(() =>
|
|
239
|
+
refreshAuth({ integration: integration!, profile: opts.profile, authMethodId })
|
|
240
|
+
)
|
|
241
|
+
);
|
|
225
242
|
|
|
226
|
-
cli
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
);
|
|
243
|
+
cli
|
|
244
|
+
.command('config get')
|
|
245
|
+
.option('--profile', 'Profile ID or name')
|
|
246
|
+
.action(opts =>
|
|
247
|
+
printResult(() => getConfig({ integration: integration!, profile: opts.profile }))
|
|
248
|
+
);
|
|
233
249
|
|
|
234
|
-
cli
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
250
|
+
cli
|
|
251
|
+
.command('config set')
|
|
252
|
+
.option('--profile', 'Profile ID or name')
|
|
253
|
+
.option('--input', 'JSON config object')
|
|
254
|
+
.action(opts =>
|
|
255
|
+
printResult(() =>
|
|
256
|
+
setConfig({ integration: integration!, profile: opts.profile, input: opts.input })
|
|
257
|
+
)
|
|
258
|
+
);
|
|
238
259
|
|
|
239
|
-
cli
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
await runVitestWithProfile({
|
|
246
|
-
integration: integration!,
|
|
247
|
-
profile: opts.profile,
|
|
248
|
-
vitestArgs: separatorIndex === -1 ? [] : process.argv.slice(separatorIndex + 1)
|
|
249
|
-
});
|
|
260
|
+
cli
|
|
261
|
+
.command('config schema')
|
|
262
|
+
.option('--profile', 'Profile ID or name')
|
|
263
|
+
.action(opts =>
|
|
264
|
+
printResult(() => getConfigSchema({ integration: integration!, profile: opts.profile }))
|
|
265
|
+
);
|
|
250
266
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
267
|
+
cli
|
|
268
|
+
.command('test')
|
|
269
|
+
.option('--profile', 'Profile ID or name')
|
|
270
|
+
.action(opts =>
|
|
271
|
+
printResult(async () => {
|
|
272
|
+
let separatorIndex = process.argv.indexOf('--');
|
|
273
|
+
await runVitestWithProfile({
|
|
274
|
+
integration: integration!,
|
|
275
|
+
profile: opts.profile,
|
|
276
|
+
vitestArgs: separatorIndex === -1 ? [] : process.argv.slice(separatorIndex + 1)
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
return { success: true };
|
|
280
|
+
})
|
|
281
|
+
);
|
|
254
282
|
|
|
255
|
-
cli
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
283
|
+
cli
|
|
284
|
+
.command('repl')
|
|
285
|
+
.option('--profile', 'Profile ID or name')
|
|
286
|
+
.action(opts =>
|
|
287
|
+
printResult(() => startRepl({ integration: integration!, profile: opts.profile }))
|
|
288
|
+
);
|
|
259
289
|
|
|
260
290
|
cli.parse([process.argv[0] ?? 'bun', process.argv[1] ?? 'slates', ...argv.slice(1)]);
|
|
261
291
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { normalizeCallbackRedirectUriForIntegration } from './auth';
|
|
3
|
+
|
|
4
|
+
describe('normalizeCallbackRedirectUriForIntegration', () => {
|
|
5
|
+
it('normalizes Notion loopback redirects to localhost', () => {
|
|
6
|
+
expect(
|
|
7
|
+
normalizeCallbackRedirectUriForIntegration('notion', 'http://127.0.0.1:45873/callback')
|
|
8
|
+
).toBe('http://localhost:45873/callback');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('leaves unrelated integration redirects unchanged', () => {
|
|
12
|
+
expect(
|
|
13
|
+
normalizeCallbackRedirectUriForIntegration('attio', 'http://127.0.0.1:45873/callback')
|
|
14
|
+
).toBe('http://127.0.0.1:45873/callback');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('normalizes HubSpot developer platform OAuth redirects to localhost', () => {
|
|
18
|
+
expect(
|
|
19
|
+
normalizeCallbackRedirectUriForIntegration(
|
|
20
|
+
'hubspot',
|
|
21
|
+
'http://127.0.0.1:45873/callback',
|
|
22
|
+
'developer_platform_oauth'
|
|
23
|
+
)
|
|
24
|
+
).toBe('http://localhost:45873/callback');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('leaves HubSpot legacy OAuth redirects unchanged', () => {
|
|
28
|
+
expect(
|
|
29
|
+
normalizeCallbackRedirectUriForIntegration(
|
|
30
|
+
'hubspot',
|
|
31
|
+
'http://127.0.0.1:45873/callback',
|
|
32
|
+
'oauth'
|
|
33
|
+
)
|
|
34
|
+
).toBe('http://127.0.0.1:45873/callback');
|
|
35
|
+
});
|
|
36
|
+
});
|
package/src/commands/auth.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { confirm, select } from '@inquirer/prompts';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
normalizeMicrosoftRedirectUri,
|
|
4
|
+
normalizeMicrosoftRedirectUriForIntegration
|
|
5
|
+
} from '@slates/oauth-microsoft';
|
|
3
6
|
import { SlatesOAuthCredentialRecord, SlatesStoredAuth } from '@slates/profiles';
|
|
4
7
|
import {
|
|
5
8
|
chooseAuthMethod,
|
|
@@ -17,6 +20,14 @@ import {
|
|
|
17
20
|
import { JsonInput, WithProfile } from '../lib/types';
|
|
18
21
|
|
|
19
22
|
type JsonObject = Record<string, any>;
|
|
23
|
+
let NOTION_INTEGRATION_KEY = 'notion';
|
|
24
|
+
let SALESFORCE_INTEGRATION_KEY = 'salesforce';
|
|
25
|
+
let HUBSPOT_INTEGRATION_KEY = 'hubspot';
|
|
26
|
+
let HUBSPOT_DEVELOPER_PLATFORM_OAUTH_METHOD_ID = 'developer_platform_oauth';
|
|
27
|
+
let LOOPBACK_REDIRECT_NORMALIZED_INTEGRATIONS = new Set([
|
|
28
|
+
NOTION_INTEGRATION_KEY,
|
|
29
|
+
SALESFORCE_INTEGRATION_KEY
|
|
30
|
+
]);
|
|
20
31
|
|
|
21
32
|
type AuthSetupOptions = WithProfile &
|
|
22
33
|
JsonInput & {
|
|
@@ -27,6 +38,22 @@ type AuthSetupOptions = WithProfile &
|
|
|
27
38
|
scopes?: string;
|
|
28
39
|
};
|
|
29
40
|
|
|
41
|
+
export let normalizeCallbackRedirectUriForIntegration = (
|
|
42
|
+
integration: string,
|
|
43
|
+
redirectUri: string,
|
|
44
|
+
authMethodId?: string
|
|
45
|
+
) => {
|
|
46
|
+
if (
|
|
47
|
+
LOOPBACK_REDIRECT_NORMALIZED_INTEGRATIONS.has(integration) ||
|
|
48
|
+
(integration === HUBSPOT_INTEGRATION_KEY &&
|
|
49
|
+
authMethodId === HUBSPOT_DEVELOPER_PLATFORM_OAUTH_METHOD_ID)
|
|
50
|
+
) {
|
|
51
|
+
return normalizeMicrosoftRedirectUri(redirectUri);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return normalizeMicrosoftRedirectUriForIntegration(integration, redirectUri);
|
|
55
|
+
};
|
|
56
|
+
|
|
30
57
|
export let listAuth = async (opts: WithProfile) => {
|
|
31
58
|
let { store, profile } = await createClientContext(opts);
|
|
32
59
|
return store.listAuth(profile.id);
|
|
@@ -232,7 +259,11 @@ let chooseOAuthCredentialsForSetup = async (opts: {
|
|
|
232
259
|
};
|
|
233
260
|
|
|
234
261
|
let runAuthSetup = async (opts: AuthSetupOptions): Promise<SlatesStoredAuth> => {
|
|
235
|
-
let { store, profile, client } = await createClientContext(
|
|
262
|
+
let { store, profile, client } = await createClientContext({
|
|
263
|
+
...opts,
|
|
264
|
+
autoRefresh: false
|
|
265
|
+
});
|
|
266
|
+
client.clearAuth();
|
|
236
267
|
let authMethod = await chooseAuthMethod({
|
|
237
268
|
client,
|
|
238
269
|
authMethodId: opts.authMethodId,
|
|
@@ -264,9 +295,10 @@ let runAuthSetup = async (opts: AuthSetupOptions): Promise<SlatesStoredAuth> =>
|
|
|
264
295
|
|
|
265
296
|
if (authMethod.type === 'auth.oauth') {
|
|
266
297
|
let callback = await createOAuthCallbackListener();
|
|
267
|
-
let redirectUri =
|
|
298
|
+
let redirectUri = normalizeCallbackRedirectUriForIntegration(
|
|
268
299
|
opts.integration,
|
|
269
|
-
callback.redirectUri
|
|
300
|
+
callback.redirectUri,
|
|
301
|
+
authMethod.id
|
|
270
302
|
);
|
|
271
303
|
console.log(`OAuth redirect URL: ${redirectUri}`);
|
|
272
304
|
|
package/src/lib/context.ts
CHANGED
|
@@ -71,9 +71,16 @@ export let chooseProfile = async (d: {
|
|
|
71
71
|
};
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
export let createClientContext = async (opts: {
|
|
74
|
+
export let createClientContext = async (opts: {
|
|
75
|
+
integration: string;
|
|
76
|
+
profile?: string;
|
|
77
|
+
autoRefresh?: boolean;
|
|
78
|
+
}) => {
|
|
75
79
|
let { integration, store, profile } = await chooseProfile(opts);
|
|
76
|
-
let client = await createSlatesClientFromProfile(profile, {
|
|
80
|
+
let client = await createSlatesClientFromProfile(profile, {
|
|
81
|
+
store,
|
|
82
|
+
autoRefresh: opts.autoRefresh
|
|
83
|
+
});
|
|
77
84
|
return { integration, store, profile, client };
|
|
78
85
|
};
|
|
79
86
|
|
package/src/lib/oauth.ts
CHANGED
|
@@ -21,7 +21,7 @@ export let chooseScopes = async (
|
|
|
21
21
|
checked:
|
|
22
22
|
initialScopes.length > 0
|
|
23
23
|
? initialScopes.includes(scope.id)
|
|
24
|
-
: scope.defaultChecked ?? true
|
|
24
|
+
: (scope.defaultChecked ?? true)
|
|
25
25
|
}))
|
|
26
26
|
})) as string[];
|
|
27
27
|
};
|
|
@@ -45,10 +45,34 @@ export let createOAuthCallbackListener = async () => {
|
|
|
45
45
|
let url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
46
46
|
let code = url.searchParams.get('code');
|
|
47
47
|
let state = url.searchParams.get('state');
|
|
48
|
+
let oauthError = url.searchParams.get('error');
|
|
49
|
+
let oauthErrorDescription = url.searchParams.get('error_description');
|
|
50
|
+
let oauthErrorUri = url.searchParams.get('error_uri');
|
|
51
|
+
|
|
52
|
+
if (oauthError) {
|
|
53
|
+
let description = oauthErrorDescription ?? 'No error description was provided.';
|
|
54
|
+
let errorMessage = `OAuth callback returned "${oauthError}": ${description}${
|
|
55
|
+
oauthErrorUri ? ` (${oauthErrorUri})` : ''
|
|
56
|
+
}`;
|
|
57
|
+
|
|
58
|
+
res.statusCode = 400;
|
|
59
|
+
res.end(errorMessage);
|
|
60
|
+
server.close();
|
|
61
|
+
settled = true;
|
|
62
|
+
waiter.reject(new Error(errorMessage));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
48
65
|
|
|
49
66
|
if (!code || !state) {
|
|
50
67
|
res.statusCode = 400;
|
|
51
68
|
res.end('Missing code or state.');
|
|
69
|
+
server.close();
|
|
70
|
+
settled = true;
|
|
71
|
+
waiter.reject(
|
|
72
|
+
new Error(
|
|
73
|
+
`OAuth callback did not include the required query parameters. Received path: ${url.pathname}${url.search}`
|
|
74
|
+
)
|
|
75
|
+
);
|
|
52
76
|
return;
|
|
53
77
|
}
|
|
54
78
|
|