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