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,7 +2,8 @@ import { Effect, Match } from 'effect';
2
2
  import type { authClientUpdateDef, OptsFromCommand } from '../../../index.ts';
3
3
  import { BadArgsError } from '../../../errors.ts';
4
4
  import { GlobalOpts } from '../../../context/globalOpts.ts';
5
- import { optOrPrompt, runUIEffect } from '../../../lib/ui.ts';
5
+ import { Args } from '../../../lib/args.ts';
6
+ import { runUIEffect } from '../../../lib/ui.ts';
6
7
  import {
7
8
  findClientByIdOrName,
8
9
  getAppsAuth,
@@ -26,11 +27,7 @@ import {
26
27
  clientSecretPrompt,
27
28
  firebaseDiscoveryEndpoint,
28
29
  firebaseProjectIdPrompt,
29
- getFlag,
30
30
  getMetaString,
31
- hasAnyFlag,
32
- hasFlag,
33
- isTrueFlag,
34
31
  readPrivateKeyFile,
35
32
  redirectSetupMessages,
36
33
  redirectUriPrompt,
@@ -148,31 +145,10 @@ const updateGoogleToDevCredentials = Effect.fn(function* (
148
145
  type GoogleUpdateMode = 'dev' | 'custom' | 'redirect' | 'none';
149
146
 
150
147
  const hasGoogleCustomCredentialFlags = (opts: Record<string, unknown>) =>
151
- hasAnyFlag(opts, ['client-id', 'client-secret', 'custom-redirect-uri']);
148
+ Args.hasAny(opts, ['client-id', 'client-secret', 'custom-redirect-uri']);
152
149
 
153
150
  const hasGoogleUpdateFlags = (opts: Record<string, unknown>) =>
154
- isTrueFlag(getFlag(opts, 'dev-credentials')) ||
155
- hasGoogleCustomCredentialFlags(opts);
156
-
157
- const optOrPromptWhenNeeded = (
158
- opts: Record<string, unknown>,
159
- flag: string,
160
- params: {
161
- promptIf: boolean;
162
- required?: boolean;
163
- prompt: UI.TextInputProps;
164
- },
165
- ) =>
166
- Effect.gen(function* () {
167
- const value = getFlag(opts, flag);
168
- if (value === undefined && !params.promptIf) return undefined;
169
- return yield* optOrPrompt(value, {
170
- simpleName: `--${flag}`,
171
- required: params.required ?? params.promptIf,
172
- skipIf: false,
173
- prompt: params.prompt,
174
- });
175
- });
151
+ Args.isTrue(opts, 'dev-credentials') || hasGoogleCustomCredentialFlags(opts);
176
152
 
177
153
  const selectGoogleUpdateMode = Effect.fn(function* ({
178
154
  isWeb,
@@ -230,7 +206,7 @@ const resolveGoogleUpdateMode = Effect.fn(function* ({
230
206
  switchingFromShared: boolean;
231
207
  }) {
232
208
  const { yes } = yield* GlobalOpts;
233
- const devCredentialsFlag = isTrueFlag(getFlag(opts, 'dev-credentials'));
209
+ const devCredentialsFlag = Args.isTrue(opts, 'dev-credentials');
234
210
  const hasProvidedSomeCustomCredentials = hasGoogleCustomCredentialFlags(opts);
235
211
 
236
212
  if (devCredentialsFlag && !isWeb) {
@@ -241,7 +217,7 @@ const resolveGoogleUpdateMode = Effect.fn(function* ({
241
217
 
242
218
  if (
243
219
  !isWeb &&
244
- (hasFlag(opts, 'client-secret') || hasFlag(opts, 'custom-redirect-uri'))
220
+ (Args.has(opts, 'client-secret') || Args.has(opts, 'custom-redirect-uri'))
245
221
  ) {
246
222
  return yield* BadArgsError.make({
247
223
  message:
@@ -273,7 +249,7 @@ const resolveGoogleUpdateMode = Effect.fn(function* ({
273
249
  yes &&
274
250
  isWeb &&
275
251
  switchingFromShared &&
276
- (!hasFlag(opts, 'client-id') || !hasFlag(opts, 'client-secret'))
252
+ (!Args.has(opts, 'client-id') || !Args.has(opts, 'client-secret'))
277
253
  ) {
278
254
  return yield* BadArgsError.make({
279
255
  message:
@@ -295,16 +271,11 @@ const updateGoogleRedirect = Effect.fn(function* ({
295
271
  opts: Record<string, unknown>;
296
272
  client: OAuthClientRow;
297
273
  }) {
298
- const redirectTo = yield* optOrPromptWhenNeeded(opts, 'custom-redirect-uri', {
299
- promptIf: true,
300
- required: true,
301
- prompt: newRedirectPrompt,
302
- });
303
- if (!redirectTo) {
304
- return yield* BadArgsError.make({
305
- message: 'Missing required value for --custom-redirect-uri',
306
- });
307
- }
274
+ const redirectTo = yield* Args.text(opts, 'custom-redirect-uri').pipe(
275
+ Args.prompt(newRedirectPrompt),
276
+ Args.required(),
277
+ );
278
+
308
279
  const response = yield* updateOAuthClient({
309
280
  oauthClientId: client.id,
310
281
  redirectTo,
@@ -339,31 +310,29 @@ const updateGoogleCustomCredentials = Effect.fn(function* ({
339
310
  promptCredentials: boolean;
340
311
  }) {
341
312
  const mustCollectCredentials = promptCredentials || switchingFromShared;
342
- const shouldPromptClientId =
343
- promptCredentials || (switchingFromShared && !hasFlag(opts, 'client-id'));
344
- const shouldPromptClientSecret =
345
- isWeb &&
346
- (promptCredentials ||
347
- (switchingFromShared && !hasFlag(opts, 'client-secret')));
348
313
  const shouldPromptRedirectUri =
349
314
  isWeb && switchingFromShared && promptCredentials;
350
315
 
351
- const clientId = yield* optOrPromptWhenNeeded(opts, 'client-id', {
352
- promptIf: shouldPromptClientId,
353
- required: mustCollectCredentials,
354
- prompt: clientIdPrompt({ providerUrl: googleConsoleUrl }),
355
- });
356
- const clientSecret = yield* optOrPromptWhenNeeded(opts, 'client-secret', {
357
- promptIf: shouldPromptClientSecret,
358
- required: isWeb && mustCollectCredentials,
359
- prompt: clientSecretPrompt({ providerUrl: googleConsoleUrl }),
360
- });
316
+ const clientId = yield* Args.text(opts, 'client-id').pipe(
317
+ Args.availableWhen(mustCollectCredentials || Args.has(opts, 'client-id')),
318
+ Args.prompt(clientIdPrompt({ providerUrl: googleConsoleUrl })),
319
+ Args.required(),
320
+ );
321
+ const clientSecret = yield* Args.text(opts, 'client-secret').pipe(
322
+ Args.availableWhen(
323
+ isWeb && (mustCollectCredentials || Args.has(opts, 'client-secret')),
324
+ ),
325
+ Args.prompt(clientSecretPrompt({ providerUrl: googleConsoleUrl })),
326
+ Args.required(),
327
+ );
361
328
  const customRedirectUri = isWeb
362
- ? yield* optOrPromptWhenNeeded(opts, 'custom-redirect-uri', {
363
- promptIf: shouldPromptRedirectUri,
364
- required: false,
365
- prompt: redirectPrompt,
366
- })
329
+ ? yield* Args.text(opts, 'custom-redirect-uri').pipe(
330
+ Args.availableWhen(
331
+ shouldPromptRedirectUri || Args.has(opts, 'custom-redirect-uri'),
332
+ ),
333
+ Args.prompt(redirectPrompt),
334
+ Args.optional(),
335
+ )
367
336
  : undefined;
368
337
 
369
338
  const redirectTo = switchingFromShared
@@ -461,7 +430,7 @@ const handleClientIdSecretUpdate = Effect.fn(function* (params: {
461
430
  redirectSetupPrompt: string;
462
431
  }) {
463
432
  const { yes } = yield* GlobalOpts;
464
- const hasAnyUpdateFlag = hasAnyFlag(params.opts, [
433
+ const hasAnyUpdateFlag = Args.hasAny(params.opts, [
465
434
  'client-id',
466
435
  'client-secret',
467
436
  'custom-redirect-uri',
@@ -485,28 +454,27 @@ const handleClientIdSecretUpdate = Effect.fn(function* (params: {
485
454
  promptRedirect = action === 'redirect';
486
455
  }
487
456
 
488
- const clientId = yield* optOrPromptWhenNeeded(params.opts, 'client-id', {
489
- promptIf: promptCredentials,
490
- required: promptCredentials,
491
- prompt: clientIdPrompt({ providerUrl: params.providerUrl }),
492
- });
493
- const clientSecret = yield* optOrPromptWhenNeeded(
494
- params.opts,
495
- 'client-secret',
496
- {
497
- promptIf: promptCredentials,
498
- required: promptCredentials,
499
- prompt: clientSecretPrompt({ providerUrl: params.providerUrl }),
500
- },
457
+ const clientId = yield* Args.text(params.opts, 'client-id').pipe(
458
+ Args.availableWhen(promptCredentials || Args.has(params.opts, 'client-id')),
459
+ Args.prompt(clientIdPrompt({ providerUrl: params.providerUrl })),
460
+ Args.required(),
461
+ );
462
+ const clientSecret = yield* Args.text(params.opts, 'client-secret').pipe(
463
+ Args.availableWhen(
464
+ promptCredentials || Args.has(params.opts, 'client-secret'),
465
+ ),
466
+ Args.prompt(clientSecretPrompt({ providerUrl: params.providerUrl })),
467
+ Args.required(),
501
468
  );
502
- const customRedirectUri = yield* optOrPromptWhenNeeded(
469
+ const customRedirectUri = yield* Args.text(
503
470
  params.opts,
504
471
  'custom-redirect-uri',
505
- {
506
- promptIf: promptRedirect,
507
- required: promptRedirect,
508
- prompt: promptRedirect ? newRedirectPrompt : redirectPrompt,
509
- },
472
+ ).pipe(
473
+ Args.availableWhen(
474
+ promptRedirect || Args.has(params.opts, 'custom-redirect-uri'),
475
+ ),
476
+ Args.prompt(promptRedirect ? newRedirectPrompt : redirectPrompt),
477
+ Args.required(),
510
478
  );
511
479
 
512
480
  const response = yield* updateOAuthClient({
@@ -548,10 +516,10 @@ const appleWebFlags = [
548
516
  const appleUpdateFlags = ['services-id', ...appleWebFlags];
549
517
 
550
518
  const hasAppleWebFlags = (opts: Record<string, unknown>) =>
551
- hasAnyFlag(opts, appleWebFlags);
519
+ Args.hasAny(opts, appleWebFlags);
552
520
 
553
521
  const hasAppleUpdateFlags = (opts: Record<string, unknown>) =>
554
- hasAnyFlag(opts, appleUpdateFlags);
522
+ Args.hasAny(opts, appleUpdateFlags);
555
523
 
556
524
  const appleClientHasWebConfig = (client: OAuthClientRow) =>
557
525
  Boolean(
@@ -617,36 +585,28 @@ const readAppleWebUpdate = Effect.fn(function* ({
617
585
  client: OAuthClientRow;
618
586
  promptAll: boolean;
619
587
  }) {
620
- const teamId = yield* optOrPromptWhenNeeded(opts, 'team-id', {
621
- promptIf: promptAll,
622
- required: promptAll,
623
- prompt: appleTeamIdPrompt({}),
624
- });
625
- const keyId = yield* optOrPromptWhenNeeded(opts, 'key-id', {
626
- promptIf: promptAll,
627
- required: promptAll,
628
- prompt: appleKeyIdPrompt({}),
629
- });
630
- const privateKeyPath = yield* optOrPromptWhenNeeded(
631
- opts,
632
- 'private-key-file',
633
- {
634
- promptIf: promptAll,
635
- required: promptAll,
636
- prompt: applePrivateKeyFilePrompt({}),
637
- },
588
+ const teamId = yield* Args.text(opts, 'team-id').pipe(
589
+ Args.availableWhen(promptAll || Args.has(opts, 'team-id')),
590
+ Args.prompt(appleTeamIdPrompt({})),
591
+ Args.required(),
592
+ );
593
+ const keyId = yield* Args.text(opts, 'key-id').pipe(
594
+ Args.availableWhen(promptAll || Args.has(opts, 'key-id')),
595
+ Args.prompt(appleKeyIdPrompt({})),
596
+ Args.required(),
597
+ );
598
+ const privateKeyPath = yield* Args.text(opts, 'private-key-file').pipe(
599
+ Args.availableWhen(promptAll || Args.has(opts, 'private-key-file')),
600
+ Args.prompt(applePrivateKeyFilePrompt({})),
601
+ Args.required(),
638
602
  );
639
603
  const privateKey = privateKeyPath
640
604
  ? yield* readPrivateKeyFile(privateKeyPath)
641
605
  : undefined;
642
- const customRedirectUri = yield* optOrPromptWhenNeeded(
643
- opts,
644
- 'custom-redirect-uri',
645
- {
646
- promptIf: promptAll,
647
- required: false,
648
- prompt: redirectPrompt,
649
- },
606
+ const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(
607
+ Args.availableWhen(promptAll || Args.has(opts, 'custom-redirect-uri')),
608
+ Args.prompt(redirectPrompt),
609
+ Args.optional(),
650
610
  );
651
611
 
652
612
  const meta: Record<string, string> = {};
@@ -674,11 +634,11 @@ const handleAppleUpdate = Effect.fn(function* (
674
634
  yes,
675
635
  });
676
636
 
677
- const servicesId = yield* optOrPromptWhenNeeded(opts, 'services-id', {
678
- promptIf: promptAll,
679
- required: promptAll,
680
- prompt: appleServicesIdPrompt({}),
681
- });
637
+ const servicesId = yield* Args.text(opts, 'services-id').pipe(
638
+ Args.availableWhen(promptAll || Args.has(opts, 'services-id')),
639
+ Args.prompt(appleServicesIdPrompt({})),
640
+ Args.required(),
641
+ );
682
642
  const webUpdate: AppleWebUpdate = configureWeb
683
643
  ? yield* readAppleWebUpdate({ opts, client, promptAll })
684
644
  : {};
@@ -718,18 +678,10 @@ const handleClerkUpdate = Effect.fn(function* (
718
678
  opts: Record<string, unknown>,
719
679
  client: OAuthClientRow,
720
680
  ) {
721
- const { yes } = yield* GlobalOpts;
722
- const publishableKey = yield* optOrPromptWhenNeeded(opts, 'publishable-key', {
723
- promptIf: !yes && !hasFlag(opts, 'publishable-key'),
724
- required: true,
725
- prompt: clerkPublishableKeyPrompt({}),
726
- });
727
-
728
- if (!publishableKey) {
729
- return yield* BadArgsError.make({
730
- message: 'Missing required value for --publishable-key',
731
- });
732
- }
681
+ const publishableKey = yield* Args.text(opts, 'publishable-key').pipe(
682
+ Args.prompt(clerkPublishableKeyPrompt({})),
683
+ Args.required(),
684
+ );
733
685
 
734
686
  const domain = clerkDomainFromPublishableKey(publishableKey);
735
687
  if (!domain) {
@@ -760,21 +712,15 @@ const handleFirebaseUpdate = Effect.fn(function* (
760
712
  opts: Record<string, unknown>,
761
713
  client: OAuthClientRow,
762
714
  ) {
763
- const { yes } = yield* GlobalOpts;
764
- const projectId = yield* optOrPromptWhenNeeded(opts, 'project-id', {
765
- promptIf: !yes && !hasFlag(opts, 'project-id'),
766
- required: true,
767
- prompt: firebaseProjectIdPrompt({}),
768
- });
769
-
770
- const validationError = validateFirebaseProjectId(projectId ?? '');
771
- if (validationError) {
772
- return yield* BadArgsError.make({ message: validationError });
773
- }
715
+ const projectId = yield* Args.text(opts, 'project-id').pipe(
716
+ Args.prompt(firebaseProjectIdPrompt({})),
717
+ Args.validate(validateFirebaseProjectId),
718
+ Args.required(),
719
+ );
774
720
 
775
721
  const response = yield* updateOAuthClient({
776
722
  oauthClientId: client.id,
777
- discoveryEndpoint: firebaseDiscoveryEndpoint(projectId!),
723
+ discoveryEndpoint: firebaseDiscoveryEndpoint(projectId),
778
724
  });
779
725
 
780
726
  yield* Effect.log(
@@ -2,7 +2,8 @@ import { Effect, Match, Option, Schema } from 'effect';
2
2
  import type { authOriginAddDef, OptsFromCommand } from '../../../index.ts';
3
3
  import { BadArgsError } from '../../../errors.ts';
4
4
  import { GlobalOpts } from '../../../context/globalOpts.ts';
5
- import { optOrPrompt, runUIEffect } from '../../../lib/ui.ts';
5
+ import { Args } from '../../../lib/args.ts';
6
+ import { runUIEffect } from '../../../lib/ui.ts';
6
7
  import { addAuthorizedOrigin } from '../../../lib/oauth.ts';
7
8
  import { UI } from '../../../ui/index.ts';
8
9
  import chalk from 'chalk';
@@ -94,23 +95,17 @@ const addOriginHandler = Effect.fn(function* (
94
95
  const handleGenericOrigin = Effect.fn(function* (
95
96
  opts: Record<string, unknown>,
96
97
  ) {
97
- const url = yield* optOrPrompt(opts.url, {
98
- simpleName: '--url',
99
- required: true,
100
- skipIf: false,
101
- prompt: {
98
+ const url = yield* Args.text(opts, 'url').pipe(
99
+ Args.prompt({
102
100
  prompt: 'Website URL:',
103
101
  placeholder: 'example.com',
104
102
  modifyOutput: UI.modifiers.piped([
105
103
  UI.modifiers.topPadding,
106
104
  UI.modifiers.dimOnComplete,
107
105
  ]),
108
- },
109
- });
110
-
111
- if (!url) {
112
- return yield* BadArgsError.make({ message: 'URL is required.' });
113
- }
106
+ }),
107
+ Args.required(),
108
+ );
114
109
 
115
110
  const validated = validateGenericUrl(url);
116
111
  if (validated.type === 'error') {
@@ -121,21 +116,19 @@ const handleGenericOrigin = Effect.fn(function* (
121
116
  });
122
117
 
123
118
  const handleVercelOrigin = Effect.fn(function* (opts: Record<string, unknown>) {
124
- const project = yield* optOrPrompt(opts.project, {
125
- simpleName: '--project',
126
- required: true,
127
- skipIf: false,
128
- prompt: {
119
+ const project = yield* Args.text(opts, 'project').pipe(
120
+ Args.prompt({
129
121
  prompt: 'Vercel project name:',
130
122
  placeholder: 'vercel-project-name',
131
123
  modifyOutput: UI.modifiers.piped([
132
124
  UI.modifiers.topPadding,
133
125
  UI.modifiers.dimOnComplete,
134
126
  ]),
135
- },
136
- });
127
+ }),
128
+ Args.required(),
129
+ );
137
130
 
138
- const validated = validateVercelUrl(project ?? '');
131
+ const validated = validateVercelUrl(project);
139
132
  if (validated.type === 'error') {
140
133
  return yield* BadArgsError.make({ message: validated.message });
141
134
  }
@@ -146,21 +139,19 @@ const handleVercelOrigin = Effect.fn(function* (opts: Record<string, unknown>) {
146
139
  const handleNetlifyOrigin = Effect.fn(function* (
147
140
  opts: Record<string, unknown>,
148
141
  ) {
149
- const site = yield* optOrPrompt(opts.site, {
150
- simpleName: '--site',
151
- required: true,
152
- skipIf: false,
153
- prompt: {
142
+ const site = yield* Args.text(opts, 'site').pipe(
143
+ Args.prompt({
154
144
  prompt: 'Netlify site name:',
155
145
  placeholder: 'netlify-site-name',
156
146
  modifyOutput: UI.modifiers.piped([
157
147
  UI.modifiers.topPadding,
158
148
  UI.modifiers.dimOnComplete,
159
149
  ]),
160
- },
161
- });
150
+ }),
151
+ Args.required(),
152
+ );
162
153
 
163
- const validated = validateNetlifyUrl(site ?? '');
154
+ const validated = validateNetlifyUrl(site);
164
155
  if (validated.type === 'error') {
165
156
  return yield* BadArgsError.make({ message: validated.message });
166
157
  }
@@ -171,21 +162,19 @@ const handleNetlifyOrigin = Effect.fn(function* (
171
162
  const handleCustomSchemeOrigin = Effect.fn(function* (
172
163
  opts: Record<string, unknown>,
173
164
  ) {
174
- const scheme = yield* optOrPrompt(opts.scheme, {
175
- simpleName: '--scheme',
176
- required: true,
177
- skipIf: false,
178
- prompt: {
165
+ const scheme = yield* Args.text(opts, 'scheme').pipe(
166
+ Args.prompt({
179
167
  prompt: 'App scheme:',
180
168
  placeholder: 'app-scheme://',
181
169
  modifyOutput: UI.modifiers.piped([
182
170
  UI.modifiers.topPadding,
183
171
  UI.modifiers.dimOnComplete,
184
172
  ]),
185
- },
186
- });
173
+ }),
174
+ Args.required(),
175
+ );
187
176
 
188
- const validated = validateCustomScheme(scheme ?? '');
177
+ const validated = validateCustomScheme(scheme);
189
178
  if (validated.type === 'error') {
190
179
  return yield* BadArgsError.make({ message: validated.message });
191
180
  }