instant-cli 0.22.177 → 0.22.178
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 +2 -2
- package/__tests__/e2e/cli.e2e.test.ts +3 -3
- package/__tests__/e2e/helpers.ts +1 -1
- package/__tests__/effectHelpers.ts +45 -0
- package/__tests__/mergeSchema.test.ts +2 -2
- package/dist/commands/claim.d.ts +6 -0
- package/dist/commands/claim.d.ts.map +1 -0
- package/dist/commands/claim.js +22 -0
- package/dist/commands/claim.js.map +1 -0
- package/dist/commands/explorer.d.ts +6 -0
- package/dist/commands/explorer.d.ts.map +1 -0
- package/dist/commands/explorer.js +13 -0
- package/dist/commands/explorer.js.map +1 -0
- package/dist/commands/info.d.ts +3 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +24 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +39 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/initWithoutFiles.d.ts +6 -0
- package/dist/commands/initWithoutFiles.d.ts.map +1 -0
- package/dist/commands/initWithoutFiles.js +64 -0
- package/dist/commands/initWithoutFiles.js.map +1 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +52 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +4 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +21 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/pull.d.ts +6 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +16 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +6 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +20 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/query.d.ts +7 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +52 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/context/authToken.d.ts +30 -0
- package/dist/context/authToken.d.ts.map +1 -0
- package/dist/context/authToken.js +86 -0
- package/dist/context/authToken.js.map +1 -0
- package/dist/context/currentApp.d.ts +37 -0
- package/dist/context/currentApp.d.ts.map +1 -0
- package/dist/context/currentApp.js +204 -0
- package/dist/context/currentApp.js.map +1 -0
- package/dist/context/globalOpts.d.ts +11 -0
- package/dist/context/globalOpts.d.ts.map +1 -0
- package/dist/context/globalOpts.js +13 -0
- package/dist/context/globalOpts.js.map +1 -0
- package/dist/context/platformApi.d.ts +19 -0
- package/dist/context/platformApi.d.ts.map +1 -0
- package/dist/context/platformApi.js +24 -0
- package/dist/context/platformApi.js.map +1 -0
- package/dist/context/projectInfo.d.ts +29 -0
- package/dist/context/projectInfo.d.ts.map +1 -0
- package/dist/context/projectInfo.js +149 -0
- package/dist/context/projectInfo.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +6 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +41 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +169 -1781
- package/dist/index.js.map +1 -1
- package/dist/layer.d.ts +23 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +68 -0
- package/dist/layer.js.map +1 -0
- package/dist/lib/createApp.d.ts +12 -0
- package/dist/lib/createApp.d.ts.map +1 -0
- package/dist/lib/createApp.js +15 -0
- package/dist/lib/createApp.js.map +1 -0
- package/dist/lib/handleEnv.d.ts +7 -0
- package/dist/lib/handleEnv.d.ts.map +1 -0
- package/dist/lib/handleEnv.js +91 -0
- package/dist/lib/handleEnv.js.map +1 -0
- package/dist/lib/http.d.ts +32 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +67 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/login.d.ts +13 -0
- package/dist/lib/login.d.ts.map +1 -0
- package/dist/lib/login.js +39 -0
- package/dist/lib/login.js.map +1 -0
- package/dist/lib/pullPerms.d.ts +7 -0
- package/dist/lib/pullPerms.d.ts.map +1 -0
- package/dist/lib/pullPerms.js +41 -0
- package/dist/lib/pullPerms.js.map +1 -0
- package/dist/lib/pullSchema.d.ts +12 -0
- package/dist/lib/pullSchema.d.ts.map +1 -0
- package/dist/lib/pullSchema.js +62 -0
- package/dist/lib/pullSchema.js.map +1 -0
- package/dist/lib/pushPerms.d.ts +13 -0
- package/dist/lib/pushPerms.d.ts.map +1 -0
- package/dist/lib/pushPerms.js +54 -0
- package/dist/lib/pushPerms.js.map +1 -0
- package/dist/lib/pushSchema.d.ts +53 -0
- package/dist/lib/pushSchema.d.ts.map +1 -0
- package/dist/lib/pushSchema.js +160 -0
- package/dist/lib/pushSchema.js.map +1 -0
- package/dist/lib/ui.d.ts +16 -0
- package/dist/lib/ui.d.ts.map +1 -0
- package/dist/lib/ui.js +22 -0
- package/dist/lib/ui.js.map +1 -0
- package/dist/logging.d.ts +4 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +17 -0
- package/dist/logging.js.map +1 -0
- package/dist/old.d.ts +14 -0
- package/dist/old.d.ts.map +1 -0
- package/dist/old.js +417 -0
- package/dist/old.js.map +1 -0
- package/dist/program.d.ts +3 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +3 -0
- package/dist/program.js.map +1 -0
- package/dist/renderSchemaPlan.d.ts +3 -3
- package/dist/renderSchemaPlan.d.ts.map +1 -1
- package/dist/renderSchemaPlan.js +2 -14
- package/dist/renderSchemaPlan.js.map +1 -1
- package/dist/ui/index.d.ts +4 -3
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +2 -2
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/lib.js +1 -0
- package/dist/ui/lib.js.map +1 -1
- package/dist/util/findConfigCandidates.d.ts +1 -1
- package/dist/util/findConfigCandidates.d.ts.map +1 -1
- package/dist/util/findConfigCandidates.js +1 -3
- package/dist/util/findConfigCandidates.js.map +1 -1
- package/dist/util/fs.d.ts +1 -1
- package/dist/util/fs.d.ts.map +1 -1
- package/dist/util/fs.js.map +1 -1
- package/dist/util/getAuthPaths.d.ts.map +1 -1
- package/dist/util/getAuthPaths.js.map +1 -1
- package/dist/util/isHeadlessEnvironment.d.ts +3 -1
- package/dist/util/isHeadlessEnvironment.d.ts.map +1 -1
- package/dist/util/isHeadlessEnvironment.js.map +1 -1
- package/dist/util/loadConfig.d.ts +1 -1
- package/dist/util/loadConfig.d.ts.map +1 -1
- package/dist/util/loadConfig.js +2 -2
- package/dist/util/loadConfig.js.map +1 -1
- package/dist/util/mergeSchema.d.ts +9 -1
- package/dist/util/mergeSchema.d.ts.map +1 -1
- package/dist/util/mergeSchema.js +4 -0
- package/dist/util/mergeSchema.js.map +1 -1
- package/dist/util/renamePrompt.d.ts +2 -1
- package/dist/util/renamePrompt.d.ts.map +1 -1
- package/dist/util/renamePrompt.js +1 -1
- package/dist/util/renamePrompt.js.map +1 -1
- package/package.json +17 -7
- package/src/commands/claim.ts +31 -0
- package/src/commands/explorer.ts +21 -0
- package/src/commands/info.ts +34 -0
- package/src/commands/init.ts +58 -0
- package/src/commands/initWithoutFiles.ts +107 -0
- package/src/commands/login.ts +76 -0
- package/src/commands/logout.ts +23 -0
- package/src/commands/pull.ts +23 -0
- package/src/commands/push.ts +25 -0
- package/src/commands/query.ts +61 -0
- package/src/context/authToken.ts +149 -0
- package/src/context/currentApp.ts +277 -0
- package/src/context/globalOpts.ts +22 -0
- package/src/context/platformApi.ts +35 -0
- package/src/context/projectInfo.ts +215 -0
- package/src/errors.ts +7 -0
- package/src/index.ts +428 -0
- package/src/layer.ts +155 -0
- package/src/lib/createApp.ts +28 -0
- package/src/lib/handleEnv.ts +115 -0
- package/src/lib/http.ts +148 -0
- package/src/lib/login.ts +54 -0
- package/src/lib/pullPerms.ts +50 -0
- package/src/lib/pullSchema.ts +95 -0
- package/src/lib/pushPerms.ts +80 -0
- package/src/lib/pushSchema.ts +240 -0
- package/src/lib/ui.ts +36 -0
- package/src/logging.ts +32 -0
- package/src/old.js +495 -0
- package/src/program.ts +3 -0
- package/src/renderSchemaPlan.ts +6 -18
- package/src/ui/index.ts +4 -3
- package/src/util/findConfigCandidates.ts +1 -2
- package/src/util/fs.ts +1 -1
- package/src/util/getAuthPaths.ts +1 -0
- package/src/util/isHeadlessEnvironment.ts +1 -1
- package/src/util/loadConfig.ts +3 -6
- package/src/util/{mergeSchema.js → mergeSchema.ts} +26 -16
- package/src/util/renamePrompt.ts +2 -1
- package/tsconfig.build.json +20 -0
- package/tsconfig.json +15 -5
- package/vitest.config.ts +2 -1
- package/dist/util/packageManager.d.ts +0 -3
- package/dist/util/packageManager.d.ts.map +0 -1
- package/dist/util/packageManager.js +0 -70
- package/dist/util/packageManager.js.map +0 -1
- package/dist/util/promptOk.d.ts +0 -4
- package/dist/util/promptOk.d.ts.map +0 -1
- package/dist/util/promptOk.js +0 -18
- package/dist/util/promptOk.js.map +0 -1
- package/src/index.js +0 -2333
- package/src/util/packageManager.js +0 -78
- package/src/util/promptOk.ts +0 -26
package/src/old.js
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import boxen from 'boxen';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { program } from '@commander-js/extra-typings';
|
|
4
|
+
import { readFile } from 'fs/promises';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import terminalLink from 'terminal-link';
|
|
7
|
+
import { UI } from './ui/index.ts';
|
|
8
|
+
import { deferred, renderUnwrap } from './ui/lib.ts';
|
|
9
|
+
import {
|
|
10
|
+
getPermsReadCandidates,
|
|
11
|
+
getSchemaReadCandidates,
|
|
12
|
+
} from './util/findConfigCandidates.ts';
|
|
13
|
+
import { getAuthPaths } from './util/getAuthPaths.ts';
|
|
14
|
+
import { loadConfig } from './util/loadConfig.ts';
|
|
15
|
+
import { loadEnv } from './util/loadEnv.ts';
|
|
16
|
+
import { ResolveRenamePrompt } from './util/renamePrompt.ts';
|
|
17
|
+
import version from './version.js';
|
|
18
|
+
|
|
19
|
+
const dev = Boolean(process.env.INSTANT_CLI_DEV);
|
|
20
|
+
const verbose = Boolean(process.env.INSTANT_CLI_VERBOSE);
|
|
21
|
+
|
|
22
|
+
function error(firstArg, ...rest) {
|
|
23
|
+
console.error(chalk.red('[error]') + ' ' + firstArg, ...rest);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const potentialAdminTokenEnvs = {
|
|
27
|
+
default: 'INSTANT_APP_ADMIN_TOKEN',
|
|
28
|
+
short: 'INSTANT_ADMIN_TOKEN',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const instantDashOrigin = dev
|
|
32
|
+
? 'http://localhost:3000'
|
|
33
|
+
: 'https://instantdb.com';
|
|
34
|
+
|
|
35
|
+
const instantBackendOrigin =
|
|
36
|
+
process.env.INSTANT_CLI_API_URI ||
|
|
37
|
+
(dev ? 'http://localhost:8888' : 'https://api.instantdb.com');
|
|
38
|
+
|
|
39
|
+
function indexingJobCompletedActionMessage(job) {
|
|
40
|
+
if (job.job_type === 'check-data-type') {
|
|
41
|
+
return `setting type of ${job.attr_name} to ${job.checked_data_type}`;
|
|
42
|
+
}
|
|
43
|
+
if (job.job_type === 'remove-data-type') {
|
|
44
|
+
return `removing type from ${job.attr_name}`;
|
|
45
|
+
}
|
|
46
|
+
if (job.job_type === 'index') {
|
|
47
|
+
return `adding index to ${job.attr_name}`;
|
|
48
|
+
}
|
|
49
|
+
if (job.job_type === 'remove-index') {
|
|
50
|
+
return `removing index from ${job.attr_name}`;
|
|
51
|
+
}
|
|
52
|
+
if (job.job_type === 'unique') {
|
|
53
|
+
return `adding uniqueness constraint to ${job.attr_name}`;
|
|
54
|
+
}
|
|
55
|
+
if (job.job_type === 'remove-unique') {
|
|
56
|
+
return `removing uniqueness constraint from ${job.attr_name}`;
|
|
57
|
+
}
|
|
58
|
+
if (job.job_type === 'required') {
|
|
59
|
+
return `adding required constraint to ${job.attr_name}`;
|
|
60
|
+
}
|
|
61
|
+
if (job.job_type === 'remove-required') {
|
|
62
|
+
return `removing required constraint from ${job.attr_name}`;
|
|
63
|
+
}
|
|
64
|
+
return `unexpected job type ${job.job_type} - please ping us on discord with this job id (${job.id})`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function truncate(s, maxLen) {
|
|
68
|
+
if (s.length > maxLen) {
|
|
69
|
+
return `${s.substr(0, maxLen - 3)}...`;
|
|
70
|
+
}
|
|
71
|
+
return s;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function formatSamples(triples_samples) {
|
|
75
|
+
return triples_samples.slice(0, 3).map((t) => {
|
|
76
|
+
return { ...t, value: truncate(JSON.stringify(t.value), 32) };
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createUrl(triple, job) {
|
|
81
|
+
const urlParams = new URLSearchParams({
|
|
82
|
+
s: 'main',
|
|
83
|
+
app: job.app_id,
|
|
84
|
+
t: 'explorer',
|
|
85
|
+
ns: job.attr_name.split('.')[0],
|
|
86
|
+
where: JSON.stringify(['id', triple.entity_id]),
|
|
87
|
+
});
|
|
88
|
+
const url = new URL(instantDashOrigin);
|
|
89
|
+
url.pathname = '/dash';
|
|
90
|
+
url.search = urlParams.toString();
|
|
91
|
+
return url;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function padCell(value, width) {
|
|
95
|
+
const trimmed = value.length > width ? value.substring(0, width) : value;
|
|
96
|
+
return trimmed + ' '.repeat(width - trimmed.length);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function indexingJobCompletedMessage(job) {
|
|
100
|
+
const actionMessage = indexingJobCompletedActionMessage(job);
|
|
101
|
+
if (job.job_status === 'canceled') {
|
|
102
|
+
return `Canceled ${actionMessage} before it could finish.`;
|
|
103
|
+
}
|
|
104
|
+
if (job.job_status === 'completed') {
|
|
105
|
+
return `Finished ${actionMessage}.`;
|
|
106
|
+
}
|
|
107
|
+
if (job.job_status === 'errored') {
|
|
108
|
+
if (job.invalid_triples_sample?.length) {
|
|
109
|
+
const [etype, label] = job.attr_name.split('.');
|
|
110
|
+
const samples = formatSamples(job.invalid_triples_sample);
|
|
111
|
+
const longestValue = samples.reduce(
|
|
112
|
+
(acc, { value }) => Math.max(acc, value.length),
|
|
113
|
+
label.length,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const columns = [
|
|
117
|
+
{ header: 'namespace', width: 15, getValue: () => etype },
|
|
118
|
+
{
|
|
119
|
+
header: 'id',
|
|
120
|
+
width: 37,
|
|
121
|
+
getValue: (triple) =>
|
|
122
|
+
terminalLink(triple.entity_id, createUrl(triple, job).toString(), {
|
|
123
|
+
fallback: () => triple.entity_id,
|
|
124
|
+
}),
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
header: label,
|
|
128
|
+
width: longestValue + 2,
|
|
129
|
+
getValue: (triple) => triple.value,
|
|
130
|
+
},
|
|
131
|
+
{ header: 'type', width: 8, getValue: (triple) => triple.json_type },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
let msg = `${chalk.red('INVALID DATA')} ${actionMessage}.\n`;
|
|
135
|
+
if (job.invalid_unique_value) {
|
|
136
|
+
msg += ` Found multiple entities with value ${truncate(JSON.stringify(job.invalid_unique_value), 64)}.\n`;
|
|
137
|
+
}
|
|
138
|
+
if (job.error === 'triple-too-large-error') {
|
|
139
|
+
msg += ` Some of the existing data is too large to index.\n`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
msg += ` First few examples:\n`;
|
|
143
|
+
msg += ` ${columns.map((col) => chalk.bold(padCell(col.header, col.width))).join(' | ')}\n`;
|
|
144
|
+
msg += ` ${columns.map((col) => '-'.repeat(col.width)).join('-|-')}\n`;
|
|
145
|
+
|
|
146
|
+
for (const triple of samples) {
|
|
147
|
+
const cells = columns.map((col) =>
|
|
148
|
+
padCell(col.getValue(triple), col.width),
|
|
149
|
+
);
|
|
150
|
+
msg += ` ${cells.join(' | ')}\n`;
|
|
151
|
+
}
|
|
152
|
+
return msg;
|
|
153
|
+
}
|
|
154
|
+
return `Error ${actionMessage}.`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function joinInSentence(items) {
|
|
159
|
+
if (items.length === 0) {
|
|
160
|
+
return '';
|
|
161
|
+
}
|
|
162
|
+
if (items.length === 1) {
|
|
163
|
+
return items[0];
|
|
164
|
+
}
|
|
165
|
+
if (items.length === 2) {
|
|
166
|
+
return `${items[0]} and ${items[1]}`;
|
|
167
|
+
}
|
|
168
|
+
return `${items.slice(0, -1).join(', ')}, and ${items[items.length - 1]}`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function jobGroupDescription(jobs) {
|
|
172
|
+
const actions = new Set();
|
|
173
|
+
const jobActions = {
|
|
174
|
+
'check-data-type': 'updating types',
|
|
175
|
+
'remove-data-type': 'updating types',
|
|
176
|
+
index: 'updating indexes',
|
|
177
|
+
'remove-index': 'updating indexes',
|
|
178
|
+
unique: 'updating uniqueness constraints',
|
|
179
|
+
'remove-unique': 'updating uniqueness constraints',
|
|
180
|
+
required: 'making attributes required',
|
|
181
|
+
'remove-required': 'making attributes optional',
|
|
182
|
+
};
|
|
183
|
+
for (const job of jobs) {
|
|
184
|
+
actions.add(jobActions[job.job_type]);
|
|
185
|
+
}
|
|
186
|
+
return joinInSentence([...actions].sort()) || 'updating schema';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// TODO: rewrite in effect
|
|
190
|
+
export async function waitForIndexingJobsToFinish(appId, data, authToken) {
|
|
191
|
+
const spinnerDefferedPromise = deferred();
|
|
192
|
+
const spinner = new UI.Spinner({
|
|
193
|
+
promise: spinnerDefferedPromise.promise,
|
|
194
|
+
});
|
|
195
|
+
const spinnerRenderPromise = renderUnwrap(spinner);
|
|
196
|
+
|
|
197
|
+
const groupId = data['group-id'];
|
|
198
|
+
let jobs = data.jobs;
|
|
199
|
+
let waitMs = 20;
|
|
200
|
+
let lastUpdatedAt = new Date(0);
|
|
201
|
+
|
|
202
|
+
const completedIds = new Set();
|
|
203
|
+
|
|
204
|
+
const errorMessages = [];
|
|
205
|
+
|
|
206
|
+
while (true) {
|
|
207
|
+
let stillRunning = false;
|
|
208
|
+
let updated = false;
|
|
209
|
+
let workEstimateTotal = 0;
|
|
210
|
+
let workCompletedTotal = 0;
|
|
211
|
+
|
|
212
|
+
for (const job of jobs) {
|
|
213
|
+
const updatedAt = new Date(job.updated_at);
|
|
214
|
+
if (updatedAt > lastUpdatedAt) {
|
|
215
|
+
updated = true;
|
|
216
|
+
lastUpdatedAt = updatedAt;
|
|
217
|
+
}
|
|
218
|
+
if (job.job_status === 'waiting' || job.job_status === 'processing') {
|
|
219
|
+
stillRunning = true;
|
|
220
|
+
// Default estimate to high value to prevent % from jumping around
|
|
221
|
+
workEstimateTotal += job.work_estimate ?? 50000;
|
|
222
|
+
workCompletedTotal += job.work_completed ?? 0;
|
|
223
|
+
} else {
|
|
224
|
+
if (!completedIds.has(job.id)) {
|
|
225
|
+
completedIds.add(job.id);
|
|
226
|
+
const msg = indexingJobCompletedMessage(job);
|
|
227
|
+
if (msg) {
|
|
228
|
+
if (job.job_status === 'errored') {
|
|
229
|
+
spinner.addMessage(msg);
|
|
230
|
+
errorMessages.push(msg);
|
|
231
|
+
} else {
|
|
232
|
+
spinner.addMessage(msg);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (!stillRunning) {
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
if (workEstimateTotal) {
|
|
242
|
+
const percent = Math.floor(
|
|
243
|
+
(workCompletedTotal / workEstimateTotal) * 100,
|
|
244
|
+
);
|
|
245
|
+
spinner.updateText(`${jobGroupDescription(jobs)} ${percent}%`);
|
|
246
|
+
}
|
|
247
|
+
waitMs = updated ? 1 : Math.min(10000, waitMs * 2);
|
|
248
|
+
await sleep(waitMs);
|
|
249
|
+
const res = await fetchJson({
|
|
250
|
+
debugName: 'Check indexing status',
|
|
251
|
+
method: 'GET',
|
|
252
|
+
authToken,
|
|
253
|
+
path: `/dash/apps/${appId}/indexing-jobs/group/${groupId}`,
|
|
254
|
+
errorMessage: 'Failed to check indexing status.',
|
|
255
|
+
command: 'push',
|
|
256
|
+
});
|
|
257
|
+
if (!res.ok) {
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
jobs = res.data.jobs;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
spinnerDefferedPromise.resolve(null);
|
|
264
|
+
|
|
265
|
+
await spinnerRenderPromise;
|
|
266
|
+
|
|
267
|
+
// Log errors at the end so that they're easier to see.
|
|
268
|
+
if (errorMessages.length) {
|
|
269
|
+
for (const msg of errorMessages) {
|
|
270
|
+
console.log(msg);
|
|
271
|
+
}
|
|
272
|
+
console.log(chalk.red('Some steps failed while updating schema.'));
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export const resolveRenames = async (created, promptData, extraInfo) => {
|
|
278
|
+
const answer = await renderUnwrap(
|
|
279
|
+
new ResolveRenamePrompt(
|
|
280
|
+
created,
|
|
281
|
+
promptData,
|
|
282
|
+
extraInfo,
|
|
283
|
+
UI.modifiers.piped([
|
|
284
|
+
(out) =>
|
|
285
|
+
boxen(out, {
|
|
286
|
+
dimBorder: true,
|
|
287
|
+
padding: {
|
|
288
|
+
left: 1,
|
|
289
|
+
right: 1,
|
|
290
|
+
},
|
|
291
|
+
}),
|
|
292
|
+
UI.modifiers.vanishOnComplete,
|
|
293
|
+
]),
|
|
294
|
+
),
|
|
295
|
+
);
|
|
296
|
+
return answer;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Fetches JSON data from a specified path using the POST method.
|
|
301
|
+
*
|
|
302
|
+
* @param {Object} options
|
|
303
|
+
* @param {string} options.debugName
|
|
304
|
+
* @param {string} options.errorMessage
|
|
305
|
+
* @param {string} options.path
|
|
306
|
+
* @param {'POST' | 'GET'} [options.method]
|
|
307
|
+
* @param {Object} [options.body=undefined]
|
|
308
|
+
* @param {boolean} [options.noAuth]
|
|
309
|
+
* @param {boolean} [options.noLogError]
|
|
310
|
+
* @param {string} [options.command] - The CLI command being executed (e.g., 'push', 'pull', 'login')
|
|
311
|
+
* @param {string} [options.authToken] - Optional auth token to use instead of reading from config
|
|
312
|
+
* @param {Record<string, string>} [options.headers] - Extra headers to include in the request
|
|
313
|
+
* @returns {Promise<{ ok: boolean; data: any }>}
|
|
314
|
+
*/
|
|
315
|
+
async function fetchJson({
|
|
316
|
+
debugName,
|
|
317
|
+
errorMessage,
|
|
318
|
+
path,
|
|
319
|
+
body,
|
|
320
|
+
method,
|
|
321
|
+
noAuth,
|
|
322
|
+
noLogError,
|
|
323
|
+
command,
|
|
324
|
+
authToken: providedAuthToken,
|
|
325
|
+
headers: extraHeaders,
|
|
326
|
+
}) {
|
|
327
|
+
const withAuth = !noAuth;
|
|
328
|
+
const withErrorLogging = !noLogError;
|
|
329
|
+
let authToken = null;
|
|
330
|
+
if (withAuth) {
|
|
331
|
+
authToken =
|
|
332
|
+
providedAuthToken ?? (await readConfigAuthTokenWithErrorLogging());
|
|
333
|
+
if (!authToken) {
|
|
334
|
+
return { ok: false, data: undefined };
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const timeoutMs = 1000 * 60 * 5; // 5 minutes
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
const res = await fetch(`${instantBackendOrigin}${path}`, {
|
|
341
|
+
method: method ?? 'GET',
|
|
342
|
+
headers: {
|
|
343
|
+
...(withAuth ? { Authorization: `Bearer ${authToken}` } : {}),
|
|
344
|
+
'Content-Type': 'application/json',
|
|
345
|
+
'X-Instant-Source': 'instant-cli',
|
|
346
|
+
'X-Instant-Version': version,
|
|
347
|
+
...(command ? { 'X-Instant-Command': command } : {}),
|
|
348
|
+
...extraHeaders,
|
|
349
|
+
},
|
|
350
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
351
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
if (verbose) {
|
|
355
|
+
console.log(debugName, 'response:', res.status, res.statusText);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
let data;
|
|
359
|
+
try {
|
|
360
|
+
data = await res.json();
|
|
361
|
+
} catch {
|
|
362
|
+
data = null;
|
|
363
|
+
}
|
|
364
|
+
if (verbose && data) {
|
|
365
|
+
console.log(debugName, 'json:', JSON.stringify(data, null, 2));
|
|
366
|
+
}
|
|
367
|
+
if (!res.ok) {
|
|
368
|
+
if (withErrorLogging) {
|
|
369
|
+
error(errorMessage);
|
|
370
|
+
prettyPrintJSONErr(data);
|
|
371
|
+
}
|
|
372
|
+
return { ok: false, data };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return { ok: true, data };
|
|
376
|
+
} catch (err) {
|
|
377
|
+
if (withErrorLogging) {
|
|
378
|
+
if (err.name === 'AbortError') {
|
|
379
|
+
error(
|
|
380
|
+
`Timeout: It took more than ${timeoutMs / 60000} minutes to get the result.`,
|
|
381
|
+
);
|
|
382
|
+
} else {
|
|
383
|
+
error(`Error: type: ${err.name}, message: ${err.message}`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return { ok: false, data: null };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function prettyPrintJSONErr(data) {
|
|
391
|
+
if (data?.message) {
|
|
392
|
+
error(data.message);
|
|
393
|
+
}
|
|
394
|
+
if (Array.isArray(data?.hint?.errors)) {
|
|
395
|
+
for (const err of data.hint.errors) {
|
|
396
|
+
error(`${err.in ? err.in.join('->') + ': ' : ''}${err.message}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (!data) {
|
|
400
|
+
error('Failed to parse error response');
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export async function readLocalPermsFile() {
|
|
405
|
+
const readCandidates = getPermsReadCandidates();
|
|
406
|
+
const res = await loadConfig({
|
|
407
|
+
sources: readCandidates,
|
|
408
|
+
merge: false,
|
|
409
|
+
});
|
|
410
|
+
if (!res.config) return;
|
|
411
|
+
const relativePath = path.relative(process.cwd(), res.sources[0]);
|
|
412
|
+
return { path: relativePath, perms: res.config };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export async function readLocalSchemaFile() {
|
|
416
|
+
const readCandidates = getSchemaReadCandidates();
|
|
417
|
+
const res = await loadConfig({
|
|
418
|
+
sources: readCandidates,
|
|
419
|
+
merge: false,
|
|
420
|
+
});
|
|
421
|
+
if (!res.config) return;
|
|
422
|
+
const relativePath = path.relative(process.cwd(), res.sources[0]);
|
|
423
|
+
return { path: relativePath, schema: res.config };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export async function readInstantConfigFile() {
|
|
427
|
+
return (
|
|
428
|
+
await loadConfig({
|
|
429
|
+
sources: [
|
|
430
|
+
// load from `instant.config.xx`
|
|
431
|
+
{
|
|
432
|
+
files: 'instant.config',
|
|
433
|
+
extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs', 'json'],
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
// if false, the only the first matched will be loaded
|
|
437
|
+
// if true, all matched will be loaded and deep merged
|
|
438
|
+
merge: false,
|
|
439
|
+
})
|
|
440
|
+
).config;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function readConfigAuthToken(allowAdminToken = true) {
|
|
444
|
+
const options = program.opts();
|
|
445
|
+
// @ts-expect-error command opts type is unknown
|
|
446
|
+
if (typeof options.token === 'string') {
|
|
447
|
+
// @ts-expect-error command opts type is unknown
|
|
448
|
+
return options.token;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (process.env.INSTANT_CLI_AUTH_TOKEN) {
|
|
452
|
+
return process.env.INSTANT_CLI_AUTH_TOKEN;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (allowAdminToken) {
|
|
456
|
+
const adminTokenNames = Object.values(potentialAdminTokenEnvs);
|
|
457
|
+
for (const envName of adminTokenNames) {
|
|
458
|
+
const token = process.env[envName];
|
|
459
|
+
if (token) {
|
|
460
|
+
return token;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const authToken = await readFile(
|
|
466
|
+
getAuthPaths().authConfigFilePath,
|
|
467
|
+
'utf-8',
|
|
468
|
+
).catch(() => null);
|
|
469
|
+
|
|
470
|
+
if (authToken) {
|
|
471
|
+
return authToken;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export async function readConfigAuthTokenWithErrorLogging() {
|
|
478
|
+
const token = await readConfigAuthToken();
|
|
479
|
+
if (!token) {
|
|
480
|
+
error(
|
|
481
|
+
`Looks like you are not logged in. Please log in with ${chalk.green('`instant-cli login`')}`,
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
return token;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// utils
|
|
488
|
+
|
|
489
|
+
function sleep(ms) {
|
|
490
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export function countEntities(o) {
|
|
494
|
+
return Object.keys(o).length;
|
|
495
|
+
}
|
package/src/program.ts
ADDED
package/src/renderSchemaPlan.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { convertTxSteps } from '@instantdb/platform';
|
|
2
|
+
import type {
|
|
3
3
|
MigrationTx,
|
|
4
4
|
MigrationTxSpecific,
|
|
5
5
|
MigrationTxTypes,
|
|
6
6
|
} from '@instantdb/platform';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import stripAnsi from 'strip-ansi';
|
|
9
|
-
import { promptOk } from './util/promptOk.js';
|
|
10
9
|
|
|
11
10
|
// Hack to prevent using @instantdb/core as a dependency for cli
|
|
12
11
|
type InstantDBAttr = Parameters<typeof convertTxSteps>[1][0];
|
|
@@ -98,7 +97,7 @@ type AddOrDeleteAttr =
|
|
|
98
97
|
| MigrationTxSpecific<'add-attr'>
|
|
99
98
|
| MigrationTxSpecific<'delete-attr'>;
|
|
100
99
|
|
|
101
|
-
type SuperMigrationTx =
|
|
100
|
+
export type SuperMigrationTx =
|
|
102
101
|
| MigrationTx
|
|
103
102
|
| { type: 'create-namespace'; namespace: string; innerSteps: MigrationTx[] }
|
|
104
103
|
| { type: 'delete-namespace'; namespace: string; innerSteps: MigrationTx[] };
|
|
@@ -169,19 +168,6 @@ export const groupSteps = (steps: MigrationTx[]): SuperMigrationTx[] => {
|
|
|
169
168
|
return [...collapsed, ...otherSteps];
|
|
170
169
|
};
|
|
171
170
|
|
|
172
|
-
export const confirmImportantSteps = async (planSteps: SuperMigrationTx[]) => {
|
|
173
|
-
for (const step of planSteps) {
|
|
174
|
-
if (step.type === 'delete-namespace') {
|
|
175
|
-
const ok = await promptOk({
|
|
176
|
-
promptText: `Are you sure you want to delete namespace ${step.namespace}?`,
|
|
177
|
-
});
|
|
178
|
-
if (!ok) {
|
|
179
|
-
throw new CancelSchemaError(`Deletion of namespace ${step.namespace}`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
|
-
|
|
185
171
|
const createDotName = (step: MigrationTx) => {
|
|
186
172
|
return `${step.identifier.namespace}.${step.identifier.attrName}`;
|
|
187
173
|
};
|
|
@@ -328,7 +314,9 @@ export const renderSchemaPlan = (
|
|
|
328
314
|
break;
|
|
329
315
|
|
|
330
316
|
default:
|
|
331
|
-
|
|
317
|
+
throw new Error(
|
|
318
|
+
`Unknown migration step: ${(step as { type: string }).type}`,
|
|
319
|
+
);
|
|
332
320
|
}
|
|
333
321
|
}
|
|
334
322
|
|
package/src/ui/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import boxen from 'boxen';
|
|
3
3
|
import stringWidth from 'string-width';
|
|
4
|
-
import {
|
|
4
|
+
import { Prompt, SelectState } from './lib.ts';
|
|
5
|
+
import type { AnyKey, ModifyOutputFn } from './lib.ts';
|
|
5
6
|
|
|
6
|
-
export { render, renderUnwrap, setRawModeWindowsFriendly } from './lib.
|
|
7
|
+
export { render, renderUnwrap, setRawModeWindowsFriendly } from './lib.ts';
|
|
7
8
|
|
|
8
9
|
export namespace UI {
|
|
9
10
|
type Status = 'idle' | 'submitted' | 'aborted';
|
|
@@ -864,7 +865,7 @@ ${inputDisplay}`;
|
|
|
864
865
|
}
|
|
865
866
|
}
|
|
866
867
|
|
|
867
|
-
interface AppSelectorApi {
|
|
868
|
+
export interface AppSelectorApi {
|
|
868
869
|
getDash: () => { apps: App[]; orgs: Org[] };
|
|
869
870
|
createEphemeralApp: (title: string) => Promise<{
|
|
870
871
|
appId: string;
|
|
@@ -187,8 +187,7 @@ export function getSchemaPathToWrite(existingPath?: string): string {
|
|
|
187
187
|
return 'instant.schema.ts';
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
export function getPermsPathToWrite(
|
|
191
|
-
if (existingPath) return existingPath;
|
|
190
|
+
export function getPermsPathToWrite(): string {
|
|
192
191
|
if (process.env.INSTANT_PERMS_FILE_PATH) {
|
|
193
192
|
return process.env.INSTANT_PERMS_FILE_PATH;
|
|
194
193
|
}
|
package/src/util/fs.ts
CHANGED
package/src/util/getAuthPaths.ts
CHANGED
package/src/util/loadConfig.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
LoadConfigOptions,
|
|
4
|
-
LoadConfigResult,
|
|
5
|
-
} from 'unconfig';
|
|
1
|
+
import { loadConfig as _loadConfig } from 'unconfig';
|
|
2
|
+
import type { LoadConfigOptions, LoadConfigResult } from 'unconfig';
|
|
6
3
|
import { createRequire } from 'module';
|
|
7
4
|
import path from 'path';
|
|
8
|
-
import { findProjectDir } from './projectDir.
|
|
5
|
+
import { findProjectDir } from './projectDir.ts';
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* Resolve @instantdb packages from CLI's dependency tree.
|