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.
Files changed (43) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/__tests__/args.test.ts +358 -0
  3. package/__tests__/authClientAddApple.test.ts +9 -10
  4. package/__tests__/authClientAddClerk.test.ts +6 -5
  5. package/__tests__/authClientAddGithub.test.ts +6 -5
  6. package/__tests__/authClientAddGoogle.test.ts +5 -4
  7. package/__tests__/authClientAddLinkedin.test.ts +6 -5
  8. package/__tests__/oauthMock.ts +8 -9
  9. package/dist/commands/auth/client/add.d.ts.map +1 -1
  10. package/dist/commands/auth/client/add.js +53 -167
  11. package/dist/commands/auth/client/add.js.map +1 -1
  12. package/dist/commands/auth/client/shared.d.ts +0 -4
  13. package/dist/commands/auth/client/shared.d.ts.map +1 -1
  14. package/dist/commands/auth/client/shared.js +0 -4
  15. package/dist/commands/auth/client/shared.js.map +1 -1
  16. package/dist/commands/auth/client/update.d.ts +1 -1
  17. package/dist/commands/auth/client/update.d.ts.map +1 -1
  18. package/dist/commands/auth/client/update.js +25 -112
  19. package/dist/commands/auth/client/update.js.map +1 -1
  20. package/dist/commands/auth/origin/add.d.ts.map +1 -1
  21. package/dist/commands/auth/origin/add.js +37 -59
  22. package/dist/commands/auth/origin/add.js.map +1 -1
  23. package/dist/lib/args.d.ts +212 -0
  24. package/dist/lib/args.d.ts.map +1 -0
  25. package/dist/lib/args.js +313 -0
  26. package/dist/lib/args.js.map +1 -0
  27. package/dist/lib/oauth.d.ts +2 -2
  28. package/dist/lib/oauth.d.ts.map +1 -1
  29. package/dist/lib/oauth.js +13 -17
  30. package/dist/lib/oauth.js.map +1 -1
  31. package/dist/lib/ui.d.ts +0 -18
  32. package/dist/lib/ui.d.ts.map +1 -1
  33. package/dist/lib/ui.js +0 -76
  34. package/dist/lib/ui.js.map +1 -1
  35. package/package.json +4 -4
  36. package/src/commands/auth/client/add.ts +114 -180
  37. package/src/commands/auth/client/shared.ts +0 -12
  38. package/src/commands/auth/client/update.ts +85 -139
  39. package/src/commands/auth/origin/add.ts +25 -36
  40. package/src/lib/args.ts +453 -0
  41. package/src/lib/oauth.ts +8 -14
  42. package/src/lib/ui.ts +0 -127
  43. package/__tests__/optOrPrompt.test.ts +0 -229
@@ -2,12 +2,8 @@ import { Effect, Match, Option, Schema } from 'effect';
2
2
  import type { authClientAddDef, OptsFromCommand } from '../../../index.ts';
3
3
  import { BadArgsError } from '../../../errors.ts';
4
4
  import { GlobalOpts } from '../../../context/globalOpts.ts';
