instant-cli 0.22.98-experimental.highl.20766596946.1 → 0.22.99-experimental.add-user-perm-rules.20792844601.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/index.js +1146 -1041
- package/dist/index.js.map +1 -1
- package/dist/rename.js +69 -58
- package/dist/rename.js.map +1 -1
- package/dist/renderSchemaPlan.js +22 -10
- package/dist/renderSchemaPlan.js.map +1 -1
- package/dist/ui/index.js +102 -115
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/lib.js +30 -29
- package/dist/ui/lib.js.map +1 -1
- package/dist/util/fs.js +30 -17
- package/dist/util/fs.js.map +1 -1
- package/dist/util/isHeadlessEnvironment.js +1 -1
- package/dist/util/isHeadlessEnvironment.js.map +1 -1
- package/dist/util/loadConfig.js +32 -32
- package/dist/util/loadConfig.js.map +1 -1
- package/dist/util/packageManager.js +37 -26
- package/dist/util/packageManager.js.map +1 -1
- package/dist/util/projectDir.js +27 -16
- package/dist/util/projectDir.js.map +1 -1
- package/dist/util/promptOk.js +21 -14
- package/dist/util/promptOk.js.map +1 -1
- package/dist/util/renamePrompt.js +2 -4
- package/dist/util/renamePrompt.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
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
|
+
};
|
|
1
10
|
// @ts-check
|
|
2
11
|
import { generatePermsTypescriptFile, apiSchemaToInstantSchemaDef, generateSchemaTypescriptFile, diffSchemas, convertTxSteps, validateSchema, SchemaValidationError, PlatformApi, } from '@instantdb/platform';
|
|
3
12
|
import version from './version.js';
|
|
@@ -56,27 +65,30 @@ const potentialAdminTokenEnvs = {
|
|
|
56
65
|
default: 'INSTANT_APP_ADMIN_TOKEN',
|
|
57
66
|
short: 'INSTANT_ADMIN_TOKEN',
|
|
58
67
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
+
}
|
|
62
90
|
return 'catchall';
|
|
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';
|
|
91
|
+
});
|
|
80
92
|
}
|
|
81
93
|
const instantDashOrigin = dev
|
|
82
94
|
? 'http://localhost:3000'
|
|
@@ -102,13 +114,15 @@ function convertPushPullToCurrentFormat(arg, opts) {
|
|
|
102
114
|
return { ok: false };
|
|
103
115
|
return { ok: true, bag, opts };
|
|
104
116
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
+
});
|
|
112
126
|
}
|
|
113
127
|
// cli
|
|
114
128
|
// Header -- this shows up in every command
|
|
@@ -244,16 +258,16 @@ program
|
|
|
244
258
|
.description('Log into your account')
|
|
245
259
|
.option('-p --print', 'Prints the auth token into the console.')
|
|
246
260
|
.option('--headless', 'Print the login URL instead of trying to open the browser')
|
|
247
|
-
.action(
|
|
261
|
+
.action((opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
248
262
|
console.log("Let's log you in!");
|
|
249
|
-
|
|
250
|
-
});
|
|
263
|
+
yield login(opts);
|
|
264
|
+
}));
|
|
251
265
|
program
|
|
252
266
|
.command('logout')
|
|
253
267
|
.description('Log out of your Instant account')
|
|
254
|
-
.action(
|
|
255
|
-
|
|
256
|
-
});
|
|
268
|
+
.action(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
269
|
+
yield logout();
|
|
270
|
+
}));
|
|
257
271
|
program
|
|
258
272
|
.command('init')
|
|
259
273
|
.description('Set up a new project.')
|
|
@@ -276,10 +290,10 @@ program
|
|
|
276
290
|
.argument('[app-id]')
|
|
277
291
|
.description('Push schema to production.')
|
|
278
292
|
.option('--skip-check-types', "Don't check types on the server when pushing schema")
|
|
279
|
-
.action(
|
|
293
|
+
.action((appIdOrName, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
280
294
|
warnDeprecation('push-schema', 'push schema');
|
|
281
|
-
|
|
282
|
-
});
|
|
295
|
+
yield handlePush('schema', Object.assign({ app: appIdOrName }, opts));
|
|
296
|
+
}));
|
|
283
297
|
// Note: Nov 20, 2024
|
|
284
298
|
// We can eventually delete this,
|
|
285
299
|
// once we know most people use the new pull and push commands
|
|
@@ -287,10 +301,10 @@ program
|
|
|
287
301
|
.command('push-perms', { hidden: true })
|
|
288
302
|
.argument('[app-id]')
|
|
289
303
|
.description('Push perms to production.')
|
|
290
|
-
.action(
|
|
304
|
+
.action((appIdOrName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
291
305
|
warnDeprecation('push-perms', 'push perms');
|
|
292
|
-
|
|
293
|
-
});
|
|
306
|
+
yield handlePush('perms', { app: appIdOrName });
|
|
307
|
+
}));
|
|
294
308
|
program
|
|
295
309
|
.command('push')
|
|
296
310
|
.argument('[schema|perms|all]', 'Which configuration to push. Defaults to `all`')
|
|
@@ -304,12 +318,14 @@ Environment Variables:
|
|
|
304
318
|
INSTANT_SCHEMA_FILE_PATH Override schema file location (default: instant.schema.ts)
|
|
305
319
|
INSTANT_PERMS_FILE_PATH Override perms file location (default: instant.perms.ts)
|
|
306
320
|
`)
|
|
307
|
-
.action(
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
+
});
|
|
313
329
|
});
|
|
314
330
|
// Note: Nov 20, 2024
|
|
315
331
|
// We can eventually delete this,
|
|
@@ -318,10 +334,10 @@ program
|
|
|
318
334
|
.command('pull-schema', { hidden: true })
|
|
319
335
|
.argument('[app-id]')
|
|
320
336
|
.description('Generate instant.schema.ts from production')
|
|
321
|
-
.action(
|
|
337
|
+
.action((appIdOrName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
322
338
|
warnDeprecation('pull-schema', 'pull schema');
|
|
323
|
-
|
|
324
|
-
});
|
|
339
|
+
yield handlePull('schema', { app: appIdOrName });
|
|
340
|
+
}));
|
|
325
341
|
// Note: Nov 20, 2024
|
|
326
342
|
// We can eventually delete this,
|
|
327
343
|
// once we know most people use the new pull and push commands
|
|
@@ -329,10 +345,10 @@ program
|
|
|
329
345
|
.command('pull-perms', { hidden: true })
|
|
330
346
|
.argument('[app-id]')
|
|
331
347
|
.description('Generate instant.perms.ts from production.')
|
|
332
|
-
.action(
|
|
348
|
+
.action((appIdOrName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
333
349
|
warnDeprecation('pull-perms', 'pull perms');
|
|
334
|
-
|
|
335
|
-
});
|
|
350
|
+
yield handlePull('perms', { app: appIdOrName });
|
|
351
|
+
}));
|
|
336
352
|
program
|
|
337
353
|
.command('pull')
|
|
338
354
|
.argument('[schema|perms|all]', 'Which configuration to push. Defaults to `all`')
|
|
@@ -345,159 +361,173 @@ Environment Variables:
|
|
|
345
361
|
INSTANT_SCHEMA_FILE_PATH Override schema file location (default: instant.schema.ts)
|
|
346
362
|
INSTANT_PERMS_FILE_PATH Override perms file location (default: instant.perms.ts)
|
|
347
363
|
`)
|
|
348
|
-
.action(
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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
|
+
});
|
|
354
372
|
});
|
|
355
373
|
program
|
|
356
374
|
.command('claim')
|
|
357
375
|
.description('Transfer a tempoary app into your Instant account')
|
|
358
|
-
.action(
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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);
|
|
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);
|
|
402
382
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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);
|
|
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);
|
|
417
389
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
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.`);
|
|
390
|
+
if (!envResult.adminToken) {
|
|
391
|
+
error('No admin token found in environment variables.');
|
|
392
|
+
return process.exit(1);
|
|
425
393
|
}
|
|
426
|
-
|
|
427
|
-
|
|
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);
|
|
428
409
|
}
|
|
429
|
-
if
|
|
430
|
-
|
|
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);
|
|
431
415
|
}
|
|
432
|
-
|
|
433
|
-
|
|
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
|
+
}
|
|
434
424
|
}
|
|
435
|
-
|
|
436
|
-
if
|
|
437
|
-
|
|
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);
|
|
438
430
|
}
|
|
439
431
|
else {
|
|
440
|
-
|
|
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
|
+
}
|
|
441
439
|
}
|
|
442
|
-
|
|
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
|
-
}
|
|
440
|
+
});
|
|
456
441
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
+
});
|
|
483
480
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const
|
|
487
|
-
if (!
|
|
481
|
+
function handlePush(bag, opts) {
|
|
482
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
483
|
+
const pkgAndAuthInfo = yield enforcePackageAndAuthInfoWithErrorLogging(opts);
|
|
484
|
+
if (!pkgAndAuthInfo)
|
|
488
485
|
return process.exit(1);
|
|
489
|
-
|
|
490
|
-
if (bag === 'perms' || bag === 'all') {
|
|
491
|
-
const { ok } = await pushPerms(appId);
|
|
486
|
+
const { ok, appId } = yield detectAppWithErrorLogging(opts);
|
|
492
487
|
if (!ok)
|
|
493
488
|
return process.exit(1);
|
|
494
|
-
|
|
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) {
|
|
503
|
+
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
|
+
});
|
|
495
525
|
}
|
|
496
526
|
function printDotEnvInfo(envType, appId) {
|
|
497
527
|
console.log(`\nPicked app ${chalk.green(appId)}!\n`);
|
|
498
528
|
console.log(`To use this app automatically from now on, update your ${chalk.green('`.env`')} file:`);
|
|
499
529
|
const picked = potentialEnvs[envType];
|
|
500
|
-
const rest = {
|
|
530
|
+
const rest = Object.assign({}, potentialEnvs);
|
|
501
531
|
delete rest[envType];
|
|
502
532
|
console.log(` ${chalk.green(picked)}=${appId}`);
|
|
503
533
|
const otherEnvs = Object.values(rest);
|
|
@@ -506,121 +536,132 @@ function printDotEnvInfo(envType, appId) {
|
|
|
506
536
|
console.log(`Alternative names: \n${otherEnvStr} \n`);
|
|
507
537
|
console.log(terminalLink('Dashboard:', appDashUrl(appId)) + '\n');
|
|
508
538
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
[
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
+
});
|
|
544
577
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
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
|
+
}
|
|
548
587
|
return ret;
|
|
549
|
-
|
|
550
|
-
if (source === 'created' || source === 'imported') {
|
|
551
|
-
await handleEnvFile(pkgAndAuthInfo, { appId, appToken });
|
|
552
|
-
}
|
|
553
|
-
return ret;
|
|
588
|
+
});
|
|
554
589
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
+
});
|
|
603
|
+
}
|
|
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) {
|
|
559
615
|
return process.exit(1);
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
if (
|
|
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) {
|
|
564
634
|
return process.exit(1);
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
|
|
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!'));
|
|
635
|
+
}
|
|
636
|
+
const { token, email } = authTokenRes;
|
|
637
|
+
if (options.print) {
|
|
638
|
+
console.log(chalk.red('[Do not share] Your Instant auth token:', token));
|
|
618
639
|
}
|
|
619
640
|
else {
|
|
620
|
-
|
|
641
|
+
yield saveConfigAuthToken(token);
|
|
642
|
+
console.log(chalk.green(`Successfully logged in as ${email}!`));
|
|
621
643
|
}
|
|
622
|
-
return
|
|
623
|
-
}
|
|
644
|
+
return token;
|
|
645
|
+
});
|
|
646
|
+
}
|
|
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;
|
|
654
|
+
}
|
|
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;
|
|
663
|
+
}
|
|
664
|
+
});
|
|
624
665
|
}
|
|
625
666
|
const packageAliasAndFullNames = {
|
|
626
667
|
react: '@instantdb/react',
|
|
@@ -628,376 +669,404 @@ const packageAliasAndFullNames = {
|
|
|
628
669
|
core: '@instantdb/core',
|
|
629
670
|
admin: '@instantdb/admin',
|
|
630
671
|
};
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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);
|
|
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;
|
|
651
678
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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');
|
|
712
|
+
}
|
|
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}.`,
|
|
663
718
|
}));
|
|
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',
|
|
719
|
+
return moduleName;
|
|
702
720
|
});
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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,
|
|
716
|
-
}));
|
|
717
|
-
if (choice) {
|
|
718
|
-
org_id = choice;
|
|
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;
|
|
719
729
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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
|
+
};
|
|
729
784
|
});
|
|
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
|
-
};
|
|
739
785
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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,
|
|
770
819
|
},
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
};
|
|
820
|
+
}));
|
|
821
|
+
return {
|
|
822
|
+
ok: true,
|
|
823
|
+
appId: result.appId,
|
|
824
|
+
appToken: result.adminToken,
|
|
825
|
+
source: result.approach === 'import' ? 'imported' : 'created',
|
|
826
|
+
};
|
|
827
|
+
});
|
|
780
828
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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 };
|
|
792
845
|
});
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
return
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
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);
|
|
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' };
|
|
832
861
|
}
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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
|
+
});
|
|
840
872
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
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
|
+
}
|
|
846
895
|
});
|
|
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;
|
|
870
896
|
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
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);
|
|
902
|
+
});
|
|
903
|
+
}
|
|
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;
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
function getPackageJson(pkgDir) {
|
|
918
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
919
|
+
return yield readJsonFile(join(pkgDir, 'package.json'));
|
|
920
|
+
});
|
|
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;
|
|
928
|
+
}
|
|
929
|
+
return pkgJson;
|
|
930
|
+
});
|
|
931
|
+
}
|
|
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();
|
|
880
961
|
if (!authToken) {
|
|
881
962
|
return;
|
|
882
963
|
}
|
|
883
|
-
return {
|
|
884
|
-
|
|
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 };
|
|
964
|
+
return { pkgDir, projectType, instantModuleName, authToken };
|
|
965
|
+
});
|
|
903
966
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
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();
|
|
913
992
|
if (!authToken) {
|
|
914
993
|
return;
|
|
915
994
|
}
|
|
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',
|
|
995
|
+
return { pkgDir, projectType, instantModuleName, authToken };
|
|
940
996
|
});
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
if (!shouldContinue)
|
|
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.');
|
|
957
1012
|
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);
|
|
966
1013
|
}
|
|
967
|
-
|
|
968
|
-
|
|
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 };
|
|
969
1024
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
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 };
|
|
1063
|
+
}
|
|
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 };
|
|
982
1069
|
});
|
|
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 };
|
|
1001
1070
|
}
|
|
1002
1071
|
function indexingJobCompletedActionMessage(job) {
|
|
1003
1072
|
if (job.job_type === 'check-data-type') {
|
|
@@ -1034,7 +1103,7 @@ function truncate(s, maxLen) {
|
|
|
1034
1103
|
}
|
|
1035
1104
|
function formatSamples(triples_samples) {
|
|
1036
1105
|
return triples_samples.slice(0, 3).map((t) => {
|
|
1037
|
-
return {
|
|
1106
|
+
return Object.assign(Object.assign({}, t), { value: truncate(JSON.stringify(t.value), 32) });
|
|
1038
1107
|
});
|
|
1039
1108
|
}
|
|
1040
1109
|
function createUrl(triple, job) {
|
|
@@ -1055,6 +1124,7 @@ function padCell(value, width) {
|
|
|
1055
1124
|
return trimmed + ' '.repeat(width - trimmed.length);
|
|
1056
1125
|
}
|
|
1057
1126
|
function indexingJobCompletedMessage(job) {
|
|
1127
|
+
var _a;
|
|
1058
1128
|
const actionMessage = indexingJobCompletedActionMessage(job);
|
|
1059
1129
|
if (job.job_status === 'canceled') {
|
|
1060
1130
|
return `Canceled ${actionMessage} before it could finish.`;
|
|
@@ -1063,7 +1133,7 @@ function indexingJobCompletedMessage(job) {
|
|
|
1063
1133
|
return `Finished ${actionMessage}.`;
|
|
1064
1134
|
}
|
|
1065
1135
|
if (job.job_status === 'errored') {
|
|
1066
|
-
if (job.invalid_triples_sample
|
|
1136
|
+
if ((_a = job.invalid_triples_sample) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1067
1137
|
const [etype, label] = job.attr_name.split('.');
|
|
1068
1138
|
const samples = formatSamples(job.invalid_triples_sample);
|
|
1069
1139
|
const longestValue = samples.reduce((acc, { value }) => Math.max(acc, value.length), label.length);
|
|
@@ -1131,85 +1201,88 @@ function jobGroupDescription(jobs) {
|
|
|
1131
1201
|
}
|
|
1132
1202
|
return joinInSentence([...actions].sort()) || 'updating schema';
|
|
1133
1203
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
lastUpdatedAt
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
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
|
+
}
|
|
1174
1247
|
}
|
|
1175
1248
|
}
|
|
1176
1249
|
}
|
|
1177
1250
|
}
|
|
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;
|
|
1178
1271
|
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
if (
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
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;
|
|
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);
|
|
1197
1281
|
}
|
|
1198
|
-
|
|
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
|
-
}
|
|
1282
|
+
});
|
|
1210
1283
|
}
|
|
1211
|
-
const resolveRenames =
|
|
1212
|
-
const answer =
|
|
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([
|
|
1213
1286
|
(out) => boxen(out, {
|
|
1214
1287
|
dimBorder: true,
|
|
1215
1288
|
padding: {
|
|
@@ -1220,7 +1293,7 @@ const resolveRenames = async (created, promptData, extraInfo) => {
|
|
|
1220
1293
|
UI.modifiers.vanishOnComplete,
|
|
1221
1294
|
])));
|
|
1222
1295
|
return answer;
|
|
1223
|
-
};
|
|
1296
|
+
});
|
|
1224
1297
|
function collectSystemCatalogIdentNames(currentAttrs) {
|
|
1225
1298
|
const allSystemIdents = currentAttrs
|
|
1226
1299
|
.filter((attr) => attr.catalog === 'system')
|
|
@@ -1233,64 +1306,151 @@ function collectSystemCatalogIdentNames(currentAttrs) {
|
|
|
1233
1306
|
}
|
|
1234
1307
|
return res;
|
|
1235
1308
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
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
|
+
}
|
|
1262
1404
|
}
|
|
1263
1405
|
else {
|
|
1264
|
-
console.
|
|
1406
|
+
console.info('Schema migration cancelled!');
|
|
1265
1407
|
}
|
|
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!'));
|
|
1278
1408
|
return { ok: true };
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
const
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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 };
|
|
1287
1435
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
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 };
|
|
1449
|
+
}
|
|
1450
|
+
const okPush = yield promptOk({
|
|
1451
|
+
promptText: 'Push these changes to your perms?',
|
|
1292
1452
|
modifyOutput: (output) => {
|
|
1293
|
-
let both =
|
|
1453
|
+
let both = diffedStr + '\n' + output;
|
|
1294
1454
|
return boxen(both, {
|
|
1295
1455
|
dimBorder: true,
|
|
1296
1456
|
padding: {
|
|
@@ -1300,130 +1460,52 @@ async function pushSchema(appId, opts) {
|
|
|
1300
1460
|
});
|
|
1301
1461
|
},
|
|
1302
1462
|
}, program.opts());
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
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({
|
|
1463
|
+
if (!okPush)
|
|
1464
|
+
return { ok: true };
|
|
1465
|
+
const permsRes = yield fetchJson({
|
|
1315
1466
|
method: 'POST',
|
|
1316
|
-
path: `/dash/apps/${appId}/
|
|
1467
|
+
path: `/dash/apps/${appId}/rules`,
|
|
1317
1468
|
debugName: 'Schema apply',
|
|
1318
1469
|
errorMessage: 'Failed to update schema.',
|
|
1319
1470
|
body: {
|
|
1320
|
-
|
|
1471
|
+
code: res.perms,
|
|
1321
1472
|
},
|
|
1322
1473
|
command: 'push',
|
|
1323
1474
|
});
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
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',
|
|
1347
|
-
});
|
|
1348
|
-
if (!res.ok)
|
|
1349
|
-
return res;
|
|
1350
|
-
console.log(chalk.green('App claimed!'));
|
|
1351
|
-
return { ok: true };
|
|
1352
|
-
}
|
|
1353
|
-
async function pushPerms(appId) {
|
|
1354
|
-
const res = await readLocalPermsFileWithErrorLogging();
|
|
1355
|
-
if (!res) {
|
|
1475
|
+
if (!permsRes.ok)
|
|
1476
|
+
return permsRes;
|
|
1477
|
+
console.log(chalk.green('Permissions updated!'));
|
|
1356
1478
|
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
1479
|
});
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
right: 1,
|
|
1381
|
-
},
|
|
1480
|
+
}
|
|
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',
|
|
1382
1495
|
});
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
body: {
|
|
1393
|
-
code: res.perms,
|
|
1394
|
-
},
|
|
1395
|
-
command: 'push',
|
|
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;
|
|
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;
|
|
1420
1505
|
}
|
|
1421
|
-
error('
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
}
|
|
1425
|
-
error('Timed out waiting for authentication');
|
|
1426
|
-
return null;
|
|
1506
|
+
error('Timed out waiting for authentication');
|
|
1507
|
+
return null;
|
|
1508
|
+
});
|
|
1427
1509
|
}
|
|
1428
1510
|
// resources
|
|
1429
1511
|
/**
|
|
@@ -1440,69 +1522,66 @@ async function waitForAuthToken({ secret }) {
|
|
|
1440
1522
|
* @param {string} [options.command] - The CLI command being executed (e.g., 'push', 'pull', 'login')
|
|
1441
1523
|
* @returns {Promise<{ ok: boolean; data: any }>}
|
|
1442
1524
|
*/
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
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);
|
|
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
|
+
}
|
|
1469
1535
|
}
|
|
1470
|
-
|
|
1536
|
+
const timeoutMs = 1000 * 60 * 5; // 5 minutes
|
|
1471
1537
|
try {
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
if (!res.ok) {
|
|
1481
|
-
if (withErrorLogging) {
|
|
1482
|
-
error(errorMessage);
|
|
1483
|
-
prettyPrintJSONErr(data);
|
|
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);
|
|
1484
1546
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
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.`);
|
|
1547
|
+
let data;
|
|
1548
|
+
try {
|
|
1549
|
+
data = yield res.json();
|
|
1493
1550
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
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 };
|
|
1496
1563
|
}
|
|
1564
|
+
return { ok: true, data };
|
|
1497
1565
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1566
|
+
catch (err) {
|
|
1567
|
+
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
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
return { ok: false, data: null };
|
|
1576
|
+
}
|
|
1577
|
+
});
|
|
1500
1578
|
}
|
|
1501
1579
|
function prettyPrintJSONErr(data) {
|
|
1502
|
-
|
|
1580
|
+
var _a;
|
|
1581
|
+
if (data === null || data === void 0 ? void 0 : data.message) {
|
|
1503
1582
|
error(data.message);
|
|
1504
1583
|
}
|
|
1505
|
-
if (Array.isArray(data
|
|
1584
|
+
if (Array.isArray((_a = data === null || data === void 0 ? void 0 : data.hint) === null || _a === void 0 ? void 0 : _a.errors)) {
|
|
1506
1585
|
for (const err of data.hint.errors) {
|
|
1507
1586
|
error(`${err.in ? err.in.join('->') + ': ' : ''}${err.message}`);
|
|
1508
1587
|
}
|
|
@@ -1511,109 +1590,128 @@ function prettyPrintJSONErr(data) {
|
|
|
1511
1590
|
error('Failed to parse error response');
|
|
1512
1591
|
}
|
|
1513
1592
|
}
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
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 };
|
|
1519
1604
|
});
|
|
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;
|
|
1531
1605
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
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;
|
|
1537
1613
|
});
|
|
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;
|
|
1572
1614
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
const
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
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;
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
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;
|
|
1588
1651
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
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;
|
|
1661
|
+
});
|
|
1595
1662
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
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
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
const authToken = yield readFile(getAuthPaths().authConfigFilePath, 'utf-8').catch(() => null);
|
|
1682
|
+
if (authToken) {
|
|
1683
|
+
return authToken;
|
|
1684
|
+
}
|
|
1685
|
+
return null;
|
|
1686
|
+
});
|
|
1602
1687
|
}
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
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
|
+
}
|
|
1606
1694
|
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,
|
|
1615
1695
|
});
|
|
1616
|
-
|
|
1696
|
+
}
|
|
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
|
+
});
|
|
1706
|
+
}
|
|
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');
|
|
1714
|
+
});
|
|
1617
1715
|
}
|
|
1618
1716
|
// utils
|
|
1619
1717
|
function sleep(ms) {
|
|
@@ -1639,16 +1737,20 @@ function identName(ident) {
|
|
|
1639
1737
|
return `${identEtype(ident)}.${identLabel(ident)}`;
|
|
1640
1738
|
}
|
|
1641
1739
|
function attrFwdLabel(attr) {
|
|
1642
|
-
|
|
1740
|
+
var _a;
|
|
1741
|
+
return (_a = attr['forward-identity']) === null || _a === void 0 ? void 0 : _a[2];
|
|
1643
1742
|
}
|
|
1644
1743
|
function attrFwdEtype(attr) {
|
|
1645
|
-
|
|
1744
|
+
var _a;
|
|
1745
|
+
return (_a = attr['forward-identity']) === null || _a === void 0 ? void 0 : _a[1];
|
|
1646
1746
|
}
|
|
1647
1747
|
function attrRevLabel(attr) {
|
|
1648
|
-
|
|
1748
|
+
var _a;
|
|
1749
|
+
return (_a = attr['reverse-identity']) === null || _a === void 0 ? void 0 : _a[2];
|
|
1649
1750
|
}
|
|
1650
1751
|
function attrRevEtype(attr) {
|
|
1651
|
-
|
|
1752
|
+
var _a;
|
|
1753
|
+
return (_a = attr['reverse-identity']) === null || _a === void 0 ? void 0 : _a[1];
|
|
1652
1754
|
}
|
|
1653
1755
|
function attrFwdName(attr) {
|
|
1654
1756
|
return `${attrFwdEtype(attr)}.${attrFwdLabel(attr)}`;
|
|
@@ -1669,23 +1771,26 @@ function isUUID(uuid) {
|
|
|
1669
1771
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1670
1772
|
return uuidRegex.test(uuid);
|
|
1671
1773
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
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
|
+
});
|
|
1689
1794
|
}
|
|
1690
1795
|
function detectAppIdFromEnvWithErrorLogging() {
|
|
1691
1796
|
const found = Object.keys(potentialEnvs)
|