instant-cli 0.22.99-experimental.add-user-perm-rules.20792844601.1 → 0.22.99-experimental.drewh-perms-map.20797152806.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/dist/index.js CHANGED
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  // @ts-check
11
2
  import { generatePermsTypescriptFile, apiSchemaToInstantSchemaDef, generateSchemaTypescriptFile, diffSchemas, convertTxSteps, validateSchema, SchemaValidationError, PlatformApi, } from '@instantdb/platform';
12
3
  import version from './version.js';
@@ -65,30 +56,27 @@ const potentialAdminTokenEnvs = {
65
56
  default: 'INSTANT_APP_ADMIN_TOKEN',
66
57
  short: 'INSTANT_ADMIN_TOKEN',
67
58
  };
68
- function detectEnvType(_a) {
69
- return __awaiter(this, arguments, void 0, function* ({ pkgDir }) {
70
- var _b, _c, _d, _e, _f;
71
- const packageJSON = yield getPackageJson(pkgDir);
72
- if (!packageJSON) {
73
- return 'catchall';
74
- }
75
- if ((_b = packageJSON.dependencies) === null || _b === void 0 ? void 0 : _b.next) {
76
- return 'next';
77
- }
78
- if ((_c = packageJSON.devDependencies) === null || _c === void 0 ? void 0 : _c.svelte) {
79
- return 'svelte';
80
- }
81
- if ((_d = packageJSON.devDependencies) === null || _d === void 0 ? void 0 : _d.vite) {
82
- return 'vite';
83
- }
84
- if ((_e = packageJSON.dependencies) === null || _e === void 0 ? void 0 : _e.expo) {
85
- return 'expo';
86
- }
87
- if ((_f = packageJSON.dependencies) === null || _f === void 0 ? void 0 : _f.nuxt) {
88
- return 'nuxt';
89
- }
59
+ async function detectEnvType({ pkgDir }) {
60
+ const packageJSON = await getPackageJson(pkgDir);
61
+ if (!packageJSON) {
90
62
  return 'catchall';
91
- });
63
+ }
64
+ if (packageJSON.dependencies?.next) {
65
+ return 'next';
66
+ }
67
+ if (packageJSON.devDependencies?.svelte) {
68
+ return 'svelte';
69
+ }
70
+ if (packageJSON.devDependencies?.vite) {
71
+ return 'vite';
72
+ }
73
+ if (packageJSON.dependencies?.expo) {
74
+ return 'expo';
75
+ }
76
+ if (packageJSON.dependencies?.nuxt) {
77
+ return 'nuxt';
78
+ }
79
+ return 'catchall';
92
80
  }
93
81
  const instantDashOrigin = dev
94
82
  ? 'http://localhost:3000'
@@ -114,15 +102,13 @@ function convertPushPullToCurrentFormat(arg, opts) {
114
102
  return { ok: false };
115
103
  return { ok: true, bag, opts };
116
104
  }
117
- function packageDirectoryWithErrorLogging() {
118
- return __awaiter(this, void 0, void 0, function* () {
119
- const projectInfo = yield findProjectDir();
120
- if (!projectInfo) {
121
- error("Couldn't find your root directory. Is there a package.json or deno.json file?");
122
- return;
123
- }
124
- return projectInfo;
125
- });
105
+ async function packageDirectoryWithErrorLogging() {
106
+ const projectInfo = await findProjectDir();
107
+ if (!projectInfo) {
108
+ error("Couldn't find your root directory. Is there a package.json or deno.json file?");
109
+ return;
110
+ }
111
+ return projectInfo;
126
112
  }
127
113
  // cli
128
114
  // Header -- this shows up in every command
@@ -258,16 +244,16 @@ program
258
244
  .description('Log into your account')
259
245
  .option('-p --print', 'Prints the auth token into the console.')
260
246
  .option('--headless', 'Print the login URL instead of trying to open the browser')
261
- .action((opts) => __awaiter(void 0, void 0, void 0, function* () {
247
+ .action(async (opts) => {
262
248
  console.log("Let's log you in!");
263
- yield login(opts);
264
- }));
249
+ await login(opts);
250
+ });
265
251
  program
266
252
  .command('logout')
267
253
  .description('Log out of your Instant account')
268
- .action(() => __awaiter(void 0, void 0, void 0, function* () {
269
- yield logout();
270
- }));
254
+ .action(async () => {
255
+ await logout();
256
+ });
271
257
  program
272
258
  .command('init')
273
259
  .description('Set up a new project.')
@@ -290,10 +276,10 @@ program
290
276
  .argument('[app-id]')
291
277
  .description('Push schema to production.')
292
278
  .option('--skip-check-types', "Don't check types on the server when pushing schema")
293
- .action((appIdOrName, opts) => __awaiter(void 0, void 0, void 0, function* () {
279
+ .action(async (appIdOrName, opts) => {
294
280
  warnDeprecation('push-schema', 'push schema');
295
- yield handlePush('schema', Object.assign({ app: appIdOrName }, opts));
296
- }));
281
+ await handlePush('schema', { app: appIdOrName, ...opts });
282
+ });
297
283
  // Note: Nov 20, 2024
298
284
  // We can eventually delete this,
299
285
  // once we know most people use the new pull and push commands
@@ -301,10 +287,10 @@ program
301
287
  .command('push-perms', { hidden: true })
302
288
  .argument('[app-id]')
303
289
  .description('Push perms to production.')
304
- .action((appIdOrName) => __awaiter(void 0, void 0, void 0, function* () {
290
+ .action(async (appIdOrName) => {
305
291
  warnDeprecation('push-perms', 'push perms');
306
- yield handlePush('perms', { app: appIdOrName });
307
- }));
292
+ await handlePush('perms', { app: appIdOrName });
293
+ });
308
294
  program
309
295
  .command('push')
310
296
  .argument('[schema|perms|all]', 'Which configuration to push. Defaults to `all`')
@@ -318,14 +304,12 @@ Environment Variables:
318
304
  INSTANT_SCHEMA_FILE_PATH Override schema file location (default: instant.schema.ts)
319
305
  INSTANT_PERMS_FILE_PATH Override perms file location (default: instant.perms.ts)
320
306
  `)
321
- .action(function (arg, inputOpts) {
322
- return __awaiter(this, void 0, void 0, function* () {
323
- const ret = convertPushPullToCurrentFormat(arg, inputOpts);
324
- if (!ret.ok)
325
- return process.exit(1);
326
- const { bag, opts } = ret;
327
- yield handlePush(bag, opts);
328
- });
307
+ .action(async function (arg, inputOpts) {
308
+ const ret = convertPushPullToCurrentFormat(arg, inputOpts);
309
+ if (!ret.ok)
310
+ return process.exit(1);
311
+ const { bag, opts } = ret;
312
+ await handlePush(bag, opts);
329
313
  });
330
314
  // Note: Nov 20, 2024
331
315
  // We can eventually delete this,
@@ -334,10 +318,10 @@ program
334
318
  .command('pull-schema', { hidden: true })
335
319
  .argument('[app-id]')
336
320
  .description('Generate instant.schema.ts from production')
337
- .action((appIdOrName) => __awaiter(void 0, void 0, void 0, function* () {
321
+ .action(async (appIdOrName) => {
338
322
  warnDeprecation('pull-schema', 'pull schema');
339
- yield handlePull('schema', { app: appIdOrName });
340
- }));
323
+ await handlePull('schema', { app: appIdOrName });
324
+ });
341
325
  // Note: Nov 20, 2024
342
326
  // We can eventually delete this,
343
327
  // once we know most people use the new pull and push commands
@@ -345,10 +329,10 @@ program
345
329
  .command('pull-perms', { hidden: true })
346
330
  .argument('[app-id]')
347
331
  .description('Generate instant.perms.ts from production.')
348
- .action((appIdOrName) => __awaiter(void 0, void 0, void 0, function* () {
332
+ .action(async (appIdOrName) => {
349
333
  warnDeprecation('pull-perms', 'pull perms');
350
- yield handlePull('perms', { app: appIdOrName });
351
- }));
334
+ await handlePull('perms', { app: appIdOrName });
335
+ });
352
336
  program
353
337
  .command('pull')
354
338
  .argument('[schema|perms|all]', 'Which configuration to push. Defaults to `all`')
@@ -361,173 +345,159 @@ Environment Variables:
361
345
  INSTANT_SCHEMA_FILE_PATH Override schema file location (default: instant.schema.ts)
362
346
  INSTANT_PERMS_FILE_PATH Override perms file location (default: instant.perms.ts)
363
347
  `)
364
- .action(function (arg, inputOpts) {
365
- return __awaiter(this, void 0, void 0, function* () {
366
- const ret = convertPushPullToCurrentFormat(arg, inputOpts);
367
- if (!ret.ok)
368
- return process.exit(1);
369
- const { bag, opts } = ret;
370
- yield handlePull(bag, opts);
371
- });
348
+ .action(async function (arg, inputOpts) {
349
+ const ret = convertPushPullToCurrentFormat(arg, inputOpts);
350
+ if (!ret.ok)
351
+ return process.exit(1);
352
+ const { bag, opts } = ret;
353
+ await handlePull(bag, opts);
372
354
  });
373
355
  program
374
356
  .command('claim')
375
357
  .description('Transfer a tempoary app into your Instant account')
376
- .action(function () {
377
- return __awaiter(this, void 0, void 0, function* () {
378
- const token = yield readConfigAuthToken(false);
379
- if (!token) {
380
- console.error(`Please log in first with ${chalk.bgGray.white('instant-cli login')} to claim an app`);
381
- process.exit(1);
358
+ .action(async function () {
359
+ const token = await readConfigAuthToken(false);
360
+ if (!token) {
361
+ console.error(`Please log in first with ${chalk.bgGray.white('instant-cli login')} to claim an app`);
362
+ process.exit(1);
363
+ }
364
+ const envResult = detectAppIdAndAdminTokenFromEnvWithErrorLogging();
365
+ if (!envResult.ok)
366
+ return process.exit(1);
367
+ if (!envResult.appId) {
368
+ error('No app ID found in environment variables.');
369
+ return process.exit(1);
370
+ }
371
+ if (!envResult.adminToken) {
372
+ error('No admin token found in environment variables.');
373
+ return process.exit(1);
374
+ }
375
+ const appId = envResult.appId.value;
376
+ const adminToken = envResult.adminToken.value;
377
+ console.log(`Found ${chalk.green(envResult.appId.envName)}: ${appId}`);
378
+ await claimEphemeralApp(appId, adminToken);
379
+ });
380
+ program.parse(process.argv);
381
+ async function handleInit(opts) {
382
+ const pkgAndAuthInfo = await getOrPromptPackageAndAuthInfoWithErrorLogging(opts);
383
+ if (!pkgAndAuthInfo)
384
+ return process.exit(1);
385
+ const { ok, appId } = await getOrCreateAppAndWriteToEnv(pkgAndAuthInfo, opts);
386
+ if (!ok) {
387
+ return process.exit(1);
388
+ }
389
+ // Create schema file if it doesn't exist
390
+ // or ask to push if local schema exists
391
+ const localSchemaExists = await readLocalSchemaFile();
392
+ if (!localSchemaExists) {
393
+ await pull('schema', appId, pkgAndAuthInfo);
394
+ }
395
+ else {
396
+ const doSchemaPush = await promptOk({
397
+ promptText: 'Found local schema. Push it to the new app?',
398
+ inline: true,
399
+ }, program.opts());
400
+ if (doSchemaPush) {
401
+ await push('schema', appId, opts);
382
402
  }
383
- const envResult = detectAppIdAndAdminTokenFromEnvWithErrorLogging();
384
- if (!envResult.ok)
385
- return process.exit(1);
386
- if (!envResult.appId) {
387
- error('No app ID found in environment variables.');
388
- return process.exit(1);
403
+ }
404
+ // Create perms file if it doesn't exist
405
+ // or ask to push if local perms exists
406
+ const localPermsExists = await readLocalPermsFile();
407
+ if (!localPermsExists) {
408
+ await pull('perms', appId, pkgAndAuthInfo);
409
+ }
410
+ else {
411
+ const doPermsPush = await promptOk({
412
+ promptText: 'Found local perms. Push it to the new app?',
413
+ inline: true,
414
+ }, program.opts());
415
+ if (doPermsPush) {
416
+ await push('perms', appId, opts);
389
417
  }
390
- if (!envResult.adminToken) {
391
- error('No admin token found in environment variables.');
392
- return process.exit(1);
418
+ }
419
+ }
420
+ async function handleInitWithoutFiles(opts) {
421
+ try {
422
+ const authToken = await readConfigAuthToken(false);
423
+ if (!authToken) {
424
+ throw new Error(`Please log in first with 'instant-cli login' before running this command.`);
393
425
  }
394
- const appId = envResult.appId.value;
395
- const adminToken = envResult.adminToken.value;
396
- console.log(`Found ${chalk.green(envResult.appId.envName)}: ${appId}`);
397
- yield claimEphemeralApp(appId, adminToken);
398
- });
399
- });
400
- program.parse(process.argv);
401
- function handleInit(opts) {
402
- return __awaiter(this, void 0, void 0, function* () {
403
- const pkgAndAuthInfo = yield getOrPromptPackageAndAuthInfoWithErrorLogging(opts);
404
- if (!pkgAndAuthInfo)
405
- return process.exit(1);
406
- const { ok, appId } = yield getOrCreateAppAndWriteToEnv(pkgAndAuthInfo, opts);
407
- if (!ok) {
408
- return process.exit(1);
426
+ if (!opts?.title) {
427
+ throw new Error('Title is required for creating a new app without local files.');
409
428
  }
410
- // Create schema file if it doesn't exist
411
- // or ask to push if local schema exists
412
- const localSchemaExists = yield readLocalSchemaFile();
413
- if (!localSchemaExists) {
414
- yield pull('schema', appId, pkgAndAuthInfo);
429
+ if (opts.title.startsWith('-')) {
430
+ throw new Error(`Invalid title: "${opts.title}". Title cannot be a flag.`);
415
431
  }
416
- else {
417
- const doSchemaPush = yield promptOk({
418
- promptText: 'Found local schema. Push it to the new app?',
419
- inline: true,
420
- }, program.opts());
421
- if (doSchemaPush) {
422
- yield push('schema', appId, opts);
423
- }
432
+ if (opts?.temp && opts?.orgId) {
433
+ throw new Error('Cannot use --temp and --org-id flags together.');
424
434
  }
425
- // Create perms file if it doesn't exist
426
- // or ask to push if local perms exists
427
- const localPermsExists = yield readLocalPermsFile();
428
- if (!localPermsExists) {
429
- yield pull('perms', appId, pkgAndAuthInfo);
435
+ let result;
436
+ if (opts?.temp) {
437
+ result = await createEphemeralApp(opts.title);
430
438
  }
431
439
  else {
432
- const doPermsPush = yield promptOk({
433
- promptText: 'Found local perms. Push it to the new app?',
434
- inline: true,
435
- }, program.opts());
436
- if (doPermsPush) {
437
- yield push('perms', appId, opts);
438
- }
440
+ result = await createApp(opts.title, opts.orgId);
439
441
  }
440
- });
442
+ console.error(`${chalk.green('Successfully created new app!')}\n`);
443
+ console.log(toJson({
444
+ app: result,
445
+ error: null,
446
+ }));
447
+ }
448
+ catch (error) {
449
+ console.error(`${chalk.red('Failed to create app.')}\n`);
450
+ console.log(toJson({
451
+ app: null,
452
+ error: { message: error.message },
453
+ }));
454
+ process.exit(1);
455
+ }
441
456
  }
442
- function handleInitWithoutFiles(opts) {
443
- return __awaiter(this, void 0, void 0, function* () {
444
- try {
445
- const authToken = yield readConfigAuthToken(false);
446
- if (!authToken) {
447
- throw new Error(`Please log in first with 'instant-cli login' before running this command.`);
448
- }
449
- if (!(opts === null || opts === void 0 ? void 0 : opts.title)) {
450
- throw new Error('Title is required for creating a new app without local files.');
451
- }
452
- if (opts.title.startsWith('-')) {
453
- throw new Error(`Invalid title: "${opts.title}". Title cannot be a flag.`);
454
- }
455
- if ((opts === null || opts === void 0 ? void 0 : opts.temp) && (opts === null || opts === void 0 ? void 0 : opts.orgId)) {
456
- throw new Error('Cannot use --temp and --org-id flags together.');
457
- }
458
- let result;
459
- if (opts === null || opts === void 0 ? void 0 : opts.temp) {
460
- result = yield createEphemeralApp(opts.title);
461
- }
462
- else {
463
- result = yield createApp(opts.title, opts.orgId);
464
- }
465
- console.error(`${chalk.green('Successfully created new app!')}\n`);
466
- console.log(toJson({
467
- app: result,
468
- error: null,
469
- }));
470
- }
471
- catch (error) {
472
- console.error(`${chalk.red('Failed to create app.')}\n`);
473
- console.log(toJson({
474
- app: null,
475
- error: { message: error.message },
476
- }));
477
- process.exit(1);
478
- }
479
- });
457
+ async function handlePush(bag, opts) {
458
+ const pkgAndAuthInfo = await enforcePackageAndAuthInfoWithErrorLogging(opts);
459
+ if (!pkgAndAuthInfo)
460
+ return process.exit(1);
461
+ const { ok, appId } = await detectAppWithErrorLogging(opts);
462
+ if (!ok)
463
+ return process.exit(1);
464
+ if (!appId) {
465
+ error('No app ID detected. Please specify one with --app or set up with `instant-cli init`');
466
+ return;
467
+ }
468
+ await push(bag, appId, opts);
469
+ }
470
+ async function handlePull(bag, opts) {
471
+ const pkgAndAuthInfo = await enforcePackageAndAuthInfoWithErrorLogging(opts);
472
+ if (!pkgAndAuthInfo)
473
+ return process.exit(1);
474
+ const { ok, appId } = await detectAppWithErrorLogging(opts);
475
+ if (!ok) {
476
+ return process.exit(1);
477
+ }
478
+ if (!appId) {
479
+ error('No app ID detected. Please specify one with --app or set up with `instant-cli init`');
480
+ return;
481
+ }
482
+ await pull(bag, appId, { ...pkgAndAuthInfo, ...opts });
480
483
  }
481
- function handlePush(bag, opts) {
482
- return __awaiter(this, void 0, void 0, function* () {
483
- const pkgAndAuthInfo = yield enforcePackageAndAuthInfoWithErrorLogging(opts);
484
- if (!pkgAndAuthInfo)
485
- return process.exit(1);
486
- const { ok, appId } = yield detectAppWithErrorLogging(opts);
484
+ async function push(bag, appId, opts) {
485
+ if (bag === 'schema' || bag === 'all') {
486
+ const { ok } = await pushSchema(appId, opts);
487
487
  if (!ok)
488
488
  return process.exit(1);
489
- if (!appId) {
490
- error('No app ID detected. Please specify one with --app or set up with `instant-cli init`');
491
- return;
492
- }
493
- yield push(bag, appId, opts);
494
- });
495
- }
496
- function handlePull(bag, opts) {
497
- return __awaiter(this, void 0, void 0, function* () {
498
- const pkgAndAuthInfo = yield enforcePackageAndAuthInfoWithErrorLogging(opts);
499
- if (!pkgAndAuthInfo)
500
- return process.exit(1);
501
- const { ok, appId } = yield detectAppWithErrorLogging(opts);
502
- if (!ok) {
489
+ }
490
+ if (bag === 'perms' || bag === 'all') {
491
+ const { ok } = await pushPerms(appId);
492
+ if (!ok)
503
493
  return process.exit(1);
504
- }
505
- if (!appId) {
506
- error('No app ID detected. Please specify one with --app or set up with `instant-cli init`');
507
- return;
508
- }
509
- yield pull(bag, appId, Object.assign(Object.assign({}, pkgAndAuthInfo), opts));
510
- });
511
- }
512
- function push(bag, appId, opts) {
513
- return __awaiter(this, void 0, void 0, function* () {
514
- if (bag === 'schema' || bag === 'all') {
515
- const { ok } = yield pushSchema(appId, opts);
516
- if (!ok)
517
- return process.exit(1);
518
- }
519
- if (bag === 'perms' || bag === 'all') {
520
- const { ok } = yield pushPerms(appId);
521
- if (!ok)
522
- return process.exit(1);
523
- }
524
- });
494
+ }
525
495
  }
526
496
  function printDotEnvInfo(envType, appId) {
527
497
  console.log(`\nPicked app ${chalk.green(appId)}!\n`);
528
498
  console.log(`To use this app automatically from now on, update your ${chalk.green('`.env`')} file:`);
529
499
  const picked = potentialEnvs[envType];
530
- const rest = Object.assign({}, potentialEnvs);
500
+ const rest = { ...potentialEnvs };
531
501
  delete rest[envType];
532
502
  console.log(` ${chalk.green(picked)}=${appId}`);
533
503
  const otherEnvs = Object.values(rest);
@@ -536,132 +506,121 @@ function printDotEnvInfo(envType, appId) {
536
506
  console.log(`Alternative names: \n${otherEnvStr} \n`);
537
507
  console.log(terminalLink('Dashboard:', appDashUrl(appId)) + '\n');
538
508
  }
539
- function handleEnvFile(pkgAndAuthInfo_1, _a) {
540
- return __awaiter(this, arguments, void 0, function* (pkgAndAuthInfo, { appId, appToken }) {
541
- var _b;
542
- const { pkgDir } = pkgAndAuthInfo;
543
- const envType = yield detectEnvType(pkgAndAuthInfo);
544
- const envName = potentialEnvs[envType];
545
- const envFile = (_b = program.optsWithGlobals().env) !== null && _b !== void 0 ? _b : '.env';
546
- const hasEnvFile = yield pathExists(join(pkgDir, envFile));
547
- if (hasEnvFile) {
548
- printDotEnvInfo(envType, appId);
549
- return;
550
- }
551
- console.log(`\nLooks like you don't have a ${chalk.green(`\`${envFile}\``)} file yet.`);
552
- console.log(`If we set ${chalk.green(envName)} & ${chalk.green('INSTANT_APP_ADMIN_TOKEN')}, we can remember the app that you chose for all future commands.`);
553
- const saveExtraInfo = envFile !== '.env' ? chalk.green(' (will create `' + envFile + '`)') : '';
554
- const ok = yield promptOk({
555
- inline: true,
556
- promptText: 'Want us to create this env file for you?' + saveExtraInfo,
557
- modifyOutput: (a) => a,
558
- }, program.opts(), true);
559
- if (!ok) {
560
- console.log(`No .env file created. You can always set ${chalk.green('`' + envName + '`')} later. \n`);
561
- return;
562
- }
563
- const content = [
564
- [envName, appId],
565
- ['INSTANT_APP_ADMIN_TOKEN', appToken],
566
- ]
567
- .map(([k, v]) => `${k}=${v}`)
568
- .join('\n') + '\n';
569
- yield writeFile(join(pkgDir, envFile), content, 'utf-8');
570
- if (envFile !== '.env') {
571
- console.log(`Created ${chalk.green(envFile)}!`);
572
- }
573
- else {
574
- console.log(`Created ${chalk.green('.env')} file!`);
575
- }
576
- });
509
+ async function handleEnvFile(pkgAndAuthInfo, { appId, appToken }) {
510
+ const { pkgDir } = pkgAndAuthInfo;
511
+ const envType = await detectEnvType(pkgAndAuthInfo);
512
+ const envName = potentialEnvs[envType];
513
+ const envFile = program.optsWithGlobals().env ?? '.env';
514
+ const hasEnvFile = await pathExists(join(pkgDir, envFile));
515
+ if (hasEnvFile) {
516
+ printDotEnvInfo(envType, appId);
517
+ return;
518
+ }
519
+ console.log(`\nLooks like you don't have a ${chalk.green(`\`${envFile}\``)} file yet.`);
520
+ console.log(`If we set ${chalk.green(envName)} & ${chalk.green('INSTANT_APP_ADMIN_TOKEN')}, we can remember the app that you chose for all future commands.`);
521
+ const saveExtraInfo = envFile !== '.env' ? chalk.green(' (will create `' + envFile + '`)') : '';
522
+ const ok = await promptOk({
523
+ inline: true,
524
+ promptText: 'Want us to create this env file for you?' + saveExtraInfo,
525
+ modifyOutput: (a) => a,
526
+ }, program.opts(), true);
527
+ if (!ok) {
528
+ console.log(`No .env file created. You can always set ${chalk.green('`' + envName + '`')} later. \n`);
529
+ return;
530
+ }
531
+ const content = [
532
+ [envName, appId],
533
+ ['INSTANT_APP_ADMIN_TOKEN', appToken],
534
+ ]
535
+ .map(([k, v]) => `${k}=${v}`)
536
+ .join('\n') + '\n';
537
+ await writeFile(join(pkgDir, envFile), content, 'utf-8');
538
+ if (envFile !== '.env') {
539
+ console.log(`Created ${chalk.green(envFile)}!`);
540
+ }
541
+ else {
542
+ console.log(`Created ${chalk.green('.env')} file!`);
543
+ }
577
544
  }
578
- function getOrCreateAppAndWriteToEnv(pkgAndAuthInfo, opts) {
579
- return __awaiter(this, void 0, void 0, function* () {
580
- const ret = yield detectOrCreateAppWithErrorLogging(opts);
581
- if (!ret.ok)
582
- return ret;
583
- const { appId, appToken, source } = ret;
584
- if (source === 'created' || source === 'imported') {
585
- yield handleEnvFile(pkgAndAuthInfo, { appId, appToken });
586
- }
545
+ async function getOrCreateAppAndWriteToEnv(pkgAndAuthInfo, opts) {
546
+ const ret = await detectOrCreateAppWithErrorLogging(opts);
547
+ if (!ret.ok)
587
548
  return ret;
588
- });
589
- }
590
- function pull(bag, appId, pkgAndAuthInfo) {
591
- return __awaiter(this, void 0, void 0, function* () {
592
- if (bag === 'schema' || bag === 'all') {
593
- const { ok } = yield pullSchema(appId, pkgAndAuthInfo);
594
- if (!ok)
595
- return process.exit(1);
596
- }
597
- if (bag === 'perms' || bag === 'all') {
598
- const { ok } = yield pullPerms(appId, pkgAndAuthInfo);
599
- if (!ok)
600
- return process.exit(1);
601
- }
602
- });
549
+ const { appId, appToken, source } = ret;
550
+ if (source === 'created' || source === 'imported') {
551
+ await handleEnvFile(pkgAndAuthInfo, { appId, appToken });
552
+ }
553
+ return ret;
603
554
  }
604
- function login(options) {
605
- return __awaiter(this, void 0, void 0, function* () {
606
- const registerRes = yield fetchJson({
607
- method: 'POST',
608
- path: '/dash/cli/auth/register',
609
- debugName: 'Login register',
610
- errorMessage: 'Failed to register login.',
611
- noAuth: true,
612
- command: 'login',
613
- });
614
- if (!registerRes.ok) {
555
+ async function pull(bag, appId, pkgAndAuthInfo) {
556
+ if (bag === 'schema' || bag === 'all') {
557
+ const { ok } = await pullSchema(appId, pkgAndAuthInfo);
558
+ if (!ok)
615
559
  return process.exit(1);
616
- }
617
- const { secret, ticket } = registerRes.data;
618
- console.log();
619
- if (isHeadlessEnvironment(options)) {
620
- console.log(`Open this URL in a browser to log in:\n ${instantDashOrigin}/dash?ticket=${ticket}\n`);
621
- }
622
- else {
623
- const ok = yield promptOk({
624
- promptText: `This will open instantdb.com in your browser, OK to proceed?`,
625
- }, program.opts(),
626
- /*defaultAnswer=*/ true);
627
- if (!ok)
628
- return;
629
- openInBrowser(`${instantDashOrigin}/dash?ticket=${ticket}`);
630
- }
631
- console.log('Waiting for authentication...');
632
- const authTokenRes = yield waitForAuthToken({ secret });
633
- if (!authTokenRes) {
560
+ }
561
+ if (bag === 'perms' || bag === 'all') {
562
+ const { ok } = await pullPerms(appId, pkgAndAuthInfo);
563
+ if (!ok)
634
564
  return process.exit(1);
635
- }
636
- const { token, email } = authTokenRes;
637
- if (options.print) {
638
- console.log(chalk.red('[Do not share] Your Instant auth token:', token));
639
- }
640
- else {
641
- yield saveConfigAuthToken(token);
642
- console.log(chalk.green(`Successfully logged in as ${email}!`));
643
- }
644
- return token;
645
- });
565
+ }
646
566
  }
647
- function logout() {
648
- return __awaiter(this, void 0, void 0, function* () {
649
- const { authConfigFilePath } = getAuthPaths();
650
- try {
651
- yield unlink(authConfigFilePath);
652
- console.log(chalk.green('Successfully logged out from Instant!'));
653
- return true;
567
+ async function login(options) {
568
+ const registerRes = await fetchJson({
569
+ method: 'POST',
570
+ path: '/dash/cli/auth/register',
571
+ debugName: 'Login register',
572
+ errorMessage: 'Failed to register login.',
573
+ noAuth: true,
574
+ command: 'login',
575
+ });
576
+ if (!registerRes.ok) {
577
+ return process.exit(1);
578
+ }
579
+ const { secret, ticket } = registerRes.data;
580
+ console.log();
581
+ if (isHeadlessEnvironment(options)) {
582
+ console.log(`Open this URL in a browser to log in:\n ${instantDashOrigin}/dash?ticket=${ticket}\n`);
583
+ }
584
+ else {
585
+ const ok = await promptOk({
586
+ promptText: `This will open instantdb.com in your browser, OK to proceed?`,
587
+ }, program.opts(),
588
+ /*defaultAnswer=*/ true);
589
+ if (!ok)
590
+ return;
591
+ openInBrowser(`${instantDashOrigin}/dash?ticket=${ticket}`);
592
+ }
593
+ console.log('Waiting for authentication...');
594
+ const authTokenRes = await waitForAuthToken({ secret });
595
+ if (!authTokenRes) {
596
+ return process.exit(1);
597
+ }
598
+ const { token, email } = authTokenRes;
599
+ if (options.print) {
600
+ console.log(chalk.red('[Do not share] Your Instant auth token:', token));
601
+ }
602
+ else {
603
+ await saveConfigAuthToken(token);
604
+ console.log(chalk.green(`Successfully logged in as ${email}!`));
605
+ }
606
+ return token;
607
+ }
608
+ async function logout() {
609
+ const { authConfigFilePath } = getAuthPaths();
610
+ try {
611
+ await unlink(authConfigFilePath);
612
+ console.log(chalk.green('Successfully logged out from Instant!'));
613
+ return true;
614
+ }
615
+ catch (error) {
616
+ if (error.code === 'ENOENT') {
617
+ console.log(chalk.green('You were already logged out!'));
654
618
  }
655
- catch (error) {
656
- if (error.code === 'ENOENT') {
657
- console.log(chalk.green('You were already logged out!'));
658
- }
659
- else {
660
- error('Failed to logout: ' + error.message);
661
- }
662
- return false;
619
+ else {
620
+ error('Failed to logout: ' + error.message);
663
621
  }
664
- });
622
+ return false;
623
+ }
665
624
  }
666
625
  const packageAliasAndFullNames = {
667
626
  react: '@instantdb/react',
@@ -669,404 +628,376 @@ const packageAliasAndFullNames = {
669
628
  core: '@instantdb/core',
670
629
  admin: '@instantdb/admin',
671
630
  };
672
- function getOrInstallInstantModuleWithErrorLogging(pkgDir, opts) {
673
- return __awaiter(this, void 0, void 0, function* () {
674
- var _a;
675
- const pkgJson = yield getPackageJSONWithErrorLogging(pkgDir);
676
- if (!pkgJson) {
677
- return;
678
- }
679
- console.log('Checking for an Instant SDK...');
680
- const instantModuleName = yield getInstantModuleName(pkgJson);
681
- if (instantModuleName) {
682
- console.log(`Found ${chalk.green(instantModuleName)} in your package.json.`);
683
- return instantModuleName;
684
- }
685
- console.log("Couldn't find an Instant SDK in your package.json, let's install one!");
686
- let moduleName;
687
- if (opts.package) {
688
- moduleName = packageAliasAndFullNames[opts.package];
689
- }
690
- else {
691
- if ((_a = program.optsWithGlobals()) === null || _a === void 0 ? void 0 : _a.yes) {
692
- console.error('--yes was provided without a package specificaion and no Instant SDK was found');
693
- process.exit(1);
694
- }
695
- moduleName = yield renderUnwrap(new UI.Select({
696
- promptText: 'Which package would you like to use?',
697
- options: [
698
- { label: '@instantdb/react', value: '@instantdb/react' },
699
- {
700
- label: '@instantdb/react-native',
701
- value: '@instantdb/react-native',
702
- },
703
- { label: '@instantdb/core', value: '@instantdb/core' },
704
- { label: '@instantdb/admin', value: '@instantdb/admin' },
705
- ],
706
- }));
707
- }
708
- const packageManager = yield detectPackageManager(pkgDir);
709
- const packagesToInstall = [moduleName];
710
- if (moduleName === '@instantdb/react-native') {
711
- packagesToInstall.push('react-native-get-random-values', '@react-native-async-storage/async-storage');
631
+ async function getOrInstallInstantModuleWithErrorLogging(pkgDir, opts) {
632
+ const pkgJson = await getPackageJSONWithErrorLogging(pkgDir);
633
+ if (!pkgJson) {
634
+ return;
635
+ }
636
+ console.log('Checking for an Instant SDK...');
637
+ const instantModuleName = await getInstantModuleName(pkgJson);
638
+ if (instantModuleName) {
639
+ console.log(`Found ${chalk.green(instantModuleName)} in your package.json.`);
640
+ return instantModuleName;
641
+ }
642
+ console.log("Couldn't find an Instant SDK in your package.json, let's install one!");
643
+ let moduleName;
644
+ if (opts.package) {
645
+ moduleName = packageAliasAndFullNames[opts.package];
646
+ }
647
+ else {
648
+ if (program.optsWithGlobals()?.yes) {
649
+ console.error('--yes was provided without a package specificaion and no Instant SDK was found');
650
+ process.exit(1);
712
651
  }
713
- const installCommand = getInstallCommand(packageManager, packagesToInstall.join(' '));
714
- yield renderUnwrap(new UI.Spinner({
715
- promise: execAsync(installCommand, pkgDir),
716
- workingText: `Installing ${packagesToInstall.join(', ')} using ${packageManager}...`,
717
- doneText: `Installed ${packagesToInstall.join(', ')} using ${packageManager}.`,
652
+ moduleName = await renderUnwrap(new UI.Select({
653
+ promptText: 'Which package would you like to use?',
654
+ options: [
655
+ { label: '@instantdb/react', value: '@instantdb/react' },
656
+ {
657
+ label: '@instantdb/react-native',
658
+ value: '@instantdb/react-native',
659
+ },
660
+ { label: '@instantdb/core', value: '@instantdb/core' },
661
+ { label: '@instantdb/admin', value: '@instantdb/admin' },
662
+ ],
718
663
  }));
719
- return moduleName;
720
- });
721
- }
722
- function promptCreateApp(opts) {
723
- return __awaiter(this, void 0, void 0, function* () {
724
- const id = randomUUID();
725
- const token = randomUUID();
726
- let _title;
727
- if (opts === null || opts === void 0 ? void 0 : opts.title) {
728
- _title = opts.title;
729
- }
730
- else {
731
- _title = yield renderUnwrap(new UI.TextInput({
732
- prompt: 'What would you like to call it?',
733
- placeholder: 'My cool app',
734
- })).catch(() => null);
735
- }
736
- const title = _title === null || _title === void 0 ? void 0 : _title.trim();
737
- if (!title) {
738
- error('No name provided.');
739
- return { ok: false };
740
- }
741
- const res = yield fetchJson({
742
- debugName: 'Fetching orgs',
743
- method: 'GET',
744
- path: '/dash',
745
- errorMessage: 'Failed to fetch apps.',
746
- command: 'init',
747
- });
748
- if (!res.ok) {
749
- return { ok: false };
750
- }
751
- const allowedOrgs = res.data.orgs.filter((org) => org.role !== 'app-member');
752
- let org_id = opts.org;
753
- if (!org_id && allowedOrgs.length) {
754
- const choices = [{ label: '(No organization)', value: null }];
755
- for (const org of allowedOrgs) {
756
- choices.push({ label: org.title, value: org.id });
757
- }
758
- const choice = yield renderUnwrap(new UI.Select({
759
- promptText: 'Would you like to create the app in an organization?',
760
- options: choices,
761
- }));
762
- if (choice) {
763
- org_id = choice;
764
- }
765
- }
766
- const app = { id, title, admin_token: token, org_id };
767
- const appRes = yield fetchJson({
768
- method: 'POST',
769
- path: '/dash/apps',
770
- debugName: 'App create',
771
- errorMessage: 'Failed to create app.',
772
- body: app,
773
- command: 'init',
774
- });
775
- if (!appRes.ok)
776
- return { ok: false };
777
- return {
778
- ok: true,
779
- appId: id,
780
- appTitle: title,
781
- appToken: token,
782
- source: 'created',
783
- };
664
+ }
665
+ const packageManager = await detectPackageManager(pkgDir);
666
+ const packagesToInstall = [moduleName];
667
+ if (moduleName === '@instantdb/react-native') {
668
+ packagesToInstall.push('react-native-get-random-values', '@react-native-async-storage/async-storage');
669
+ }
670
+ const installCommand = getInstallCommand(packageManager, packagesToInstall.join(' '));
671
+ await renderUnwrap(new UI.Spinner({
672
+ promise: execAsync(installCommand, pkgDir),
673
+ workingText: `Installing ${packagesToInstall.join(', ')} using ${packageManager}...`,
674
+ doneText: `Installed ${packagesToInstall.join(', ')} using ${packageManager}.`,
675
+ }));
676
+ return moduleName;
677
+ }
678
+ async function promptCreateApp(opts) {
679
+ const id = randomUUID();
680
+ const token = randomUUID();
681
+ let _title;
682
+ if (opts?.title) {
683
+ _title = opts.title;
684
+ }
685
+ else {
686
+ _title = await renderUnwrap(new UI.TextInput({
687
+ prompt: 'What would you like to call it?',
688
+ placeholder: 'My cool app',
689
+ })).catch(() => null);
690
+ }
691
+ const title = _title?.trim();
692
+ if (!title) {
693
+ error('No name provided.');
694
+ return { ok: false };
695
+ }
696
+ const res = await fetchJson({
697
+ debugName: 'Fetching orgs',
698
+ method: 'GET',
699
+ path: '/dash',
700
+ errorMessage: 'Failed to fetch apps.',
701
+ command: 'init',
784
702
  });
785
- }
786
- function promptImportAppOrCreateApp() {
787
- return __awaiter(this, void 0, void 0, function* () {
788
- const res = yield fetchJson({
789
- debugName: 'Fetching apps',
790
- method: 'GET',
791
- path: '/dash',
792
- errorMessage: 'Failed to fetch apps.',
793
- command: 'init',
794
- });
795
- if (!res.ok) {
796
- return { ok: false };
797
- }
798
- const result = yield renderUnwrap(new UI.AppSelector({
799
- allowEphemeral: true,
800
- allowCreate: true,
801
- startingMenuIndex: 2,
802
- api: {
803
- getDash: () => res.data,
804
- createEphemeralApp,
805
- getAppsForOrg: (orgId) => __awaiter(this, void 0, void 0, function* () {
806
- const orgsRes = yield fetchJson({
807
- debugName: 'Fetching org apps',
808
- method: 'GET',
809
- path: `/dash/orgs/${orgId}`,
810
- errorMessage: 'Failed to fetch apps.',
811
- command: 'init',
812
- });
813
- if (!orgsRes.ok) {
814
- throw new Error('Failed to fetch org apps');
815
- }
816
- return { apps: orgsRes.data.apps };
817
- }),
818
- createApp,
819
- },
703
+ if (!res.ok) {
704
+ return { ok: false };
705
+ }
706
+ const allowedOrgs = res.data.orgs.filter((org) => org.role !== 'app-member');
707
+ let org_id = opts.org;
708
+ if (!org_id && allowedOrgs.length) {
709
+ const choices = [{ label: '(No organization)', value: null }];
710
+ for (const org of allowedOrgs) {
711
+ choices.push({ label: org.title, value: org.id });
712
+ }
713
+ const choice = await renderUnwrap(new UI.Select({
714
+ promptText: 'Would you like to create the app in an organization?',
715
+ options: choices,
820
716
  }));
821
- return {
822
- ok: true,
823
- appId: result.appId,
824
- appToken: result.adminToken,
825
- source: result.approach === 'import' ? 'imported' : 'created',
826
- };
827
- });
828
- }
829
- function createApp(title, orgId) {
830
- return __awaiter(this, void 0, void 0, function* () {
831
- const id = randomUUID();
832
- const token = randomUUID();
833
- const app = { id, title, admin_token: token, org_id: orgId };
834
- const appRes = yield fetchJson({
835
- method: 'POST',
836
- path: '/dash/apps',
837
- debugName: 'App create',
838
- errorMessage: 'Failed to create app.',
839
- body: app,
840
- command: 'init',
841
- });
842
- if (!appRes.ok)
843
- throw new Error('Failed to create app');
844
- return { appId: id, adminToken: token };
845
- });
846
- }
847
- function createEphemeralApp(title) {
848
- return __awaiter(this, void 0, void 0, function* () {
849
- const api = new PlatformApi({ apiURI: instantBackendOrigin });
850
- const { app } = yield api.createTemporaryApp({ title });
851
- return { appId: app.id, adminToken: app.adminToken };
852
- });
853
- }
854
- function detectAppWithErrorLogging(opts) {
855
- return __awaiter(this, void 0, void 0, function* () {
856
- const fromOpts = yield detectAppIdFromOptsWithErrorLogging(opts);
857
- if (!fromOpts.ok)
858
- return fromOpts;
859
- if (fromOpts.appId) {
860
- return { ok: true, appId: fromOpts.appId, source: 'opts' };
717
+ if (choice) {
718
+ org_id = choice;
861
719
  }
862
- const fromEnv = detectAppIdFromEnvWithErrorLogging();
863
- if (!fromEnv.ok)
864
- return fromEnv;
865
- if (fromEnv.found) {
866
- const { envName, value } = fromEnv.found;
867
- console.log(`Found ${chalk.green(envName)}: ${value}`);
868
- return { ok: true, appId: value, source: 'env' };
869
- }
870
- return { ok: true };
871
- });
872
- }
873
- function detectOrCreateAppWithErrorLogging(opts) {
874
- return __awaiter(this, void 0, void 0, function* () {
875
- const detected = yield detectAppWithErrorLogging(opts);
876
- if (!detected.ok)
877
- return detected;
878
- if (detected.appId) {
879
- return detected;
880
- }
881
- let action;
882
- if (program.optsWithGlobals().yes) {
883
- action = 'create';
884
- if (!(opts === null || opts === void 0 ? void 0 : opts.title)) {
885
- console.error(chalk.red(`Title is required when using --yes and no app is linked`));
886
- process.exit(1);
887
- }
888
- const app = yield createApp(opts.title);
889
- return { ok: true, appId: app.appId, source: 'created' };
890
- }
891
- else {
892
- console.log();
893
- return yield promptImportAppOrCreateApp();
894
- }
895
- });
896
- }
897
- function writeTypescript(path, content, encoding) {
898
- return __awaiter(this, void 0, void 0, function* () {
899
- const prettierConfig = yield prettier.resolveConfig(path);
900
- const formattedCode = yield prettier.format(content, Object.assign(Object.assign({}, prettierConfig), { parser: 'typescript' }));
901
- return yield writeFile(path, formattedCode, encoding);
720
+ }
721
+ const app = { id, title, admin_token: token, org_id };
722
+ const appRes = await fetchJson({
723
+ method: 'POST',
724
+ path: '/dash/apps',
725
+ debugName: 'App create',
726
+ errorMessage: 'Failed to create app.',
727
+ body: app,
728
+ command: 'init',
902
729
  });
730
+ if (!appRes.ok)
731
+ return { ok: false };
732
+ return {
733
+ ok: true,
734
+ appId: id,
735
+ appTitle: title,
736
+ appToken: token,
737
+ source: 'created',
738
+ };
903
739
  }
904
- function getInstantModuleName(pkgJson) {
905
- return __awaiter(this, void 0, void 0, function* () {
906
- const deps = pkgJson.dependencies || {};
907
- const devDeps = pkgJson.devDependencies || {};
908
- const instantModuleName = [
909
- '@instantdb/react',
910
- '@instantdb/react-native',
911
- '@instantdb/core',
912
- '@instantdb/admin',
913
- ].find((name) => deps[name] || devDeps[name]);
914
- return instantModuleName;
740
+ async function promptImportAppOrCreateApp() {
741
+ const res = await fetchJson({
742
+ debugName: 'Fetching apps',
743
+ method: 'GET',
744
+ path: '/dash',
745
+ errorMessage: 'Failed to fetch apps.',
746
+ command: 'init',
915
747
  });
748
+ if (!res.ok) {
749
+ return { ok: false };
750
+ }
751
+ const result = await renderUnwrap(new UI.AppSelector({
752
+ allowEphemeral: true,
753
+ allowCreate: true,
754
+ startingMenuIndex: 2,
755
+ api: {
756
+ getDash: () => res.data,
757
+ createEphemeralApp,
758
+ getAppsForOrg: async (orgId) => {
759
+ const orgsRes = await fetchJson({
760
+ debugName: 'Fetching org apps',
761
+ method: 'GET',
762
+ path: `/dash/orgs/${orgId}`,
763
+ errorMessage: 'Failed to fetch apps.',
764
+ command: 'init',
765
+ });
766
+ if (!orgsRes.ok) {
767
+ throw new Error('Failed to fetch org apps');
768
+ }
769
+ return { apps: orgsRes.data.apps };
770
+ },
771
+ createApp,
772
+ },
773
+ }));
774
+ return {
775
+ ok: true,
776
+ appId: result.appId,
777
+ appToken: result.adminToken,
778
+ source: result.approach === 'import' ? 'imported' : 'created',
779
+ };
916
780
  }
917
- function getPackageJson(pkgDir) {
918
- return __awaiter(this, void 0, void 0, function* () {
919
- return yield readJsonFile(join(pkgDir, 'package.json'));
781
+ async function createApp(title, orgId) {
782
+ const id = randomUUID();
783
+ const token = randomUUID();
784
+ const app = { id, title, admin_token: token, org_id: orgId };
785
+ const appRes = await fetchJson({
786
+ method: 'POST',
787
+ path: '/dash/apps',
788
+ debugName: 'App create',
789
+ errorMessage: 'Failed to create app.',
790
+ body: app,
791
+ command: 'init',
920
792
  });
921
- }
922
- function getPackageJSONWithErrorLogging(pkgDir) {
923
- return __awaiter(this, void 0, void 0, function* () {
924
- const pkgJson = yield getPackageJson(pkgDir);
925
- if (!pkgJson) {
926
- error(`Couldn't find a packge.json file in: ${pkgDir}. Please add one.`);
927
- return;
793
+ if (!appRes.ok)
794
+ throw new Error('Failed to create app');
795
+ return { appId: id, adminToken: token };
796
+ }
797
+ async function createEphemeralApp(title) {
798
+ const api = new PlatformApi({ apiURI: instantBackendOrigin });
799
+ const { app } = await api.createTemporaryApp({ title });
800
+ return { appId: app.id, adminToken: app.adminToken };
801
+ }
802
+ async function detectAppWithErrorLogging(opts) {
803
+ const fromOpts = await detectAppIdFromOptsWithErrorLogging(opts);
804
+ if (!fromOpts.ok)
805
+ return fromOpts;
806
+ if (fromOpts.appId) {
807
+ return { ok: true, appId: fromOpts.appId, source: 'opts' };
808
+ }
809
+ const fromEnv = detectAppIdFromEnvWithErrorLogging();
810
+ if (!fromEnv.ok)
811
+ return fromEnv;
812
+ if (fromEnv.found) {
813
+ const { envName, value } = fromEnv.found;
814
+ console.log(`Found ${chalk.green(envName)}: ${value}`);
815
+ return { ok: true, appId: value, source: 'env' };
816
+ }
817
+ return { ok: true };
818
+ }
819
+ async function detectOrCreateAppWithErrorLogging(opts) {
820
+ const detected = await detectAppWithErrorLogging(opts);
821
+ if (!detected.ok)
822
+ return detected;
823
+ if (detected.appId) {
824
+ return detected;
825
+ }
826
+ let action;
827
+ if (program.optsWithGlobals().yes) {
828
+ action = 'create';
829
+ if (!opts?.title) {
830
+ console.error(chalk.red(`Title is required when using --yes and no app is linked`));
831
+ process.exit(1);
928
832
  }
929
- return pkgJson;
833
+ const app = await createApp(opts.title);
834
+ return { ok: true, appId: app.appId, source: 'created' };
835
+ }
836
+ else {
837
+ console.log();
838
+ return await promptImportAppOrCreateApp();
839
+ }
840
+ }
841
+ async function writeTypescript(path, content, encoding) {
842
+ const prettierConfig = await prettier.resolveConfig(path);
843
+ const formattedCode = await prettier.format(content, {
844
+ ...prettierConfig,
845
+ parser: 'typescript',
930
846
  });
847
+ return await writeFile(path, formattedCode, encoding);
848
+ }
849
+ async function getInstantModuleName(pkgJson) {
850
+ const deps = pkgJson.dependencies || {};
851
+ const devDeps = pkgJson.devDependencies || {};
852
+ const instantModuleName = [
853
+ '@instantdb/react',
854
+ '@instantdb/react-native',
855
+ '@instantdb/core',
856
+ '@instantdb/admin',
857
+ ].find((name) => deps[name] || devDeps[name]);
858
+ return instantModuleName;
859
+ }
860
+ async function getPackageJson(pkgDir) {
861
+ return await readJsonFile(join(pkgDir, 'package.json'));
862
+ }
863
+ async function getPackageJSONWithErrorLogging(pkgDir) {
864
+ const pkgJson = await getPackageJson(pkgDir);
865
+ if (!pkgJson) {
866
+ error(`Couldn't find a packge.json file in: ${pkgDir}. Please add one.`);
867
+ return;
868
+ }
869
+ return pkgJson;
931
870
  }
932
- function enforcePackageAndAuthInfoWithErrorLogging(_opts) {
933
- return __awaiter(this, void 0, void 0, function* () {
934
- const projectInfo = yield packageDirectoryWithErrorLogging();
935
- if (!projectInfo) {
936
- return;
937
- }
938
- const { dir: pkgDir, type: projectType } = projectInfo;
939
- // Deno projects don't have package.json or node_modules
940
- if (projectType === 'deno') {
941
- const authToken = yield readConfigAuthTokenWithErrorLogging();
942
- if (!authToken) {
943
- return;
944
- }
945
- return {
946
- pkgDir,
947
- projectType,
948
- instantModuleName: '@instantdb/core',
949
- authToken,
950
- };
951
- }
952
- const pkgJson = yield getPackageJSONWithErrorLogging(pkgDir);
953
- if (!pkgJson) {
954
- return;
955
- }
956
- const instantModuleName = yield getInstantModuleName(pkgJson);
957
- if (!instantModuleName) {
958
- error("We couldn't find an Instant SDK. Install one, or run `init`");
959
- }
960
- const authToken = yield readConfigAuthTokenWithErrorLogging();
871
+ async function enforcePackageAndAuthInfoWithErrorLogging(_opts) {
872
+ const projectInfo = await packageDirectoryWithErrorLogging();
873
+ if (!projectInfo) {
874
+ return;
875
+ }
876
+ const { dir: pkgDir, type: projectType } = projectInfo;
877
+ // Deno projects don't have package.json or node_modules
878
+ if (projectType === 'deno') {
879
+ const authToken = await readConfigAuthTokenWithErrorLogging();
961
880
  if (!authToken) {
962
881
  return;
963
882
  }
964
- return { pkgDir, projectType, instantModuleName, authToken };
965
- });
883
+ return {
884
+ pkgDir,
885
+ projectType,
886
+ instantModuleName: '@instantdb/core',
887
+ authToken,
888
+ };
889
+ }
890
+ const pkgJson = await getPackageJSONWithErrorLogging(pkgDir);
891
+ if (!pkgJson) {
892
+ return;
893
+ }
894
+ const instantModuleName = await getInstantModuleName(pkgJson);
895
+ if (!instantModuleName) {
896
+ error("We couldn't find an Instant SDK. Install one, or run `init`");
897
+ }
898
+ const authToken = await readConfigAuthTokenWithErrorLogging();
899
+ if (!authToken) {
900
+ return;
901
+ }
902
+ return { pkgDir, projectType, instantModuleName, authToken };
966
903
  }
967
- function getOrPromptPackageAndAuthInfoWithErrorLogging(opts) {
968
- return __awaiter(this, void 0, void 0, function* () {
969
- const projectInfo = yield packageDirectoryWithErrorLogging();
970
- if (!projectInfo) {
971
- return;
972
- }
973
- const { dir: pkgDir, type: projectType } = projectInfo;
974
- // Deno projects don't have package.json or node_modules
975
- if (projectType === 'deno') {
976
- const authToken = yield readAuthTokenOrLoginWithErrorLogging();
977
- if (!authToken) {
978
- return;
979
- }
980
- return {
981
- pkgDir,
982
- projectType,
983
- instantModuleName: '@instantdb/core',
984
- authToken,
985
- };
986
- }
987
- const instantModuleName = yield getOrInstallInstantModuleWithErrorLogging(pkgDir, opts);
988
- if (!instantModuleName) {
989
- return;
990
- }
991
- const authToken = yield readAuthTokenOrLoginWithErrorLogging();
904
+ async function getOrPromptPackageAndAuthInfoWithErrorLogging(opts) {
905
+ const projectInfo = await packageDirectoryWithErrorLogging();
906
+ if (!projectInfo) {
907
+ return;
908
+ }
909
+ const { dir: pkgDir, type: projectType } = projectInfo;
910
+ // Deno projects don't have package.json or node_modules
911
+ if (projectType === 'deno') {
912
+ const authToken = await readAuthTokenOrLoginWithErrorLogging();
992
913
  if (!authToken) {
993
914
  return;
994
915
  }
995
- return { pkgDir, projectType, instantModuleName, authToken };
916
+ return {
917
+ pkgDir,
918
+ projectType,
919
+ instantModuleName: '@instantdb/core',
920
+ authToken,
921
+ };
922
+ }
923
+ const instantModuleName = await getOrInstallInstantModuleWithErrorLogging(pkgDir, opts);
924
+ if (!instantModuleName) {
925
+ return;
926
+ }
927
+ const authToken = await readAuthTokenOrLoginWithErrorLogging();
928
+ if (!authToken) {
929
+ return;
930
+ }
931
+ return { pkgDir, projectType, instantModuleName, authToken };
932
+ }
933
+ async function pullSchema(appId, { pkgDir, instantModuleName, experimentalTypePreservation }) {
934
+ console.log('Pulling schema...');
935
+ const pullRes = await fetchJson({
936
+ path: `/dash/apps/${appId}/schema/pull`,
937
+ debugName: 'Schema pull',
938
+ errorMessage: 'Failed to pull schema.',
939
+ command: 'pull',
996
940
  });
997
- }
998
- function pullSchema(appId_1, _a) {
999
- return __awaiter(this, arguments, void 0, function* (appId, { pkgDir, instantModuleName, experimentalTypePreservation }) {
1000
- console.log('Pulling schema...');
1001
- const pullRes = yield fetchJson({
1002
- path: `/dash/apps/${appId}/schema/pull`,
1003
- debugName: 'Schema pull',
1004
- errorMessage: 'Failed to pull schema.',
1005
- command: 'pull',
1006
- });
1007
- if (!pullRes.ok)
1008
- return pullRes;
1009
- if (!countEntities(pullRes.data.schema.refs) &&
1010
- !countEntities(pullRes.data.schema.blobs)) {
1011
- console.log('Schema is empty. Skipping.');
941
+ if (!pullRes.ok)
942
+ return pullRes;
943
+ if (!countEntities(pullRes.data.schema.refs) &&
944
+ !countEntities(pullRes.data.schema.blobs)) {
945
+ console.log('Schema is empty. Skipping.');
946
+ return { ok: true };
947
+ }
948
+ const prev = await readLocalSchemaFile();
949
+ if (prev) {
950
+ const shouldContinue = await promptOk({
951
+ promptText: 'This will overwrite your local instant.schema.ts file, OK to proceed?',
952
+ modifyOutput: UI.modifiers.yPadding,
953
+ inline: true,
954
+ }, program.opts());
955
+ console.log();
956
+ if (!shouldContinue)
1012
957
  return { ok: true };
958
+ }
959
+ const shortSchemaPath = getSchemaPathToWrite(prev?.path);
960
+ const schemaPath = join(pkgDir, shortSchemaPath);
961
+ let newSchemaContent = generateSchemaTypescriptFile(prev?.schema, apiSchemaToInstantSchemaDef(pullRes.data.schema), instantModuleName);
962
+ if (prev && experimentalTypePreservation) {
963
+ try {
964
+ const oldSchemaContent = await readFile(prev.path, 'utf-8');
965
+ newSchemaContent = mergeSchema(oldSchemaContent, newSchemaContent);
1013
966
  }
1014
- const prev = yield readLocalSchemaFile();
1015
- if (prev) {
1016
- const shouldContinue = yield promptOk({
1017
- promptText: 'This will overwrite your local instant.schema.ts file, OK to proceed?',
1018
- modifyOutput: UI.modifiers.yPadding,
1019
- inline: true,
1020
- }, program.opts());
1021
- console.log();
1022
- if (!shouldContinue)
1023
- return { ok: true };
1024
- }
1025
- const shortSchemaPath = getSchemaPathToWrite(prev === null || prev === void 0 ? void 0 : prev.path);
1026
- const schemaPath = join(pkgDir, shortSchemaPath);
1027
- let newSchemaContent = generateSchemaTypescriptFile(prev === null || prev === void 0 ? void 0 : prev.schema, apiSchemaToInstantSchemaDef(pullRes.data.schema), instantModuleName);
1028
- if (prev && experimentalTypePreservation) {
1029
- try {
1030
- const oldSchemaContent = yield readFile(prev.path, 'utf-8');
1031
- newSchemaContent = mergeSchema(oldSchemaContent, newSchemaContent);
1032
- }
1033
- catch (e) {
1034
- warn('Failed to merge schema with existing file. Overwriting instead.', e);
1035
- }
1036
- }
1037
- yield writeTypescript(schemaPath, newSchemaContent, 'utf-8');
1038
- console.log('✅ Wrote schema to ' + shortSchemaPath);
1039
- return { ok: true };
1040
- });
1041
- }
1042
- function pullPerms(appId_1, _a) {
1043
- return __awaiter(this, arguments, void 0, function* (appId, { pkgDir, instantModuleName }) {
1044
- console.log('Pulling perms...');
1045
- const pullRes = yield fetchJson({
1046
- path: `/dash/apps/${appId}/perms/pull`,
1047
- debugName: 'Perms pull',
1048
- errorMessage: 'Failed to pull perms.',
1049
- command: 'pull',
1050
- });
1051
- if (!pullRes.ok)
1052
- return pullRes;
1053
- const prev = yield readLocalPermsFile();
1054
- if (prev) {
1055
- const shouldContinue = yield promptOk({
1056
- promptText: 'This will overwrite your local instant.perms.ts file, OK to proceed?',
1057
- modifyOutput: UI.modifiers.yPadding,
1058
- inline: true,
1059
- }, program.opts());
1060
- console.log();
1061
- if (!shouldContinue)
1062
- return { ok: true };
967
+ catch (e) {
968
+ warn('Failed to merge schema with existing file. Overwriting instead.', e);
1063
969
  }
1064
- const shortPermsPath = getPermsPathToWrite(prev === null || prev === void 0 ? void 0 : prev.path);
1065
- const permsPath = join(pkgDir, shortPermsPath);
1066
- yield writeTypescript(permsPath, generatePermsTypescriptFile(pullRes.data.perms || {}, instantModuleName), 'utf-8');
1067
- console.log('✅ Wrote permissions to ' + shortPermsPath);
1068
- return { ok: true };
970
+ }
971
+ await writeTypescript(schemaPath, newSchemaContent, 'utf-8');
972
+ console.log('✅ Wrote schema to ' + shortSchemaPath);
973
+ return { ok: true };
974
+ }
975
+ async function pullPerms(appId, { pkgDir, instantModuleName }) {
976
+ console.log('Pulling perms...');
977
+ const pullRes = await fetchJson({
978
+ path: `/dash/apps/${appId}/perms/pull`,
979
+ debugName: 'Perms pull',
980
+ errorMessage: 'Failed to pull perms.',
981
+ command: 'pull',
1069
982
  });
983
+ if (!pullRes.ok)
984
+ return pullRes;
985
+ const prev = await readLocalPermsFile();
986
+ if (prev) {
987
+ const shouldContinue = await promptOk({
988
+ promptText: 'This will overwrite your local instant.perms.ts file, OK to proceed?',
989
+ modifyOutput: UI.modifiers.yPadding,
990
+ inline: true,
991
+ }, program.opts());
992
+ console.log();
993
+ if (!shouldContinue)
994
+ return { ok: true };
995
+ }
996
+ const shortPermsPath = getPermsPathToWrite(prev?.path);
997
+ const permsPath = join(pkgDir, shortPermsPath);
998
+ await writeTypescript(permsPath, generatePermsTypescriptFile(pullRes.data.perms || {}, instantModuleName), 'utf-8');
999
+ console.log('✅ Wrote permissions to ' + shortPermsPath);
1000
+ return { ok: true };
1070
1001
  }
1071
1002
  function indexingJobCompletedActionMessage(job) {
1072
1003
  if (job.job_type === 'check-data-type') {
@@ -1103,7 +1034,7 @@ function truncate(s, maxLen) {
1103
1034
  }
1104
1035
  function formatSamples(triples_samples) {
1105
1036
  return triples_samples.slice(0, 3).map((t) => {
1106
- return Object.assign(Object.assign({}, t), { value: truncate(JSON.stringify(t.value), 32) });
1037
+ return { ...t, value: truncate(JSON.stringify(t.value), 32) };
1107
1038
  });
1108
1039
  }
1109
1040
  function createUrl(triple, job) {
@@ -1124,7 +1055,6 @@ function padCell(value, width) {
1124
1055
  return trimmed + ' '.repeat(width - trimmed.length);
1125
1056
  }
1126
1057
  function indexingJobCompletedMessage(job) {
1127
- var _a;
1128
1058
  const actionMessage = indexingJobCompletedActionMessage(job);
1129
1059
  if (job.job_status === 'canceled') {
1130
1060
  return `Canceled ${actionMessage} before it could finish.`;
@@ -1133,7 +1063,7 @@ function indexingJobCompletedMessage(job) {
1133
1063
  return `Finished ${actionMessage}.`;
1134
1064
  }
1135
1065
  if (job.job_status === 'errored') {
1136
- if ((_a = job.invalid_triples_sample) === null || _a === void 0 ? void 0 : _a.length) {
1066
+ if (job.invalid_triples_sample?.length) {
1137
1067
  const [etype, label] = job.attr_name.split('.');
1138
1068
  const samples = formatSamples(job.invalid_triples_sample);
1139
1069
  const longestValue = samples.reduce((acc, { value }) => Math.max(acc, value.length), label.length);
@@ -1201,88 +1131,85 @@ function jobGroupDescription(jobs) {
1201
1131
  }
1202
1132
  return joinInSentence([...actions].sort()) || 'updating schema';
1203
1133
  }
1204
- function waitForIndexingJobsToFinish(appId, data) {
1205
- return __awaiter(this, void 0, void 0, function* () {
1206
- var _a, _b;
1207
- const spinnerDefferedPromise = deferred();
1208
- const spinner = new UI.Spinner({
1209
- promise: spinnerDefferedPromise.promise,
1210
- });
1211
- const spinnerRenderPromise = renderUnwrap(spinner);
1212
- const groupId = data['group-id'];
1213
- let jobs = data.jobs;
1214
- let waitMs = 20;
1215
- let lastUpdatedAt = new Date(0);
1216
- const completedIds = new Set();
1217
- const errorMessages = [];
1218
- while (true) {
1219
- let stillRunning = false;
1220
- let updated = false;
1221
- let workEstimateTotal = 0;
1222
- let workCompletedTotal = 0;
1223
- for (const job of jobs) {
1224
- const updatedAt = new Date(job.updated_at);
1225
- if (updatedAt > lastUpdatedAt) {
1226
- updated = true;
1227
- lastUpdatedAt = updatedAt;
1228
- }
1229
- if (job.job_status === 'waiting' || job.job_status === 'processing') {
1230
- stillRunning = true;
1231
- // Default estimate to high value to prevent % from jumping around
1232
- workEstimateTotal += (_a = job.work_estimate) !== null && _a !== void 0 ? _a : 50000;
1233
- workCompletedTotal += (_b = job.work_completed) !== null && _b !== void 0 ? _b : 0;
1234
- }
1235
- else {
1236
- if (!completedIds.has(job.id)) {
1237
- completedIds.add(job.id);
1238
- const msg = indexingJobCompletedMessage(job);
1239
- if (msg) {
1240
- if (job.job_status === 'errored') {
1241
- spinner.addMessage(msg);
1242
- errorMessages.push(msg);
1243
- }
1244
- else {
1245
- spinner.addMessage(msg);
1246
- }
1134
+ async function waitForIndexingJobsToFinish(appId, data) {
1135
+ const spinnerDefferedPromise = deferred();
1136
+ const spinner = new UI.Spinner({
1137
+ promise: spinnerDefferedPromise.promise,
1138
+ });
1139
+ const spinnerRenderPromise = renderUnwrap(spinner);
1140
+ const groupId = data['group-id'];
1141
+ let jobs = data.jobs;
1142
+ let waitMs = 20;
1143
+ let lastUpdatedAt = new Date(0);
1144
+ const completedIds = new Set();
1145
+ const errorMessages = [];
1146
+ while (true) {
1147
+ let stillRunning = false;
1148
+ let updated = false;
1149
+ let workEstimateTotal = 0;
1150
+ let workCompletedTotal = 0;
1151
+ for (const job of jobs) {
1152
+ const updatedAt = new Date(job.updated_at);
1153
+ if (updatedAt > lastUpdatedAt) {
1154
+ updated = true;
1155
+ lastUpdatedAt = updatedAt;
1156
+ }
1157
+ if (job.job_status === 'waiting' || job.job_status === 'processing') {
1158
+ stillRunning = true;
1159
+ // Default estimate to high value to prevent % from jumping around
1160
+ workEstimateTotal += job.work_estimate ?? 50000;
1161
+ workCompletedTotal += job.work_completed ?? 0;
1162
+ }
1163
+ else {
1164
+ if (!completedIds.has(job.id)) {
1165
+ completedIds.add(job.id);
1166
+ const msg = indexingJobCompletedMessage(job);
1167
+ if (msg) {
1168
+ if (job.job_status === 'errored') {
1169
+ spinner.addMessage(msg);
1170
+ errorMessages.push(msg);
1171
+ }
1172
+ else {
1173
+ spinner.addMessage(msg);
1247
1174
  }
1248
1175
  }
1249
1176
  }
1250
1177
  }
1251
- if (!stillRunning) {
1252
- break;
1253
- }
1254
- if (workEstimateTotal) {
1255
- const percent = Math.floor((workCompletedTotal / workEstimateTotal) * 100);
1256
- spinner.updateText(`${jobGroupDescription(jobs)} ${percent}%`);
1257
- }
1258
- waitMs = updated ? 1 : Math.min(10000, waitMs * 2);
1259
- yield sleep(waitMs);
1260
- const res = yield fetchJson({
1261
- debugName: 'Check indexing status',
1262
- method: 'GET',
1263
- path: `/dash/apps/${appId}/indexing-jobs/group/${groupId}`,
1264
- errorMessage: 'Failed to check indexing status.',
1265
- command: 'push',
1266
- });
1267
- if (!res.ok) {
1268
- break;
1269
- }
1270
- jobs = res.data.jobs;
1271
1178
  }
1272
- spinnerDefferedPromise.resolve(null);
1273
- yield spinnerRenderPromise;
1274
- // Log errors at the end so that they're easier to see.
1275
- if (errorMessages.length) {
1276
- for (const msg of errorMessages) {
1277
- console.log(msg);
1278
- }
1279
- console.log(chalk.red('Some steps failed while updating schema.'));
1280
- process.exit(1);
1179
+ if (!stillRunning) {
1180
+ break;
1281
1181
  }
1282
- });
1182
+ if (workEstimateTotal) {
1183
+ const percent = Math.floor((workCompletedTotal / workEstimateTotal) * 100);
1184
+ spinner.updateText(`${jobGroupDescription(jobs)} ${percent}%`);
1185
+ }
1186
+ waitMs = updated ? 1 : Math.min(10000, waitMs * 2);
1187
+ await sleep(waitMs);
1188
+ const res = await fetchJson({
1189
+ debugName: 'Check indexing status',
1190
+ method: 'GET',
1191
+ path: `/dash/apps/${appId}/indexing-jobs/group/${groupId}`,
1192
+ errorMessage: 'Failed to check indexing status.',
1193
+ command: 'push',
1194
+ });
1195
+ if (!res.ok) {
1196
+ break;
1197
+ }
1198
+ jobs = res.data.jobs;
1199
+ }
1200
+ spinnerDefferedPromise.resolve(null);
1201
+ await spinnerRenderPromise;
1202
+ // Log errors at the end so that they're easier to see.
1203
+ if (errorMessages.length) {
1204
+ for (const msg of errorMessages) {
1205
+ console.log(msg);
1206
+ }
1207
+ console.log(chalk.red('Some steps failed while updating schema.'));
1208
+ process.exit(1);
1209
+ }
1283
1210
  }
1284
- const resolveRenames = (created, promptData, extraInfo) => __awaiter(void 0, void 0, void 0, function* () {
1285
- const answer = yield renderUnwrap(new ResolveRenamePrompt(created, promptData, extraInfo, UI.modifiers.piped([
1211
+ const resolveRenames = async (created, promptData, extraInfo) => {
1212
+ const answer = await renderUnwrap(new ResolveRenamePrompt(created, promptData, extraInfo, UI.modifiers.piped([
1286
1213
  (out) => boxen(out, {
1287
1214
  dimBorder: true,
1288
1215
  padding: {
@@ -1293,7 +1220,7 @@ const resolveRenames = (created, promptData, extraInfo) => __awaiter(void 0, voi
1293
1220
  UI.modifiers.vanishOnComplete,
1294
1221
  ])));
1295
1222
  return answer;
1296
- });
1223
+ };
1297
1224
  function collectSystemCatalogIdentNames(currentAttrs) {
1298
1225
  const allSystemIdents = currentAttrs
1299
1226
  .filter((attr) => attr.catalog === 'system')
@@ -1306,151 +1233,64 @@ function collectSystemCatalogIdentNames(currentAttrs) {
1306
1233
  }
1307
1234
  return res;
1308
1235
  }
1309
- function pushSchema(appId, opts) {
1310
- return __awaiter(this, void 0, void 0, function* () {
1311
- const res = yield readLocalSchemaFileWithErrorLogging();
1312
- if (!res)
1313
- return { ok: false };
1314
- const { schema } = res;
1315
- const pulledSchemaResponse = yield fetchJson({
1316
- method: 'GET',
1317
- path: `/dash/apps/${appId}/schema/pull`,
1318
- debugName: 'Schema plan',
1319
- errorMessage: 'Failed to get old schema.',
1320
- command: 'push',
1321
- });
1322
- if (!pulledSchemaResponse.ok)
1323
- return pulledSchemaResponse;
1324
- const currentAttrs = pulledSchemaResponse.data['attrs'];
1325
- const currentApiSchema = pulledSchemaResponse.data['schema'];
1326
- const oldSchema = apiSchemaToInstantSchemaDef(currentApiSchema, {
1327
- disableTypeInference: true,
1328
- });
1329
- const systemCatalogIdentNames = collectSystemCatalogIdentNames(currentAttrs);
1330
- try {
1331
- validateSchema(schema, systemCatalogIdentNames);
1332
- }
1333
- catch (error) {
1334
- if (error instanceof SchemaValidationError) {
1335
- console.error(chalk.red('Invalid schema:', error.message));
1336
- }
1337
- else {
1338
- console.error('Unexpected error:', error);
1339
- }
1340
- return { ok: false };
1341
- }
1342
- const renameSelector = program.optsWithGlobals().yes
1343
- ? buildAutoRenameSelector(opts)
1344
- : resolveRenames;
1345
- const diffResult = yield diffSchemas(oldSchema, schema, renameSelector, systemCatalogIdentNames);
1346
- if (currentAttrs === undefined) {
1347
- throw new Error("Couldn't get current schema from server");
1348
- }
1349
- const txSteps = convertTxSteps(diffResult, currentAttrs);
1350
- if (txSteps.length === 0) {
1351
- console.log(chalk.bgGray('No schema changes to apply!'));
1352
- return { ok: true };
1353
- }
1354
- let wantsToPush = false;
1355
- try {
1356
- const groupedSteps = groupSteps(diffResult);
1357
- const lines = renderSchemaPlan(groupedSteps, currentAttrs);
1358
- if (program.optsWithGlobals().yes) {
1359
- console.log('Applying schema changes...');
1360
- console.log(lines.join('\n'));
1361
- }
1362
- wantsToPush = yield promptOk({
1363
- promptText: 'Push these changes?',
1364
- yesText: 'Push',
1365
- noText: 'Cancel',
1366
- modifyOutput: (output) => {
1367
- let both = lines.join('\n') + '\n\n' + output;
1368
- return boxen(both, {
1369
- dimBorder: true,
1370
- padding: {
1371
- left: 1,
1372
- right: 1,
1373
- },
1374
- });
1375
- },
1376
- }, program.opts());
1377
- }
1378
- catch (error) {
1379
- if (error instanceof CancelSchemaError) {
1380
- console.info('Schema migration cancelled!');
1381
- }
1382
- return { ok: false };
1383
- }
1384
- if (verbose) {
1385
- console.log(txSteps);
1386
- }
1387
- if (wantsToPush) {
1388
- const applyRes = yield fetchJson({
1389
- method: 'POST',
1390
- path: `/dash/apps/${appId}/schema/steps/apply`,
1391
- debugName: 'Schema apply',
1392
- errorMessage: 'Failed to update schema.',
1393
- body: {
1394
- steps: txSteps,
1395
- },
1396
- command: 'push',
1397
- });
1398
- console.log(chalk.green('Schema updated!'));
1399
- if (!applyRes.ok)
1400
- return applyRes;
1401
- if (applyRes.data['indexing-jobs']) {
1402
- yield waitForIndexingJobsToFinish(appId, applyRes.data['indexing-jobs']);
1403
- }
1236
+ async function pushSchema(appId, opts) {
1237
+ const res = await readLocalSchemaFileWithErrorLogging();
1238
+ if (!res)
1239
+ return { ok: false };
1240
+ const { schema } = res;
1241
+ const pulledSchemaResponse = await fetchJson({
1242
+ method: 'GET',
1243
+ path: `/dash/apps/${appId}/schema/pull`,
1244
+ debugName: 'Schema plan',
1245
+ errorMessage: 'Failed to get old schema.',
1246
+ command: 'push',
1247
+ });
1248
+ if (!pulledSchemaResponse.ok)
1249
+ return pulledSchemaResponse;
1250
+ const currentAttrs = pulledSchemaResponse.data['attrs'];
1251
+ const currentApiSchema = pulledSchemaResponse.data['schema'];
1252
+ const oldSchema = apiSchemaToInstantSchemaDef(currentApiSchema, {
1253
+ disableTypeInference: true,
1254
+ });
1255
+ const systemCatalogIdentNames = collectSystemCatalogIdentNames(currentAttrs);
1256
+ try {
1257
+ validateSchema(schema, systemCatalogIdentNames);
1258
+ }
1259
+ catch (error) {
1260
+ if (error instanceof SchemaValidationError) {
1261
+ console.error(chalk.red('Invalid schema:', error.message));
1404
1262
  }
1405
1263
  else {
1406
- console.info('Schema migration cancelled!');
1264
+ console.error('Unexpected error:', error);
1407
1265
  }
1266
+ return { ok: false };
1267
+ }
1268
+ const renameSelector = program.optsWithGlobals().yes
1269
+ ? buildAutoRenameSelector(opts)
1270
+ : resolveRenames;
1271
+ const diffResult = await diffSchemas(oldSchema, schema, renameSelector, systemCatalogIdentNames);
1272
+ if (currentAttrs === undefined) {
1273
+ throw new Error("Couldn't get current schema from server");
1274
+ }
1275
+ const txSteps = convertTxSteps(diffResult, currentAttrs);
1276
+ if (txSteps.length === 0) {
1277
+ console.log(chalk.bgGray('No schema changes to apply!'));
1408
1278
  return { ok: true };
1409
- });
1410
- }
1411
- function claimEphemeralApp(appId, adminToken) {
1412
- return __awaiter(this, void 0, void 0, function* () {
1413
- const res = yield fetchJson({
1414
- method: 'POST',
1415
- body: {
1416
- app_id: appId,
1417
- token: adminToken,
1418
- },
1419
- path: `/dash/apps/ephemeral/${appId}/claim`,
1420
- debugName: 'Claim ephemeral app',
1421
- errorMessage: 'Failed to claim ephemeral app.',
1422
- command: 'claim',
1423
- });
1424
- if (!res.ok)
1425
- return res;
1426
- console.log(chalk.green('App claimed!'));
1427
- return { ok: true };
1428
- });
1429
- }
1430
- function pushPerms(appId) {
1431
- return __awaiter(this, void 0, void 0, function* () {
1432
- const res = yield readLocalPermsFileWithErrorLogging();
1433
- if (!res) {
1434
- return { ok: true };
1435
- }
1436
- console.log('Planning perms...');
1437
- const prodPerms = yield fetchJson({
1438
- path: `/dash/apps/${appId}/perms/pull`,
1439
- debugName: 'Perms pull',
1440
- errorMessage: 'Failed to pull perms.',
1441
- command: 'push',
1442
- });
1443
- if (!prodPerms.ok)
1444
- return prodPerms;
1445
- const diffedStr = jsonDiff.diffString(prodPerms.data.perms || {}, res.perms || {});
1446
- if (!diffedStr.length) {
1447
- console.log('No perms changes detected. Skipping.');
1448
- return { ok: true };
1279
+ }
1280
+ let wantsToPush = false;
1281
+ try {
1282
+ const groupedSteps = groupSteps(diffResult);
1283
+ const lines = renderSchemaPlan(groupedSteps, currentAttrs);
1284
+ if (program.optsWithGlobals().yes) {
1285
+ console.log('Applying schema changes...');
1286
+ console.log(lines.join('\n'));
1449
1287
  }
1450
- const okPush = yield promptOk({
1451
- promptText: 'Push these changes to your perms?',
1288
+ wantsToPush = await promptOk({
1289
+ promptText: 'Push these changes?',
1290
+ yesText: 'Push',
1291
+ noText: 'Cancel',
1452
1292
  modifyOutput: (output) => {
1453
- let both = diffedStr + '\n' + output;
1293
+ let both = lines.join('\n') + '\n\n' + output;
1454
1294
  return boxen(both, {
1455
1295
  dimBorder: true,
1456
1296
  padding: {
@@ -1460,52 +1300,130 @@ function pushPerms(appId) {
1460
1300
  });
1461
1301
  },
1462
1302
  }, program.opts());
1463
- if (!okPush)
1464
- return { ok: true };
1465
- const permsRes = yield fetchJson({
1303
+ }
1304
+ catch (error) {
1305
+ if (error instanceof CancelSchemaError) {
1306
+ console.info('Schema migration cancelled!');
1307
+ }
1308
+ return { ok: false };
1309
+ }
1310
+ if (verbose) {
1311
+ console.log(txSteps);
1312
+ }
1313
+ if (wantsToPush) {
1314
+ const applyRes = await fetchJson({
1466
1315
  method: 'POST',
1467
- path: `/dash/apps/${appId}/rules`,
1316
+ path: `/dash/apps/${appId}/schema/steps/apply`,
1468
1317
  debugName: 'Schema apply',
1469
1318
  errorMessage: 'Failed to update schema.',
1470
1319
  body: {
1471
- code: res.perms,
1320
+ steps: txSteps,
1472
1321
  },
1473
1322
  command: 'push',
1474
1323
  });
1475
- if (!permsRes.ok)
1476
- return permsRes;
1477
- console.log(chalk.green('Permissions updated!'));
1478
- return { ok: true };
1324
+ console.log(chalk.green('Schema updated!'));
1325
+ if (!applyRes.ok)
1326
+ return applyRes;
1327
+ if (applyRes.data['indexing-jobs']) {
1328
+ await waitForIndexingJobsToFinish(appId, applyRes.data['indexing-jobs']);
1329
+ }
1330
+ }
1331
+ else {
1332
+ console.info('Schema migration cancelled!');
1333
+ }
1334
+ return { ok: true };
1335
+ }
1336
+ async function claimEphemeralApp(appId, adminToken) {
1337
+ const res = await fetchJson({
1338
+ method: 'POST',
1339
+ body: {
1340
+ app_id: appId,
1341
+ token: adminToken,
1342
+ },
1343
+ path: `/dash/apps/ephemeral/${appId}/claim`,
1344
+ debugName: 'Claim ephemeral app',
1345
+ errorMessage: 'Failed to claim ephemeral app.',
1346
+ command: 'claim',
1479
1347
  });
1348
+ if (!res.ok)
1349
+ return res;
1350
+ console.log(chalk.green('App claimed!'));
1351
+ return { ok: true };
1480
1352
  }
1481
- function waitForAuthToken(_a) {
1482
- return __awaiter(this, arguments, void 0, function* ({ secret }) {
1483
- var _b, _c, _d;
1484
- for (let i = 1; i <= 120; i++) {
1485
- yield sleep(1000);
1486
- const authCheckRes = yield fetchJson({
1487
- method: 'POST',
1488
- debugName: 'Auth check',
1489
- errorMessage: 'Failed to check auth status.',
1490
- path: '/dash/cli/auth/check',
1491
- body: { secret },
1492
- noAuth: true,
1493
- noLogError: true,
1494
- command: 'login',
1353
+ async function pushPerms(appId) {
1354
+ const res = await readLocalPermsFileWithErrorLogging();
1355
+ if (!res) {
1356
+ return { ok: true };
1357
+ }
1358
+ console.log('Planning perms...');
1359
+ const prodPerms = await fetchJson({
1360
+ path: `/dash/apps/${appId}/perms/pull`,
1361
+ debugName: 'Perms pull',
1362
+ errorMessage: 'Failed to pull perms.',
1363
+ command: 'push',
1364
+ });
1365
+ if (!prodPerms.ok)
1366
+ return prodPerms;
1367
+ const diffedStr = jsonDiff.diffString(prodPerms.data.perms || {}, res.perms || {});
1368
+ if (!diffedStr.length) {
1369
+ console.log('No perms changes detected. Skipping.');
1370
+ return { ok: true };
1371
+ }
1372
+ const okPush = await promptOk({
1373
+ promptText: 'Push these changes to your perms?',
1374
+ modifyOutput: (output) => {
1375
+ let both = diffedStr + '\n' + output;
1376
+ return boxen(both, {
1377
+ dimBorder: true,
1378
+ padding: {
1379
+ left: 1,
1380
+ right: 1,
1381
+ },
1495
1382
  });
1496
- if (authCheckRes.ok) {
1497
- return authCheckRes.data;
1498
- }
1499
- if (((_d = (_c = (_b = authCheckRes.data) === null || _b === void 0 ? void 0 : _b.hint.errors) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.issue) === 'waiting-for-user') {
1500
- continue;
1501
- }
1502
- error('Failed to authenticate ');
1503
- prettyPrintJSONErr(authCheckRes.data);
1504
- return;
1505
- }
1506
- error('Timed out waiting for authentication');
1507
- return null;
1383
+ },
1384
+ }, program.opts());
1385
+ if (!okPush)
1386
+ return { ok: true };
1387
+ const permsRes = await fetchJson({
1388
+ method: 'POST',
1389
+ path: `/dash/apps/${appId}/rules`,
1390
+ debugName: 'Schema apply',
1391
+ errorMessage: 'Failed to update schema.',
1392
+ body: {
1393
+ code: res.perms,
1394
+ },
1395
+ command: 'push',
1508
1396
  });
1397
+ if (!permsRes.ok)
1398
+ return permsRes;
1399
+ console.log(chalk.green('Permissions updated!'));
1400
+ return { ok: true };
1401
+ }
1402
+ async function waitForAuthToken({ secret }) {
1403
+ for (let i = 1; i <= 120; i++) {
1404
+ await sleep(1000);
1405
+ const authCheckRes = await fetchJson({
1406
+ method: 'POST',
1407
+ debugName: 'Auth check',
1408
+ errorMessage: 'Failed to check auth status.',
1409
+ path: '/dash/cli/auth/check',
1410
+ body: { secret },
1411
+ noAuth: true,
1412
+ noLogError: true,
1413
+ command: 'login',
1414
+ });
1415
+ if (authCheckRes.ok) {
1416
+ return authCheckRes.data;
1417
+ }
1418
+ if (authCheckRes.data?.hint.errors?.[0]?.issue === 'waiting-for-user') {
1419
+ continue;
1420
+ }
1421
+ error('Failed to authenticate ');
1422
+ prettyPrintJSONErr(authCheckRes.data);
1423
+ return;
1424
+ }
1425
+ error('Timed out waiting for authentication');
1426
+ return null;
1509
1427
  }
1510
1428
  // resources
1511
1429
  /**
@@ -1522,66 +1440,69 @@ function waitForAuthToken(_a) {
1522
1440
  * @param {string} [options.command] - The CLI command being executed (e.g., 'push', 'pull', 'login')
1523
1441
  * @returns {Promise<{ ok: boolean; data: any }>}
1524
1442
  */
1525
- function fetchJson(_a) {
1526
- return __awaiter(this, arguments, void 0, function* ({ debugName, errorMessage, path, body, method, noAuth, noLogError, command, }) {
1527
- const withAuth = !noAuth;
1528
- const withErrorLogging = !noLogError;
1529
- let authToken = null;
1530
- if (withAuth) {
1531
- authToken = yield readConfigAuthTokenWithErrorLogging();
1532
- if (!authToken) {
1533
- return { ok: false, data: undefined };
1534
- }
1443
+ async function fetchJson({ debugName, errorMessage, path, body, method, noAuth, noLogError, command, }) {
1444
+ const withAuth = !noAuth;
1445
+ const withErrorLogging = !noLogError;
1446
+ let authToken = null;
1447
+ if (withAuth) {
1448
+ authToken = await readConfigAuthTokenWithErrorLogging();
1449
+ if (!authToken) {
1450
+ return { ok: false, data: undefined };
1451
+ }
1452
+ }
1453
+ const timeoutMs = 1000 * 60 * 5; // 5 minutes
1454
+ try {
1455
+ const res = await fetch(`${instantBackendOrigin}${path}`, {
1456
+ method: method ?? 'GET',
1457
+ headers: {
1458
+ ...(withAuth ? { Authorization: `Bearer ${authToken}` } : {}),
1459
+ 'Content-Type': 'application/json',
1460
+ 'X-Instant-Source': 'instant-cli',
1461
+ 'X-Instant-Version': version,
1462
+ ...(command ? { 'X-Instant-Command': command } : {}),
1463
+ },
1464
+ body: body ? JSON.stringify(body) : undefined,
1465
+ signal: AbortSignal.timeout(timeoutMs),
1466
+ });
1467
+ if (verbose) {
1468
+ console.log(debugName, 'response:', res.status, res.statusText);
1535
1469
  }
1536
- const timeoutMs = 1000 * 60 * 5; // 5 minutes
1470
+ let data;
1537
1471
  try {
1538
- const res = yield fetch(`${instantBackendOrigin}${path}`, {
1539
- method: method !== null && method !== void 0 ? method : 'GET',
1540
- headers: Object.assign(Object.assign(Object.assign({}, (withAuth ? { Authorization: `Bearer ${authToken}` } : {})), { 'Content-Type': 'application/json', 'X-Instant-Source': 'instant-cli', 'X-Instant-Version': version }), (command ? { 'X-Instant-Command': command } : {})),
1541
- body: body ? JSON.stringify(body) : undefined,
1542
- signal: AbortSignal.timeout(timeoutMs),
1543
- });
1544
- if (verbose) {
1545
- console.log(debugName, 'response:', res.status, res.statusText);
1546
- }
1547
- let data;
1548
- try {
1549
- data = yield res.json();
1550
- }
1551
- catch (_b) {
1552
- data = null;
1553
- }
1554
- if (verbose && data) {
1555
- console.log(debugName, 'json:', JSON.stringify(data, null, 2));
1556
- }
1557
- if (!res.ok) {
1558
- if (withErrorLogging) {
1559
- error(errorMessage);
1560
- prettyPrintJSONErr(data);
1561
- }
1562
- return { ok: false, data };
1563
- }
1564
- return { ok: true, data };
1472
+ data = await res.json();
1473
+ }
1474
+ catch {
1475
+ data = null;
1565
1476
  }
1566
- catch (err) {
1477
+ if (verbose && data) {
1478
+ console.log(debugName, 'json:', JSON.stringify(data, null, 2));
1479
+ }
1480
+ if (!res.ok) {
1567
1481
  if (withErrorLogging) {
1568
- if (err.name === 'AbortError') {
1569
- error(`Timeout: It took more than ${timeoutMs / 60000} minutes to get the result.`);
1570
- }
1571
- else {
1572
- error(`Error: type: ${err.name}, message: ${err.message}`);
1573
- }
1482
+ error(errorMessage);
1483
+ prettyPrintJSONErr(data);
1574
1484
  }
1575
- return { ok: false, data: null };
1485
+ return { ok: false, data };
1576
1486
  }
1577
- });
1487
+ return { ok: true, data };
1488
+ }
1489
+ catch (err) {
1490
+ if (withErrorLogging) {
1491
+ if (err.name === 'AbortError') {
1492
+ error(`Timeout: It took more than ${timeoutMs / 60000} minutes to get the result.`);
1493
+ }
1494
+ else {
1495
+ error(`Error: type: ${err.name}, message: ${err.message}`);
1496
+ }
1497
+ }
1498
+ return { ok: false, data: null };
1499
+ }
1578
1500
  }
1579
1501
  function prettyPrintJSONErr(data) {
1580
- var _a;
1581
- if (data === null || data === void 0 ? void 0 : data.message) {
1502
+ if (data?.message) {
1582
1503
  error(data.message);
1583
1504
  }
1584
- if (Array.isArray((_a = data === null || data === void 0 ? void 0 : data.hint) === null || _a === void 0 ? void 0 : _a.errors)) {
1505
+ if (Array.isArray(data?.hint?.errors)) {
1585
1506
  for (const err of data.hint.errors) {
1586
1507
  error(`${err.in ? err.in.join('->') + ': ' : ''}${err.message}`);
1587
1508
  }
@@ -1590,128 +1511,109 @@ function prettyPrintJSONErr(data) {
1590
1511
  error('Failed to parse error response');
1591
1512
  }
1592
1513
  }
1593
- function readLocalPermsFile() {
1594
- return __awaiter(this, void 0, void 0, function* () {
1595
- const readCandidates = getPermsReadCandidates();
1596
- const res = yield loadConfig({
1597
- sources: readCandidates,
1598
- merge: false,
1599
- });
1600
- if (!res.config)
1601
- return;
1602
- const relativePath = path.relative(process.cwd(), res.sources[0]);
1603
- return { path: relativePath, perms: res.config };
1604
- });
1605
- }
1606
- function readLocalPermsFileWithErrorLogging() {
1607
- return __awaiter(this, void 0, void 0, function* () {
1608
- const res = yield readLocalPermsFile();
1609
- if (!res) {
1610
- error(`We couldn't find your ${chalk.yellow('`instant.perms.ts`')} file. Make sure it's in the root directory. (Hint: You can use an INSTANT_PERMS_FILE_PATH environment variable to specify it.)`);
1611
- }
1612
- return res;
1613
- });
1614
- }
1615
- function readLocalSchemaFile() {
1616
- return __awaiter(this, void 0, void 0, function* () {
1617
- const readCandidates = getSchemaReadCandidates();
1618
- const res = yield loadConfig({
1619
- sources: readCandidates,
1620
- merge: false,
1621
- });
1622
- if (!res.config)
1623
- return;
1624
- const relativePath = path.relative(process.cwd(), res.sources[0]);
1625
- return { path: relativePath, schema: res.config };
1626
- });
1627
- }
1628
- function readInstantConfigFile() {
1629
- return __awaiter(this, void 0, void 0, function* () {
1630
- return (yield loadConfig({
1631
- sources: [
1632
- // load from `instant.config.xx`
1633
- {
1634
- files: 'instant.config',
1635
- extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs', 'json'],
1636
- },
1637
- ],
1638
- // if false, the only the first matched will be loaded
1639
- // if true, all matched will be loaded and deep merged
1640
- merge: false,
1641
- })).config;
1514
+ async function readLocalPermsFile() {
1515
+ const readCandidates = getPermsReadCandidates();
1516
+ const res = await loadConfig({
1517
+ sources: readCandidates,
1518
+ merge: false,
1642
1519
  });
1520
+ if (!res.config)
1521
+ return;
1522
+ const relativePath = path.relative(process.cwd(), res.sources[0]);
1523
+ return { path: relativePath, perms: res.config };
1524
+ }
1525
+ async function readLocalPermsFileWithErrorLogging() {
1526
+ const res = await readLocalPermsFile();
1527
+ if (!res) {
1528
+ error(`We couldn't find your ${chalk.yellow('`instant.perms.ts`')} file. Make sure it's in the root directory. (Hint: You can use an INSTANT_PERMS_FILE_PATH environment variable to specify it.)`);
1529
+ }
1530
+ return res;
1643
1531
  }
1644
- function readLocalSchemaFileWithErrorLogging() {
1645
- return __awaiter(this, void 0, void 0, function* () {
1646
- var _a, _b;
1647
- const res = yield readLocalSchemaFile();
1648
- if (!res) {
1649
- error(`We couldn't find your ${chalk.yellow('`instant.schema.ts`')} file. Make sure it's in the root directory. (Hint: You can use an INSTANT_SCHEMA_FILE_PATH environment variable to specify it.)`);
1650
- return;
1651
- }
1652
- if (((_b = (_a = res.schema) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name) !== 'InstantSchemaDef') {
1653
- error("We couldn't find your schema export.");
1654
- error('In your ' +
1655
- chalk.green('`instant.schema.ts`') +
1656
- ' file, make sure you ' +
1657
- chalk.green('`export default schema`'));
1658
- return;
1659
- }
1660
- return res;
1532
+ async function readLocalSchemaFile() {
1533
+ const readCandidates = getSchemaReadCandidates();
1534
+ const res = await loadConfig({
1535
+ sources: readCandidates,
1536
+ merge: false,
1661
1537
  });
1538
+ if (!res.config)
1539
+ return;
1540
+ const relativePath = path.relative(process.cwd(), res.sources[0]);
1541
+ return { path: relativePath, schema: res.config };
1542
+ }
1543
+ async function readInstantConfigFile() {
1544
+ return (await loadConfig({
1545
+ sources: [
1546
+ // load from `instant.config.xx`
1547
+ {
1548
+ files: 'instant.config',
1549
+ extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs', 'json'],
1550
+ },
1551
+ ],
1552
+ // if false, the only the first matched will be loaded
1553
+ // if true, all matched will be loaded and deep merged
1554
+ merge: false,
1555
+ })).config;
1556
+ }
1557
+ async function readLocalSchemaFileWithErrorLogging() {
1558
+ const res = await readLocalSchemaFile();
1559
+ if (!res) {
1560
+ error(`We couldn't find your ${chalk.yellow('`instant.schema.ts`')} file. Make sure it's in the root directory. (Hint: You can use an INSTANT_SCHEMA_FILE_PATH environment variable to specify it.)`);
1561
+ return;
1562
+ }
1563
+ if (res.schema?.constructor?.name !== 'InstantSchemaDef') {
1564
+ error("We couldn't find your schema export.");
1565
+ error('In your ' +
1566
+ chalk.green('`instant.schema.ts`') +
1567
+ ' file, make sure you ' +
1568
+ chalk.green('`export default schema`'));
1569
+ return;
1570
+ }
1571
+ return res;
1662
1572
  }
1663
- function readConfigAuthToken() {
1664
- return __awaiter(this, arguments, void 0, function* (allowAdminToken = true) {
1665
- const options = program.opts();
1666
- if (typeof options.token === 'string') {
1667
- return options.token;
1668
- }
1669
- if (process.env.INSTANT_CLI_AUTH_TOKEN) {
1670
- return process.env.INSTANT_CLI_AUTH_TOKEN;
1671
- }
1672
- if (allowAdminToken) {
1673
- const adminTokenNames = Object.values(potentialAdminTokenEnvs);
1674
- for (const envName of adminTokenNames) {
1675
- const token = process.env[envName];
1676
- if (token) {
1677
- return token;
1678
- }
1573
+ async function readConfigAuthToken(allowAdminToken = true) {
1574
+ const options = program.opts();
1575
+ if (typeof options.token === 'string') {
1576
+ return options.token;
1577
+ }
1578
+ if (process.env.INSTANT_CLI_AUTH_TOKEN) {
1579
+ return process.env.INSTANT_CLI_AUTH_TOKEN;
1580
+ }
1581
+ if (allowAdminToken) {
1582
+ const adminTokenNames = Object.values(potentialAdminTokenEnvs);
1583
+ for (const envName of adminTokenNames) {
1584
+ const token = process.env[envName];
1585
+ if (token) {
1586
+ return token;
1679
1587
  }
1680
1588
  }
1681
- const authToken = yield readFile(getAuthPaths().authConfigFilePath, 'utf-8').catch(() => null);
1682
- if (authToken) {
1683
- return authToken;
1684
- }
1685
- return null;
1686
- });
1687
- }
1688
- export function readConfigAuthTokenWithErrorLogging() {
1689
- return __awaiter(this, void 0, void 0, function* () {
1690
- const token = yield readConfigAuthToken();
1691
- if (!token) {
1692
- error(`Looks like you are not logged in. Please log in with ${chalk.green('`instant-cli login`')}`);
1693
- }
1694
- return token;
1695
- });
1589
+ }
1590
+ const authToken = await readFile(getAuthPaths().authConfigFilePath, 'utf-8').catch(() => null);
1591
+ if (authToken) {
1592
+ return authToken;
1593
+ }
1594
+ return null;
1696
1595
  }
1697
- function readAuthTokenOrLoginWithErrorLogging() {
1698
- return __awaiter(this, void 0, void 0, function* () {
1699
- const token = yield readConfigAuthToken();
1700
- if (token)
1701
- return token;
1702
- console.log(`Looks like you are not logged in...`);
1703
- console.log(`Let's log in!`);
1704
- return yield login({});
1705
- });
1596
+ export async function readConfigAuthTokenWithErrorLogging() {
1597
+ const token = await readConfigAuthToken();
1598
+ if (!token) {
1599
+ error(`Looks like you are not logged in. Please log in with ${chalk.green('`instant-cli login`')}`);
1600
+ }
1601
+ return token;
1706
1602
  }
1707
- function saveConfigAuthToken(authToken) {
1708
- return __awaiter(this, void 0, void 0, function* () {
1709
- const authPaths = getAuthPaths();
1710
- yield mkdir(authPaths.appConfigDirPath, {
1711
- recursive: true,
1712
- });
1713
- return writeFile(authPaths.authConfigFilePath, authToken, 'utf-8');
1603
+ async function readAuthTokenOrLoginWithErrorLogging() {
1604
+ const token = await readConfigAuthToken();
1605
+ if (token)
1606
+ return token;
1607
+ console.log(`Looks like you are not logged in...`);
1608
+ console.log(`Let's log in!`);
1609
+ return await login({});
1610
+ }
1611
+ async function saveConfigAuthToken(authToken) {
1612
+ const authPaths = getAuthPaths();
1613
+ await mkdir(authPaths.appConfigDirPath, {
1614
+ recursive: true,
1714
1615
  });
1616
+ return writeFile(authPaths.authConfigFilePath, authToken, 'utf-8');
1715
1617
  }
1716
1618
  // utils
1717
1619
  function sleep(ms) {
@@ -1737,20 +1639,16 @@ function identName(ident) {
1737
1639
  return `${identEtype(ident)}.${identLabel(ident)}`;
1738
1640
  }
1739
1641
  function attrFwdLabel(attr) {
1740
- var _a;
1741
- return (_a = attr['forward-identity']) === null || _a === void 0 ? void 0 : _a[2];
1642
+ return attr['forward-identity']?.[2];
1742
1643
  }
1743
1644
  function attrFwdEtype(attr) {
1744
- var _a;
1745
- return (_a = attr['forward-identity']) === null || _a === void 0 ? void 0 : _a[1];
1645
+ return attr['forward-identity']?.[1];
1746
1646
  }
1747
1647
  function attrRevLabel(attr) {
1748
- var _a;
1749
- return (_a = attr['reverse-identity']) === null || _a === void 0 ? void 0 : _a[2];
1648
+ return attr['reverse-identity']?.[2];
1750
1649
  }
1751
1650
  function attrRevEtype(attr) {
1752
- var _a;
1753
- return (_a = attr['reverse-identity']) === null || _a === void 0 ? void 0 : _a[1];
1651
+ return attr['reverse-identity']?.[1];
1754
1652
  }
1755
1653
  function attrFwdName(attr) {
1756
1654
  return `${attrFwdEtype(attr)}.${attrFwdLabel(attr)}`;
@@ -1771,26 +1669,23 @@ function isUUID(uuid) {
1771
1669
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1772
1670
  return uuidRegex.test(uuid);
1773
1671
  }
1774
- function detectAppIdFromOptsWithErrorLogging(opts) {
1775
- return __awaiter(this, void 0, void 0, function* () {
1776
- var _a;
1777
- if (!opts.app)
1778
- return { ok: true };
1779
- const appId = opts.app;
1780
- const config = yield readInstantConfigFile();
1781
- const nameMatch = (_a = config === null || config === void 0 ? void 0 : config.apps) === null || _a === void 0 ? void 0 : _a[appId];
1782
- const namedAppId = (nameMatch === null || nameMatch === void 0 ? void 0 : nameMatch.id) && isUUID(nameMatch.id) ? nameMatch : null;
1783
- const uuidAppId = appId && isUUID(appId) ? appId : null;
1784
- if (nameMatch && !namedAppId) {
1785
- error(`Expected \`${appId}\` to point to a UUID, but got ${nameMatch.id}.`);
1786
- return { ok: false };
1787
- }
1788
- if (!namedAppId && !uuidAppId) {
1789
- error(`Expected App ID to be a UUID, but got: ${chalk.red(appId)}`);
1790
- return { ok: false };
1791
- }
1792
- return { ok: true, appId: namedAppId || uuidAppId };
1793
- });
1672
+ async function detectAppIdFromOptsWithErrorLogging(opts) {
1673
+ if (!opts.app)
1674
+ return { ok: true };
1675
+ const appId = opts.app;
1676
+ const config = await readInstantConfigFile();
1677
+ const nameMatch = config?.apps?.[appId];
1678
+ const namedAppId = nameMatch?.id && isUUID(nameMatch.id) ? nameMatch : null;
1679
+ const uuidAppId = appId && isUUID(appId) ? appId : null;
1680
+ if (nameMatch && !namedAppId) {
1681
+ error(`Expected \`${appId}\` to point to a UUID, but got ${nameMatch.id}.`);
1682
+ return { ok: false };
1683
+ }
1684
+ if (!namedAppId && !uuidAppId) {
1685
+ error(`Expected App ID to be a UUID, but got: ${chalk.red(appId)}`);
1686
+ return { ok: false };
1687
+ }
1688
+ return { ok: true, appId: namedAppId || uuidAppId };
1794
1689
  }
1795
1690
  function detectAppIdFromEnvWithErrorLogging() {
1796
1691
  const found = Object.keys(potentialEnvs)