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
package/.turbo/turbo-build.log
CHANGED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { test, expect, describe, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { Effect, Layer, Logger } from 'effect';
|
|
3
|
+
import { GlobalOpts } from '../src/context/globalOpts.ts';
|
|
4
|
+
import { CurrentApp } from '../src/context/currentApp.ts';
|
|
5
|
+
import { InstantHttpAuthed } from '../src/lib/http.ts';
|
|
6
|
+
|
|
7
|
+
// -- mocks --
|
|
8
|
+
|
|
9
|
+
// Prevent src/index.ts side-effect (program.parse) from running.
|
|
10
|
+
// The command files import types from index.ts, but vitest still evaluates it.
|
|
11
|
+
vi.mock('../src/index.ts', () => ({}));
|
|
12
|
+
|
|
13
|
+
let prompts: any[] = [];
|
|
14
|
+
let mockPromptReturn: any = '';
|
|
15
|
+
|
|
16
|
+
vi.mock('../src/ui/lib.ts', async (importOriginal) => {
|
|
17
|
+
const orig: any = await importOriginal();
|
|
18
|
+
return {
|
|
19
|
+
...orig,
|
|
20
|
+
renderUnwrap: (prompt: any) => {
|
|
21
|
+
prompts.push(prompt);
|
|
22
|
+
return Promise.resolve(mockPromptReturn);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
let origins: any[] = [];
|
|
28
|
+
let addedOrigins: any[] = [];
|
|
29
|
+
let removedOriginIds: string[] = [];
|
|
30
|
+
|
|
31
|
+
vi.mock('../src/lib/oauth.ts', async (importOriginal) => {
|
|
32
|
+
const orig: any = await importOriginal();
|
|
33
|
+
return {
|
|
34
|
+
...orig,
|
|
35
|
+
getAppsAuth: () =>
|
|
36
|
+
Effect.succeed({
|
|
37
|
+
authorized_redirect_origins: origins,
|
|
38
|
+
oauth_service_providers: [],
|
|
39
|
+
oauth_clients: [],
|
|
40
|
+
}),
|
|
41
|
+
addAuthorizedOrigin: (params: any) => {
|
|
42
|
+
addedOrigins.push(params);
|
|
43
|
+
return Effect.succeed({
|
|
44
|
+
origin: {
|
|
45
|
+
id: `origin-${addedOrigins.length}`,
|
|
46
|
+
service: params.service,
|
|
47
|
+
params: params.params,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
removeAuthorizedOrigin: (originId: string) => {
|
|
52
|
+
removedOriginIds.push(originId);
|
|
53
|
+
return Effect.succeed({
|
|
54
|
+
origin: origins.find((origin) => origin.id === originId) ?? {
|
|
55
|
+
id: originId,
|
|
56
|
+
service: 'generic',
|
|
57
|
+
params: ['example.com'],
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Lazy import so mocks are in place.
|
|
65
|
+
const { authOriginAddCmd } = await import('../src/commands/auth/origin/add.ts');
|
|
66
|
+
const { authOriginDeleteCmd } = await import(
|
|
67
|
+
'../src/commands/auth/origin/delete.ts'
|
|
68
|
+
);
|
|
69
|
+
const { authOriginListCmd } = await import(
|
|
70
|
+
'../src/commands/auth/origin/list.ts'
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// -- helpers --
|
|
74
|
+
|
|
75
|
+
let logs: string[] = [];
|
|
76
|
+
|
|
77
|
+
type TestContext = GlobalOpts | CurrentApp | InstantHttpAuthed;
|
|
78
|
+
|
|
79
|
+
const run = (
|
|
80
|
+
cmd: Effect.Effect<void, any, TestContext>,
|
|
81
|
+
{ yes }: { yes: boolean },
|
|
82
|
+
) =>
|
|
83
|
+
Effect.runPromise(
|
|
84
|
+
cmd.pipe(
|
|
85
|
+
Effect.provide(
|
|
86
|
+
Layer.mergeAll(
|
|
87
|
+
Layer.succeed(GlobalOpts, { yes }),
|
|
88
|
+
Layer.succeed(CurrentApp, { appId: 'test-app', source: 'env' }),
|
|
89
|
+
Layer.succeed(InstantHttpAuthed, {} as any),
|
|
90
|
+
Logger.replace(
|
|
91
|
+
Logger.defaultLogger,
|
|
92
|
+
Logger.make(({ message }) => {
|
|
93
|
+
logs.push(String(message));
|
|
94
|
+
}),
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const add = (flags: Map<string, string>, opts = { yes: true }) =>
|
|
102
|
+
run(authOriginAddCmd(Object.fromEntries(flags) as any), opts);
|
|
103
|
+
|
|
104
|
+
const list = (flags: Map<string, any>, opts = { yes: true }) =>
|
|
105
|
+
run(authOriginListCmd(Object.fromEntries(flags) as any), opts);
|
|
106
|
+
|
|
107
|
+
const remove = (flags: Map<string, string>, opts = { yes: true }) =>
|
|
108
|
+
run(authOriginDeleteCmd(Object.fromEntries(flags) as any), opts);
|
|
109
|
+
|
|
110
|
+
const without = (flags: Map<string, string>, key: string) => {
|
|
111
|
+
const copy = new Map(flags);
|
|
112
|
+
copy.delete(key);
|
|
113
|
+
return copy;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
beforeEach(() => {
|
|
117
|
+
prompts = [];
|
|
118
|
+
origins = [];
|
|
119
|
+
addedOrigins = [];
|
|
120
|
+
removedOriginIds = [];
|
|
121
|
+
logs = [];
|
|
122
|
+
mockPromptReturn = '';
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// -- flag sets --
|
|
126
|
+
|
|
127
|
+
const websiteFlags = new Map([
|
|
128
|
+
['type', 'website'],
|
|
129
|
+
['url', 'https://example.com/login'],
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
const vercelFlags = new Map([
|
|
133
|
+
['type', 'vercel'],
|
|
134
|
+
['project', 'instant-preview'],
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
const netlifyFlags = new Map([
|
|
138
|
+
['type', 'netlify'],
|
|
139
|
+
['site', 'instant-netlify'],
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
const customSchemeFlags = new Map([
|
|
143
|
+
['type', 'custom-scheme'],
|
|
144
|
+
['scheme', 'instant://'],
|
|
145
|
+
]);
|
|
146
|
+
|
|
147
|
+
// -- add: build-up with --yes --
|
|
148
|
+
|
|
149
|
+
describe('add: --yes errors on missing required flags', () => {
|
|
150
|
+
test('missing --type', async () => {
|
|
151
|
+
await add(without(websiteFlags, 'type'), { yes: true });
|
|
152
|
+
expect(logs.join('\n')).toContain('Missing required value for --type');
|
|
153
|
+
expect(addedOrigins).toHaveLength(0);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('website missing --url', async () => {
|
|
157
|
+
await add(without(websiteFlags, 'url'), { yes: true });
|
|
158
|
+
expect(logs.join('\n')).toContain('Missing required value for --url');
|
|
159
|
+
expect(addedOrigins).toHaveLength(0);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('vercel missing --project', async () => {
|
|
163
|
+
await add(without(vercelFlags, 'project'), { yes: true });
|
|
164
|
+
expect(logs.join('\n')).toContain('Missing required value for --project');
|
|
165
|
+
expect(addedOrigins).toHaveLength(0);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('netlify missing --site', async () => {
|
|
169
|
+
await add(without(netlifyFlags, 'site'), { yes: true });
|
|
170
|
+
expect(logs.join('\n')).toContain('Missing required value for --site');
|
|
171
|
+
expect(addedOrigins).toHaveLength(0);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('custom scheme missing --scheme', async () => {
|
|
175
|
+
await add(without(customSchemeFlags, 'scheme'), { yes: true });
|
|
176
|
+
expect(logs.join('\n')).toContain('Missing required value for --scheme');
|
|
177
|
+
expect(addedOrigins).toHaveLength(0);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// -- add: interactive prompts --
|
|
182
|
+
|
|
183
|
+
describe('add: interactive prompts for missing flags', () => {
|
|
184
|
+
test('missing --type -> prompts type selector', async () => {
|
|
185
|
+
mockPromptReturn = 'website';
|
|
186
|
+
await add(without(websiteFlags, 'type'), { yes: false });
|
|
187
|
+
expect((prompts[0] as any).params.promptText).toBe(
|
|
188
|
+
'Select an origin type:',
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test('website missing --url -> prompts for URL', async () => {
|
|
193
|
+
mockPromptReturn = 'example.com';
|
|
194
|
+
await add(without(websiteFlags, 'url'), { yes: false });
|
|
195
|
+
expect((prompts[0] as any).props.prompt).toBe('Website URL:');
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('delete missing --id -> prompts origin selector', async () => {
|
|
199
|
+
origins = [{ id: 'origin-1', service: 'generic', params: ['example.com'] }];
|
|
200
|
+
mockPromptReturn = origins[0];
|
|
201
|
+
await remove(new Map(), { yes: false });
|
|
202
|
+
expect((prompts[0] as any).params.promptText).toBe(
|
|
203
|
+
'Select an origin to delete:',
|
|
204
|
+
);
|
|
205
|
+
expect(removedOriginIds).toEqual(['origin-1']);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// -- add: success --
|
|
210
|
+
|
|
211
|
+
describe('add: success', () => {
|
|
212
|
+
test('website origin -> creates generic origin with host only', async () => {
|
|
213
|
+
await add(websiteFlags, { yes: true });
|
|
214
|
+
expect(addedOrigins).toEqual([
|
|
215
|
+
{ service: 'generic', params: ['example.com'] },
|
|
216
|
+
]);
|
|
217
|
+
const output = logs.join('\n');
|
|
218
|
+
expect(output).toContain('Origin added: example.com');
|
|
219
|
+
expect(output).toContain('Type: Website');
|
|
220
|
+
expect(output).toContain('ID: origin-1');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('website origin without protocol -> accepts domain', async () => {
|
|
224
|
+
await add(
|
|
225
|
+
new Map([
|
|
226
|
+
['type', 'website'],
|
|
227
|
+
['url', 'example.org'],
|
|
228
|
+
]),
|
|
229
|
+
{ yes: true },
|
|
230
|
+
);
|
|
231
|
+
expect(addedOrigins).toEqual([
|
|
232
|
+
{ service: 'generic', params: ['example.org'] },
|
|
233
|
+
]);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('vercel origin -> creates vercel origin params', async () => {
|
|
237
|
+
await add(vercelFlags, { yes: true });
|
|
238
|
+
expect(addedOrigins).toEqual([
|
|
239
|
+
{ service: 'vercel', params: ['vercel.app', 'instant-preview'] },
|
|
240
|
+
]);
|
|
241
|
+
expect(logs.join('\n')).toContain('Origin added: instant-preview');
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test('netlify origin -> creates netlify origin params', async () => {
|
|
245
|
+
await add(netlifyFlags, { yes: true });
|
|
246
|
+
expect(addedOrigins).toEqual([
|
|
247
|
+
{ service: 'netlify', params: ['instant-netlify'] },
|
|
248
|
+
]);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test('custom scheme origin -> creates custom scheme origin params', async () => {
|
|
252
|
+
await add(customSchemeFlags, { yes: true });
|
|
253
|
+
expect(addedOrigins).toEqual([
|
|
254
|
+
{ service: 'custom-scheme', params: ['instant'] },
|
|
255
|
+
]);
|
|
256
|
+
expect(logs.join('\n')).toContain('Origin added: instant://');
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// -- list and delete --
|
|
261
|
+
|
|
262
|
+
describe('list', () => {
|
|
263
|
+
test('prints configured origins', async () => {
|
|
264
|
+
origins = [
|
|
265
|
+
{ id: 'origin-1', service: 'generic', params: ['example.com'] },
|
|
266
|
+
{ id: 'origin-2', service: 'vercel', params: ['vercel.app', 'preview'] },
|
|
267
|
+
];
|
|
268
|
+
await list(new Map(), { yes: true });
|
|
269
|
+
const output = logs.join('\n');
|
|
270
|
+
expect(output).toContain('example.com');
|
|
271
|
+
expect(output).toContain('Type: Website');
|
|
272
|
+
expect(output).toContain('ID: origin-1');
|
|
273
|
+
expect(output).toContain('preview');
|
|
274
|
+
expect(output).toContain('Type: Vercel project');
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('--json prints raw origins', async () => {
|
|
278
|
+
origins = [{ id: 'origin-1', service: 'generic', params: ['example.com'] }];
|
|
279
|
+
await list(new Map([['json', true]]), { yes: true });
|
|
280
|
+
expect(JSON.parse(logs.join('\n'))).toEqual(origins);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe('delete', () => {
|
|
285
|
+
test('--id removes origin', async () => {
|
|
286
|
+
origins = [{ id: 'origin-1', service: 'generic', params: ['example.com'] }];
|
|
287
|
+
await remove(new Map([['id', 'origin-1']]), { yes: true });
|
|
288
|
+
expect(removedOriginIds).toEqual(['origin-1']);
|
|
289
|
+
expect(logs.join('\n')).toContain('Origin deleted!');
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('missing --id with --yes errors', async () => {
|
|
293
|
+
origins = [{ id: 'origin-1', service: 'generic', params: ['example.com'] }];
|
|
294
|
+
await expect(remove(new Map(), { yes: true })).rejects.toThrow(
|
|
295
|
+
'Must specify --id',
|
|
296
|
+
);
|
|
297
|
+
expect(removedOriginIds).toHaveLength(0);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test('no origins exits without deleting', async () => {
|
|
301
|
+
await remove(new Map(), { yes: false });
|
|
302
|
+
expect(logs.join('\n')).toContain(
|
|
303
|
+
'No authorized redirect origins configured.',
|
|
304
|
+
);
|
|
305
|
+
expect(prompts).toHaveLength(0);
|
|
306
|
+
expect(removedOriginIds).toHaveLength(0);
|
|
307
|
+
});
|
|
308
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Effect, Schema } from 'effect';
|
|
2
|
+
import { GlobalOpts } from '../../../context/globalOpts.ts';
|
|
3
|
+
export declare const OriginTypeSchema: Schema.Literal<["website", "vercel", "netlify", "custom-scheme"]>;
|
|
4
|
+
export declare const authOriginAddCmd: (opts: {
|
|
5
|
+
type?: string | undefined;
|
|
6
|
+
url?: string | undefined;
|
|
7
|
+
project?: string | undefined;
|
|
8
|
+
site?: string | undefined;
|
|
9
|
+
scheme?: string | undefined;
|
|
10
|
+
app?: string | undefined;
|
|
11
|
+
} & Record<string, unknown>) => Effect.Effect<void | undefined, import("../../../lib/ui.ts").UIError | import("../../../lib/http.ts").InstantHttpError | import("effect/Cause").TimeoutException | import("@effect/platform/HttpClientError").RequestError | import("effect/ParseResult").ParseError | import("@effect/platform/HttpClientError").ResponseError, GlobalOpts | import("../../../lib/http.ts").InstantHttpAuthed | import("../../../context/currentApp.ts").CurrentApp>;
|
|
12
|
+
//# sourceMappingURL=add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/commands/auth/origin/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGvD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAQ5D,eAAO,MAAM,gBAAgB,mEAK5B,CAAC;AAmLF,eAAO,MAAM,gBAAgB;;;;;;;qdAoD5B,CAAC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { Effect, Match, Option, Schema } from 'effect';
|
|
2
|
+
import { BadArgsError } from "../../../errors.js";
|
|
3
|
+
import { GlobalOpts } from "../../../context/globalOpts.js";
|
|
4
|
+
import { optOrPrompt, runUIEffect } from "../../../lib/ui.js";
|
|
5
|
+
import { addAuthorizedOrigin } from "../../../lib/oauth.js";
|
|
6
|
+
import { UI } from "../../../ui/index.js";
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import boxen from 'boxen';
|
|
9
|
+
import { originDisplay, originSource } from "./list.js";
|
|
10
|
+
export const OriginTypeSchema = Schema.Literal('website', 'vercel', 'netlify', 'custom-scheme');
|
|
11
|
+
const validateGenericUrl = (input) => {
|
|
12
|
+
const trimmed = input.trim();
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(trimmed);
|
|
15
|
+
const host = url.host;
|
|
16
|
+
if (!host) {
|
|
17
|
+
throw new Error('missing host');
|
|
18
|
+
}
|
|
19
|
+
if (host.split('.').length === 1 && !url.port) {
|
|
20
|
+
throw new Error('invalid url');
|
|
21
|
+
}
|
|
22
|
+
return { type: 'success', params: [host] };
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
if (!trimmed.startsWith('http')) {
|
|
26
|
+
return validateGenericUrl(`http://${trimmed}`);
|
|
27
|
+
}
|
|
28
|
+
return { type: 'error', message: 'Invalid URL.' };
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const validateNetlifyUrl = (input) => {
|
|
32
|
+
const trimmed = input.trim();
|
|
33
|
+
if (!trimmed) {
|
|
34
|
+
return { type: 'error', message: 'Netlify site name is required.' };
|
|
35
|
+
}
|
|
36
|
+
return { type: 'success', params: [trimmed] };
|
|
37
|
+
};
|
|
38
|
+
const validateVercelUrl = (input) => {
|
|
39
|
+
const trimmed = input.trim();
|
|
40
|
+
if (!trimmed) {
|
|
41
|
+
return { type: 'error', message: 'Vercel project name is required.' };
|
|
42
|
+
}
|
|
43
|
+
return { type: 'success', params: ['vercel.app', trimmed] };
|
|
44
|
+
};
|
|
45
|
+
const validateCustomScheme = (input) => {
|
|
46
|
+
const trimmed = input.trim();
|
|
47
|
+
try {
|
|
48
|
+
const url = new URL(trimmed);
|
|
49
|
+
const scheme = url.protocol.slice(0, -1);
|
|
50
|
+
return { type: 'success', params: [scheme] };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return { type: 'error', message: 'Invalid scheme.' };
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const addOriginHandler = Effect.fn(function* (type, validated) {
|
|
57
|
+
const response = yield* addAuthorizedOrigin({
|
|
58
|
+
service: type === 'website' ? 'generic' : type,
|
|
59
|
+
params: validated.params,
|
|
60
|
+
});
|
|
61
|
+
yield* Effect.log('\n' +
|
|
62
|
+
boxen([
|
|
63
|
+
`Origin added: ${originDisplay(response.origin)}`,
|
|
64
|
+
`Type: ${originSource(response.origin)}`,
|
|
65
|
+
`ID: ${response.origin.id}`,
|
|
66
|
+
].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
|
|
67
|
+
});
|
|
68
|
+
const handleGenericOrigin = Effect.fn(function* (opts) {
|
|
69
|
+
const url = yield* optOrPrompt(opts.url, {
|
|
70
|
+
simpleName: '--url',
|
|
71
|
+
required: true,
|
|
72
|
+
skipIf: false,
|
|
73
|
+
prompt: {
|
|
74
|
+
prompt: 'Website URL:',
|
|
75
|
+
placeholder: 'example.com',
|
|
76
|
+
modifyOutput: UI.modifiers.piped([
|
|
77
|
+
UI.modifiers.topPadding,
|
|
78
|
+
UI.modifiers.dimOnComplete,
|
|
79
|
+
]),
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
if (!url) {
|
|
83
|
+
return yield* BadArgsError.make({ message: 'URL is required.' });
|
|
84
|
+
}
|
|
85
|
+
const validated = validateGenericUrl(url);
|
|
86
|
+
if (validated.type === 'error') {
|
|
87
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
88
|
+
}
|
|
89
|
+
yield* addOriginHandler('website', validated);
|
|
90
|
+
});
|
|
91
|
+
const handleVercelOrigin = Effect.fn(function* (opts) {
|
|
92
|
+
const project = yield* optOrPrompt(opts.project, {
|
|
93
|
+
simpleName: '--project',
|
|
94
|
+
required: true,
|
|
95
|
+
skipIf: false,
|
|
96
|
+
prompt: {
|
|
97
|
+
prompt: 'Vercel project name:',
|
|
98
|
+
placeholder: 'vercel-project-name',
|
|
99
|
+
modifyOutput: UI.modifiers.piped([
|
|
100
|
+
UI.modifiers.topPadding,
|
|
101
|
+
UI.modifiers.dimOnComplete,
|
|
102
|
+
]),
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
const validated = validateVercelUrl(project ?? '');
|
|
106
|
+
if (validated.type === 'error') {
|
|
107
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
108
|
+
}
|
|
109
|
+
yield* addOriginHandler('vercel', validated);
|
|
110
|
+
});
|
|
111
|
+
const handleNetlifyOrigin = Effect.fn(function* (opts) {
|
|
112
|
+
const site = yield* optOrPrompt(opts.site, {
|
|
113
|
+
simpleName: '--site',
|
|
114
|
+
required: true,
|
|
115
|
+
skipIf: false,
|
|
116
|
+
prompt: {
|
|
117
|
+
prompt: 'Netlify site name:',
|
|
118
|
+
placeholder: 'netlify-site-name',
|
|
119
|
+
modifyOutput: UI.modifiers.piped([
|
|
120
|
+
UI.modifiers.topPadding,
|
|
121
|
+
UI.modifiers.dimOnComplete,
|
|
122
|
+
]),
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
const validated = validateNetlifyUrl(site ?? '');
|
|
126
|
+
if (validated.type === 'error') {
|
|
127
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
128
|
+
}
|
|
129
|
+
yield* addOriginHandler('netlify', validated);
|
|
130
|
+
});
|
|
131
|
+
const handleCustomSchemeOrigin = Effect.fn(function* (opts) {
|
|
132
|
+
const scheme = yield* optOrPrompt(opts.scheme, {
|
|
133
|
+
simpleName: '--scheme',
|
|
134
|
+
required: true,
|
|
135
|
+
skipIf: false,
|
|
136
|
+
prompt: {
|
|
137
|
+
prompt: 'App scheme:',
|
|
138
|
+
placeholder: 'app-scheme://',
|
|
139
|
+
modifyOutput: UI.modifiers.piped([
|
|
140
|
+
UI.modifiers.topPadding,
|
|
141
|
+
UI.modifiers.dimOnComplete,
|
|
142
|
+
]),
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
const validated = validateCustomScheme(scheme ?? '');
|
|
146
|
+
if (validated.type === 'error') {
|
|
147
|
+
return yield* BadArgsError.make({ message: validated.message });
|
|
148
|
+
}
|
|
149
|
+
yield* addOriginHandler('custom-scheme', validated);
|
|
150
|
+
});
|
|
151
|
+
export const authOriginAddCmd = Effect.fn(function* (opts) {
|
|
152
|
+
const { yes } = yield* GlobalOpts;
|
|
153
|
+
if (!opts.type && yes) {
|
|
154
|
+
return yield* BadArgsError.make({
|
|
155
|
+
message: `Missing required value for --type. Expected one of: ${OriginTypeSchema.literals.join(', ')}`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const originType = yield* Option.fromNullable(opts.type).pipe(Effect.catchTag('NoSuchElementException', () => runUIEffect(new UI.Select({
|
|
159
|
+
options: [
|
|
160
|
+
{ label: 'Website', value: 'website' },
|
|
161
|
+
{ label: 'Vercel previews', value: 'vercel' },
|
|
162
|
+
{ label: 'Netlify previews', value: 'netlify' },
|
|
163
|
+
{ label: 'App scheme', value: 'custom-scheme' },
|
|
164
|
+
],
|
|
165
|
+
promptText: 'Select an origin type:',
|
|
166
|
+
modifyOutput: UI.modifiers.piped([UI.modifiers.dimOnComplete]),
|
|
167
|
+
}))), Effect.andThen((s) => Schema.decodeUnknown(OriginTypeSchema)(s)), Effect.catchTag('ParseError', () => BadArgsError.make({
|
|
168
|
+
message: `Invalid origin type, must be one of: ${OriginTypeSchema.literals.join(', ')}`,
|
|
169
|
+
})));
|
|
170
|
+
yield* Match.value(originType).pipe(Match.withReturnType(), Match.when('website', () => handleGenericOrigin(opts)), Match.when('vercel', () => handleVercelOrigin(opts)), Match.when('netlify', () => handleNetlifyOrigin(opts)), Match.when('custom-scheme', () => handleCustomSchemeOrigin(opts)), Match.exhaustive);
|
|
171
|
+
}, Effect.catchTag('BadArgsError', (e) => Effect.gen(function* () {
|
|
172
|
+
yield* Effect.logError(e.message);
|
|
173
|
+
yield* Effect.log(chalk.dim('hint: run `instant-cli auth origin add --help` for available arguments'));
|
|
174
|
+
})));
|
|
175
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../../src/commands/auth/origin/add.ts"],"names":[],"mappings":"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","sourcesContent":["import { Effect, Match, Option, Schema } from 'effect';\nimport type { authOriginAddDef, OptsFromCommand } from '../../../index.ts';\nimport { BadArgsError } from '../../../errors.ts';\nimport { GlobalOpts } from '../../../context/globalOpts.ts';\nimport { optOrPrompt, runUIEffect } from '../../../lib/ui.ts';\nimport { addAuthorizedOrigin } from '../../../lib/oauth.ts';\nimport { UI } from '../../../ui/index.ts';\nimport chalk from 'chalk';\nimport boxen from 'boxen';\nimport { originDisplay, originSource } from './list.ts';\n\nexport const OriginTypeSchema = Schema.Literal(\n 'website',\n 'vercel',\n 'netlify',\n 'custom-scheme',\n);\n\ntype OriginParams = string[];\n\ntype Validated =\n | { type: 'success'; params: OriginParams }\n | { type: 'error'; message: string };\n\nconst validateGenericUrl = (input: string): Validated => {\n const trimmed = input.trim();\n try {\n const url = new URL(trimmed);\n const host = url.host;\n if (!host) {\n throw new Error('missing host');\n }\n if (host.split('.').length === 1 && !url.port) {\n throw new Error('invalid url');\n }\n return { type: 'success', params: [host] };\n } catch {\n if (!trimmed.startsWith('http')) {\n return validateGenericUrl(`http://${trimmed}`);\n }\n return { type: 'error', message: 'Invalid URL.' };\n }\n};\n\nconst validateNetlifyUrl = (input: string): Validated => {\n const trimmed = input.trim();\n if (!trimmed) {\n return { type: 'error', message: 'Netlify site name is required.' };\n }\n return { type: 'success', params: [trimmed] };\n};\n\nconst validateVercelUrl = (input: string): Validated => {\n const trimmed = input.trim();\n if (!trimmed) {\n return { type: 'error', message: 'Vercel project name is required.' };\n }\n return { type: 'success', params: ['vercel.app', trimmed] };\n};\n\nconst validateCustomScheme = (input: string): Validated => {\n const trimmed = input.trim();\n try {\n const url = new URL(trimmed);\n const scheme = url.protocol.slice(0, -1);\n return { type: 'success', params: [scheme] };\n } catch {\n return { type: 'error', message: 'Invalid scheme.' };\n }\n};\n\nconst addOriginHandler = Effect.fn(function* (\n type: Schema.Schema.Type<typeof OriginTypeSchema>,\n validated: { params: OriginParams },\n) {\n const response = yield* addAuthorizedOrigin({\n service: type === 'website' ? 'generic' : type,\n params: validated.params,\n });\n\n yield* Effect.log(\n '\\n' +\n boxen(\n [\n `Origin added: ${originDisplay(response.origin)}`,\n `Type: ${originSource(response.origin)}`,\n `ID: ${response.origin.id}`,\n ].join('\\n'),\n { dimBorder: true, padding: { right: 1, left: 1 } },\n ),\n );\n});\n\nconst handleGenericOrigin = Effect.fn(function* (\n opts: Record<string, unknown>,\n) {\n const url = yield* optOrPrompt(opts.url, {\n simpleName: '--url',\n required: true,\n skipIf: false,\n prompt: {\n prompt: 'Website URL:',\n placeholder: 'example.com',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n },\n });\n\n if (!url) {\n return yield* BadArgsError.make({ message: 'URL is required.' });\n }\n\n const validated = validateGenericUrl(url);\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('website', validated);\n});\n\nconst handleVercelOrigin = Effect.fn(function* (opts: Record<string, unknown>) {\n const project = yield* optOrPrompt(opts.project, {\n simpleName: '--project',\n required: true,\n skipIf: false,\n prompt: {\n prompt: 'Vercel project name:',\n placeholder: 'vercel-project-name',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n },\n });\n\n const validated = validateVercelUrl(project ?? '');\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('vercel', validated);\n});\n\nconst handleNetlifyOrigin = Effect.fn(function* (\n opts: Record<string, unknown>,\n) {\n const site = yield* optOrPrompt(opts.site, {\n simpleName: '--site',\n required: true,\n skipIf: false,\n prompt: {\n prompt: 'Netlify site name:',\n placeholder: 'netlify-site-name',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n },\n });\n\n const validated = validateNetlifyUrl(site ?? '');\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('netlify', validated);\n});\n\nconst handleCustomSchemeOrigin = Effect.fn(function* (\n opts: Record<string, unknown>,\n) {\n const scheme = yield* optOrPrompt(opts.scheme, {\n simpleName: '--scheme',\n required: true,\n skipIf: false,\n prompt: {\n prompt: 'App scheme:',\n placeholder: 'app-scheme://',\n modifyOutput: UI.modifiers.piped([\n UI.modifiers.topPadding,\n UI.modifiers.dimOnComplete,\n ]),\n },\n });\n\n const validated = validateCustomScheme(scheme ?? '');\n if (validated.type === 'error') {\n return yield* BadArgsError.make({ message: validated.message });\n }\n\n yield* addOriginHandler('custom-scheme', validated);\n});\n\nexport const authOriginAddCmd = Effect.fn(\n function* (\n opts: OptsFromCommand<typeof authOriginAddDef> & Record<string, unknown>,\n ) {\n const { yes } = yield* GlobalOpts;\n if (!opts.type && yes) {\n return yield* BadArgsError.make({\n message: `Missing required value for --type. Expected one of: ${OriginTypeSchema.literals.join(', ')}`,\n });\n }\n const originType = yield* Option.fromNullable(opts.type).pipe(\n Effect.catchTag('NoSuchElementException', () =>\n runUIEffect(\n new UI.Select({\n options: [\n { label: 'Website', value: 'website' },\n { label: 'Vercel previews', value: 'vercel' },\n { label: 'Netlify previews', value: 'netlify' },\n { label: 'App scheme', value: 'custom-scheme' },\n ],\n promptText: 'Select an origin type:',\n modifyOutput: UI.modifiers.piped([UI.modifiers.dimOnComplete]),\n }),\n ),\n ),\n Effect.andThen((s) => Schema.decodeUnknown(OriginTypeSchema)(s)),\n Effect.catchTag('ParseError', () =>\n BadArgsError.make({\n message: `Invalid origin type, must be one of: ${OriginTypeSchema.literals.join(', ')}`,\n }),\n ),\n );\n\n yield* Match.value(originType).pipe(\n Match.withReturnType<Effect.Effect<void, any, any>>(),\n Match.when('website', () => handleGenericOrigin(opts)),\n Match.when('vercel', () => handleVercelOrigin(opts)),\n Match.when('netlify', () => handleNetlifyOrigin(opts)),\n Match.when('custom-scheme', () => handleCustomSchemeOrigin(opts)),\n Match.exhaustive,\n );\n },\n Effect.catchTag('BadArgsError', (e) =>\n Effect.gen(function* () {\n yield* Effect.logError(e.message);\n yield* Effect.log(\n chalk.dim(\n 'hint: run `instant-cli auth origin add --help` for available arguments',\n ),\n );\n }),\n ),\n);\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { BadArgsError } from '../../../errors.ts';
|
|
3
|
+
import { GlobalOpts } from '../../../context/globalOpts.ts';
|
|
4
|
+
export declare const authOriginDeleteCmd: (opts: {
|
|
5
|
+
id?: string | undefined;
|
|
6
|
+
app?: string | undefined;
|
|
7
|
+
}) => Effect.Effect<undefined, BadArgsError | import("../../../lib/ui.ts").UIError | import("../../../lib/http.ts").InstantHttpError | import("effect/Cause").TimeoutException | import("@effect/platform/HttpClientError").RequestError | import("effect/ParseResult").ParseError | import("@effect/platform/HttpClientError").ResponseError, GlobalOpts | import("../../../lib/http.ts").InstantHttpAuthed | import("../../../context/currentApp.ts").CurrentApp>;
|
|
8
|
+
//# sourceMappingURL=delete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../../src/commands/auth/origin/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAK5D,eAAO,MAAM,mBAAmB;;;mcAuC9B,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { BadArgsError } from "../../../errors.js";
|
|
4
|
+
import { getAppsAuth, removeAuthorizedOrigin } from "../../../lib/oauth.js";
|
|
5
|
+
import { GlobalOpts } from "../../../context/globalOpts.js";
|
|
6
|
+
import { runUIEffect } from "../../../lib/ui.js";
|
|
7
|
+
import { UI } from "../../../ui/index.js";
|
|
8
|
+
import { originDisplay, originSource } from "./list.js";
|
|
9
|
+
export const authOriginDeleteCmd = Effect.fn(function* (opts) {
|
|
10
|
+
const info = yield* getAppsAuth();
|
|
11
|
+
const origins = info.authorized_redirect_origins ?? [];
|
|
12
|
+
if (origins.length === 0) {
|
|
13
|
+
yield* Effect.log('No authorized redirect origins configured.');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!opts.id) {
|
|
17
|
+
const { yes } = yield* GlobalOpts;
|
|
18
|
+
if (yes) {
|
|
19
|
+
return yield* BadArgsError.make({
|
|
20
|
+
message: 'Must specify --id',
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const picked = yield* runUIEffect(new UI.Select({
|
|
24
|
+
options: origins.map((origin) => ({
|
|
25
|
+
label: `${originSource(origin)} — ${originDisplay(origin)} ` +
|
|
26
|
+
chalk.dim(`(${origin.id})`),
|
|
27
|
+
value: origin,
|
|
28
|
+
})),
|
|
29
|
+
promptText: 'Select an origin to delete:',
|
|
30
|
+
}));
|
|
31
|
+
yield* removeAuthorizedOrigin(picked.id);
|
|
32
|
+
}
|
|
33
|
+
if (opts.id) {
|
|
34
|
+
yield* removeAuthorizedOrigin(opts.id);
|
|
35
|
+
}
|
|
36
|
+
yield* Effect.log('Origin deleted!');
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=delete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../../src/commands/auth/origin/delete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EACpD,IAAiD;IAEjD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,2BAA2B,IAAI,EAAE,CAAC;IAEvD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAChE,OAAO;IACT,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;QAClC,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;gBAC9B,OAAO,EAAE,mBAAmB;aAC7B,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,WAAW,CAC/B,IAAI,EAAE,CAAC,MAAM,CAAC;YACZ,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAChC,KAAK,EACH,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,aAAa,CAAC,MAAM,CAAC,GAAG;oBACrD,KAAK,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC;gBAC7B,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;YACH,UAAU,EAAE,6BAA6B;SAC1C,CAAC,CACH,CAAC;QAEF,KAAK,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;QACZ,KAAK,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC","sourcesContent":["import chalk from 'chalk';\nimport { Effect } from 'effect';\nimport type { authOriginDeleteDef, OptsFromCommand } from '../../../index.ts';\nimport { BadArgsError } from '../../../errors.ts';\nimport { getAppsAuth, removeAuthorizedOrigin } from '../../../lib/oauth.ts';\nimport { GlobalOpts } from '../../../context/globalOpts.ts';\nimport { runUIEffect } from '../../../lib/ui.ts';\nimport { UI } from '../../../ui/index.ts';\nimport { originDisplay, originSource } from './list.ts';\n\nexport const authOriginDeleteCmd = Effect.fn(function* (\n opts: OptsFromCommand<typeof authOriginDeleteDef>,\n) {\n const info = yield* getAppsAuth();\n const origins = info.authorized_redirect_origins ?? [];\n\n if (origins.length === 0) {\n yield* Effect.log('No authorized redirect origins configured.');\n return;\n }\n\n if (!opts.id) {\n const { yes } = yield* GlobalOpts;\n if (yes) {\n return yield* BadArgsError.make({\n message: 'Must specify --id',\n });\n }\n\n const picked = yield* runUIEffect(\n new UI.Select({\n options: origins.map((origin) => ({\n label:\n `${originSource(origin)} — ${originDisplay(origin)} ` +\n chalk.dim(`(${origin.id})`),\n value: origin,\n })),\n promptText: 'Select an origin to delete:',\n }),\n );\n\n yield* removeAuthorizedOrigin(picked.id);\n }\n\n if (opts.id) {\n yield* removeAuthorizedOrigin(opts.id);\n }\n\n yield* Effect.log('Origin deleted!');\n});\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Effect, Schema } from 'effect';
|
|
2
|
+
import { AuthorizedOrigin } from '../../../lib/oauth.ts';
|
|
3
|
+
export declare const originSource: (origin: Schema.Schema.Type<typeof AuthorizedOrigin>) => string;
|
|
4
|
+
export declare const originDisplay: (origin: Schema.Schema.Type<typeof AuthorizedOrigin>) => string;
|
|
5
|
+
export declare const authOriginListCmd: (_opts: {
|
|
6
|
+
app?: string | undefined;
|
|
7
|
+
json?: true | undefined;
|
|
8
|
+
}) => Effect.Effect<void, import("../../../lib/http.ts").InstantHttpError | import("effect/Cause").TimeoutException | import("@effect/platform/HttpClientError").RequestError | import("effect/ParseResult").ParseError | import("@effect/platform/HttpClientError").ResponseError, import("../../../lib/http.ts").InstantHttpAuthed | import("../../../context/currentApp.ts").CurrentApp>;
|
|
9
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../src/commands/auth/origin/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAe,MAAM,uBAAuB,CAAC;AAEtE,eAAO,MAAM,YAAY,GACvB,QAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,gBAAgB,CAAC,WAiBpD,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,QAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,gBAAgB,CAAC,WAcpD,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;2XAuB5B,CAAC"}
|