instant-cli 1.0.23-branch-cli-codex-update.25390498340.1 → 1.0.23-branch-codex-cli-args-combinators.25393207850.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 +203 -0
- package/__tests__/oauthMock.ts +7 -8
- package/__tests__/redirectUriPrompt.test.ts +7 -6
- package/dist/commands/auth/client/add.d.ts.map +1 -1
- package/dist/commands/auth/client/add.js +43 -129
- package/dist/commands/auth/client/add.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 +18 -22
- 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 +34 -53
- package/dist/commands/auth/origin/add.js.map +1 -1
- package/dist/lib/args.d.ts +45 -0
- package/dist/lib/args.d.ts.map +1 -0
- package/dist/lib/args.js +149 -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 +12 -16
- package/dist/lib/oauth.js.map +1 -1
- package/dist/lib/ui.d.ts +0 -15
- package/dist/lib/ui.d.ts.map +1 -1
- package/dist/lib/ui.js +0 -64
- package/dist/lib/ui.js.map +1 -1
- package/package.json +4 -4
- package/src/commands/auth/client/add.ts +107 -134
- package/src/commands/auth/client/update.ts +21 -22
- package/src/commands/auth/origin/add.ts +22 -29
- package/src/lib/args.ts +223 -0
- package/src/lib/oauth.ts +6 -8
- package/src/lib/ui.ts +0 -107
- package/__tests__/optOrPrompt.test.ts +0 -229
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
> instant-cli@1.0.23-branch-cli-
|
|
2
|
+
> instant-cli@1.0.23-branch-codex-cli-args-combinators.25393207850.1 build /home/runner/work/instant/instant/client/packages/cli
|
|
3
3
|
> rm -rf dist; tsc -p tsconfig.build.json
|
|
4
4
|
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { test, expect, describe, 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
|
+
|
|
6
|
+
const run = <A>(effect: Effect.Effect<A, any, GlobalOpts>, yes: boolean) =>
|
|
7
|
+
Effect.runPromise(
|
|
8
|
+
effect.pipe(Effect.provide(Layer.succeed(GlobalOpts, { yes }))),
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const runFail = <A>(effect: Effect.Effect<A, any, GlobalOpts>, yes: boolean) =>
|
|
12
|
+
Effect.runPromise(
|
|
13
|
+
effect.pipe(
|
|
14
|
+
Effect.flip,
|
|
15
|
+
Effect.provide(Layer.succeed(GlobalOpts, { yes })),
|
|
16
|
+
),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
let mockPromptReturn: unknown = '';
|
|
20
|
+
vi.mock('../src/ui/lib.ts', async (importOriginal) => {
|
|
21
|
+
const orig: any = await importOriginal();
|
|
22
|
+
return {
|
|
23
|
+
...orig,
|
|
24
|
+
renderUnwrap: () => Promise.resolve(mockPromptReturn),
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const basePrompt = { prompt: 'Client ID:' } as any;
|
|
29
|
+
|
|
30
|
+
describe('forbidIf', () => {
|
|
31
|
+
test('condition=true + value provided -> error', async () => {
|
|
32
|
+
const err = await runFail(
|
|
33
|
+
Args.text(
|
|
34
|
+
{ 'custom-redirect-uri': 'https://mysite.com/callback' },
|
|
35
|
+
'custom-redirect-uri',
|
|
36
|
+
).pipe(
|
|
37
|
+
Args.forbidIf(true, {
|
|
38
|
+
message: 'Provided custom redirect URI when not using web app type.',
|
|
39
|
+
}),
|
|
40
|
+
),
|
|
41
|
+
false,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(err.message).toBe(
|
|
45
|
+
'Provided custom redirect URI when not using web app type.',
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('condition=true + no value -> undefined', async () => {
|
|
50
|
+
const result = await run(
|
|
51
|
+
Args.text({}, 'custom-redirect-uri').pipe(Args.forbidIf(true)),
|
|
52
|
+
false,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
expect(result).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('non-interactive', () => {
|
|
60
|
+
test('required missing value -> error', async () => {
|
|
61
|
+
const err = await runFail(
|
|
62
|
+
Args.text({}, 'client-id').pipe(
|
|
63
|
+
Args.orPrompt(basePrompt),
|
|
64
|
+
Args.required(),
|
|
65
|
+
),
|
|
66
|
+
true,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
expect(err.message).toBe('Missing required value for --client-id');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('number value -> stringified', async () => {
|
|
73
|
+
const result = await run(
|
|
74
|
+
Args.text({ 'client-id': 42 }, 'client-id').pipe(Args.required()),
|
|
75
|
+
true,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(result).toBe('42');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('non-string/number value -> error', async () => {
|
|
82
|
+
const err = await runFail(
|
|
83
|
+
Args.text({ 'client-id': true }, 'client-id').pipe(Args.required()),
|
|
84
|
+
true,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(err.message).toBe('Invalid value for --client-id');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('valid string -> trimmed value', async () => {
|
|
91
|
+
const result = await run(
|
|
92
|
+
Args.text(
|
|
93
|
+
{ 'client-id': ' abc123.apps.googleusercontent.com ' },
|
|
94
|
+
'client-id',
|
|
95
|
+
).pipe(Args.required()),
|
|
96
|
+
true,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
expect(result).toBe('abc123.apps.googleusercontent.com');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('optional missing value -> undefined', async () => {
|
|
103
|
+
const result = await run(Args.text({}, 'custom-redirect-uri'), true);
|
|
104
|
+
|
|
105
|
+
expect(result).toBeUndefined();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('boolean value -> parsed', async () => {
|
|
109
|
+
const result = await run(
|
|
110
|
+
Args.bool({ 'configure-web': true }, 'configure-web'),
|
|
111
|
+
true,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
expect(result).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('boolean string value -> parsed', async () => {
|
|
118
|
+
const result = await run(
|
|
119
|
+
Args.bool({ 'configure-web': 'false' }, 'configure-web'),
|
|
120
|
+
true,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
expect(result).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('invalid boolean value -> error', async () => {
|
|
127
|
+
const err = await runFail(
|
|
128
|
+
Args.bool({ 'configure-web': 'sometimes' }, 'configure-web'),
|
|
129
|
+
true,
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
expect(err.message).toBe('Invalid value for --configure-web');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('interactive', () => {
|
|
137
|
+
test('value already provided -> use it directly', async () => {
|
|
138
|
+
const result = await run(
|
|
139
|
+
Args.text(
|
|
140
|
+
{ 'client-id': ' abc123.apps.googleusercontent.com ' },
|
|
141
|
+
'client-id',
|
|
142
|
+
).pipe(Args.orPrompt(basePrompt), Args.required()),
|
|
143
|
+
false,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
expect(result).toBe('abc123.apps.googleusercontent.com');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('no value + user types a value -> trimmed result', async () => {
|
|
150
|
+
mockPromptReturn = ' GOCSPX-secret123 ';
|
|
151
|
+
|
|
152
|
+
const result = await run(
|
|
153
|
+
Args.text({}, 'client-secret').pipe(
|
|
154
|
+
Args.orPrompt(basePrompt),
|
|
155
|
+
Args.required(),
|
|
156
|
+
),
|
|
157
|
+
false,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
expect(result).toBe('GOCSPX-secret123');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test('no value + user enters empty + required -> error', async () => {
|
|
164
|
+
mockPromptReturn = '';
|
|
165
|
+
|
|
166
|
+
const err = await runFail(
|
|
167
|
+
Args.text({}, 'client-secret').pipe(
|
|
168
|
+
Args.orPrompt(basePrompt),
|
|
169
|
+
Args.required(),
|
|
170
|
+
),
|
|
171
|
+
false,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
expect(err.message).toBe('Missing required value for --client-secret');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test('no value + user enters empty + optional -> undefined', async () => {
|
|
178
|
+
mockPromptReturn = '';
|
|
179
|
+
|
|
180
|
+
const result = await run(
|
|
181
|
+
Args.text({}, 'custom-redirect-uri').pipe(Args.orPrompt(basePrompt)),
|
|
182
|
+
false,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
expect(result).toBeUndefined();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('no boolean value + user confirms -> result', async () => {
|
|
189
|
+
mockPromptReturn = true;
|
|
190
|
+
|
|
191
|
+
const result = await run(
|
|
192
|
+
Args.bool({}, 'configure-web').pipe(
|
|
193
|
+
Args.orConfirm({
|
|
194
|
+
promptText: 'Configure web redirect flow?',
|
|
195
|
+
defaultValue: false,
|
|
196
|
+
}),
|
|
197
|
+
),
|
|
198
|
+
false,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
expect(result).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
});
|
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.orPrompt({
|
|
52
50
|
prompt: 'Client Name:',
|
|
53
51
|
defaultValue: suggested,
|
|
54
52
|
placeholder: suggested,
|
|
@@ -57,8 +55,9 @@ export const makeOAuthMock = (mocks: {
|
|
|
57
55
|
UI.modifiers.topPadding,
|
|
58
56
|
UI.modifiers.dimOnComplete,
|
|
59
57
|
]),
|
|
60
|
-
},
|
|
61
|
-
|
|
58
|
+
}),
|
|
59
|
+
Args.required(),
|
|
60
|
+
);
|
|
62
61
|
if (used.has(clientName || '')) {
|
|
63
62
|
return yield* BadArgsError.make({
|
|
64
63
|
message: `The unique name '${clientName}' is already in use.`,
|
|
@@ -3,7 +3,9 @@ import stripAnsi from 'strip-ansi';
|
|
|
3
3
|
import { redirectUriPrompt } from '../src/commands/auth/client/shared.ts';
|
|
4
4
|
|
|
5
5
|
test('redirectUriPrompt shows skipped when submitted empty', () => {
|
|
6
|
-
const prompt = redirectUriPrompt({
|
|
6
|
+
const prompt = redirectUriPrompt({
|
|
7
|
+
heading: 'Custom redirect URI (optional):',
|
|
8
|
+
});
|
|
7
9
|
|
|
8
10
|
const output = stripAnsi(prompt.modifyOutput!('\n', 'submitted'));
|
|
9
11
|
|
|
@@ -11,13 +13,12 @@ test('redirectUriPrompt shows skipped when submitted empty', () => {
|
|
|
11
13
|
});
|
|
12
14
|
|
|
13
15
|
test('redirectUriPrompt shows submitted custom redirect URI', () => {
|
|
14
|
-
const prompt = redirectUriPrompt({
|
|
16
|
+
const prompt = redirectUriPrompt({
|
|
17
|
+
heading: 'Custom redirect URI (optional):',
|
|
18
|
+
});
|
|
15
19
|
|
|
16
20
|
const output = stripAnsi(
|
|
17
|
-
prompt.modifyOutput!(
|
|
18
|
-
'\nhttps://example.com/oauth/callback',
|
|
19
|
-
'submitted',
|
|
20
|
-
),
|
|
21
|
+
prompt.modifyOutput!('\nhttps://example.com/oauth/callback', 'submitted'),
|
|
21
22
|
);
|
|
22
23
|
|
|
23
24
|
expect(output).toContain(
|
|
@@ -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;AA+C5D,eAAO,MAAM,gBAAgB,gFAO5B,CAAC;AAuoBF,eAAO,MAAM,gBAAgB;;;;wgBAwD5B,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Effect, Match, Option, Schema } from 'effect';
|
|
2
2
|
import { BadArgsError } from "../../../errors.js";
|
|
3
3
|
import { GlobalOpts } from "../../../context/globalOpts.js";
|
|
4
|
-
import {
|
|
4
|
+
import { Args } from "../../../lib/args.js";
|
|
5
|
+
import { runUIEffect, validateRequired } from "../../../lib/ui.js";
|
|
5
6
|
import { addOAuthClient, findName, getClientNameAndProvider, getOrCreateProvider, GoogleAppTypeSchema, OAuthClient, } from "../../../lib/oauth.js";
|
|
6
7
|
import { DEFAULT_OAUTH_CALLBACK_URL, GOOGLE_AUTHORIZATION_ENDPOINT, GOOGLE_DISCOVERY_ENDPOINT, GOOGLE_TOKEN_ENDPOINT, APPLE_AUTHORIZATION_ENDPOINT, APPLE_DISCOVERY_ENDPOINT, APPLE_TOKEN_ENDPOINT, clerkDomainFromPublishableKey, LINKEDIN_AUTHORIZATION_ENDPOINT, LINKEDIN_DISCOVERY_ENDPOINT, LINKEDIN_TOKEN_ENDPOINT, } from '@instantdb/platform';
|
|
7
8
|
import { UI } from "../../../ui/index.js";
|
|
@@ -142,52 +143,35 @@ const handleGoogleClient = Effect.fn(function* (opts) {
|
|
|
142
143
|
const { auth, provider } = yield* getOrCreateProvider('google');
|
|
143
144
|
const usedClientNames = new Set((auth.oauth_clients ?? []).map((client) => client.client_name));
|
|
144
145
|
const suggestedClientName = findName(`google-${appType}`, usedClientNames);
|
|
145
|
-
const clientName = yield*
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
UI.modifiers.topPadding,
|
|
156
|
-
UI.modifiers.dimOnComplete,
|
|
157
|
-
]),
|
|
158
|
-
},
|
|
159
|
-
});
|
|
146
|
+
const clientName = yield* Args.text(opts, 'name').pipe(Args.orPrompt({
|
|
147
|
+
prompt: 'Client Name:',
|
|
148
|
+
defaultValue: suggestedClientName,
|
|
149
|
+
placeholder: suggestedClientName,
|
|
150
|
+
validate: validateRequired,
|
|
151
|
+
modifyOutput: UI.modifiers.piped([
|
|
152
|
+
UI.modifiers.topPadding,
|
|
153
|
+
UI.modifiers.dimOnComplete,
|
|
154
|
+
]),
|
|
155
|
+
}), Args.required());
|
|
160
156
|
if (usedClientNames.has(clientName || '')) {
|
|
161
157
|
return yield* BadArgsError.make({
|
|
162
158
|
message: `The unique name '${clientName}' is already in use.`,
|
|
163
159
|
});
|
|
164
160
|
}
|
|
165
|
-
const clientId = yield*
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
skipIf: useSharedCredentials,
|
|
169
|
-
skipMessage: '--client-id is not compatible with --dev-credentials. Drop one or the other.',
|
|
170
|
-
prompt: clientIdPrompt({ providerUrl: googleConsoleUrl }),
|
|
171
|
-
});
|
|
161
|
+
const clientId = yield* Args.text(opts, 'client-id').pipe(Args.forbidIf(useSharedCredentials, {
|
|
162
|
+
message: '--client-id is not compatible with --dev-credentials. Drop one or the other.',
|
|
163
|
+
}), Args.orPromptIf(!useSharedCredentials, clientIdPrompt({ providerUrl: googleConsoleUrl })), Args.requiredIf(!useSharedCredentials));
|
|
172
164
|
const usesCustomWebCredentials = !useSharedCredentials && appType === 'web';
|
|
173
|
-
const clientSecret = yield*
|
|
174
|
-
|
|
175
|
-
skipIf: !usesCustomWebCredentials,
|
|
176
|
-
simpleName: '--client-secret',
|
|
177
|
-
skipMessage: useSharedCredentials
|
|
165
|
+
const clientSecret = yield* Args.text(opts, 'client-secret').pipe(Args.forbidIf(!usesCustomWebCredentials, {
|
|
166
|
+
message: useSharedCredentials
|
|
178
167
|
? '--client-secret is not compatible with --dev-credentials. Drop one or the other.'
|
|
179
168
|
: undefined,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
required: false,
|
|
184
|
-
prompt: optionalRedirectPrompt,
|
|
185
|
-
simpleName: '--custom-redirect-uri',
|
|
186
|
-
skipIf: !usesCustomWebCredentials,
|
|
187
|
-
skipMessage: useSharedCredentials
|
|
169
|
+
}), Args.orPromptIf(usesCustomWebCredentials, clientSecretPrompt({ providerUrl: googleConsoleUrl })), Args.requiredIf(usesCustomWebCredentials));
|
|
170
|
+
const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(Args.forbidIf(!usesCustomWebCredentials, {
|
|
171
|
+
message: useSharedCredentials
|
|
188
172
|
? '--custom-redirect-uri is not compatible with --dev-credentials.'
|
|
189
173
|
: 'Provided custom redirect URI when not using web app type.',
|
|
190
|
-
});
|
|
174
|
+
}), Args.orPromptIf(usesCustomWebCredentials, optionalRedirectPrompt));
|
|
191
175
|
if (!clientName) {
|
|
192
176
|
return yield* BadArgsError.make({ message: 'Client name is required.' }); // Should never reach this
|
|
193
177
|
}
|
|
@@ -226,24 +210,9 @@ const handleGoogleClient = Effect.fn(function* (opts) {
|
|
|
226
210
|
});
|
|
227
211
|
const handleGithubClient = Effect.fn(function* (opts) {
|
|
228
212
|
const { clientName, provider } = yield* getClientNameAndProvider('github', opts);
|
|
229
|
-
const clientId = yield*
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
skipIf: false,
|
|
233
|
-
prompt: clientIdPrompt({ providerUrl: githubDeveloperUrl }),
|
|
234
|
-
});
|
|
235
|
-
const clientSecret = yield* optOrPrompt(opts['client-secret'], {
|
|
236
|
-
required: true,
|
|
237
|
-
skipIf: false,
|
|
238
|
-
simpleName: '--client-secret',
|
|
239
|
-
prompt: clientSecretPrompt({ providerUrl: githubDeveloperUrl }),
|
|
240
|
-
});
|
|
241
|
-
const customRedirectUri = yield* optOrPrompt(opts['custom-redirect-uri'], {
|
|
242
|
-
required: false,
|
|
243
|
-
simpleName: '--custom-redirect-uri',
|
|
244
|
-
skipIf: false,
|
|
245
|
-
prompt: optionalRedirectPrompt,
|
|
246
|
-
});
|
|
213
|
+
const clientId = yield* Args.text(opts, 'client-id').pipe(Args.orPrompt(clientIdPrompt({ providerUrl: githubDeveloperUrl })), Args.required());
|
|
214
|
+
const clientSecret = yield* Args.text(opts, 'client-secret').pipe(Args.orPrompt(clientSecretPrompt({ providerUrl: githubDeveloperUrl })), Args.required());
|
|
215
|
+
const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(Args.orPrompt(optionalRedirectPrompt));
|
|
247
216
|
if (!clientName) {
|
|
248
217
|
return yield* BadArgsError.make({ message: 'Client name is required.' });
|
|
249
218
|
}
|
|
@@ -272,24 +241,9 @@ const handleGithubClient = Effect.fn(function* (opts) {
|
|
|
272
241
|
});
|
|
273
242
|
const handleLinkedInClient = Effect.fn(function* (opts) {
|
|
274
243
|
const { clientName, provider } = yield* getClientNameAndProvider('linkedin', opts);
|
|
275
|
-
const clientId = yield*
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
skipIf: false,
|
|
279
|
-
prompt: clientIdPrompt({ providerUrl: linkedinDeveloperUrl }),
|
|
280
|
-
});
|
|
281
|
-
const clientSecret = yield* optOrPrompt(opts['client-secret'], {
|
|
282
|
-
required: true,
|
|
283
|
-
skipIf: false,
|
|
284
|
-
simpleName: '--client-secret',
|
|
285
|
-
prompt: clientSecretPrompt({ providerUrl: linkedinDeveloperUrl }),
|
|
286
|
-
});
|
|
287
|
-
const customRedirectUri = yield* optOrPrompt(opts['custom-redirect-uri'], {
|
|
288
|
-
required: false,
|
|
289
|
-
simpleName: '--custom-redirect-uri',
|
|
290
|
-
skipIf: false,
|
|
291
|
-
prompt: optionalRedirectPrompt,
|
|
292
|
-
});
|
|
244
|
+
const clientId = yield* Args.text(opts, 'client-id').pipe(Args.orPrompt(clientIdPrompt({ providerUrl: linkedinDeveloperUrl })), Args.required());
|
|
245
|
+
const clientSecret = yield* Args.text(opts, 'client-secret').pipe(Args.orPrompt(clientSecretPrompt({ providerUrl: linkedinDeveloperUrl })), Args.required());
|
|
246
|
+
const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(Args.orPrompt(optionalRedirectPrompt));
|
|
293
247
|
if (!clientName) {
|
|
294
248
|
return yield* BadArgsError.make({ message: 'Client name is required.' });
|
|
295
249
|
}
|
|
@@ -319,12 +273,7 @@ const handleLinkedInClient = Effect.fn(function* (opts) {
|
|
|
319
273
|
const handleAppleClient = Effect.fn(function* (opts) {
|
|
320
274
|
const { yes } = yield* GlobalOpts;
|
|
321
275
|
const { clientName, provider } = yield* getClientNameAndProvider('apple', opts);
|
|
322
|
-
const servicesId = yield*
|
|
323
|
-
simpleName: '--services-id',
|
|
324
|
-
required: true,
|
|
325
|
-
skipIf: false,
|
|
326
|
-
prompt: appleServicesIdPrompt({}),
|
|
327
|
-
});
|
|
276
|
+
const servicesId = yield* Args.text(opts, 'services-id').pipe(Args.orPrompt(appleServicesIdPrompt({})), Args.required());
|
|
328
277
|
// If any web-flow flag is provided, enable web flow; otherwise ask
|
|
329
278
|
// (non-interactively with --yes we default to native-only).
|
|
330
279
|
const anyWebFlagProvided = Boolean(opts['team-id'] || opts['key-id'] || opts['private-key-file']);
|
|
@@ -332,49 +281,24 @@ const handleAppleClient = Effect.fn(function* (opts) {
|
|
|
332
281
|
? true
|
|
333
282
|
: yes
|
|
334
283
|
? false
|
|
335
|
-
: yield*
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
promptText: 'Configure web redirect flow? ' +
|
|
341
|
-
chalk.dim('(requires Team ID, Key ID, and a .p8 private key from Apple)'),
|
|
342
|
-
defaultValue: false,
|
|
343
|
-
},
|
|
344
|
-
});
|
|
284
|
+
: Boolean(yield* Args.bool(opts, 'configure-web').pipe(Args.orConfirm({
|
|
285
|
+
promptText: 'Configure web redirect flow? ' +
|
|
286
|
+
chalk.dim('(requires Team ID, Key ID, and a .p8 private key from Apple)'),
|
|
287
|
+
defaultValue: false,
|
|
288
|
+
})));
|
|
345
289
|
const skipWeb = !configureWeb;
|
|
346
290
|
const webSkipMessage = 'requires configuring the web redirect flow (also provide --team-id, --key-id, and --private-key-file).';
|
|
347
|
-
const teamId = yield*
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
prompt: appleTeamIdPrompt({}),
|
|
353
|
-
});
|
|
354
|
-
const keyId = yield* optOrPrompt(opts['key-id'], {
|
|
355
|
-
simpleName: '--key-id',
|
|
356
|
-
required: true,
|
|
357
|
-
skipIf: skipWeb,
|
|
358
|
-
skipMessage: `--key-id ${webSkipMessage}`,
|
|
359
|
-
prompt: appleKeyIdPrompt({}),
|
|
360
|
-
});
|
|
361
|
-
const privateKeyPath = yield* optOrPrompt(opts['private-key-file'], {
|
|
362
|
-
simpleName: '--private-key-file',
|
|
363
|
-
required: true,
|
|
364
|
-
skipIf: skipWeb,
|
|
365
|
-
skipMessage: `--private-key-file ${webSkipMessage}`,
|
|
366
|
-
prompt: applePrivateKeyFilePrompt({}),
|
|
367
|
-
});
|
|
291
|
+
const teamId = yield* Args.text(opts, 'team-id').pipe(Args.forbidIf(skipWeb, { message: `--team-id ${webSkipMessage}` }), Args.orPromptIf(!skipWeb, appleTeamIdPrompt({})), Args.requiredIf(!skipWeb));
|
|
292
|
+
const keyId = yield* Args.text(opts, 'key-id').pipe(Args.forbidIf(skipWeb, { message: `--key-id ${webSkipMessage}` }), Args.orPromptIf(!skipWeb, appleKeyIdPrompt({})), Args.requiredIf(!skipWeb));
|
|
293
|
+
const privateKeyPath = yield* Args.text(opts, 'private-key-file').pipe(Args.forbidIf(skipWeb, {
|
|
294
|
+
message: `--private-key-file ${webSkipMessage}`,
|
|
295
|
+
}), Args.orPromptIf(!skipWeb, applePrivateKeyFilePrompt({})), Args.requiredIf(!skipWeb));
|
|
368
296
|
const privateKey = privateKeyPath
|
|
369
297
|
? yield* readPrivateKeyFile(privateKeyPath)
|
|
370
298
|
: undefined;
|
|
371
|
-
const customRedirectUri = yield*
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
skipIf: skipWeb,
|
|
375
|
-
skipMessage: `--custom-redirect-uri ${webSkipMessage}`,
|
|
376
|
-
prompt: optionalRedirectPrompt,
|
|
377
|
-
});
|
|
299
|
+
const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(Args.forbidIf(skipWeb, {
|
|
300
|
+
message: `--custom-redirect-uri ${webSkipMessage}`,
|
|
301
|
+
}), Args.orPromptIf(!skipWeb, optionalRedirectPrompt));
|
|
378
302
|
if (!clientName) {
|
|
379
303
|
return yield* BadArgsError.make({ message: 'Client name is required.' });
|
|
380
304
|
}
|
|
@@ -418,12 +342,7 @@ const handleAppleClient = Effect.fn(function* (opts) {
|
|
|
418
342
|
});
|
|
419
343
|
const handleClerkClient = Effect.fn(function* (opts) {
|
|
420
344
|
const { clientName, provider } = yield* getClientNameAndProvider('clerk', opts);
|
|
421
|
-
const publishableKey = yield*
|
|
422
|
-
simpleName: '--publishable-key',
|
|
423
|
-
required: true,
|
|
424
|
-
skipIf: false,
|
|
425
|
-
prompt: clerkPublishableKeyPrompt({}),
|
|
426
|
-
});
|
|
345
|
+
const publishableKey = yield* Args.text(opts, 'publishable-key').pipe(Args.orPrompt(clerkPublishableKeyPrompt({})), Args.required());
|
|
427
346
|
if (!clientName) {
|
|
428
347
|
return yield* BadArgsError.make({ message: 'Client name is required.' });
|
|
429
348
|
}
|
|
@@ -459,12 +378,7 @@ const handleClerkClient = Effect.fn(function* (opts) {
|
|
|
459
378
|
});
|
|
460
379
|
const handleFirebaseClient = Effect.fn(function* (opts) {
|
|
461
380
|
const { clientName, provider } = yield* getClientNameAndProvider('firebase', opts);
|
|
462
|
-
const projectId = yield*
|
|
463
|
-
simpleName: '--project-id',
|
|
464
|
-
required: true,
|
|
465
|
-
skipIf: false,
|
|
466
|
-
prompt: firebaseProjectIdPrompt({}),
|
|
467
|
-
});
|
|
381
|
+
const projectId = yield* Args.text(opts, 'project-id').pipe(Args.orPrompt(firebaseProjectIdPrompt({})), Args.required());
|
|
468
382
|
// typeguard
|
|
469
383
|
if (!clientName || !projectId) {
|
|
470
384
|
return yield* BadArgsError.make({
|