instant-cli 1.0.19 → 1.0.20
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__/authOriginManagement.test.ts +308 -0
- package/dist/commands/auth/origin/add.d.ts +12 -0
- package/dist/commands/auth/origin/add.d.ts.map +1 -0
- package/dist/commands/auth/origin/add.js +175 -0
- package/dist/commands/auth/origin/add.js.map +1 -0
- package/dist/commands/auth/origin/delete.d.ts +8 -0
- package/dist/commands/auth/origin/delete.d.ts.map +1 -0
- package/dist/commands/auth/origin/delete.js +38 -0
- package/dist/commands/auth/origin/delete.js.map +1 -0
- package/dist/commands/auth/origin/list.d.ts +9 -0
- package/dist/commands/auth/origin/list.d.ts.map +1 -0
- package/dist/commands/auth/origin/list.js +52 -0
- package/dist/commands/auth/origin/list.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/oauth.d.ts +24 -0
- package/dist/lib/oauth.d.ts.map +1 -1
- package/dist/lib/oauth.js +22 -0
- package/dist/lib/oauth.js.map +1 -1
- package/package.json +4 -4
- package/src/commands/auth/origin/add.ts +248 -0
- package/src/commands/auth/origin/delete.ts +50 -0
- package/src/commands/auth/origin/list.ts +66 -0
- package/src/index.ts +92 -0
- package/src/lib/oauth.ts +40 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { Effect, Match, Option, Schema } from 'effect';
|
|
2
|
+
import type { authOriginAddDef, OptsFromCommand } from '../../../index.ts';
|
|
3
|
+
import { BadArgsError } from '../../../errors.ts';
|
|
4
|
+
import { GlobalOpts } from '../../../context/globalOpts.ts';
|
|
5
|
+
import { optOrPrompt, runUIEffect } from '../../../lib/ui.ts';
|
|
6
|
+
import { addAuthorizedOrigin } from '../../../lib/oauth.ts';
|
|
7
|
+
import { UI } from '../../../ui/index.ts';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import boxen from 'boxen';
|
|
10
|
+
import { originDisplay, originSource } from './list.ts';
|
|
11
|
+
|
|
12
|
+
export const OriginTypeSchema = Schema.Literal(
|
|
13
|
+
'website',
|
|
14
|
+
'vercel',
|
|
15
|
+
'netlify',
|
|
16
|
+
'custom-scheme',
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
type OriginParams = string[];
|
|
20
|
+
|
|
21
|
+
type Validated =
|
|
22
|
+
| { type: 'success'; params: OriginParams }
|
|
23
|
+
| { type: 'error'; message: string };
|
|
24
|
+
|
|
25
|
+
const validateGenericUrl = (input: string): Validated => {
|
|
26
|
+
const trimmed = input.trim();
|
|
27
|
+
try {
|
|
28
|
+
const url = new URL(trimmed);
|
|
29
|
+
const host = url.host;
|
|
30
|
+
if (!host) {
|
|
31
|
+
throw new Error('missing host');
|
|
32
|
+
}
|
|
33
|
+
if (host.split('.').length === 1 && !url.port) {
|
|
34
|
+
throw new Error('invalid url');
|
|
35
|
+
}
|
|
36
|
+
return { type: 'success', params: [host] };
|
|
37
|
+
} catch {
|
|
38
|
+
if (!trimmed.startsWith('http')) {
|
|
39
|
+
return validateGenericUrl(`http://${trimmed}`);
|
|
40
|
+
}
|
|
41
|
+
return { type: 'error', message: 'Invalid URL.' };
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const validateNetlifyUrl = (input: string): Validated => {
|
|
46
|
+
const trimmed = input.trim();
|
|
47
|
+
if (!trimmed) {
|
|
48
|
+
return { type: 'error', message: 'Netlify site name is required.' };
|
|
49
|
+
}
|
|
50
|
+
return { type: 'success', params: [trimmed] };
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const validateVercelUrl = (input: string): Validated => {
|
|
54
|
+
const trimmed = input.trim();
|
|
55
|
+
if (!trimmed) {
|
|
56
|
+
return { type: 'error', message: 'Vercel project name is required.' };
|
|
57
|
+
}
|
|
58
|
+
return { type: 'success', params: ['vercel.app', trimmed] };
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const validateCustomScheme = (input: string): Validated => {
|
|
62
|
+
const trimmed = input.trim();
|
|
63
|
+
try {
|
|
64
|
+
const url = new URL(trimmed);
|
|
65
|
+
const scheme = url.protocol.slice(0, -1);
|
|
66
|
+
return { type: 'success', params: [scheme] };
|
|
67
|
+
} catch {
|
|
68
|
+
return { type: 'error', message: 'Invalid scheme.' };
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const addOriginHandler = Effect.fn(function* (
|
|
73
|
+
type: Schema.Schema.Type<typeof OriginTypeSchema>,
|
|
74
|
+
validated: { params: OriginParams },
|
|
75
|
+
) {
|
|
76
|
+
const response = yield* addAuthorizedOrigin({
|
|
77
|
+
service: type === 'website' ? 'generic' : type,
|
|
78
|
+
params: validated.params,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
yield* Effect.log(
|
|
82
|
+
'\n' +
|
|
83
|
+
boxen(
|
|
84
|
+
[
|
|
85
|
+
`Origin added: ${originDisplay(response.origin)}`,
|
|
86
|
+
`Type: ${originSource(response.origin)}`,
|
|
87
|
+
`ID: ${response.origin.id}`,
|
|
88
|
+
].join('\n'),
|
|
89
|
+
{ dimBorder: true, padding: { right: 1, left: 1 } },
|
|
90
|
+
),
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const handleGenericOrigin = Effect.fn(function* (
|
|
95
|
+
opts: Record<string, unknown>,
|
|
96
|
+
) {
|
|
97
|
+
const url = yield* optOrPrompt(opts.url, {
|
|
98
|
+
simpleName: '--url',
|
|
99
|
+
required: true,
|
|
100
|
+
skipIf: false,
|
|
101
|
+
prompt: {
|
|
102
|
+
prompt: 'Website URL:',
|
|
103
|
+
placeholder: 'example.com',
|
|
104
|
+
modifyOutput: UI.modifiers.piped([
|
|
105
|
+
UI.modifiers.topPadding,
|
|
106
|
+
UI.modifiers.dimOnComplete,
|
|
107
|
+
]),
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!url) {
|
|
112
|
+
return yield* BadArgsError.make({ message: 'URL is required.' });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const validated = validateGenericUrl(url);
|
|
116
|
+
if (validated.type === 'error') {
|
|
117
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
yield* addOriginHandler('website', validated);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
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: {
|
|
129
|
+
prompt: 'Vercel project name:',
|
|
130
|
+
placeholder: 'vercel-project-name',
|
|
131
|
+
modifyOutput: UI.modifiers.piped([
|
|
132
|
+
UI.modifiers.topPadding,
|
|
133
|
+
UI.modifiers.dimOnComplete,
|
|
134
|
+
]),
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const validated = validateVercelUrl(project ?? '');
|
|
139
|
+
if (validated.type === 'error') {
|
|
140
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
yield* addOriginHandler('vercel', validated);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const handleNetlifyOrigin = Effect.fn(function* (
|
|
147
|
+
opts: Record<string, unknown>,
|
|
148
|
+
) {
|
|
149
|
+
const site = yield* optOrPrompt(opts.site, {
|
|
150
|
+
simpleName: '--site',
|
|
151
|
+
required: true,
|
|
152
|
+
skipIf: false,
|
|
153
|
+
prompt: {
|
|
154
|
+
prompt: 'Netlify site name:',
|
|
155
|
+
placeholder: 'netlify-site-name',
|
|
156
|
+
modifyOutput: UI.modifiers.piped([
|
|
157
|
+
UI.modifiers.topPadding,
|
|
158
|
+
UI.modifiers.dimOnComplete,
|
|
159
|
+
]),
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const validated = validateNetlifyUrl(site ?? '');
|
|
164
|
+
if (validated.type === 'error') {
|
|
165
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
yield* addOriginHandler('netlify', validated);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const handleCustomSchemeOrigin = Effect.fn(function* (
|
|
172
|
+
opts: Record<string, unknown>,
|
|
173
|
+
) {
|
|
174
|
+
const scheme = yield* optOrPrompt(opts.scheme, {
|
|
175
|
+
simpleName: '--scheme',
|
|
176
|
+
required: true,
|
|
177
|
+
skipIf: false,
|
|
178
|
+
prompt: {
|
|
179
|
+
prompt: 'App scheme:',
|
|
180
|
+
placeholder: 'app-scheme://',
|
|
181
|
+
modifyOutput: UI.modifiers.piped([
|
|
182
|
+
UI.modifiers.topPadding,
|
|
183
|
+
UI.modifiers.dimOnComplete,
|
|
184
|
+
]),
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const validated = validateCustomScheme(scheme ?? '');
|
|
189
|
+
if (validated.type === 'error') {
|
|
190
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
yield* addOriginHandler('custom-scheme', validated);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
export const authOriginAddCmd = Effect.fn(
|
|
197
|
+
function* (
|
|
198
|
+
opts: OptsFromCommand<typeof authOriginAddDef> & Record<string, unknown>,
|
|
199
|
+
) {
|
|
200
|
+
const { yes } = yield* GlobalOpts;
|
|
201
|
+
if (!opts.type && yes) {
|
|
202
|
+
return yield* BadArgsError.make({
|
|
203
|
+
message: `Missing required value for --type. Expected one of: ${OriginTypeSchema.literals.join(', ')}`,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
const originType = yield* Option.fromNullable(opts.type).pipe(
|
|
207
|
+
Effect.catchTag('NoSuchElementException', () =>
|
|
208
|
+
runUIEffect(
|
|
209
|
+
new UI.Select({
|
|
210
|
+
options: [
|
|
211
|
+
{ label: 'Website', value: 'website' },
|
|
212
|
+
{ label: 'Vercel previews', value: 'vercel' },
|
|
213
|
+
{ label: 'Netlify previews', value: 'netlify' },
|
|
214
|
+
{ label: 'App scheme', value: 'custom-scheme' },
|
|
215
|
+
],
|
|
216
|
+
promptText: 'Select an origin type:',
|
|
217
|
+
modifyOutput: UI.modifiers.piped([UI.modifiers.dimOnComplete]),
|
|
218
|
+
}),
|
|
219
|
+
),
|
|
220
|
+
),
|
|
221
|
+
Effect.andThen((s) => Schema.decodeUnknown(OriginTypeSchema)(s)),
|
|
222
|
+
Effect.catchTag('ParseError', () =>
|
|
223
|
+
BadArgsError.make({
|
|
224
|
+
message: `Invalid origin type, must be one of: ${OriginTypeSchema.literals.join(', ')}`,
|
|
225
|
+
}),
|
|
226
|
+
),
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
yield* Match.value(originType).pipe(
|
|
230
|
+
Match.withReturnType<Effect.Effect<void, any, any>>(),
|
|
231
|
+
Match.when('website', () => handleGenericOrigin(opts)),
|
|
232
|
+
Match.when('vercel', () => handleVercelOrigin(opts)),
|
|
233
|
+
Match.when('netlify', () => handleNetlifyOrigin(opts)),
|
|
234
|
+
Match.when('custom-scheme', () => handleCustomSchemeOrigin(opts)),
|
|
235
|
+
Match.exhaustive,
|
|
236
|
+
);
|
|
237
|
+
},
|
|
238
|
+
Effect.catchTag('BadArgsError', (e) =>
|
|
239
|
+
Effect.gen(function* () {
|
|
240
|
+
yield* Effect.logError(e.message);
|
|
241
|
+
yield* Effect.log(
|
|
242
|
+
chalk.dim(
|
|
243
|
+
'hint: run `instant-cli auth origin add --help` for available arguments',
|
|
244
|
+
),
|
|
245
|
+
);
|
|
246
|
+
}),
|
|
247
|
+
),
|
|
248
|
+
);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import type { authOriginDeleteDef, OptsFromCommand } from '../../../index.ts';
|
|
4
|
+
import { BadArgsError } from '../../../errors.ts';
|
|
5
|
+
import { getAppsAuth, removeAuthorizedOrigin } from '../../../lib/oauth.ts';
|
|
6
|
+
import { GlobalOpts } from '../../../context/globalOpts.ts';
|
|
7
|
+
import { runUIEffect } from '../../../lib/ui.ts';
|
|
8
|
+
import { UI } from '../../../ui/index.ts';
|
|
9
|
+
import { originDisplay, originSource } from './list.ts';
|
|
10
|
+
|
|
11
|
+
export const authOriginDeleteCmd = Effect.fn(function* (
|
|
12
|
+
opts: OptsFromCommand<typeof authOriginDeleteDef>,
|
|
13
|
+
) {
|
|
14
|
+
const info = yield* getAppsAuth();
|
|
15
|
+
const origins = info.authorized_redirect_origins ?? [];
|
|
16
|
+
|
|
17
|
+
if (origins.length === 0) {
|
|
18
|
+
yield* Effect.log('No authorized redirect origins configured.');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!opts.id) {
|
|
23
|
+
const { yes } = yield* GlobalOpts;
|
|
24
|
+
if (yes) {
|
|
25
|
+
return yield* BadArgsError.make({
|
|
26
|
+
message: 'Must specify --id',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const picked = yield* runUIEffect(
|
|
31
|
+
new UI.Select({
|
|
32
|
+
options: origins.map((origin) => ({
|
|
33
|
+
label:
|
|
34
|
+
`${originSource(origin)} — ${originDisplay(origin)} ` +
|
|
35
|
+
chalk.dim(`(${origin.id})`),
|
|
36
|
+
value: origin,
|
|
37
|
+
})),
|
|
38
|
+
promptText: 'Select an origin to delete:',
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
yield* removeAuthorizedOrigin(picked.id);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (opts.id) {
|
|
46
|
+
yield* removeAuthorizedOrigin(opts.id);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
yield* Effect.log('Origin deleted!');
|
|
50
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Effect, Schema } from 'effect';
|
|
3
|
+
import type { authOriginListDef, OptsFromCommand } from '../../../index.ts';
|
|
4
|
+
import { AuthorizedOrigin, getAppsAuth } from '../../../lib/oauth.ts';
|
|
5
|
+
|
|
6
|
+
export const originSource = (
|
|
7
|
+
origin: Schema.Schema.Type<typeof AuthorizedOrigin>,
|
|
8
|
+
) => {
|
|
9
|
+
switch (origin.service) {
|
|
10
|
+
case 'generic':
|
|
11
|
+
return 'Website';
|
|
12
|
+
case 'netlify':
|
|
13
|
+
return 'Netlify site';
|
|
14
|
+
case 'vercel':
|
|
15
|
+
if (origin.params[0] !== 'vercel.app') {
|
|
16
|
+
return `Vercel project (${origin.params[0]})`;
|
|
17
|
+
}
|
|
18
|
+
return 'Vercel project';
|
|
19
|
+
case 'custom-scheme':
|
|
20
|
+
return 'Native app';
|
|
21
|
+
default:
|
|
22
|
+
return origin.service;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const originDisplay = (
|
|
27
|
+
origin: Schema.Schema.Type<typeof AuthorizedOrigin>,
|
|
28
|
+
) => {
|
|
29
|
+
switch (origin.service) {
|
|
30
|
+
case 'generic':
|
|
31
|
+
return origin.params[0];
|
|
32
|
+
case 'netlify':
|
|
33
|
+
return origin.params[0];
|
|
34
|
+
case 'vercel':
|
|
35
|
+
return origin.params[1];
|
|
36
|
+
case 'custom-scheme':
|
|
37
|
+
return `${origin.params[0]}://`;
|
|
38
|
+
default:
|
|
39
|
+
return origin.params[0];
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const authOriginListCmd = Effect.fn(function* (
|
|
44
|
+
_opts: OptsFromCommand<typeof authOriginListDef>,
|
|
45
|
+
) {
|
|
46
|
+
const info = yield* getAppsAuth();
|
|
47
|
+
if (_opts.json) {
|
|
48
|
+
yield* Effect.log(
|
|
49
|
+
JSON.stringify(info.authorized_redirect_origins, null, 2),
|
|
50
|
+
);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const origins = info.authorized_redirect_origins ?? [];
|
|
55
|
+
|
|
56
|
+
if (origins.length === 0) {
|
|
57
|
+
yield* Effect.log('No authorized redirect origins configured.');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (const origin of origins) {
|
|
62
|
+
yield* Effect.log(chalk.cyan(originDisplay(origin)));
|
|
63
|
+
yield* Effect.log(` Type: ${originSource(origin)}`);
|
|
64
|
+
yield* Effect.log(` ID: ${origin.id}`);
|
|
65
|
+
}
|
|
66
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,9 @@ import { PACKAGE_ALIAS_AND_FULL_NAMES } from './context/projectInfo.ts';
|
|
|
29
29
|
import { authClientAddCmd } from './commands/auth/client/add.ts';
|
|
30
30
|
import { authClientListCmd } from './commands/auth/client/list.ts';
|
|
31
31
|
import { authClientDeleteCmd } from './commands/auth/client/delete.ts';
|
|
32
|
+
import { authOriginListCmd } from './commands/auth/origin/list.ts';
|
|
33
|
+
import { authOriginDeleteCmd } from './commands/auth/origin/delete.ts';
|
|
34
|
+
import { authOriginAddCmd } from './commands/auth/origin/add.ts';
|
|
32
35
|
import { link } from './logging.ts';
|
|
33
36
|
|
|
34
37
|
export type OptsFromCommand<C> =
|
|
@@ -194,6 +197,95 @@ export const authClientDeleteDef = authClient
|
|
|
194
197
|
);
|
|
195
198
|
});
|
|
196
199
|
|
|
200
|
+
const authOrigin = auth.command('origin');
|
|
201
|
+
export const authOriginListDef = authOrigin
|
|
202
|
+
.command('list')
|
|
203
|
+
.option(
|
|
204
|
+
'-a --app <app-id>',
|
|
205
|
+
'App ID to list origins for. Defaults to *_INSTANT_APP_ID in .env',
|
|
206
|
+
)
|
|
207
|
+
.option('--json', 'Enable JSON output')
|
|
208
|
+
.action((opts) => {
|
|
209
|
+
return runCommandEffect(
|
|
210
|
+
authOriginListCmd(opts).pipe(
|
|
211
|
+
Effect.provide(
|
|
212
|
+
WithAppLayer({
|
|
213
|
+
coerce: false,
|
|
214
|
+
coerceAuth: false,
|
|
215
|
+
appId: opts.app,
|
|
216
|
+
allowAdminToken: true,
|
|
217
|
+
}).pipe(Layer.annotateLogs('silent', !!opts.json)),
|
|
218
|
+
),
|
|
219
|
+
),
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
export const authOriginAddDef = authOrigin
|
|
224
|
+
.command('add')
|
|
225
|
+
.option(
|
|
226
|
+
'--type <website|vercel|netlify|custom-scheme>',
|
|
227
|
+
'Type of origin to add.',
|
|
228
|
+
)
|
|
229
|
+
.option('--url <url>', 'Website URL (for website type, e.g. example.com)')
|
|
230
|
+
.option(
|
|
231
|
+
'--project <name>',
|
|
232
|
+
'Vercel project name (for vercel type, e.g. my-project)',
|
|
233
|
+
)
|
|
234
|
+
.option('--site <name>', 'Netlify site name (for netlify type, e.g. my-site)')
|
|
235
|
+
.option(
|
|
236
|
+
'--scheme <scheme>',
|
|
237
|
+
'App scheme (for custom-scheme type, e.g. myapp://)',
|
|
238
|
+
)
|
|
239
|
+
.option(
|
|
240
|
+
'-a --app <app-id>',
|
|
241
|
+
'App ID to add an origin to. Defaults to *_INSTANT_APP_ID in .env',
|
|
242
|
+
)
|
|
243
|
+
.addHelpText(
|
|
244
|
+
'after',
|
|
245
|
+
`
|
|
246
|
+
Origin Types:
|
|
247
|
+
website A standard website origin (e.g. example.com)
|
|
248
|
+
vercel Vercel preview deployments (project name)
|
|
249
|
+
netlify Netlify preview deployments (site name)
|
|
250
|
+
custom-scheme Native app scheme (e.g. your-app-scheme://)
|
|
251
|
+
`,
|
|
252
|
+
)
|
|
253
|
+
.action((opts) => {
|
|
254
|
+
return runCommandEffect(
|
|
255
|
+
authOriginAddCmd(opts).pipe(
|
|
256
|
+
Effect.provide(
|
|
257
|
+
WithAppLayer({
|
|
258
|
+
coerce: false,
|
|
259
|
+
coerceAuth: false,
|
|
260
|
+
appId: opts.app,
|
|
261
|
+
allowAdminToken: true,
|
|
262
|
+
}),
|
|
263
|
+
),
|
|
264
|
+
),
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
export const authOriginDeleteDef = authOrigin
|
|
269
|
+
.command('delete')
|
|
270
|
+
.option('--id <origin-id>', 'Origin ID to delete')
|
|
271
|
+
.option(
|
|
272
|
+
'-a --app <app-id>',
|
|
273
|
+
'App ID to delete an origin from. Defaults to *_INSTANT_APP_ID in .env',
|
|
274
|
+
)
|
|
275
|
+
.action((opts) => {
|
|
276
|
+
return runCommandEffect(
|
|
277
|
+
authOriginDeleteCmd(opts).pipe(
|
|
278
|
+
Effect.provide(
|
|
279
|
+
WithAppLayer({
|
|
280
|
+
coerce: false,
|
|
281
|
+
appId: opts.app,
|
|
282
|
+
allowAdminToken: true,
|
|
283
|
+
}),
|
|
284
|
+
),
|
|
285
|
+
),
|
|
286
|
+
);
|
|
287
|
+
});
|
|
288
|
+
|
|
197
289
|
export const initWithoutFilesDef = program
|
|
198
290
|
.command('init-without-files')
|
|
199
291
|
.description('Generate a new app id and admin token pair without any files.')
|
package/src/lib/oauth.ts
CHANGED
|
@@ -56,6 +56,10 @@ export const AddOAuthClientResponse = Schema.Struct({
|
|
|
56
56
|
client: OAuthClient,
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
+
export const AuthorizedOriginResponse = Schema.Struct({
|
|
60
|
+
origin: AuthorizedOrigin,
|
|
61
|
+
});
|
|
62
|
+
|
|
59
63
|
const NullableArray = <A, I, R>(schema: Schema.Schema<A, I, R>) =>
|
|
60
64
|
Schema.Union(Schema.Array(schema).pipe(Schema.mutable), Schema.Null).pipe(
|
|
61
65
|
Schema.optional,
|
|
@@ -231,3 +235,39 @@ export const getClientNameAndProvider = Effect.fn(function* (
|
|
|
231
235
|
}
|
|
232
236
|
return { provider, clientName };
|
|
233
237
|
});
|
|
238
|
+
|
|
239
|
+
export const removeAuthorizedOrigin = Effect.fn(function* (originId: string) {
|
|
240
|
+
const http = (yield* InstantHttpAuthed).pipe(
|
|
241
|
+
withCommand('auth origin delete'),
|
|
242
|
+
);
|
|
243
|
+
const { appId } = yield* CurrentApp;
|
|
244
|
+
|
|
245
|
+
return yield* http
|
|
246
|
+
.del(`/dash/apps/${appId}/authorized_redirect_origins/${originId}`)
|
|
247
|
+
.pipe(
|
|
248
|
+
Effect.flatMap(
|
|
249
|
+
HttpClientResponse.schemaBodyJson(AuthorizedOriginResponse),
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
export const addAuthorizedOrigin = Effect.fn(function* (params: {
|
|
255
|
+
service: Schema.Schema.Type<typeof AuthorizedOriginService>;
|
|
256
|
+
params: string[];
|
|
257
|
+
}) {
|
|
258
|
+
const http = (yield* InstantHttpAuthed).pipe(withCommand('auth origin add'));
|
|
259
|
+
const { appId } = yield* CurrentApp;
|
|
260
|
+
|
|
261
|
+
return yield* http
|
|
262
|
+
.post(`/dash/apps/${appId}/authorized_redirect_origins`, {
|
|
263
|
+
body: HttpBody.unsafeJson({
|
|
264
|
+
service: params.service,
|
|
265
|
+
params: params.params,
|
|
266
|
+
}),
|
|
267
|
+
})
|
|
268
|
+
.pipe(
|
|
269
|
+
Effect.flatMap(
|
|
270
|
+
HttpClientResponse.schemaBodyJson(AuthorizedOriginResponse),
|
|
271
|
+
),
|
|
272
|
+
);
|
|
273
|
+
});
|