@revoengine/cli 1.0.1 → 1.0.3
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/README.md +4 -0
- package/dist/src/cli.js +1 -0
- package/dist/src/client.d.ts +3 -1
- package/dist/src/client.js +33 -3
- package/dist/src/commands/auth.js +5 -1
- package/dist/src/commands/component.js +36 -47
- package/dist/src/config.d.ts +6 -3
- package/dist/src/config.js +13 -2
- package/dist/src/project.d.ts +3 -0
- package/dist/src/project.js +33 -0
- package/dist/src/runtime-view.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@ revo auth login
|
|
|
29
29
|
|
|
30
30
|
`revo auth login` opens an interactive terminal prompt for your API key. If you are already logged in, the CLI warns and asks you to `revo auth logout` first.
|
|
31
31
|
|
|
32
|
+
The CLI validates the API key against `/api/v1/me` and infers the RevoEngine instance from the authenticated profile for tenant-scoped operations such as component push.
|
|
33
|
+
|
|
32
34
|
Check the active session:
|
|
33
35
|
|
|
34
36
|
```bash
|
|
@@ -134,11 +136,13 @@ Components with `category: null` are stored under `Components/__no_category__/..
|
|
|
134
136
|
Bulk sync behavior:
|
|
135
137
|
|
|
136
138
|
- `revo component pull --all` and `revo component push --all` require terminal confirmation unless `--force` is passed.
|
|
139
|
+
- `revo component pull --all` requests only active remote components where `deletedAt` is empty.
|
|
137
140
|
- Pull compares the full local workspace contract before overwriting anything.
|
|
138
141
|
- Pull skips with `no changes` when the local workspace already matches the remote component.
|
|
139
142
|
- Pull skips with `changed` when local files differ from the remote contract.
|
|
140
143
|
- Pull skips with `stale version` when the local version is older than the remote version, unless `--stale` or `--force` is passed.
|
|
141
144
|
- Push treats backend `Not modified` responses as skipped instead of failing the whole run.
|
|
145
|
+
- Push treats backend `404` responses as skipped with `doesn't exist remotely`; restore the component in RevoEngine before pushing local changes to it.
|
|
142
146
|
- Debug posts the local `component.json` plus `elements/{order}_{key}.{js|ts}` source files to the authenticated sandbox `debug` endpoint.
|
|
143
147
|
- Sync logs show direction explicitly: `RevoEngine -> path` for pull and `RevoEngine <- path` for push.
|
|
144
148
|
- Bulk runs print a summary such as `Deployed 54/67, Skipped 13/67 in 13s`.
|
package/dist/src/cli.js
CHANGED
|
@@ -138,6 +138,7 @@ function printError(error) {
|
|
|
138
138
|
function resolveClient(args) {
|
|
139
139
|
const runtime = resolveRuntimeConfig({
|
|
140
140
|
baseUrl: typeof args.url === 'string' ? args.url : typeof args.baseUrl === 'string' ? args.baseUrl : undefined,
|
|
141
|
+
instance: typeof args.instance === 'string' ? args.instance : typeof args.i === 'string' ? args.i : undefined,
|
|
141
142
|
token: typeof args.token === 'string' ? args.token : typeof args.t === 'string' ? args.t : undefined,
|
|
142
143
|
});
|
|
143
144
|
return new RevoClient(runtime);
|
package/dist/src/client.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type ComponentListRequest = {
|
|
|
11
11
|
};
|
|
12
12
|
export type ClientOptions = {
|
|
13
13
|
baseUrl?: string;
|
|
14
|
+
instance?: string;
|
|
14
15
|
token?: string;
|
|
15
16
|
fetch?: typeof fetch;
|
|
16
17
|
};
|
|
@@ -34,8 +35,10 @@ export declare class PermissionDeniedError extends ApiError {
|
|
|
34
35
|
}
|
|
35
36
|
declare function buildUrl(baseUrl: string, requestPath: string, query?: Record<string, unknown>): URL;
|
|
36
37
|
declare function normalizeToken(token?: string): string;
|
|
38
|
+
export declare function extractProfileInstanceId(profile: unknown): string;
|
|
37
39
|
export declare class RevoClient {
|
|
38
40
|
baseUrl: string;
|
|
41
|
+
instance: string;
|
|
39
42
|
token: string;
|
|
40
43
|
fetchImpl: typeof fetch | undefined;
|
|
41
44
|
constructor(options?: ClientOptions);
|
|
@@ -64,7 +67,6 @@ export declare class RevoClient {
|
|
|
64
67
|
search(params: Record<string, unknown>): Promise<unknown>;
|
|
65
68
|
listComponents(options?: ComponentListRequest): Promise<unknown>;
|
|
66
69
|
getComponent(componentId: string): Promise<unknown>;
|
|
67
|
-
createComponent(body: Record<string, unknown>): Promise<ApiResponse<unknown>>;
|
|
68
70
|
saveComponentElements(componentId: string, body: unknown): Promise<ApiResponse<unknown>>;
|
|
69
71
|
}
|
|
70
72
|
export { buildUrl, normalizeToken };
|
package/dist/src/client.js
CHANGED
|
@@ -125,13 +125,39 @@ async function readResponseData(response) {
|
|
|
125
125
|
}
|
|
126
126
|
return text;
|
|
127
127
|
}
|
|
128
|
+
function readProfileInstanceId(profile) {
|
|
129
|
+
if (!profile || typeof profile !== 'object' || Array.isArray(profile)) {
|
|
130
|
+
return '';
|
|
131
|
+
}
|
|
132
|
+
const record = profile;
|
|
133
|
+
if (typeof record.id === 'string') {
|
|
134
|
+
return record.id;
|
|
135
|
+
}
|
|
136
|
+
const instance = record.instance;
|
|
137
|
+
if (instance && typeof instance === 'object' && !Array.isArray(instance)) {
|
|
138
|
+
const instanceId = instance.id;
|
|
139
|
+
if (typeof instanceId === 'string') {
|
|
140
|
+
return instanceId;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const data = record.data;
|
|
144
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
145
|
+
return readProfileInstanceId(data);
|
|
146
|
+
}
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
export function extractProfileInstanceId(profile) {
|
|
150
|
+
return readProfileInstanceId(profile);
|
|
151
|
+
}
|
|
128
152
|
export class RevoClient {
|
|
129
153
|
baseUrl;
|
|
154
|
+
instance;
|
|
130
155
|
token;
|
|
131
156
|
fetchImpl;
|
|
132
157
|
constructor(options = {}) {
|
|
133
158
|
const config = resolveRuntimeConfig(options);
|
|
134
159
|
this.baseUrl = config.baseUrl;
|
|
160
|
+
this.instance = config.instance || '';
|
|
135
161
|
this.token = config.token;
|
|
136
162
|
this.fetchImpl = options.fetch || globalThis.fetch;
|
|
137
163
|
}
|
|
@@ -141,6 +167,7 @@ export class RevoClient {
|
|
|
141
167
|
get authValidationKey() {
|
|
142
168
|
return buildAuthValidationKey({
|
|
143
169
|
baseUrl: this.baseUrl,
|
|
170
|
+
instance: this.instance,
|
|
144
171
|
token: this.token,
|
|
145
172
|
});
|
|
146
173
|
}
|
|
@@ -164,6 +191,7 @@ export class RevoClient {
|
|
|
164
191
|
throw new AuthenticationError(401, 'Not authenticated. Run `revo auth login`.', null);
|
|
165
192
|
}
|
|
166
193
|
if (cached.profile !== undefined) {
|
|
194
|
+
this.instance = this.instance || extractProfileInstanceId(cached.profile);
|
|
167
195
|
return {
|
|
168
196
|
authenticated: true,
|
|
169
197
|
fromCache: true,
|
|
@@ -173,6 +201,7 @@ export class RevoClient {
|
|
|
173
201
|
}
|
|
174
202
|
try {
|
|
175
203
|
const profile = await this.requestData('GET', '/api/v1/me', { authGuard: false });
|
|
204
|
+
this.instance = this.instance || extractProfileInstanceId(profile);
|
|
176
205
|
saveAuthValidationState({
|
|
177
206
|
key: this.authValidationKey,
|
|
178
207
|
status: 'authenticated',
|
|
@@ -206,6 +235,10 @@ export class RevoClient {
|
|
|
206
235
|
const headers = new Headers(options.headers || {});
|
|
207
236
|
headers.set('Authorization', this.authHeader);
|
|
208
237
|
headers.set('x-api-key', this.token);
|
|
238
|
+
if (this.instance) {
|
|
239
|
+
headers.set('instance', this.instance);
|
|
240
|
+
headers.set('x-api-instance', this.instance);
|
|
241
|
+
}
|
|
209
242
|
let body = options.body;
|
|
210
243
|
if (body !== undefined && body !== null && method.toUpperCase() !== 'GET') {
|
|
211
244
|
headers.set('Content-Type', 'application/json');
|
|
@@ -294,9 +327,6 @@ export class RevoClient {
|
|
|
294
327
|
async getComponent(componentId) {
|
|
295
328
|
return this.requestData('GET', `/api/v1/component/${componentId}`);
|
|
296
329
|
}
|
|
297
|
-
async createComponent(body) {
|
|
298
|
-
return this.request('POST', '/api/v1/component', { body });
|
|
299
|
-
}
|
|
300
330
|
async saveComponentElements(componentId, body) {
|
|
301
331
|
return this.request('POST', `/api/v1/component/${componentId}/save`, { body });
|
|
302
332
|
}
|
|
@@ -62,6 +62,7 @@ export async function handleAuthCommand(context) {
|
|
|
62
62
|
println(`Imported legacy config from ${filePath}.`);
|
|
63
63
|
if (!offline) {
|
|
64
64
|
client.token = imported.token;
|
|
65
|
+
client.instance = imported.instance;
|
|
65
66
|
client.baseUrl = imported.baseUrl;
|
|
66
67
|
if (imported.token) {
|
|
67
68
|
try {
|
|
@@ -99,7 +100,10 @@ export async function handleAuthCommand(context) {
|
|
|
99
100
|
error(`Saved credentials, but validation failed: ${String(validationError)}`);
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
102
|
-
saveStoredConfig(
|
|
103
|
+
saveStoredConfig({
|
|
104
|
+
...next,
|
|
105
|
+
instance: client.instance || undefined,
|
|
106
|
+
});
|
|
103
107
|
clearAuthValidationState();
|
|
104
108
|
println(`Logged in and saved credentials to ${getConfigDir()}.`);
|
|
105
109
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { ApiError, PermissionDeniedError } from "../client.js";
|
|
4
|
-
import { buildSandboxDebugUrl, extractSandboxEndpoint } from "../project.js";
|
|
4
|
+
import { buildSandboxDebugUrl, extractSandboxEndpoint, resolveProjectWorkspace } from "../project.js";
|
|
5
5
|
import { isInteractiveTerminal, promptConfirm } from "../prompt.js";
|
|
6
6
|
import { deepClone, readBoolFlag, readFlag, readValues, sanitizeSegment, writeJsonFile } from "../utils.js";
|
|
7
7
|
const NULL_CATEGORY_FOLDER = '__no_category__';
|
|
8
|
-
const COMPONENT_LIST_PAGE_SIZE =
|
|
8
|
+
const COMPONENT_LIST_PAGE_SIZE = 200;
|
|
9
|
+
const ACTIVE_COMPONENT_LIST_FILTER = {
|
|
10
|
+
'filter[and][0][field]': 'deletedAt',
|
|
11
|
+
'filter[and][0][op]': 'isNull',
|
|
12
|
+
};
|
|
9
13
|
const ANSI = {
|
|
10
14
|
reset: '\u001b[0m',
|
|
11
15
|
bold: '\u001b[1m',
|
|
@@ -188,7 +192,8 @@ function normalizeComponentType(component) {
|
|
|
188
192
|
return 'CODE_JS';
|
|
189
193
|
}
|
|
190
194
|
function getWorkspaceRoot(cwd) {
|
|
191
|
-
|
|
195
|
+
const projectWorkspace = resolveProjectWorkspace(cwd);
|
|
196
|
+
return path.join(projectWorkspace || cwd, 'Components');
|
|
192
197
|
}
|
|
193
198
|
function getCategoryFolder(component) {
|
|
194
199
|
if (component.category == null || component.category === '') {
|
|
@@ -202,23 +207,6 @@ function getComponentFolder(component) {
|
|
|
202
207
|
const componentId = sanitizeSegment(component.componentId || component.id || 'unknown');
|
|
203
208
|
return path.join(categoryFolder, `${name}-${componentId}`);
|
|
204
209
|
}
|
|
205
|
-
function getCategoryFromManifestPath(manifestPath) {
|
|
206
|
-
const componentDir = path.dirname(manifestPath);
|
|
207
|
-
const categoryDir = path.basename(path.dirname(componentDir));
|
|
208
|
-
if (categoryDir === NULL_CATEGORY_FOLDER) {
|
|
209
|
-
return null;
|
|
210
|
-
}
|
|
211
|
-
return categoryDir;
|
|
212
|
-
}
|
|
213
|
-
function normalizeCategoryForApi(manifestPath, category) {
|
|
214
|
-
if (category === NULL_CATEGORY_FOLDER) {
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
if (category != null) {
|
|
218
|
-
return category;
|
|
219
|
-
}
|
|
220
|
-
return getCategoryFromManifestPath(manifestPath);
|
|
221
|
-
}
|
|
222
210
|
function getDetailsExtension(component) {
|
|
223
211
|
return componentTypeToExtension(normalizeComponentType(component));
|
|
224
212
|
}
|
|
@@ -351,6 +339,27 @@ function resolveNextComponentListRequest(value) {
|
|
|
351
339
|
}
|
|
352
340
|
return Object.keys(query).length > 0 ? { query } : null;
|
|
353
341
|
}
|
|
342
|
+
function buildActiveComponentListQuery(skip, take = COMPONENT_LIST_PAGE_SIZE) {
|
|
343
|
+
return {
|
|
344
|
+
take,
|
|
345
|
+
skip,
|
|
346
|
+
count: true,
|
|
347
|
+
...ACTIVE_COMPONENT_LIST_FILTER,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function withActiveComponentListFilter(request) {
|
|
351
|
+
if (!request.query) {
|
|
352
|
+
return request;
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
...request,
|
|
356
|
+
query: {
|
|
357
|
+
...request.query,
|
|
358
|
+
count: request.query.count ?? true,
|
|
359
|
+
...ACTIVE_COMPONENT_LIST_FILTER,
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
}
|
|
354
363
|
function unwrapComponentListPage(value) {
|
|
355
364
|
const items = unwrapList(value);
|
|
356
365
|
if (!isRecord(value)) {
|
|
@@ -571,10 +580,7 @@ async function pullAllComponents(context, options) {
|
|
|
571
580
|
const components = [];
|
|
572
581
|
const seenRequests = new Set();
|
|
573
582
|
let nextRequest = {
|
|
574
|
-
query:
|
|
575
|
-
take: COMPONENT_LIST_PAGE_SIZE,
|
|
576
|
-
skip: 0,
|
|
577
|
-
},
|
|
583
|
+
query: buildActiveComponentListQuery(0),
|
|
578
584
|
};
|
|
579
585
|
let discoveredTotal = null;
|
|
580
586
|
while (nextRequest) {
|
|
@@ -604,17 +610,14 @@ async function pullAllComponents(context, options) {
|
|
|
604
610
|
continue;
|
|
605
611
|
}
|
|
606
612
|
if (page.nextRequest) {
|
|
607
|
-
nextRequest = page.nextRequest;
|
|
613
|
+
nextRequest = withActiveComponentListFilter(page.nextRequest);
|
|
608
614
|
continue;
|
|
609
615
|
}
|
|
610
616
|
if (nextRequest.query
|
|
611
617
|
&& typeof nextRequest.query.take === 'number'
|
|
612
618
|
&& page.items.length === nextRequest.query.take) {
|
|
613
619
|
nextRequest = {
|
|
614
|
-
query:
|
|
615
|
-
take: nextRequest.query.take,
|
|
616
|
-
skip: components.length,
|
|
617
|
-
},
|
|
620
|
+
query: buildActiveComponentListQuery(components.length, nextRequest.query.take),
|
|
618
621
|
};
|
|
619
622
|
continue;
|
|
620
623
|
}
|
|
@@ -655,15 +658,6 @@ async function pushSingleComponent(context, manifestPath) {
|
|
|
655
658
|
if (!component.name) {
|
|
656
659
|
throw new Error(`Missing component name in ${manifestPath}.`);
|
|
657
660
|
}
|
|
658
|
-
const payload = {
|
|
659
|
-
componentId,
|
|
660
|
-
name: component.name,
|
|
661
|
-
category: normalizeCategoryForApi(manifestPath, component.category),
|
|
662
|
-
desc: component.desc,
|
|
663
|
-
type: normalizeComponentType(component),
|
|
664
|
-
active: component.active ?? true,
|
|
665
|
-
async: component.async ?? false,
|
|
666
|
-
};
|
|
667
661
|
const elements = (component.elements || []).map((element) => ({
|
|
668
662
|
key: element.key,
|
|
669
663
|
desc: element.desc,
|
|
@@ -717,21 +711,16 @@ async function pushSingleComponent(context, manifestPath) {
|
|
|
717
711
|
throw new Error('Access denied (403). You are authenticated, but you do not have permission to push components.');
|
|
718
712
|
}
|
|
719
713
|
if (error instanceof ApiError && error.status === 404) {
|
|
720
|
-
try {
|
|
721
|
-
await client.createComponent(payload);
|
|
722
|
-
await client.saveComponentElements(componentId, elements);
|
|
723
|
-
}
|
|
724
|
-
catch (createError) {
|
|
725
|
-
rethrowComponentAccessError(createError, 'push');
|
|
726
|
-
}
|
|
727
714
|
const result = {
|
|
728
|
-
status: '
|
|
715
|
+
status: 'skipped',
|
|
729
716
|
targetPath,
|
|
717
|
+
reason: "doesn't exist remotely",
|
|
730
718
|
};
|
|
731
719
|
printSyncStatus(println, {
|
|
732
|
-
status: '
|
|
720
|
+
status: 'Skipped',
|
|
733
721
|
direction: 'push',
|
|
734
722
|
targetPath,
|
|
723
|
+
reason: result.reason,
|
|
735
724
|
});
|
|
736
725
|
return result;
|
|
737
726
|
}
|
package/dist/src/config.d.ts
CHANGED
|
@@ -2,13 +2,15 @@ export declare const APP_NAME = "revoengine";
|
|
|
2
2
|
export declare const DEFAULT_BASE_URL = "https://api.revoengine.com";
|
|
3
3
|
export type RuntimeConfig = {
|
|
4
4
|
baseUrl: string;
|
|
5
|
+
instance: string;
|
|
5
6
|
token: string;
|
|
6
7
|
};
|
|
7
8
|
export type RuntimeConfigOptions = {
|
|
8
9
|
baseUrl?: string;
|
|
10
|
+
instance?: string;
|
|
9
11
|
token?: string;
|
|
10
12
|
};
|
|
11
|
-
type
|
|
13
|
+
type StoredConfig = Omit<RuntimeConfig, 'instance'> & {
|
|
12
14
|
instance?: string;
|
|
13
15
|
};
|
|
14
16
|
export type AuthValidationState = {
|
|
@@ -27,7 +29,7 @@ export declare function getConfigPaths(): {
|
|
|
27
29
|
};
|
|
28
30
|
export declare function readProjectInstanceId(startDir?: string): string;
|
|
29
31
|
export declare function isUuid(value: unknown): value is string;
|
|
30
|
-
export declare function saveStoredConfig(nextConfig: Partial<
|
|
32
|
+
export declare function saveStoredConfig(nextConfig: Partial<StoredConfig>): void;
|
|
31
33
|
export declare function clearStoredConfig(): void;
|
|
32
34
|
export declare function loadStoredConfigIndex(): {
|
|
33
35
|
defaultInstance: string;
|
|
@@ -42,13 +44,14 @@ export declare function loadStoredConfigIndex(): {
|
|
|
42
44
|
};
|
|
43
45
|
export declare function loadStoredConfig(options?: {
|
|
44
46
|
allowLegacy?: boolean;
|
|
45
|
-
}):
|
|
47
|
+
}): StoredConfig;
|
|
46
48
|
export declare function buildAuthValidationKey(runtime: RuntimeConfigOptions): string;
|
|
47
49
|
export declare function readAuthValidationState(key?: string): AuthValidationState;
|
|
48
50
|
export declare function saveAuthValidationState(state: AuthValidationState): void;
|
|
49
51
|
export declare function clearAuthValidationState(key?: string): void;
|
|
50
52
|
export declare function resolveRuntimeConfig(options?: RuntimeConfigOptions): {
|
|
51
53
|
baseUrl: string;
|
|
54
|
+
instance: string;
|
|
52
55
|
token: string;
|
|
53
56
|
};
|
|
54
57
|
export {};
|
package/dist/src/config.js
CHANGED
|
@@ -73,10 +73,13 @@ export function saveStoredConfig(nextConfig) {
|
|
|
73
73
|
const { dir, configFile, credentialsFile } = getConfigPaths();
|
|
74
74
|
ensureDirectory(dir);
|
|
75
75
|
const current = readStoredConfigFile();
|
|
76
|
-
|
|
76
|
+
const instance = nextConfig.instance || current.instance || '';
|
|
77
|
+
const config = {
|
|
77
78
|
baseUrl: nextConfig.baseUrl || current.baseUrl || DEFAULT_BASE_URL,
|
|
78
79
|
token: nextConfig.token || current.token || '',
|
|
79
|
-
|
|
80
|
+
...(instance ? { instance } : {}),
|
|
81
|
+
};
|
|
82
|
+
writeJsonFile(configFile, config);
|
|
80
83
|
removeFileIfExists(credentialsFile);
|
|
81
84
|
}
|
|
82
85
|
export function clearStoredConfig() {
|
|
@@ -156,6 +159,7 @@ function parseFlatConfig(raw, credentials) {
|
|
|
156
159
|
: typeof raw.url === 'string'
|
|
157
160
|
? raw.url
|
|
158
161
|
: DEFAULT_BASE_URL,
|
|
162
|
+
...(typeof raw.instance === 'string' && isUuid(raw.instance) ? { instance: raw.instance } : {}),
|
|
159
163
|
token,
|
|
160
164
|
};
|
|
161
165
|
}
|
|
@@ -181,6 +185,7 @@ function parseMappedConfig(raw) {
|
|
|
181
185
|
return selected
|
|
182
186
|
? {
|
|
183
187
|
baseUrl: selected.baseUrl,
|
|
188
|
+
instance: defaultInstance,
|
|
184
189
|
token: selected.token,
|
|
185
190
|
}
|
|
186
191
|
: emptyStoredConfigFile();
|
|
@@ -194,6 +199,9 @@ function parseLegacyConfig(config, credentials) {
|
|
|
194
199
|
const token = isRecord(credentials) && typeof credentials.token === 'string' ? credentials.token : '';
|
|
195
200
|
return {
|
|
196
201
|
baseUrl,
|
|
202
|
+
...(isRecord(config) && typeof config.instance === 'string' && isUuid(config.instance)
|
|
203
|
+
? { instance: config.instance }
|
|
204
|
+
: {}),
|
|
197
205
|
token,
|
|
198
206
|
};
|
|
199
207
|
}
|
|
@@ -263,6 +271,7 @@ export function buildAuthValidationKey(runtime) {
|
|
|
263
271
|
return createHash('sha256')
|
|
264
272
|
.update(JSON.stringify({
|
|
265
273
|
baseUrl: runtime.baseUrl || DEFAULT_BASE_URL,
|
|
274
|
+
instance: runtime.instance || '',
|
|
266
275
|
token: runtime.token || '',
|
|
267
276
|
}))
|
|
268
277
|
.digest('hex');
|
|
@@ -346,11 +355,13 @@ export function clearAuthValidationState(key) {
|
|
|
346
355
|
export function resolveRuntimeConfig(options = {}) {
|
|
347
356
|
const env = {
|
|
348
357
|
baseUrl: resolveEnvValue(['REVO_URL', 'REVO_BASE_URL', 'REVOENGINE_URL', 'REVOENGINE_BASE_URL']),
|
|
358
|
+
instance: resolveEnvValue(['REVO_INSTANCE', 'REVOENGINE_INSTANCE']),
|
|
349
359
|
token: resolveEnvValue(['REVO_TOKEN', 'REVO_API_KEY', 'REVOENGINE_TOKEN', 'REVOENGINE_API_KEY']),
|
|
350
360
|
};
|
|
351
361
|
const stored = loadStoredConfig();
|
|
352
362
|
return {
|
|
353
363
|
baseUrl: options.baseUrl || env.baseUrl || stored.baseUrl || DEFAULT_BASE_URL,
|
|
364
|
+
instance: options.instance || env.instance || stored.instance || '',
|
|
354
365
|
token: options.token || env.token || stored.token || '',
|
|
355
366
|
};
|
|
356
367
|
}
|
package/dist/src/project.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export declare const REVO_PROJECT_DIR = ".revoengine";
|
|
|
3
3
|
export declare const REVO_TYPES_DIR: string;
|
|
4
4
|
export declare const REVO_TYPES_FILE: string;
|
|
5
5
|
export declare const REVO_METADATA_FILE: string;
|
|
6
|
+
export declare const REVO_VSCODE_CONFIG_FILE: string;
|
|
6
7
|
export declare const REVO_TYPES_GITIGNORE_ENTRY = ".revoengine/types/";
|
|
7
8
|
export declare const REVO_DEBUG_JS_FILE: string;
|
|
8
9
|
export declare const REVO_DEBUG_TS_FILE: string;
|
|
@@ -31,6 +32,7 @@ export type RevoProjectMetadata = {
|
|
|
31
32
|
libVersion: string;
|
|
32
33
|
hash: string;
|
|
33
34
|
lastSyncAt: string;
|
|
35
|
+
workspace?: string;
|
|
34
36
|
};
|
|
35
37
|
export type ProjectSyncInput = {
|
|
36
38
|
endpoint: string;
|
|
@@ -71,6 +73,7 @@ export declare function buildProjectMetadata(input: {
|
|
|
71
73
|
export declare function findProjectMetadataFile(startDir?: string): string;
|
|
72
74
|
export declare function readProjectMetadata(startDir?: string): RevoProjectMetadata | null;
|
|
73
75
|
export declare function resolveProjectRoot(startDir?: string): string;
|
|
76
|
+
export declare function resolveProjectWorkspace(startDir?: string): string;
|
|
74
77
|
export declare function buildProjectSyncState(input: {
|
|
75
78
|
fallbackEndpoint: string;
|
|
76
79
|
bundle: EditorTypesBundle;
|
package/dist/src/project.js
CHANGED
|
@@ -5,6 +5,7 @@ export const REVO_PROJECT_DIR = '.revoengine';
|
|
|
5
5
|
export const REVO_TYPES_DIR = path.join(REVO_PROJECT_DIR, 'types');
|
|
6
6
|
export const REVO_TYPES_FILE = path.join(REVO_TYPES_DIR, 'revo.editor.d.ts');
|
|
7
7
|
export const REVO_METADATA_FILE = path.join(REVO_PROJECT_DIR, 'revo.json');
|
|
8
|
+
export const REVO_VSCODE_CONFIG_FILE = path.join(REVO_PROJECT_DIR, 'vscode.json');
|
|
8
9
|
export const REVO_TYPES_GITIGNORE_ENTRY = '.revoengine/types/';
|
|
9
10
|
export const REVO_DEBUG_JS_FILE = path.join(REVO_PROJECT_DIR, 'debug_code.js');
|
|
10
11
|
export const REVO_DEBUG_TS_FILE = path.join(REVO_PROJECT_DIR, 'debug_code.ts');
|
|
@@ -335,6 +336,38 @@ export function resolveProjectRoot(startDir = process.cwd()) {
|
|
|
335
336
|
const metadataFile = findProjectMetadataFile(startDir);
|
|
336
337
|
return metadataFile ? path.dirname(path.dirname(metadataFile)) : '';
|
|
337
338
|
}
|
|
339
|
+
function readWorkspaceDirectoryFromProjectConfig(projectRoot, metadata) {
|
|
340
|
+
const vscodeConfigPath = path.join(projectRoot, REVO_VSCODE_CONFIG_FILE);
|
|
341
|
+
if (fs.existsSync(vscodeConfigPath)) {
|
|
342
|
+
const config = parseConfigFile(vscodeConfigPath);
|
|
343
|
+
const workspaceDirectory = readString(config.workspaceDirectory);
|
|
344
|
+
if (workspaceDirectory) {
|
|
345
|
+
return workspaceDirectory;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return readString(metadata.workspace) || '';
|
|
349
|
+
}
|
|
350
|
+
function resolveProjectWorkspaceRoot(projectRoot, workspaceDirectory) {
|
|
351
|
+
const resolved = path.resolve(projectRoot, workspaceDirectory || '.');
|
|
352
|
+
const relative = path.relative(projectRoot, resolved);
|
|
353
|
+
if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) {
|
|
354
|
+
return resolved;
|
|
355
|
+
}
|
|
356
|
+
throw new Error('Project workspace directory must stay inside the Revo project root.');
|
|
357
|
+
}
|
|
358
|
+
export function resolveProjectWorkspace(startDir = process.cwd()) {
|
|
359
|
+
const metadataFile = findProjectMetadataFile(startDir);
|
|
360
|
+
if (!metadataFile) {
|
|
361
|
+
return '';
|
|
362
|
+
}
|
|
363
|
+
const projectRoot = path.dirname(path.dirname(metadataFile));
|
|
364
|
+
const raw = readJsonFile(metadataFile);
|
|
365
|
+
if (!isRecord(raw)) {
|
|
366
|
+
return projectRoot;
|
|
367
|
+
}
|
|
368
|
+
const workspaceDirectory = readWorkspaceDirectoryFromProjectConfig(projectRoot, raw);
|
|
369
|
+
return resolveProjectWorkspaceRoot(projectRoot, workspaceDirectory);
|
|
370
|
+
}
|
|
338
371
|
export function buildProjectSyncState(input) {
|
|
339
372
|
const metadata = buildProjectMetadata({
|
|
340
373
|
baseUrl: input.fallbackEndpoint,
|
package/dist/src/runtime-view.js
CHANGED
|
@@ -7,6 +7,11 @@ function resolveArgsRuntime(context) {
|
|
|
7
7
|
: typeof context.args.baseUrl === 'string'
|
|
8
8
|
? context.args.baseUrl
|
|
9
9
|
: undefined,
|
|
10
|
+
instance: typeof context.args.instance === 'string'
|
|
11
|
+
? context.args.instance
|
|
12
|
+
: typeof context.args.i === 'string'
|
|
13
|
+
? context.args.i
|
|
14
|
+
: undefined,
|
|
10
15
|
token: typeof context.args.token === 'string'
|
|
11
16
|
? context.args.token
|
|
12
17
|
: typeof context.args.t === 'string'
|
|
@@ -46,6 +51,7 @@ export async function buildRuntimeViewModel(context, options = {}) {
|
|
|
46
51
|
};
|
|
47
52
|
if (runtime.token) {
|
|
48
53
|
context.client.baseUrl = runtime.baseUrl;
|
|
54
|
+
context.client.instance = runtime.instance || '';
|
|
49
55
|
context.client.token = runtime.token;
|
|
50
56
|
try {
|
|
51
57
|
const profile = await context.client.me({ force: options.forceValidation });
|