instant-cli 1.0.23 → 1.0.24-branch-codex-cli-args-combinators.25405829034.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/.turbo/turbo-build.log +1 -1
- package/__tests__/args.test.ts +358 -0
- package/__tests__/authClientAddApple.test.ts +9 -10
- package/__tests__/authClientAddClerk.test.ts +6 -5
- package/__tests__/authClientAddGithub.test.ts +6 -5
- package/__tests__/authClientAddGoogle.test.ts +5 -4
- package/__tests__/authClientAddLinkedin.test.ts +6 -5
- package/__tests__/oauthMock.ts +8 -9
- package/dist/commands/auth/client/add.d.ts.map +1 -1
- package/dist/commands/auth/client/add.js +53 -167
- package/dist/commands/auth/client/add.js.map +1 -1
- package/dist/commands/auth/client/shared.d.ts +0 -4
- package/dist/commands/auth/client/shared.d.ts.map +1 -1
- package/dist/commands/auth/client/shared.js +0 -4
- package/dist/commands/auth/client/shared.js.map +1 -1
- package/dist/commands/auth/client/update.d.ts +1 -1
- package/dist/commands/auth/client/update.d.ts.map +1 -1
- package/dist/commands/auth/client/update.js +25 -112
- package/dist/commands/auth/client/update.js.map +1 -1
- package/dist/commands/auth/origin/add.d.ts.map +1 -1
- package/dist/commands/auth/origin/add.js +37 -59
- package/dist/commands/auth/origin/add.js.map +1 -1
- package/dist/lib/args.d.ts +212 -0
- package/dist/lib/args.d.ts.map +1 -0
- package/dist/lib/args.js +313 -0
- package/dist/lib/args.js.map +1 -0
- package/dist/lib/oauth.d.ts +2 -2
- package/dist/lib/oauth.d.ts.map +1 -1
- package/dist/lib/oauth.js +13 -17
- package/dist/lib/oauth.js.map +1 -1
- package/dist/lib/ui.d.ts +0 -18
- package/dist/lib/ui.d.ts.map +1 -1
- package/dist/lib/ui.js +0 -76
- package/dist/lib/ui.js.map +1 -1
- package/package.json +4 -4
- package/src/commands/auth/client/add.ts +114 -180
- package/src/commands/auth/client/shared.ts +0 -12
- package/src/commands/auth/client/update.ts +85 -139
- package/src/commands/auth/origin/add.ts +25 -36
- package/src/lib/args.ts +453 -0
- package/src/lib/oauth.ts +8 -14
- package/src/lib/ui.ts +0 -127
- package/__tests__/optOrPrompt.test.ts +0 -229
package/.turbo/turbo-build.log
CHANGED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { test, expect, describe, expectTypeOf, vi } from 'vitest';
|
|
2
|
+
import { Effect, Layer } from 'effect';
|
|
3
|
+
import { Args } from '../src/lib/args.ts';
|
|
4
|
+
import { GlobalOpts } from '../src/context/globalOpts.ts';
|
|
5
|
+
import { BadArgsError } from '../src/errors.ts';
|
|
6
|
+
|
|
7
|
+
const run = <A>(effect: Effect.Effect<A, any, GlobalOpts>, yes: boolean) =>
|
|
8
|
+
Effect.runPromise(
|
|
9
|
+
effect.pipe(Effect.provide(Layer.succeed(GlobalOpts, { yes }))),
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const runFail = <A>(effect: Effect.Effect<A, any, GlobalOpts>, yes: boolean) =>
|
|
13
|
+
Effect.runPromise(
|
|
14
|
+
effect.pipe(
|
|
15
|
+
Effect.flip,
|
|
16
|
+
Effect.provide(Layer.succeed(GlobalOpts, { yes })),
|
|
17
|
+
),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
let mockPromptReturn: unknown = '';
|
|
21
|
+
vi.mock('../src/ui/lib.ts', async (importOriginal) => {
|
|
22
|
+
const orig: any = await importOriginal();
|
|
23
|
+
return {
|
|
24
|
+
...orig,
|
|
25
|
+
renderUnwrap: () => Promise.resolve(mockPromptReturn),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const basePrompt = { prompt: 'Client ID:' } as any;
|
|
30
|
+
|
|
31
|
+
describe('types', () => {
|
|
32
|
+
test('required return type accounts for inactive args', () => {
|
|
33
|
+
const requiredValue = Args.text(
|
|
34
|
+
{ 'client-id': 'abc123' },
|
|
35
|
+
'client-id',
|
|
36
|
+
).pipe(Args.required());
|
|
37
|
+
|
|
38
|
+
expectTypeOf(requiredValue).toEqualTypeOf<
|
|
39
|
+
Effect.Effect<string, BadArgsError>
|
|
40
|
+
>();
|
|
41
|
+
|
|
42
|
+
const conditionallyRequiredValue = Args.text({}, 'client-id').pipe(
|
|
43
|
+
Args.availableWhen(false),
|
|
44
|
+
Args.required(),
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expectTypeOf(conditionallyRequiredValue).toEqualTypeOf<
|
|
48
|
+
Effect.Effect<string | undefined, BadArgsError>
|
|
49
|
+
>();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('availableWhen', () => {
|
|
54
|
+
test('unavailable + value provided -> error', async () => {
|
|
55
|
+
const err = await runFail(
|
|
56
|
+
Args.text(
|
|
57
|
+
{
|
|
58
|
+
'custom-redirect-uri': 'https://mysite.com/callback',
|
|
59
|
+
},
|
|
60
|
+
'custom-redirect-uri',
|
|
61
|
+
).pipe(
|
|
62
|
+
Args.availableWhen(false, {
|
|
63
|
+
message: 'Provided custom redirect URI when not using web app type.',
|
|
64
|
+
}),
|
|
65
|
+
Args.optional(),
|
|
66
|
+
),
|
|
67
|
+
false,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
expect(err.message).toBe(
|
|
71
|
+
'Provided custom redirect URI when not using web app type.',
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('unavailable + empty value provided -> error', async () => {
|
|
76
|
+
const err = await runFail(
|
|
77
|
+
Args.text({ 'custom-redirect-uri': '' }, 'custom-redirect-uri').pipe(
|
|
78
|
+
Args.availableWhen(false, {
|
|
79
|
+
message: 'Provided custom redirect URI when not using web app type.',
|
|
80
|
+
}),
|
|
81
|
+
Args.optional(),
|
|
82
|
+
),
|
|
83
|
+
false,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
expect(err.message).toBe(
|
|
87
|
+
'Provided custom redirect URI when not using web app type.',
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('unavailable + no value -> undefined', async () => {
|
|
92
|
+
const result = await run(
|
|
93
|
+
Args.text({}, 'custom-redirect-uri').pipe(
|
|
94
|
+
Args.availableWhen(false),
|
|
95
|
+
Args.optional(),
|
|
96
|
+
),
|
|
97
|
+
false,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(result).toBeUndefined();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('validate', () => {
|
|
105
|
+
test('valid value -> passes through', async () => {
|
|
106
|
+
const result = await run(
|
|
107
|
+
Args.text({ 'project-id': 'my-project' }, 'project-id').pipe(
|
|
108
|
+
Args.validate((value) =>
|
|
109
|
+
value.includes('_')
|
|
110
|
+
? 'Project ID cannot include underscores.'
|
|
111
|
+
: undefined,
|
|
112
|
+
),
|
|
113
|
+
Args.required(),
|
|
114
|
+
),
|
|
115
|
+
true,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(result).toBe('my-project');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('invalid value -> error', async () => {
|
|
122
|
+
const err = await runFail(
|
|
123
|
+
Args.text({ 'project-id': 'my_project' }, 'project-id').pipe(
|
|
124
|
+
Args.validate((value) =>
|
|
125
|
+
value.includes('_')
|
|
126
|
+
? 'Project ID cannot include underscores.'
|
|
127
|
+
: undefined,
|
|
128
|
+
),
|
|
129
|
+
Args.required(),
|
|
130
|
+
),
|
|
131
|
+
true,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
expect(err.message).toBe('Project ID cannot include underscores.');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('non-interactive', () => {
|
|
139
|
+
test('required missing value -> error', async () => {
|
|
140
|
+
const err = await runFail(
|
|
141
|
+
Args.text({}, 'client-id').pipe(Args.prompt(basePrompt), Args.required()),
|
|
142
|
+
true,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
expect(err.message).toBe('Missing required value for --client-id');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('required missing value with prompt default -> default value', async () => {
|
|
149
|
+
const result = await run(
|
|
150
|
+
Args.text({}, 'name').pipe(
|
|
151
|
+
Args.prompt({ prompt: 'Client Name:', defaultValue: 'github' }),
|
|
152
|
+
Args.required(),
|
|
153
|
+
),
|
|
154
|
+
true,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
expect(result).toBe('github');
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('number value -> stringified', async () => {
|
|
161
|
+
const result = await run(
|
|
162
|
+
Args.text({ 'client-id': 42 }, 'client-id').pipe(Args.required()),
|
|
163
|
+
true,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(result).toBe('42');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('non-string/number value -> error', async () => {
|
|
170
|
+
const err = await runFail(
|
|
171
|
+
Args.text({ 'client-id': true }, 'client-id').pipe(Args.required()),
|
|
172
|
+
true,
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
expect(err.message).toBe('Invalid value for --client-id');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('valid string -> trimmed value', async () => {
|
|
179
|
+
const result = await run(
|
|
180
|
+
Args.text(
|
|
181
|
+
{ 'client-id': ' abc123.apps.googleusercontent.com ' },
|
|
182
|
+
'client-id',
|
|
183
|
+
).pipe(Args.required()),
|
|
184
|
+
true,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
expect(result).toBe('abc123.apps.googleusercontent.com');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('optional missing value -> undefined', async () => {
|
|
191
|
+
const result = await run(
|
|
192
|
+
Args.text({}, 'custom-redirect-uri').pipe(Args.optional()),
|
|
193
|
+
true,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
expect(result).toBeUndefined();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('simpleName overrides display flag without changing lookup key', async () => {
|
|
200
|
+
const result = await run(
|
|
201
|
+
Args.text(
|
|
202
|
+
{ customRedirectUri: 'https://example.com/callback' },
|
|
203
|
+
'customRedirectUri',
|
|
204
|
+
{ simpleName: '--custom-redirect-uri' },
|
|
205
|
+
).pipe(Args.required()),
|
|
206
|
+
true,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
expect(result).toBe('https://example.com/callback');
|
|
210
|
+
|
|
211
|
+
const err = await runFail(
|
|
212
|
+
Args.text({}, 'customRedirectUri', {
|
|
213
|
+
simpleName: '--custom-redirect-uri',
|
|
214
|
+
}).pipe(Args.required()),
|
|
215
|
+
true,
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
expect(err.message).toBe(
|
|
219
|
+
'Missing required value for --custom-redirect-uri',
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('does not fall back to other key shapes', async () => {
|
|
224
|
+
const err = await runFail(
|
|
225
|
+
Args.text(
|
|
226
|
+
{ 'custom-redirect-uri': 'https://example.com/callback' },
|
|
227
|
+
'customRedirectUri',
|
|
228
|
+
{ simpleName: '--custom-redirect-uri' },
|
|
229
|
+
).pipe(Args.required()),
|
|
230
|
+
true,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(err.message).toBe(
|
|
234
|
+
'Missing required value for --custom-redirect-uri',
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test('boolean value -> parsed', async () => {
|
|
239
|
+
const result = await run(
|
|
240
|
+
Args.bool({ 'configure-web': true }, 'configure-web').pipe(
|
|
241
|
+
Args.optional(),
|
|
242
|
+
),
|
|
243
|
+
true,
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
expect(result).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('boolean string value -> parsed', async () => {
|
|
250
|
+
const result = await run(
|
|
251
|
+
Args.bool({ 'configure-web': 'false' }, 'configure-web').pipe(
|
|
252
|
+
Args.optional(),
|
|
253
|
+
),
|
|
254
|
+
true,
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
expect(result).toBe(false);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('invalid boolean value -> error', async () => {
|
|
261
|
+
const err = await runFail(
|
|
262
|
+
Args.bool({ 'configure-web': 'sometimes' }, 'configure-web').pipe(
|
|
263
|
+
Args.optional(),
|
|
264
|
+
),
|
|
265
|
+
true,
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
expect(err.message).toBe('Invalid value for --configure-web');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test('missing confirmation returns default value', async () => {
|
|
272
|
+
const result = await run(
|
|
273
|
+
Args.bool({}, 'configure-web').pipe(
|
|
274
|
+
Args.confirm({
|
|
275
|
+
promptText: 'Configure web redirect flow?',
|
|
276
|
+
defaultValue: false,
|
|
277
|
+
}),
|
|
278
|
+
Args.required(),
|
|
279
|
+
),
|
|
280
|
+
true,
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
expect(result).toBe(false);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('interactive', () => {
|
|
288
|
+
test('value already provided -> use it directly', async () => {
|
|
289
|
+
const result = await run(
|
|
290
|
+
Args.text(
|
|
291
|
+
{ 'client-id': ' abc123.apps.googleusercontent.com ' },
|
|
292
|
+
'client-id',
|
|
293
|
+
).pipe(Args.prompt(basePrompt), Args.required()),
|
|
294
|
+
false,
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
expect(result).toBe('abc123.apps.googleusercontent.com');
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test('no value + user types a value -> trimmed result', async () => {
|
|
301
|
+
mockPromptReturn = ' GOCSPX-secret123 ';
|
|
302
|
+
|
|
303
|
+
const result = await run(
|
|
304
|
+
Args.text({}, 'client-secret').pipe(
|
|
305
|
+
Args.prompt(basePrompt),
|
|
306
|
+
Args.required(),
|
|
307
|
+
),
|
|
308
|
+
false,
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
expect(result).toBe('GOCSPX-secret123');
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test('no value + user enters empty + required -> error', async () => {
|
|
315
|
+
mockPromptReturn = '';
|
|
316
|
+
|
|
317
|
+
const err = await runFail(
|
|
318
|
+
Args.text({}, 'client-secret').pipe(
|
|
319
|
+
Args.prompt(basePrompt),
|
|
320
|
+
Args.required(),
|
|
321
|
+
),
|
|
322
|
+
false,
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
expect(err.message).toBe('Missing required value for --client-secret');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test('no value + user enters empty + optional -> undefined', async () => {
|
|
329
|
+
mockPromptReturn = '';
|
|
330
|
+
|
|
331
|
+
const result = await run(
|
|
332
|
+
Args.text({}, 'custom-redirect-uri').pipe(
|
|
333
|
+
Args.prompt(basePrompt),
|
|
334
|
+
Args.optional(),
|
|
335
|
+
),
|
|
336
|
+
false,
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
expect(result).toBeUndefined();
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test('no boolean value + user confirms -> result', async () => {
|
|
343
|
+
mockPromptReturn = true;
|
|
344
|
+
|
|
345
|
+
const result = await run(
|
|
346
|
+
Args.bool({}, 'configure-web').pipe(
|
|
347
|
+
Args.confirm({
|
|
348
|
+
promptText: 'Configure web redirect flow?',
|
|
349
|
+
defaultValue: false,
|
|
350
|
+
}),
|
|
351
|
+
Args.optional(),
|
|
352
|
+
),
|
|
353
|
+
false,
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
expect(result).toBe(true);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
@@ -141,17 +141,18 @@ const webFlags = new Map([
|
|
|
141
141
|
|
|
142
142
|
// -- native-only (no web flow): build-up with --yes --
|
|
143
143
|
|
|
144
|
-
describe('native: --yes
|
|
144
|
+
describe('native: --yes handles missing values', () => {
|
|
145
145
|
test('missing --type', async () => {
|
|
146
146
|
await run(without(nativeFlags, 'type'), { yes: true });
|
|
147
147
|
expect(logs.join('\n')).toContain('Missing required value for --type');
|
|
148
148
|
expect(addedClients).toHaveLength(0);
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
-
test('missing --name', async () => {
|
|
151
|
+
test('missing --name uses suggested default', async () => {
|
|
152
152
|
await run(without(nativeFlags, 'name'), { yes: true });
|
|
153
|
-
expect(
|
|
154
|
-
expect(addedClients).toHaveLength(
|
|
153
|
+
expect(prompts).toHaveLength(0);
|
|
154
|
+
expect(addedClients).toHaveLength(1);
|
|
155
|
+
expect(addedClients[0].clientName).toBe('apple');
|
|
155
156
|
});
|
|
156
157
|
|
|
157
158
|
test('missing --services-id', async () => {
|
|
@@ -361,17 +362,15 @@ describe('private key file errors', () => {
|
|
|
361
362
|
});
|
|
362
363
|
});
|
|
363
364
|
|
|
364
|
-
// --
|
|
365
|
+
// -- web-flow flag detection --
|
|
365
366
|
|
|
366
|
-
describe('
|
|
367
|
-
test('--custom-redirect-uri
|
|
367
|
+
describe('web-flow flag detection', () => {
|
|
368
|
+
test('--custom-redirect-uri enables web flow and requires web credentials', async () => {
|
|
368
369
|
await run(
|
|
369
370
|
withEntry(nativeFlags, 'custom-redirect-uri', 'https://example.com'),
|
|
370
371
|
{ yes: true },
|
|
371
372
|
);
|
|
372
|
-
expect(logs.join('\n')).toContain(
|
|
373
|
-
'--custom-redirect-uri requires configuring the web redirect flow',
|
|
374
|
-
);
|
|
373
|
+
expect(logs.join('\n')).toContain('Missing required value for --team-id');
|
|
375
374
|
expect(addedClients).toHaveLength(0);
|
|
376
375
|
});
|
|
377
376
|
});
|
|
@@ -116,19 +116,20 @@ const webFlags = new Map([
|
|
|
116
116
|
],
|
|
117
117
|
]);
|
|
118
118
|
|
|
119
|
-
// -- --yes: build-up
|
|
119
|
+
// -- --yes: build-up behavior --
|
|
120
120
|
|
|
121
|
-
describe('--yes
|
|
121
|
+
describe('--yes handles missing values', () => {
|
|
122
122
|
test('missing --type', async () => {
|
|
123
123
|
await run(without(webFlags, 'type'), { yes: true });
|
|
124
124
|
expect(logs.join('\n')).toContain('Missing required value for --type');
|
|
125
125
|
expect(addedClients).toHaveLength(0);
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
test('missing --name', async () => {
|
|
128
|
+
test('missing --name uses suggested default', async () => {
|
|
129
129
|
await run(without(webFlags, 'name'), { yes: true });
|
|
130
|
-
expect(
|
|
131
|
-
expect(addedClients).toHaveLength(
|
|
130
|
+
expect(prompts).toHaveLength(0);
|
|
131
|
+
expect(addedClients).toHaveLength(1);
|
|
132
|
+
expect(addedClients[0].clientName).toBe('clerk');
|
|
132
133
|
});
|
|
133
134
|
|
|
134
135
|
test('missing --publishable-key', async () => {
|
|
@@ -105,19 +105,20 @@ const webFlags = new Map([
|
|
|
105
105
|
['client-secret', 'ghs_abc123'],
|
|
106
106
|
]);
|
|
107
107
|
|
|
108
|
-
// -- --yes: build-up
|
|
108
|
+
// -- --yes: build-up behavior --
|
|
109
109
|
|
|
110
|
-
describe('--yes
|
|
110
|
+
describe('--yes handles missing values', () => {
|
|
111
111
|
test('missing --type', async () => {
|
|
112
112
|
await run(without(webFlags, 'type'), { yes: true });
|
|
113
113
|
expect(logs.join('\n')).toContain('Missing required value for --type');
|
|
114
114
|
expect(addedClients).toHaveLength(0);
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
test('missing --name', async () => {
|
|
117
|
+
test('missing --name uses suggested default', async () => {
|
|
118
118
|
await run(without(webFlags, 'name'), { yes: true });
|
|
119
|
-
expect(
|
|
120
|
-
expect(addedClients).toHaveLength(
|
|
119
|
+
expect(prompts).toHaveLength(0);
|
|
120
|
+
expect(addedClients).toHaveLength(1);
|
|
121
|
+
expect(addedClients[0].clientName).toBe('github');
|
|
121
122
|
});
|
|
122
123
|
|
|
123
124
|
test('missing --client-id', async () => {
|
|
@@ -115,7 +115,7 @@ const iosFlags = new Map([
|
|
|
115
115
|
|
|
116
116
|
// -- web: build-up with --yes --
|
|
117
117
|
|
|
118
|
-
describe('web: --yes
|
|
118
|
+
describe('web: --yes handles missing values', () => {
|
|
119
119
|
test('missing --type', async () => {
|
|
120
120
|
await run(without(webFlags, 'type'), { yes: true });
|
|
121
121
|
expect(logs.join('\n')).toContain('Missing required value for --type');
|
|
@@ -128,10 +128,11 @@ describe('web: --yes errors on each missing required flag', () => {
|
|
|
128
128
|
expect(addedClients).toHaveLength(0);
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
test('missing --name', async () => {
|
|
131
|
+
test('missing --name uses suggested default', async () => {
|
|
132
132
|
await run(without(webFlags, 'name'), { yes: true });
|
|
133
|
-
expect(
|
|
134
|
-
expect(addedClients).toHaveLength(
|
|
133
|
+
expect(prompts).toHaveLength(0);
|
|
134
|
+
expect(addedClients).toHaveLength(1);
|
|
135
|
+
expect(addedClients[0].clientName).toBe('google-web');
|
|
135
136
|
});
|
|
136
137
|
|
|
137
138
|
test('missing --client-id', async () => {
|
|
@@ -113,19 +113,20 @@ const webFlags = new Map([
|
|
|
113
113
|
['client-secret', 'secret123'],
|
|
114
114
|
]);
|
|
115
115
|
|
|
116
|
-
// -- --yes: build-up
|
|
116
|
+
// -- --yes: build-up behavior --
|
|
117
117
|
|
|
118
|
-
describe('--yes
|
|
118
|
+
describe('--yes handles missing values', () => {
|
|
119
119
|
test('missing --type', async () => {
|
|
120
120
|
await run(without(webFlags, 'type'), { yes: true });
|
|
121
121
|
expect(logs.join('\n')).toContain('Missing required value for --type');
|
|
122
122
|
expect(addedClients).toHaveLength(0);
|
|
123
123
|
});
|
|
124
124
|
|
|
125
|
-
test('missing --name', async () => {
|
|
125
|
+
test('missing --name uses suggested default', async () => {
|
|
126
126
|
await run(without(webFlags, 'name'), { yes: true });
|
|
127
|
-
expect(
|
|
128
|
-
expect(addedClients).toHaveLength(
|
|
127
|
+
expect(prompts).toHaveLength(0);
|
|
128
|
+
expect(addedClients).toHaveLength(1);
|
|
129
|
+
expect(addedClients[0].clientName).toBe('linkedin');
|
|
129
130
|
});
|
|
130
131
|
|
|
131
132
|
test('missing --client-id', async () => {
|
package/__tests__/oauthMock.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Effect, Schema } from 'effect';
|
|
2
|
-
import {
|
|
2
|
+
import { Args } from '../src/lib/args.ts';
|
|
3
|
+
import { validateRequired } from '../src/lib/ui.ts';
|
|
3
4
|
import { UI } from '../src/ui/index.ts';
|
|
4
5
|
import { BadArgsError } from '../src/errors.ts';
|
|
5
6
|
|
|
@@ -44,11 +45,8 @@ export const makeOAuthMock = (mocks: {
|
|
|
44
45
|
(auth.oauth_clients ?? []).map((c: any) => c.client_name),
|
|
45
46
|
);
|
|
46
47
|
const suggested = findName(providerType, used);
|
|
47
|
-
const clientName = yield*
|
|
48
|
-
|
|
49
|
-
required: true,
|
|
50
|
-
skipIf: false,
|
|
51
|
-
prompt: {
|
|
48
|
+
const clientName = yield* Args.text(opts, 'name').pipe(
|
|
49
|
+
Args.prompt({
|
|
52
50
|
prompt: 'Client Name:',
|
|
53
51
|
defaultValue: suggested,
|
|
54
52
|
placeholder: suggested,
|
|
@@ -57,9 +55,10 @@ export const makeOAuthMock = (mocks: {
|
|
|
57
55
|
UI.modifiers.topPadding,
|
|
58
56
|
UI.modifiers.dimOnComplete,
|
|
59
57
|
]),
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
}),
|
|
59
|
+
Args.required(),
|
|
60
|
+
);
|
|
61
|
+
if (used.has(clientName)) {
|
|
63
62
|
return yield* BadArgsError.make({
|
|
64
63
|
message: `The unique name '${clientName}' is already in use.`,
|
|
65
64
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/commands/auth/client/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGvD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/commands/auth/client/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGvD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AA4C5D,eAAO,MAAM,gBAAgB,gFAO5B,CAAC;AAmmBF,eAAO,MAAM,gBAAgB;;;;wgBAwD5B,CAAC"}
|