5
- import {
6
- optOrPrompt,
7
- optOrPromptBoolean,
8
- runUIEffect,
9
- validateRequired,
10
- } from '../../../lib/ui.ts';
5
+ import { Args } from '../../../lib/args.ts';
6
+ import { runUIEffect, validateRequired } from '../../../lib/ui.ts';
11
7
  import {
12
8
  addOAuthClient,
13
9
  findName,
@@ -43,9 +39,6 @@ import {
43
39
  clientSecretPrompt,
44
40
  firebaseDiscoveryEndpoint,
45
41
  firebaseProjectIdPrompt,
46
- getFlag,
47
- hasAnyFlag,
48
- isTrueFlag,
49
42
  readPrivateKeyFile,
50
43
  redirectSetupMessages,
51
44
  redirectUriPrompt,
@@ -155,8 +148,8 @@ const resolveGoogleCredentialMode = Effect.fn(function* ({
155
148
  opts: Record<string, unknown>;
156
149
  }): Effect.fn.Return<'custom' | 'dev', BadArgsError, GlobalOpts> {
157
150
  const { yes } = yield* GlobalOpts;
158
- const devCredentialsFlag = isTrueFlag(getFlag(opts, 'dev-credentials'));
159
- const hasProvidedSomeCustomCredentials = hasAnyFlag(opts, [
151
+ const devCredentialsFlag = Args.isTrue(opts, 'dev-credentials');
152
+ const hasProvidedSomeCustomCredentials = Args.hasAny(opts, [
160
153
  'client-id',
161
154
  'client-secret',
162
155
  'custom-redirect-uri',
@@ -275,11 +268,8 @@ const handleGoogleClient = Effect.fn(function* (opts: Record<string, unknown>) {
275
268
  );
276
269
  const suggestedClientName = findName(`google-${appType}`, usedClientNames);
277
270
 
278
- const clientName = yield* optOrPrompt(opts.name, {
279
- simpleName: '--name',
280
- required: true,
281
- skipIf: false,
282
- prompt: {
271
+ const clientName = yield* Args.text(opts, 'name').pipe(
272
+ Args.prompt({
283
273
  prompt: 'Client Name:',
284
274
  defaultValue: suggestedClientName,
285
275
  placeholder: suggestedClientName,
@@ -288,48 +278,46 @@ const handleGoogleClient = Effect.fn(function* (opts: Record<string, unknown>) {
288
278
  UI.modifiers.topPadding,
289
279
  UI.modifiers.dimOnComplete,
290
280
  ]),
291
- },
292
- });
281
+ }),
282
+ Args.required(),
283
+ );
293
284
 
294
- if (usedClientNames.has(clientName || '')) {
285
+ if (usedClientNames.has(clientName)) {
295
286
  return yield* BadArgsError.make({
296
287
  message: `The unique name '${clientName}' is already in use.`,
297
288
  });
298
289
  }
299
290
 
300
- const clientId = yield* optOrPrompt(opts['client-id'], {
301
- simpleName: '--client-id',
302
- required: !useSharedCredentials,
303
- skipIf: useSharedCredentials,
304
- skipMessage:
305
- '--client-id is not compatible with --dev-credentials. Drop one or the other.',
306
- prompt: clientIdPrompt({ providerUrl: googleConsoleUrl }),
307
- });
291
+ const clientId = yield* Args.text(opts, 'client-id').pipe(
292
+ Args.availableWhen(!useSharedCredentials, {
293
+ message:
294
+ '--client-id is not compatible with --dev-credentials. Drop one or the other.',
295
+ }),
296
+ Args.prompt(clientIdPrompt({ providerUrl: googleConsoleUrl })),
297
+ Args.required(),
298
+ );
308
299
 
309
300
  const usesCustomWebCredentials = !useSharedCredentials && appType === 'web';
310
- const clientSecret = yield* optOrPrompt(opts['client-secret'], {
311
- required: usesCustomWebCredentials,
312
- skipIf: !usesCustomWebCredentials,
313
- simpleName: '--client-secret',
314
- skipMessage: useSharedCredentials
315
- ? '--client-secret is not compatible with --dev-credentials. Drop one or the other.'
316
- : undefined,
317
- prompt: clientSecretPrompt({ providerUrl: googleConsoleUrl }),
318
- });
301
+ const clientSecret = yield* Args.text(opts, 'client-secret').pipe(
302
+ Args.availableWhen(usesCustomWebCredentials, {
303
+ message: useSharedCredentials
304
+ ? '--client-secret is not compatible with --dev-credentials. Drop one or the other.'
305
+ : undefined,
306
+ }),
307
+ Args.prompt(clientSecretPrompt({ providerUrl: googleConsoleUrl })),
308
+ Args.required(),
309
+ );
319
310
 
320
- const customRedirectUri = yield* optOrPrompt(opts['custom-redirect-uri'], {
321
- required: false,
322
- prompt: optionalRedirectPrompt,
323
- simpleName: '--custom-redirect-uri',
324
- skipIf: !usesCustomWebCredentials,
325
- skipMessage: useSharedCredentials
326
- ? '--custom-redirect-uri is not compatible with --dev-credentials.'
327
- : 'Provided custom redirect URI when not using web app type.',
328
- });
311
+ const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(
312
+ Args.availableWhen(usesCustomWebCredentials, {
313
+ message: useSharedCredentials
314
+ ? '--custom-redirect-uri is not compatible with --dev-credentials.'
315
+ : 'Provided custom redirect URI when not using web app type.',
316
+ }),
317
+ Args.prompt(optionalRedirectPrompt),
318
+ Args.optional(),
319
+ );
329
320
 
330
- if (!clientName) {
331
- return yield* BadArgsError.make({ message: 'Client name is required.' }); // Should never reach this
332
- }
333
321
  const redirectUri = useSharedCredentials
334
322
  ? undefined
335
323
  : customRedirectUri || DEFAULT_OAUTH_CALLBACK_URL;
@@ -373,30 +361,20 @@ const handleGithubClient = Effect.fn(function* (opts: Record<string, unknown>) {
373
361
  opts,
374
362
  );
375
363
 
376
- const clientId = yield* optOrPrompt(opts['client-id'], {
377
- simpleName: '--client-id',
378
- required: true,
379
- skipIf: false,
380
- prompt: clientIdPrompt({ providerUrl: githubDeveloperUrl }),
381
- });
382
-
383
- const clientSecret = yield* optOrPrompt(opts['client-secret'], {
384
- required: true,
385
- skipIf: false,
386
- simpleName: '--client-secret',
387
- prompt: clientSecretPrompt({ providerUrl: githubDeveloperUrl }),
388
- });
364
+ const clientId = yield* Args.text(opts, 'client-id').pipe(
365
+ Args.prompt(clientIdPrompt({ providerUrl: githubDeveloperUrl })),
366
+ Args.required(),
367
+ );
389
368
 
390
- const customRedirectUri = yield* optOrPrompt(opts['custom-redirect-uri'], {
391
- required: false,
392
- simpleName: '--custom-redirect-uri',
393
- skipIf: false,
394
- prompt: optionalRedirectPrompt,
395
- });
369
+ const clientSecret = yield* Args.text(opts, 'client-secret').pipe(
370
+ Args.prompt(clientSecretPrompt({ providerUrl: githubDeveloperUrl })),
371
+ Args.required(),
372
+ );
396
373
 
397
- if (!clientName) {
398
- return yield* BadArgsError.make({ message: 'Client name is required.' });
399
- }
374
+ const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(
375
+ Args.prompt(optionalRedirectPrompt),
376
+ Args.optional(),
377
+ );
400
378
 
401
379
  const redirectUri = customRedirectUri || DEFAULT_OAUTH_CALLBACK_URL;
402
380
 
@@ -438,30 +416,20 @@ const handleLinkedInClient = Effect.fn(function* (
438
416
  opts,
439
417
  );
440
418
 
441
- const clientId = yield* optOrPrompt(opts['client-id'], {
442
- simpleName: '--client-id',
443
- required: true,
444
- skipIf: false,
445
- prompt: clientIdPrompt({ providerUrl: linkedinDeveloperUrl }),
446
- });
447
-
448
- const clientSecret = yield* optOrPrompt(opts['client-secret'], {
449
- required: true,
450
- skipIf: false,
451
- simpleName: '--client-secret',
452
- prompt: clientSecretPrompt({ providerUrl: linkedinDeveloperUrl }),
453
- });
419
+ const clientId = yield* Args.text(opts, 'client-id').pipe(
420
+ Args.prompt(clientIdPrompt({ providerUrl: linkedinDeveloperUrl })),
421
+ Args.required(),
422
+ );
454
423
 
455
- const customRedirectUri = yield* optOrPrompt(opts['custom-redirect-uri'], {
456
- required: false,
457
- simpleName: '--custom-redirect-uri',
458
- skipIf: false,
459
- prompt: optionalRedirectPrompt,
460
- });
424
+ const clientSecret = yield* Args.text(opts, 'client-secret').pipe(
425
+ Args.prompt(clientSecretPrompt({ providerUrl: linkedinDeveloperUrl })),
426
+ Args.required(),
427
+ );
461
428
 
462
- if (!clientName) {
463
- return yield* BadArgsError.make({ message: 'Client name is required.' });
464
- }
429
+ const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(
430
+ Args.prompt(optionalRedirectPrompt),
431
+ Args.optional(),
432
+ );
465
433
 
466
434
  const redirectUri = customRedirectUri || DEFAULT_OAUTH_CALLBACK_URL;
467
435
 
@@ -496,86 +464,74 @@ const handleLinkedInClient = Effect.fn(function* (
496
464
  });
497
465
 
498
466
  const handleAppleClient = Effect.fn(function* (opts: Record<string, unknown>) {
499
- const { yes } = yield* GlobalOpts;
500
467
  const { clientName, provider } = yield* getClientNameAndProvider(
501
468
  'apple',
502
469
  opts,
503
470
  );
504
471
 
505
- const servicesId = yield* optOrPrompt(opts['services-id'], {
506
- simpleName: '--services-id',
507
- required: true,
508
- skipIf: false,
509
- prompt: appleServicesIdPrompt({}),
510
- });
472
+ const servicesId = yield* Args.text(opts, 'services-id').pipe(
473
+ Args.prompt(appleServicesIdPrompt({})),
474
+ Args.required(),
475
+ );
511
476
 
512
477
  // If any web-flow flag is provided, enable web flow; otherwise ask
513
478
  // (non-interactively with --yes we default to native-only).
514
- const anyWebFlagProvided = Boolean(
515
- opts['team-id'] || opts['key-id'] || opts['private-key-file'],
516
- );
479
+ const anyWebFlagProvided = Args.hasAny(opts, [
480
+ 'team-id',
481
+ 'key-id',
482
+ 'private-key-file',
483
+ 'custom-redirect-uri',
484
+ ]);
517
485
 
518
486
  const configureWeb = anyWebFlagProvided
519
487
  ? true
520
- : yes
521
- ? false
522
- : yield* optOrPromptBoolean(undefined, {
523
- simpleName: '--configure-web',
524
- required: false,
525
- skipIf: false,
526
- prompt: {
527
- promptText:
528
- 'Configure web redirect flow? ' +
529
- chalk.dim(
530
- '(requires Team ID, Key ID, and a .p8 private key from Apple)',
531
- ),
532
- defaultValue: false,
533
- },
534
- });
488
+ : yield* Args.bool(opts, 'configure-web').pipe(
489
+ Args.confirm({
490
+ promptText:
491
+ 'Configure web redirect flow? ' +
492
+ chalk.dim(
493
+ '(requires Team ID, Key ID, and a .p8 private key from Apple)',
494
+ ),
495
+ defaultValue: false,
496
+ }),
497
+ Args.required(),
498
+ );
535
499
 
536
500
  const skipWeb = !configureWeb;
537
501
  const webSkipMessage =
538
502
  'requires configuring the web redirect flow (also provide --team-id, --key-id, and --private-key-file).';
539
503
 
540
- const teamId = yield* optOrPrompt(opts['team-id'], {
541
- simpleName: '--team-id',
542
- required: true,
543
- skipIf: skipWeb,
544
- skipMessage: `--team-id ${webSkipMessage}`,
545
- prompt: appleTeamIdPrompt({}),
546
- });
504
+ const teamId = yield* Args.text(opts, 'team-id').pipe(
505
+ Args.availableWhen(!skipWeb, { message: `--team-id ${webSkipMessage}` }),
506
+ Args.prompt(appleTeamIdPrompt({})),
507
+ Args.required(),
508
+ );
547
509
 
548
- const keyId = yield* optOrPrompt(opts['key-id'], {
549
- simpleName: '--key-id',
550
- required: true,
551
- skipIf: skipWeb,
552
- skipMessage: `--key-id ${webSkipMessage}`,
553
- prompt: appleKeyIdPrompt({}),
554
- });
510
+ const keyId = yield* Args.text(opts, 'key-id').pipe(
511
+ Args.availableWhen(!skipWeb, { message: `--key-id ${webSkipMessage}` }),
512
+ Args.prompt(appleKeyIdPrompt({})),
513
+ Args.required(),
514
+ );
555
515
 
556
- const privateKeyPath = yield* optOrPrompt(opts['private-key-file'], {
557
- simpleName: '--private-key-file',
558
- required: true,
559
- skipIf: skipWeb,
560
- skipMessage: `--private-key-file ${webSkipMessage}`,
561
- prompt: applePrivateKeyFilePrompt({}),
562
- });
516
+ const privateKeyPath = yield* Args.text(opts, 'private-key-file').pipe(
517
+ Args.availableWhen(!skipWeb, {
518
+ message: `--private-key-file ${webSkipMessage}`,
519
+ }),
520
+ Args.prompt(applePrivateKeyFilePrompt({})),
521
+ Args.required(),
522
+ );
563
523
 
564
524
  const privateKey = privateKeyPath
565
525
  ? yield* readPrivateKeyFile(privateKeyPath)
566
526
  : undefined;
567
527
 
568
- const customRedirectUri = yield* optOrPrompt(opts['custom-redirect-uri'], {
569
- required: false,
570
- simpleName: '--custom-redirect-uri',
571
- skipIf: skipWeb,
572
- skipMessage: `--custom-redirect-uri ${webSkipMessage}`,
573
- prompt: optionalRedirectPrompt,
574
- });
575
-
576
- if (!clientName) {
577
- return yield* BadArgsError.make({ message: 'Client name is required.' });
578
- }
528
+ const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(
529
+ Args.availableWhen(!skipWeb, {
530
+ message: `--custom-redirect-uri ${webSkipMessage}`,
531
+ }),
532
+ Args.prompt(optionalRedirectPrompt),
533
+ Args.optional(),
534
+ );
579
535
 
580
536
  const redirectUri = privateKey
581
537
  ? customRedirectUri || DEFAULT_OAUTH_CALLBACK_URL
@@ -628,21 +584,10 @@ const handleClerkClient = Effect.fn(function* (opts: Record<string, unknown>) {
628
584
  opts,
629
585
  );
630
586
 
631
- const publishableKey = yield* optOrPrompt(opts['publishable-key'], {
632
- simpleName: '--publishable-key',
633
- required: true,
634
- skipIf: false,
635
- prompt: clerkPublishableKeyPrompt({}),
636
- });
637
-
638
- if (!clientName) {
639
- return yield* BadArgsError.make({ message: 'Client name is required.' });
640
- }
641
- if (!publishableKey) {
642
- return yield* BadArgsError.make({
643
- message: 'Publishable key is required.',
644
- });
645
- }
587
+ const publishableKey = yield* Args.text(opts, 'publishable-key').pipe(
588
+ Args.prompt(clerkPublishableKeyPrompt({})),
589
+ Args.required(),
590
+ );
646
591
 
647
592
  const domain = clerkDomainFromPublishableKey(publishableKey);
648
593
  if (!domain) {
@@ -695,22 +640,11 @@ const handleFirebaseClient = Effect.fn(function* (
695
640
  opts,
696
641
  );
697
642
 
698
- const projectId = yield* optOrPrompt(opts['project-id'], {
699
- simpleName: '--project-id',
700
- required: true,
701
- skipIf: false,
702
- prompt: firebaseProjectIdPrompt({}),
703
- });
704
- // typeguard
705
- if (!clientName || !projectId) {
706
- return yield* BadArgsError.make({
707
- message: 'Missing required arguments',
708
- });
709
- }
710
- const validationError = validateFirebaseProjectId(projectId);
711
- if (validationError) {
712
- return yield* BadArgsError.make({ message: validationError });
713
- }
643
+ const projectId = yield* Args.text(opts, 'project-id').pipe(
644
+ Args.prompt(firebaseProjectIdPrompt({})),
645
+ Args.validate(validateFirebaseProjectId),
646
+ Args.required(),
647
+ );
714
648
  const response = yield* addOAuthClient({
715
649
  providerId: provider.id,
716
650
  clientName,
@@ -9,18 +9,6 @@ import { UI } from '../../../ui/index.ts';
9
9
 
10
10
  type EmptyPromptArgs = Record<string, never>;
11
11
 
12
- export const getFlag = (opts: Record<string, unknown>, flag: string) =>
13
- opts[flag];
14
-
15
- export const hasFlag = (opts: Record<string, unknown>, flag: string) =>
16
- flag in opts;
17
-
18
- export const hasAnyFlag = (opts: Record<string, unknown>, flags: string[]) =>
19
- flags.some((flag) => hasFlag(opts, flag));
20
-
21
- export const isTrueFlag = (value: unknown) =>
22
- value === true || value === 'true';
23
-
24
12
  export const getMetaString = (meta: unknown, key: string) => {
25
13
  if (!meta || typeof meta !== 'object') return undefined;
26
14
  const value = (meta as Record<string, unknown>)[key];