instant-cli 1.0.21-branch-cli-codex.25190871505.1 → 1.0.21-branch-cli-codex-update.25190875900.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.
@@ -0,0 +1,587 @@
1
+ import { Effect } from 'effect';
2
+ import { FileSystem } from '@effect/platform';
3
+ import { BadArgsError } from "../../../errors.js";
4
+ import { GlobalOpts } from "../../../context/globalOpts.js";
5
+ import { optOrPrompt, runUIEffect, validateRequired } from "../../../lib/ui.js";
6
+ import { findClientByIdOrName, getAppsAuth, updateOAuthClient, } from "../../../lib/oauth.js";
7
+ import { UI } from "../../../ui/index.js";
8
+ import { DEFAULT_OAUTH_CALLBACK_URL } from '@instantdb/platform';
9
+ import chalk from 'chalk';
10
+ import boxen from 'boxen';
11
+ import { link } from "../../../logging.js";
12
+ const camelize = (flag) => flag.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
13
+ const getFlag = (opts, flag) => opts[flag] ?? opts[camelize(flag)];
14
+ const hasFlag = (opts, flag) => getFlag(opts, flag) !== undefined;
15
+ const hasAnyFlag = (opts, flags) => flags.some((flag) => hasFlag(opts, flag));
16
+ const isTrueFlag = (value) => value === true || value === 'true';
17
+ const metaString = (client, key) => {
18
+ if (!client.meta || typeof client.meta !== 'object')
19
+ return undefined;
20
+ const value = client.meta[key];
21
+ return typeof value === 'string' ? value : undefined;
22
+ };
23
+ const promptFlag = (opts, flag, params) => Effect.gen(function* () {
24
+ const value = getFlag(opts, flag);
25
+ if (value === undefined && !params.promptIf)
26
+ return undefined;
27
+ return yield* optOrPrompt(value, {
28
+ simpleName: `--${flag}`,
29
+ required: params.required ?? params.promptIf,
30
+ skipIf: false,
31
+ prompt: params.prompt,
32
+ });
33
+ });
34
+ const clientIdPrompt = (provider) => ({
35
+ prompt: `Client ID: ${chalk.dim(`(from ${provider})`)}`,
36
+ validate: validateRequired,
37
+ modifyOutput: UI.modifiers.piped([
38
+ UI.modifiers.topPadding,
39
+ UI.modifiers.dimOnComplete,
40
+ ]),
41
+ });
42
+ const clientSecretPrompt = (provider) => ({
43
+ prompt: `Client Secret: ${chalk.dim(`(from ${provider})`)}`,
44
+ validate: validateRequired,
45
+ sensitive: true,
46
+ modifyOutput: UI.modifiers.piped([
47
+ UI.modifiers.topPadding,
48
+ UI.modifiers.dimOnComplete,
49
+ ]),
50
+ });
51
+ const makeRedirectPrompt = (heading) => ({
52
+ prompt: '',
53
+ placeholder: 'https://yoursite.com/oauth/callback',
54
+ modifyOutput: UI.modifiers.piped([
55
+ (output, status) => {
56
+ if (status === 'idle') {
57
+ return (`\n${heading}
58
+ ${chalk.dim('With a custom redirect URI, users will see "Redirecting to yoursite.com..." for a more branded experience.')}
59
+ ${chalk.dim(`Your URI must forward to ${DEFAULT_OAUTH_CALLBACK_URL} with all query parameters preserved.`)}\n\n` +
60
+ output.replace(/^\n/, ''));
61
+ }
62
+ return `\n${heading}\n${output.replace(/^\n/, '')}`;
63
+ },
64
+ UI.modifiers.dimOnComplete,
65
+ ]),
66
+ });
67
+ const redirectPrompt = makeRedirectPrompt('Custom redirect URI (optional):');
68
+ const newRedirectPrompt = makeRedirectPrompt('New redirect URI:');
69
+ const readPrivateKeyFile = Effect.fn('readPrivateKeyFile')(function* (path) {
70
+ const fs = yield* FileSystem.FileSystem;
71
+ const normalizedPath = process.platform === 'win32' ? path : path.replace(/\\(.)/g, '$1');
72
+ const contents = yield* fs.readFileString(normalizedPath, 'utf8').pipe(Effect.mapError((e) => new BadArgsError({
73
+ message: `Could not read private key file at ${normalizedPath}: ${e.message}`,
74
+ })));
75
+ const trimmed = contents.trim();
76
+ if (!trimmed) {
77
+ return yield* BadArgsError.make({
78
+ message: `Private key file at ${normalizedPath} is empty.`,
79
+ });
80
+ }
81
+ return trimmed;
82
+ });
83
+ const resolveClient = Effect.fn(function* (params) {
84
+ if (params.id && params.name) {
85
+ return yield* BadArgsError.make({
86
+ message: 'Cannot specify both --id and --name',
87
+ });
88
+ }
89
+ if (params.id) {
90
+ const match = params.clients.find((client) => client.id === params.id);
91
+ if (!match) {
92
+ return yield* BadArgsError.make({
93
+ message: `OAuth client not found: ${params.id}`,
94
+ });
95
+ }
96
+ return match;
97
+ }
98
+ if (params.name) {
99
+ const match = params.clients.find((client) => client.client_name === params.name);
100
+ if (!match) {
101
+ return yield* BadArgsError.make({
102
+ message: `OAuth client not found: ${params.name}`,
103
+ });
104
+ }
105
+ return match;
106
+ }
107
+ if (params.yes) {
108
+ return yield* BadArgsError.make({ message: 'Must specify --id or --name' });
109
+ }
110
+ if (params.clients.length === 0) {
111
+ return yield* BadArgsError.make({
112
+ message: 'No OAuth clients found for this app.',
113
+ });
114
+ }
115
+ return yield* runUIEffect(new UI.Select({
116
+ options: params.clients.map((client) => ({
117
+ label: client.client_name +
118
+ (client.use_shared_credentials
119
+ ? chalk.dim(' (dev credentials)')
120
+ : '') +
121
+ chalk.dim(` (${client.id})`),
122
+ value: client,
123
+ })),
124
+ promptText: 'Select a client to update:',
125
+ modifyOutput: UI.modifiers.piped([UI.modifiers.dimOnComplete]),
126
+ })).pipe(Effect.catchTag('UIError', (e) => BadArgsError.make({ message: `UI error: ${e.message}` })));
127
+ });
128
+ const selectUpdateAction = Effect.fn(function* (options) {
129
+ return yield* runUIEffect(new UI.Select({
130
+ options,
131
+ promptText: 'What do you want to update?',
132
+ modifyOutput: UI.modifiers.piped([UI.modifiers.dimOnComplete]),
133
+ })).pipe(Effect.catchTag('UIError', (e) => BadArgsError.make({ message: `UI error: ${e.message}` })));
134
+ });
135
+ const updateGoogleToDevCredentials = Effect.fn(function* (client) {
136
+ const response = yield* updateOAuthClient({
137
+ oauthClientId: client.id,
138
+ useSharedCredentials: true,
139
+ redirectTo: null,
140
+ });
141
+ yield* Effect.log(boxen([
142
+ `Google OAuth client updated: ${response.client.client_name}`,
143
+ 'Credentials: Instant dev credentials',
144
+ `ID: ${response.client.id}`,
145
+ '',
146
+ 'No Google Console setup required.',
147
+ 'Works on localhost and Expo during development.',
148
+ ].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
149
+ });
150
+ const handleGoogleUpdate = Effect.fn(function* (opts, client) {
151
+ const { yes } = yield* GlobalOpts;
152
+ const consoleUrl = link('https://console.developers.google.com/apis/credentials');
153
+ const appType = metaString(client, 'appType');
154
+ const isWeb = appType === 'web' || appType === undefined;
155
+ const devCredentialsFlag = isTrueFlag(getFlag(opts, 'dev-credentials'));
156
+ const hasCustomCredentialFlag = hasAnyFlag(opts, [
157
+ 'client-id',
158
+ 'client-secret',
159
+ 'custom-redirect-uri',
160
+ ]);
161
+ if (!isWeb) {
162
+ if (devCredentialsFlag) {
163
+ return yield* BadArgsError.make({
164
+ message: '--dev-credentials is only supported for Google web clients.',
165
+ });
166
+ }
167
+ if (hasFlag(opts, 'client-secret') ||
168
+ hasFlag(opts, 'custom-redirect-uri')) {
169
+ return yield* BadArgsError.make({
170
+ message: '--client-secret and --custom-redirect-uri are only supported for Google web clients.',
171
+ });
172
+ }
173
+ }
174
+ if (devCredentialsFlag && hasCustomCredentialFlag) {
175
+ return yield* BadArgsError.make({
176
+ message: '--dev-credentials cannot be combined with --client-id, --client-secret, or --custom-redirect-uri.',
177
+ });
178
+ }
179
+ if (isWeb && devCredentialsFlag) {
180
+ return yield* updateGoogleToDevCredentials(client);
181
+ }
182
+ const hasAnyUpdateFlag = hasAnyFlag(opts, [
183
+ 'client-id',
184
+ 'client-secret',
185
+ 'custom-redirect-uri',
186
+ 'dev-credentials',
187
+ ]);
188
+ if (yes && !hasAnyUpdateFlag) {
189
+ return yield* BadArgsError.make({
190
+ message: 'Must specify at least one of --client-id, --client-secret, --custom-redirect-uri, or --dev-credentials.',
191
+ });
192
+ }
193
+ const switchingFromShared = Boolean(client.use_shared_credentials);
194
+ if (!hasAnyUpdateFlag && !yes) {
195
+ yield* Effect.log(`\nCurrent mode: ${switchingFromShared
196
+ ? chalk.bold('Instant dev credentials')
197
+ : 'custom credentials'}`);
198
+ if (!switchingFromShared) {
199
+ const action = yield* selectUpdateAction([
200
+ { label: 'Rotate credentials', value: 'rotate' },
201
+ {
202
+ label: 'Switch to Instant dev credentials' +
203
+ chalk.dim(' (localhost and Expo, no Google setup)'),
204
+ value: 'dev-credentials',
205
+ },
206
+ { label: 'Update redirect URI', value: 'redirect' },
207
+ ]);
208
+ if (action === 'dev-credentials') {
209
+ return yield* updateGoogleToDevCredentials(client);
210
+ }
211
+ if (action === 'redirect') {
212
+ const redirectTo = yield* promptFlag(opts, 'custom-redirect-uri', {
213
+ promptIf: true,
214
+ required: true,
215
+ prompt: newRedirectPrompt,
216
+ });
217
+ const response = yield* updateOAuthClient({
218
+ oauthClientId: client.id,
219
+ redirectTo,
220
+ });
221
+ yield* Effect.log(boxen([
222
+ `Google OAuth client updated: ${response.client.client_name}`,
223
+ `ID: ${response.client.id}`,
224
+ `Redirect URI: ${redirectTo}`,
225
+ ].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
226
+ return;
227
+ }
228
+ }
229
+ }
230
+ const promptCredentials = !hasAnyUpdateFlag && !yes;
231
+ const clientId = yield* promptFlag(opts, 'client-id', {
232
+ promptIf: promptCredentials || (switchingFromShared && !hasFlag(opts, 'client-id')),
233
+ required: promptCredentials || switchingFromShared,
234
+ prompt: clientIdPrompt(consoleUrl),
235
+ });
236
+ const clientSecret = yield* promptFlag(opts, 'client-secret', {
237
+ promptIf: isWeb &&
238
+ (promptCredentials ||
239
+ (switchingFromShared && !hasFlag(opts, 'client-secret'))),
240
+ required: isWeb && (promptCredentials || switchingFromShared),
241
+ prompt: clientSecretPrompt(consoleUrl),
242
+ });
243
+ const customRedirectUri = isWeb
244
+ ? yield* promptFlag(opts, 'custom-redirect-uri', {
245
+ promptIf: switchingFromShared && promptCredentials,
246
+ required: false,
247
+ prompt: redirectPrompt,
248
+ })
249
+ : undefined;
250
+ const redirectTo = switchingFromShared
251
+ ? customRedirectUri || client.redirect_to || DEFAULT_OAUTH_CALLBACK_URL
252
+ : customRedirectUri;
253
+ const response = yield* updateOAuthClient({
254
+ oauthClientId: client.id,
255
+ clientId,
256
+ clientSecret,
257
+ redirectTo,
258
+ useSharedCredentials: switchingFromShared ? false : undefined,
259
+ });
260
+ const lines = [
261
+ `Google OAuth client updated: ${response.client.client_name}`,
262
+ 'Credentials: custom',
263
+ `ID: ${response.client.id}`,
264
+ ];
265
+ if (switchingFromShared) {
266
+ lines.push('', 'This client no longer uses Instant dev credentials.');
267
+ }
268
+ if (isWeb && redirectTo) {
269
+ lines.push('', chalk.bold(`Add this redirect URI in Google Console:\n${redirectTo}`));
270
+ }
271
+ yield* Effect.log(boxen(lines.join('\n'), {
272
+ dimBorder: true,
273
+ padding: { right: 1, left: 1 },
274
+ }));
275
+ });
276
+ const handleClientIdSecretUpdate = Effect.fn(function* (params) {
277
+ const { yes } = yield* GlobalOpts;
278
+ const hasAnyUpdateFlag = hasAnyFlag(params.opts, [
279
+ 'client-id',
280
+ 'client-secret',
281
+ 'custom-redirect-uri',
282
+ ]);
283
+ if (yes && !hasAnyUpdateFlag) {
284
+ return yield* BadArgsError.make({
285
+ message: 'Must specify at least one of --client-id, --client-secret, or --custom-redirect-uri.',
286
+ });
287
+ }
288
+ let promptCredentials = false;
289
+ let promptRedirect = false;
290
+ if (!hasAnyUpdateFlag && !yes) {
291
+ const action = yield* selectUpdateAction([
292
+ { label: 'Rotate credentials', value: 'rotate' },
293
+ { label: 'Update redirect URI', value: 'redirect' },
294
+ ]);
295
+ promptCredentials = action === 'rotate';
296
+ promptRedirect = action === 'redirect';
297
+ }
298
+ const clientId = yield* promptFlag(params.opts, 'client-id', {
299
+ promptIf: promptCredentials,
300
+ required: promptCredentials,
301
+ prompt: clientIdPrompt(link(params.providerUrl)),
302
+ });
303
+ const clientSecret = yield* promptFlag(params.opts, 'client-secret', {
304
+ promptIf: promptCredentials,
305
+ required: promptCredentials,
306
+ prompt: clientSecretPrompt(link(params.providerUrl)),
307
+ });
308
+ const customRedirectUri = yield* promptFlag(params.opts, 'custom-redirect-uri', {
309
+ promptIf: promptRedirect,
310
+ required: promptRedirect,
311
+ prompt: promptRedirect ? newRedirectPrompt : redirectPrompt,
312
+ });
313
+ const response = yield* updateOAuthClient({
314
+ oauthClientId: params.client.id,
315
+ clientId,
316
+ clientSecret,
317
+ redirectTo: customRedirectUri,
318
+ });
319
+ yield* Effect.log(boxen([
320
+ `${params.providerLabel} OAuth client updated: ${response.client.client_name}`,
321
+ `ID: ${response.client.id}`,
322
+ ].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
323
+ });
324
+ const handleAppleUpdate = Effect.fn(function* (opts, client) {
325
+ const { yes } = yield* GlobalOpts;
326
+ const webFlags = [
327
+ 'team-id',
328
+ 'key-id',
329
+ 'private-key-file',
330
+ 'custom-redirect-uri',
331
+ ];
332
+ const updateFlags = ['services-id', ...webFlags];
333
+ const hasAnyUpdateFlag = hasAnyFlag(opts, updateFlags);
334
+ if (yes && !hasAnyUpdateFlag) {
335
+ return yield* BadArgsError.make({
336
+ message: 'Must specify at least one of --services-id, --team-id, --key-id, --private-key-file, or --custom-redirect-uri.',
337
+ });
338
+ }
339
+ const existingWeb = Boolean(metaString(client, 'teamId') ||
340
+ metaString(client, 'keyId') ||
341
+ client.redirect_to);
342
+ const promptAll = !hasAnyUpdateFlag && !yes;
343
+ const configureWeb = promptAll
344
+ ? yield* runUIEffect(new UI.Confirmation({
345
+ promptText: 'Configure web redirect flow? ' +
346
+ chalk.dim('(requires Team ID, Key ID, and a .p8 private key from Apple)'),
347
+ defaultValue: existingWeb,
348
+ })).pipe(Effect.catchTag('UIError', (e) => BadArgsError.make({ message: `UI error: ${e.message}` })))
349
+ : hasAnyFlag(opts, webFlags);
350
+ const servicesId = yield* promptFlag(opts, 'services-id', {
351
+ promptIf: promptAll,
352
+ required: promptAll,
353
+ prompt: {
354
+ prompt: `Services ID ${chalk.dim(`(from ${link('https://developer.apple.com/account/resources/identifiers/list/serviceId')})`)}`,
355
+ validate: validateRequired,
356
+ modifyOutput: UI.modifiers.piped([
357
+ UI.modifiers.topPadding,
358
+ UI.modifiers.dimOnComplete,
359
+ ]),
360
+ },
361
+ });
362
+ const teamId = configureWeb
363
+ ? yield* promptFlag(opts, 'team-id', {
364
+ promptIf: promptAll,
365
+ required: promptAll,
366
+ prompt: {
367
+ prompt: `Team ID ${chalk.dim(`(from ${link('https://developer.apple.com/account#MembershipDetailsCard')})`)}`,
368
+ validate: validateRequired,
369
+ modifyOutput: UI.modifiers.piped([
370
+ UI.modifiers.topPadding,
371
+ UI.modifiers.dimOnComplete,
372
+ ]),
373
+ },
374
+ })
375
+ : undefined;
376
+ const keyId = configureWeb
377
+ ? yield* promptFlag(opts, 'key-id', {
378
+ promptIf: promptAll,
379
+ required: promptAll,
380
+ prompt: {
381
+ prompt: `Key ID ${chalk.dim(`(from ${link('https://developer.apple.com/account/resources/authkeys/list')})`)}`,
382
+ validate: validateRequired,
383
+ modifyOutput: UI.modifiers.piped([
384
+ UI.modifiers.topPadding,
385
+ UI.modifiers.dimOnComplete,
386
+ ]),
387
+ },
388
+ })
389
+ : undefined;
390
+ const privateKeyPath = configureWeb
391
+ ? yield* promptFlag(opts, 'private-key-file', {
392
+ promptIf: promptAll,
393
+ required: promptAll,
394
+ prompt: {
395
+ prompt: `Path to .p8 private key file ${chalk.dim('(downloaded from Apple)')}`,
396
+ validate: validateRequired,
397
+ modifyOutput: UI.modifiers.piped([
398
+ UI.modifiers.topPadding,
399
+ UI.modifiers.dimOnComplete,
400
+ ]),
401
+ },
402
+ })
403
+ : undefined;
404
+ const privateKey = privateKeyPath
405
+ ? yield* readPrivateKeyFile(privateKeyPath)
406
+ : undefined;
407
+ const customRedirectUri = configureWeb
408
+ ? yield* promptFlag(opts, 'custom-redirect-uri', {
409
+ promptIf: promptAll,
410
+ required: false,
411
+ prompt: redirectPrompt,
412
+ })
413
+ : undefined;
414
+ const meta = {};
415
+ if (teamId)
416
+ meta.teamId = teamId;
417
+ if (keyId)
418
+ meta.keyId = keyId;
419
+ const response = yield* updateOAuthClient({
420
+ oauthClientId: client.id,
421
+ clientId: servicesId,
422
+ clientSecret: privateKey,
423
+ redirectTo: configureWeb && privateKey
424
+ ? customRedirectUri || client.redirect_to || DEFAULT_OAUTH_CALLBACK_URL
425
+ : customRedirectUri,
426
+ meta: Object.keys(meta).length ? meta : undefined,
427
+ });
428
+ yield* Effect.log(boxen([
429
+ `Apple OAuth client updated: ${response.client.client_name}`,
430
+ `ID: ${response.client.id}`,
431
+ ].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
432
+ });
433
+ const handleClerkUpdate = Effect.fn(function* (opts, client) {
434
+ const { yes } = yield* GlobalOpts;
435
+ const publishableKey = yield* promptFlag(opts, 'publishable-key', {
436
+ promptIf: !yes && !hasFlag(opts, 'publishable-key'),
437
+ required: true,
438
+ prompt: {
439
+ prompt: `Clerk publishable key ${chalk.dim(`(from ${link('https://dashboard.clerk.com/last-active?path=api-keys')})`)}`,
440
+ placeholder: 'pk_********************************************************',
441
+ validate: (val) => {
442
+ if (!val)
443
+ return 'Publishable key is required';
444
+ if (!val.startsWith('pk_')) {
445
+ return 'Invalid publishable key. It should start with "pk_".';
446
+ }
447
+ },
448
+ modifyOutput: UI.modifiers.piped([
449
+ UI.modifiers.topPadding,
450
+ UI.modifiers.dimOnComplete,
451
+ ]),
452
+ },
453
+ });
454
+ if (!publishableKey) {
455
+ return yield* BadArgsError.make({
456
+ message: 'Missing required value for --publishable-key',
457
+ });
458
+ }
459
+ const domain = domainFromClerkKey(publishableKey);
460
+ if (!domain) {
461
+ return yield* BadArgsError.make({
462
+ message: 'Invalid publishable key. Could not extract domain.',
463
+ });
464
+ }
465
+ const response = yield* updateOAuthClient({
466
+ oauthClientId: client.id,
467
+ discoveryEndpoint: `https://${domain}/.well-known/openid-configuration`,
468
+ meta: { clerkPublishableKey: publishableKey },
469
+ });
470
+ yield* Effect.log(boxen([
471
+ `Clerk OAuth client updated: ${response.client.client_name}`,
472
+ `ID: ${response.client.id}`,
473
+ `Clerk Domain: https://${domain}`,
474
+ ].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
475
+ });
476
+ const handleFirebaseUpdate = Effect.fn(function* (opts, client) {
477
+ const { yes } = yield* GlobalOpts;
478
+ const projectId = yield* promptFlag(opts, 'project-id', {
479
+ promptIf: !yes && !hasFlag(opts, 'project-id'),
480
+ required: true,
481
+ prompt: {
482
+ prompt: `Firebase project ID: (From Project Settings page on ${link('https://console.firebase.google.com/')})`,
483
+ validate: validateFirebaseProjectId,
484
+ modifyOutput: UI.modifiers.piped([
485
+ UI.modifiers.topPadding,
486
+ UI.modifiers.dimOnComplete,
487
+ ]),
488
+ },
489
+ });
490
+ const validationError = validateFirebaseProjectId(projectId ?? '');
491
+ if (validationError) {
492
+ return yield* BadArgsError.make({ message: validationError });
493
+ }
494
+ const response = yield* updateOAuthClient({
495
+ oauthClientId: client.id,
496
+ discoveryEndpoint: firebaseDiscoveryEndpoint(projectId),
497
+ });
498
+ yield* Effect.log(boxen([
499
+ `Firebase OAuth client updated: ${response.client.client_name}`,
500
+ `ID: ${response.client.id}`,
501
+ `Firebase Project ID: ${projectId}`,
502
+ ].join('\n'), { dimBorder: true, padding: { right: 1, left: 1 } }));
503
+ });
504
+ export const authClientUpdateCmd = Effect.fn(function* (opts) {
505
+ const { yes } = yield* GlobalOpts;
506
+ const id = getFlag(opts, 'id');
507
+ const name = getFlag(opts, 'name');
508
+ const { auth, client } = id || name
509
+ ? yield* findClientByIdOrName({ id, name })
510
+ : {
511
+ auth: yield* getAppsAuth(),
512
+ client: undefined,
513
+ };
514
+ const resolvedClient = client ??
515
+ (yield* resolveClient({
516
+ yes,
517
+ clients: (auth.oauth_clients ?? []),
518
+ }));
519
+ const provider = (auth.oauth_service_providers ?? []).find((entry) => entry.id === resolvedClient.provider_id);
520
+ if (!provider) {
521
+ return yield* BadArgsError.make({
522
+ message: `OAuth provider not found for client: ${resolvedClient.client_name}`,
523
+ });
524
+ }
525
+ switch (provider.provider_name) {
526
+ case 'google':
527
+ return yield* handleGoogleUpdate(opts, resolvedClient);
528
+ case 'github':
529
+ return yield* handleClientIdSecretUpdate({
530
+ opts,
531
+ client: resolvedClient,
532
+ providerLabel: 'GitHub',
533
+ providerUrl: 'https://github.com/settings/developers',
534
+ });
535
+ case 'linkedin':
536
+ return yield* handleClientIdSecretUpdate({
537
+ opts,
538
+ client: resolvedClient,
539
+ providerLabel: 'LinkedIn',
540
+ providerUrl: 'https://www.linkedin.com/developers/apps',
541
+ });
542
+ case 'apple':
543
+ return yield* handleAppleUpdate(opts, resolvedClient);
544
+ case 'clerk':
545
+ return yield* handleClerkUpdate(opts, resolvedClient);
546
+ case 'firebase':
547
+ return yield* handleFirebaseUpdate(opts, resolvedClient);
548
+ default:
549
+ return yield* BadArgsError.make({
550
+ message: `Updating ${provider.provider_name} OAuth clients is not supported.`,
551
+ });
552
+ }
553
+ }, Effect.catchTag('BadArgsError', (e) => Effect.gen(function* () {
554
+ yield* Effect.logError(e.message);
555
+ yield* Effect.log(chalk.dim('hint: run `instant-cli auth client update --help` for available arguments'));
556
+ })));
557
+ function domainFromClerkKey(key) {
558
+ try {
559
+ const parts = key.split('_');
560
+ const domainPartB64 = parts[parts.length - 1];
561
+ const domainPart = base64Decode(domainPartB64);
562
+ return domainPart.replace('$', '');
563
+ }
564
+ catch {
565
+ return null;
566
+ }
567
+ }
568
+ function base64Decode(s) {
569
+ try {
570
+ return Buffer.from(s, 'base64').toString('utf-8');
571
+ }
572
+ catch {
573
+ return Buffer.from(s, 'base64url').toString('utf-8');
574
+ }
575
+ }
576
+ function validateFirebaseProjectId(value) {
577
+ const projectIdRegex = /^[a-z][a-z0-9-]{4,28}[a-z0-9]$/;
578
+ if (!value)
579
+ return 'Project ID is required';
580
+ if (!projectIdRegex.test(value)) {
581
+ return 'Invalid Firebase project ID. It must be 6-30 characters, start with a lowercase letter, contain only lowercase letters, digits, and hyphens, and not end with a hyphen.';
582
+ }
583
+ }
584
+ function firebaseDiscoveryEndpoint(projectId) {
585
+ return `https://securetoken.google.com/${encodeURIComponent(projectId)}/.well-known/openid-configuration`;
586
+ }
587
+ //# sourceMappingURL=update.js.map