@revoengine/cli 1.0.9 → 1.0.11
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 +464 -8
- package/dist/src/cli.js +65 -6
- package/dist/src/client.d.ts +366 -5
- package/dist/src/client.js +954 -13
- package/dist/src/commands/auth.js +4 -2
- package/dist/src/commands/component.js +839 -412
- package/dist/src/commands/database-schemas.d.ts +2 -0
- package/dist/src/commands/database-schemas.js +188 -0
- package/dist/src/commands/database-views.d.ts +2 -0
- package/dist/src/commands/database-views.js +123 -0
- package/dist/src/commands/endpoints.js +114 -0
- package/dist/src/commands/env.d.ts +2 -0
- package/dist/src/commands/env.js +380 -0
- package/dist/src/commands/events.d.ts +2 -0
- package/dist/src/commands/events.js +146 -0
- package/dist/src/commands/groups.d.ts +2 -0
- package/dist/src/commands/groups.js +169 -0
- package/dist/src/commands/index.d.ts +10 -0
- package/dist/src/commands/index.js +10 -0
- package/dist/src/commands/job-templates.d.ts +2 -0
- package/dist/src/commands/job-templates.js +101 -0
- package/dist/src/commands/metadata.d.ts +2 -0
- package/dist/src/commands/metadata.js +159 -0
- package/dist/src/commands/project.js +82 -1
- package/dist/src/commands/role-groups.d.ts +2 -0
- package/dist/src/commands/role-groups.js +152 -0
- package/dist/src/commands/schedules.d.ts +2 -0
- package/dist/src/commands/schedules.js +141 -0
- package/dist/src/commands/terminal-service.d.ts +38 -0
- package/dist/src/commands/terminal-service.js +210 -0
- package/dist/src/commands/terminal.d.ts +22 -0
- package/dist/src/commands/terminal.js +511 -0
- package/dist/src/component-lock.d.ts +126 -2
- package/dist/src/component-lock.js +378 -15
- package/dist/src/config.d.ts +20 -0
- package/dist/src/config.js +121 -6
- package/dist/src/database-schema-artifacts.d.ts +7 -0
- package/dist/src/database-schema-artifacts.js +8 -0
- package/dist/src/env-sync.d.ts +83 -0
- package/dist/src/env-sync.js +315 -0
- package/dist/src/metadata-backfill.d.ts +56 -0
- package/dist/src/metadata-backfill.js +1176 -0
- package/dist/src/project.d.ts +17 -9
- package/dist/src/project.js +87 -11
- package/dist/src/prompt.js +10 -18
- package/dist/src/resource-metadata.d.ts +25 -0
- package/dist/src/resource-metadata.js +132 -0
- package/dist/src/resource-syncs/database-schema-sync.d.ts +117 -0
- package/dist/src/resource-syncs/database-schema-sync.js +2289 -0
- package/dist/src/resource-syncs/database-view-sync.d.ts +124 -0
- package/dist/src/resource-syncs/database-view-sync.js +1317 -0
- package/dist/src/resource-syncs/endpoint-sync.d.ts +96 -0
- package/dist/src/resource-syncs/endpoint-sync.js +1283 -0
- package/dist/src/resource-syncs/event-sync.d.ts +99 -0
- package/dist/src/resource-syncs/event-sync.js +949 -0
- package/dist/src/resource-syncs/group-sync.d.ts +86 -0
- package/dist/src/resource-syncs/group-sync.js +882 -0
- package/dist/src/resource-syncs/job-template-sync.d.ts +85 -0
- package/dist/src/resource-syncs/job-template-sync.js +782 -0
- package/dist/src/resource-syncs/role-group-sync.d.ts +83 -0
- package/dist/src/resource-syncs/role-group-sync.js +597 -0
- package/dist/src/resource-syncs/schedule-sync.d.ts +111 -0
- package/dist/src/resource-syncs/schedule-sync.js +1302 -0
- package/dist/src/resource-syncs/util.d.ts +19 -0
- package/dist/src/resource-syncs/util.js +116 -0
- package/dist/src/runtime-view.d.ts +1 -0
- package/dist/src/runtime-view.js +6 -1
- package/dist/src/sync-output.d.ts +38 -0
- package/dist/src/sync-output.js +131 -0
- package/dist/src/tracked-resources.d.ts +7 -0
- package/dist/src/tracked-resources.js +61 -0
- package/dist/src/types.d.ts +227 -0
- package/dist/src/ui.d.ts +3 -0
- package/dist/src/ui.js +68 -10
- package/dist/src/utils.d.ts +2 -0
- package/dist/src/utils.js +64 -0
- package/dist/src/workspace-component.d.ts +2 -0
- package/dist/src/workspace-component.js +34 -0
- package/dist/src/workspace-resource.d.ts +2 -0
- package/dist/src/workspace-resource.js +52 -0
- package/package.json +8 -3
|
@@ -2,6 +2,7 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { REVO_PROJECT_DIR } from "./project.js";
|
|
5
|
+
import { COMPONENT_IDENTITY_BY_ID, normalizeComponentIdentityConfig, readComponentIdentityValue, sameComponentIdentityConfig, } from "./resource-metadata.js";
|
|
5
6
|
import { readJsonFile, writeJsonFile } from "./utils.js";
|
|
6
7
|
export const REVO_LOCK_FILE = path.join(REVO_PROJECT_DIR, 'revo.lock.json');
|
|
7
8
|
const VOLATILE_COMPONENT_FIELDS = new Set([
|
|
@@ -21,6 +22,9 @@ const VOLATILE_COMPONENT_FIELDS = new Set([
|
|
|
21
22
|
'hash',
|
|
22
23
|
'remoteHash',
|
|
23
24
|
]);
|
|
25
|
+
function isRecord(value) {
|
|
26
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
27
|
+
}
|
|
24
28
|
function normalizeValue(value, fallback = null) {
|
|
25
29
|
return value ?? fallback;
|
|
26
30
|
}
|
|
@@ -63,10 +67,10 @@ export function normalizeComponentSource(component) {
|
|
|
63
67
|
async: Boolean(source.async),
|
|
64
68
|
elements: [...(source.elements || [])]
|
|
65
69
|
.map((element) => ({
|
|
66
|
-
key: element.key,
|
|
70
|
+
key: typeof element.key === 'string' ? element.key : '',
|
|
67
71
|
desc: normalizeValue(element.desc),
|
|
68
72
|
hidden: Boolean(element.hidden),
|
|
69
|
-
order: element.order,
|
|
73
|
+
order: Number.isFinite(Number(element.order)) ? Number(element.order) : 0,
|
|
70
74
|
details: element.details ?? '',
|
|
71
75
|
}))
|
|
72
76
|
.sort((left, right) => left.order - right.order || left.key.localeCompare(right.key)),
|
|
@@ -75,6 +79,51 @@ export function normalizeComponentSource(component) {
|
|
|
75
79
|
export function hashComponentSource(component) {
|
|
76
80
|
return hashStable(normalizeComponentSource(component));
|
|
77
81
|
}
|
|
82
|
+
// componentId is instance-local, so comparing components across two RevoEngine
|
|
83
|
+
// environments must project it away; element componentElementIds are already
|
|
84
|
+
// excluded by normalizeComponentSource.
|
|
85
|
+
export function normalizePortableComponentSource(component) {
|
|
86
|
+
const { componentId, ...portable } = normalizeComponentSource(component);
|
|
87
|
+
return portable;
|
|
88
|
+
}
|
|
89
|
+
export function hashPortableComponentSource(component) {
|
|
90
|
+
return hashStable(normalizePortableComponentSource(component));
|
|
91
|
+
}
|
|
92
|
+
export const PORTABLE_COMPONENT_CONFIG_FIELDS = [
|
|
93
|
+
'name',
|
|
94
|
+
'category',
|
|
95
|
+
'desc',
|
|
96
|
+
'active',
|
|
97
|
+
'type',
|
|
98
|
+
'async',
|
|
99
|
+
];
|
|
100
|
+
export function diffPortableComponentSource(source, target) {
|
|
101
|
+
const sourcePortable = normalizePortableComponentSource(source);
|
|
102
|
+
const targetPortable = normalizePortableComponentSource(target);
|
|
103
|
+
const configurationFields = PORTABLE_COMPONENT_CONFIG_FIELDS.filter((field) => sourcePortable[field] !== targetPortable[field]);
|
|
104
|
+
const elementsChanged = hashStable(sourcePortable.elements) !== hashStable(targetPortable.elements);
|
|
105
|
+
return {
|
|
106
|
+
configurationFields,
|
|
107
|
+
elementsChanged,
|
|
108
|
+
changedFields: [
|
|
109
|
+
...configurationFields,
|
|
110
|
+
...(elementsChanged ? ['elements'] : []),
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function buildPortableComponentUpdatePayload(source, target, changedFields) {
|
|
115
|
+
if (!Number.isInteger(target.version)) {
|
|
116
|
+
throw new Error('target component version is required to update component configuration');
|
|
117
|
+
}
|
|
118
|
+
const sourcePortable = normalizePortableComponentSource(source);
|
|
119
|
+
const payload = { version: target.version };
|
|
120
|
+
for (const field of PORTABLE_COMPONENT_CONFIG_FIELDS) {
|
|
121
|
+
if (changedFields.includes(field)) {
|
|
122
|
+
payload[field] = sourcePortable[field];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return payload;
|
|
126
|
+
}
|
|
78
127
|
export function getLockPath(projectRoot) {
|
|
79
128
|
return path.join(projectRoot, REVO_LOCK_FILE);
|
|
80
129
|
}
|
|
@@ -82,35 +131,349 @@ export function readComponentLock(projectRoot) {
|
|
|
82
131
|
const lockPath = getLockPath(projectRoot);
|
|
83
132
|
if (!fs.existsSync(lockPath)) {
|
|
84
133
|
return {
|
|
85
|
-
schemaVersion:
|
|
134
|
+
schemaVersion: 2,
|
|
135
|
+
componentIdentity: COMPONENT_IDENTITY_BY_ID,
|
|
86
136
|
components: {},
|
|
137
|
+
groups: {},
|
|
138
|
+
roleGroups: {},
|
|
139
|
+
jobTemplates: {},
|
|
140
|
+
schedules: {},
|
|
141
|
+
events: {},
|
|
142
|
+
endpoints: {},
|
|
143
|
+
databaseSchemas: {},
|
|
144
|
+
databaseViews: {},
|
|
87
145
|
};
|
|
88
146
|
}
|
|
89
147
|
const raw = readJsonFile(lockPath);
|
|
148
|
+
const componentIdentity = normalizeComponentIdentityConfig(raw.componentIdentity, COMPONENT_IDENTITY_BY_ID);
|
|
149
|
+
const components = Object.fromEntries(Object.entries(raw.components && typeof raw.components === 'object' ? raw.components : {})
|
|
150
|
+
.map(([key, entry]) => {
|
|
151
|
+
const remoteComponentId = String(entry.remoteComponentId || entry.componentId || key);
|
|
152
|
+
const identityMode = entry.identityMode || componentIdentity.mode;
|
|
153
|
+
return [key, {
|
|
154
|
+
...entry,
|
|
155
|
+
identityMode,
|
|
156
|
+
...(identityMode === 'stableKey'
|
|
157
|
+
? {
|
|
158
|
+
metadataProperty: entry.metadataProperty || componentIdentity.metadataProperty,
|
|
159
|
+
stableKey: entry.stableKey || key,
|
|
160
|
+
}
|
|
161
|
+
: {}),
|
|
162
|
+
componentId: String(entry.componentId || remoteComponentId),
|
|
163
|
+
remoteComponentId,
|
|
164
|
+
...(entry.environments && typeof entry.environments === 'object'
|
|
165
|
+
? {
|
|
166
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
167
|
+
.filter(([, baseline]) => (typeof baseline.remoteComponentId === 'string'
|
|
168
|
+
&& typeof baseline.remoteHash === 'string'
|
|
169
|
+
&& typeof baseline.syncedAt === 'string'))
|
|
170
|
+
.map(([envName, baseline]) => [envName, {
|
|
171
|
+
remoteComponentId: String(baseline.remoteComponentId),
|
|
172
|
+
remoteVersion: typeof baseline.remoteVersion === 'number' ? baseline.remoteVersion : null,
|
|
173
|
+
remoteHash: String(baseline.remoteHash),
|
|
174
|
+
syncedAt: String(baseline.syncedAt),
|
|
175
|
+
}])),
|
|
176
|
+
}
|
|
177
|
+
: {}),
|
|
178
|
+
}];
|
|
179
|
+
}));
|
|
90
180
|
return {
|
|
91
|
-
schemaVersion:
|
|
92
|
-
|
|
181
|
+
schemaVersion: 2,
|
|
182
|
+
componentIdentity,
|
|
183
|
+
components,
|
|
184
|
+
groups: Object.fromEntries(Object.entries(raw.groups && typeof raw.groups === 'object' ? raw.groups : {})
|
|
185
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
186
|
+
&& typeof entry.path === 'string'
|
|
187
|
+
&& typeof entry.sourceHash === 'string'
|
|
188
|
+
&& entry.environments
|
|
189
|
+
&& typeof entry.environments === 'object'))
|
|
190
|
+
.map(([key, entry]) => [key, {
|
|
191
|
+
stableKey: String(entry.stableKey),
|
|
192
|
+
path: String(entry.path),
|
|
193
|
+
sourceHash: String(entry.sourceHash),
|
|
194
|
+
...((isRecord(entry.owner) && entry.owner.type === 'group' && typeof entry.owner.stableKey === 'string')
|
|
195
|
+
? { owner: { type: 'group', stableKey: entry.owner.stableKey } }
|
|
196
|
+
: (isRecord(entry.owner) && entry.owner.type === 'manual-user')
|
|
197
|
+
? { owner: { type: 'manual-user' } }
|
|
198
|
+
: (isRecord(entry.owner) && entry.owner.type === 'unresolved' && typeof entry.owner.reason === 'string')
|
|
199
|
+
? { owner: { type: 'unresolved', reason: entry.owner.reason } }
|
|
200
|
+
: {}),
|
|
201
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
202
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string' && typeof baseline.syncedAt === 'string')
|
|
203
|
+
.map(([envName, baseline]) => [envName, {
|
|
204
|
+
remoteHash: String(baseline.remoteHash),
|
|
205
|
+
syncedAt: String(baseline.syncedAt),
|
|
206
|
+
}])),
|
|
207
|
+
}])),
|
|
208
|
+
roleGroups: Object.fromEntries(Object.entries(raw.roleGroups && typeof raw.roleGroups === 'object' ? raw.roleGroups : {})
|
|
209
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
210
|
+
&& typeof entry.path === 'string'
|
|
211
|
+
&& typeof entry.sourceHash === 'string'
|
|
212
|
+
&& entry.environments
|
|
213
|
+
&& typeof entry.environments === 'object'))
|
|
214
|
+
.map(([key, entry]) => [key, {
|
|
215
|
+
stableKey: String(entry.stableKey),
|
|
216
|
+
path: String(entry.path),
|
|
217
|
+
sourceHash: String(entry.sourceHash),
|
|
218
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
219
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string' && typeof baseline.syncedAt === 'string')
|
|
220
|
+
.map(([envName, baseline]) => [envName, {
|
|
221
|
+
remoteHash: String(baseline.remoteHash),
|
|
222
|
+
syncedAt: String(baseline.syncedAt),
|
|
223
|
+
}])),
|
|
224
|
+
}])),
|
|
225
|
+
jobTemplates: Object.fromEntries(Object.entries(raw.jobTemplates && typeof raw.jobTemplates === 'object' ? raw.jobTemplates : {})
|
|
226
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
227
|
+
&& typeof entry.path === 'string'
|
|
228
|
+
&& typeof entry.sourceHash === 'string'
|
|
229
|
+
&& entry.environments
|
|
230
|
+
&& typeof entry.environments === 'object'))
|
|
231
|
+
.map(([key, entry]) => [key, {
|
|
232
|
+
stableKey: String(entry.stableKey),
|
|
233
|
+
path: String(entry.path),
|
|
234
|
+
sourceHash: String(entry.sourceHash),
|
|
235
|
+
...((isRecord(entry.migration) && (entry.migration.componentBinding === 'pinned-unsupported'
|
|
236
|
+
|| entry.migration.executionPrincipal === 'excluded')) ? {
|
|
237
|
+
migration: {
|
|
238
|
+
...(entry.migration.componentBinding === 'pinned-unsupported' ? { componentBinding: 'pinned-unsupported' } : {}),
|
|
239
|
+
...(entry.migration.executionPrincipal === 'excluded' ? { executionPrincipal: 'excluded' } : {}),
|
|
240
|
+
},
|
|
241
|
+
} : {}),
|
|
242
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
243
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string' && typeof baseline.syncedAt === 'string')
|
|
244
|
+
.map(([envName, baseline]) => [envName, {
|
|
245
|
+
remoteHash: String(baseline.remoteHash),
|
|
246
|
+
syncedAt: String(baseline.syncedAt),
|
|
247
|
+
}])),
|
|
248
|
+
}])),
|
|
249
|
+
schedules: Object.fromEntries(Object.entries(raw.schedules && typeof raw.schedules === 'object' ? raw.schedules : {})
|
|
250
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
251
|
+
&& typeof entry.path === 'string'
|
|
252
|
+
&& typeof entry.sourceHash === 'string'
|
|
253
|
+
&& entry.environments
|
|
254
|
+
&& typeof entry.environments === 'object'))
|
|
255
|
+
.map(([key, entry]) => [key, {
|
|
256
|
+
stableKey: String(entry.stableKey),
|
|
257
|
+
path: String(entry.path),
|
|
258
|
+
sourceHash: String(entry.sourceHash),
|
|
259
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
260
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string' && typeof baseline.syncedAt === 'string')
|
|
261
|
+
.map(([envName, baseline]) => [envName, {
|
|
262
|
+
remoteHash: String(baseline.remoteHash),
|
|
263
|
+
syncedAt: String(baseline.syncedAt),
|
|
264
|
+
}])),
|
|
265
|
+
}])),
|
|
266
|
+
events: Object.fromEntries(Object.entries(raw.events && typeof raw.events === 'object' ? raw.events : {})
|
|
267
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
268
|
+
&& typeof entry.path === 'string'
|
|
269
|
+
&& typeof entry.sourceHash === 'string'
|
|
270
|
+
&& entry.environments
|
|
271
|
+
&& typeof entry.environments === 'object'))
|
|
272
|
+
.map(([key, entry]) => [key, {
|
|
273
|
+
stableKey: String(entry.stableKey),
|
|
274
|
+
path: String(entry.path),
|
|
275
|
+
sourceHash: String(entry.sourceHash),
|
|
276
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
277
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string' && typeof baseline.syncedAt === 'string')
|
|
278
|
+
.map(([envName, baseline]) => [envName, {
|
|
279
|
+
remoteHash: String(baseline.remoteHash),
|
|
280
|
+
syncedAt: String(baseline.syncedAt),
|
|
281
|
+
}])),
|
|
282
|
+
}])),
|
|
283
|
+
endpoints: Object.fromEntries(Object.entries(raw.endpoints && typeof raw.endpoints === 'object' ? raw.endpoints : {})
|
|
284
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
285
|
+
&& typeof entry.path === 'string'
|
|
286
|
+
&& typeof entry.sourceHash === 'string'
|
|
287
|
+
&& entry.environments
|
|
288
|
+
&& typeof entry.environments === 'object'))
|
|
289
|
+
.map(([key, entry]) => [key, {
|
|
290
|
+
stableKey: String(entry.stableKey),
|
|
291
|
+
path: String(entry.path),
|
|
292
|
+
sourceHash: String(entry.sourceHash),
|
|
293
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
294
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string' && typeof baseline.syncedAt === 'string')
|
|
295
|
+
.map(([envName, baseline]) => [envName, {
|
|
296
|
+
remoteHash: String(baseline.remoteHash),
|
|
297
|
+
syncedAt: String(baseline.syncedAt),
|
|
298
|
+
}])),
|
|
299
|
+
}])),
|
|
300
|
+
databaseSchemas: Object.fromEntries(Object.entries(raw.databaseSchemas && typeof raw.databaseSchemas === 'object' ? raw.databaseSchemas : {})
|
|
301
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
302
|
+
&& typeof entry.path === 'string'
|
|
303
|
+
&& typeof entry.sourceHash === 'string'
|
|
304
|
+
&& entry.environments
|
|
305
|
+
&& typeof entry.environments === 'object'))
|
|
306
|
+
.map(([key, entry]) => [key, {
|
|
307
|
+
stableKey: String(entry.stableKey),
|
|
308
|
+
path: String(entry.path),
|
|
309
|
+
sourceHash: String(entry.sourceHash),
|
|
310
|
+
...(typeof entry.sourceRestricted === 'boolean' ? { sourceRestricted: entry.sourceRestricted } : {}),
|
|
311
|
+
...(typeof entry.parentStableKey === 'string' ? { parentStableKey: entry.parentStableKey } : {}),
|
|
312
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
313
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string')
|
|
314
|
+
.map(([envName, baseline]) => [envName, {
|
|
315
|
+
remoteHash: String(baseline.remoteHash),
|
|
316
|
+
...(typeof baseline.tombstone?.deletedAt === 'string' && typeof baseline.tombstone.parentStableKey === 'string'
|
|
317
|
+
? { tombstone: {
|
|
318
|
+
deletedAt: baseline.tombstone.deletedAt,
|
|
319
|
+
parentStableKey: baseline.tombstone.parentStableKey,
|
|
320
|
+
} }
|
|
321
|
+
: {}),
|
|
322
|
+
}])),
|
|
323
|
+
}])),
|
|
324
|
+
databaseViews: Object.fromEntries(Object.entries(raw.databaseViews && typeof raw.databaseViews === 'object' ? raw.databaseViews : {})
|
|
325
|
+
.filter(([, entry]) => (typeof entry.stableKey === 'string'
|
|
326
|
+
&& typeof entry.path === 'string'
|
|
327
|
+
&& typeof entry.sourceHash === 'string'
|
|
328
|
+
&& entry.environments
|
|
329
|
+
&& typeof entry.environments === 'object'))
|
|
330
|
+
.map(([key, entry]) => [key, {
|
|
331
|
+
stableKey: String(entry.stableKey),
|
|
332
|
+
path: String(entry.path),
|
|
333
|
+
sourceHash: String(entry.sourceHash),
|
|
334
|
+
environments: Object.fromEntries(Object.entries(entry.environments)
|
|
335
|
+
.filter(([, baseline]) => typeof baseline.remoteHash === 'string' && typeof baseline.syncedAt === 'string')
|
|
336
|
+
.map(([envName, baseline]) => [envName, {
|
|
337
|
+
remoteHash: String(baseline.remoteHash),
|
|
338
|
+
syncedAt: String(baseline.syncedAt),
|
|
339
|
+
}])),
|
|
340
|
+
}])),
|
|
93
341
|
};
|
|
94
342
|
}
|
|
95
343
|
export function writeComponentLock(projectRoot, lock) {
|
|
96
344
|
const sortedComponents = Object.fromEntries(Object.entries(lock.components).sort(([left], [right]) => left.localeCompare(right)));
|
|
345
|
+
const sortedRoleGroups = Object.fromEntries(Object.entries(lock.roleGroups).sort(([left], [right]) => left.localeCompare(right)));
|
|
346
|
+
const sortedGroups = Object.fromEntries(Object.entries(lock.groups || {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
347
|
+
const sortedJobTemplates = Object.fromEntries(Object.entries(lock.jobTemplates || {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
348
|
+
const sortedSchedules = Object.fromEntries(Object.entries(lock.schedules || {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
349
|
+
const sortedEvents = Object.fromEntries(Object.entries(lock.events || {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
350
|
+
const sortedEndpoints = Object.fromEntries(Object.entries(lock.endpoints || {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
351
|
+
const sortedDatabaseSchemas = Object.fromEntries(Object.entries(lock.databaseSchemas || {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
352
|
+
const sortedDatabaseViews = Object.fromEntries(Object.entries(lock.databaseViews || {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
97
353
|
writeJsonFile(getLockPath(projectRoot), {
|
|
98
|
-
schemaVersion:
|
|
354
|
+
schemaVersion: 2,
|
|
355
|
+
componentIdentity: normalizeComponentIdentityConfig(lock.componentIdentity),
|
|
99
356
|
components: sortedComponents,
|
|
357
|
+
...(Object.keys(sortedGroups).length > 0 ? { groups: sortedGroups } : {}),
|
|
358
|
+
roleGroups: sortedRoleGroups,
|
|
359
|
+
jobTemplates: sortedJobTemplates,
|
|
360
|
+
...(Object.keys(sortedSchedules).length > 0 ? { schedules: sortedSchedules } : {}),
|
|
361
|
+
...(Object.keys(sortedEvents).length > 0 ? { events: sortedEvents } : {}),
|
|
362
|
+
...(Object.keys(sortedEndpoints).length > 0 ? { endpoints: sortedEndpoints } : {}),
|
|
363
|
+
...(Object.keys(sortedDatabaseSchemas).length > 0 ? { databaseSchemas: sortedDatabaseSchemas } : {}),
|
|
364
|
+
...(Object.keys(sortedDatabaseViews).length > 0 ? { databaseViews: sortedDatabaseViews } : {}),
|
|
100
365
|
});
|
|
101
366
|
}
|
|
102
|
-
export function
|
|
367
|
+
export function componentLockKey(identity, component) {
|
|
368
|
+
return readComponentIdentityValue(component, identity);
|
|
369
|
+
}
|
|
370
|
+
export function componentLockMatchesIdentity(lock, identity) {
|
|
371
|
+
return sameComponentIdentityConfig(lock.componentIdentity, identity);
|
|
372
|
+
}
|
|
373
|
+
export function getComponentLockEntry(lock, identity, component, environmentName) {
|
|
374
|
+
if (!componentLockMatchesIdentity(lock, identity)) {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
const key = componentLockKey(identity, component);
|
|
378
|
+
const entry = key ? lock.components[key] || null : null;
|
|
379
|
+
if (!entry || !environmentName) {
|
|
380
|
+
return entry;
|
|
381
|
+
}
|
|
382
|
+
const baseline = entry.environments?.[environmentName];
|
|
383
|
+
if (!baseline) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
...entry,
|
|
388
|
+
remoteComponentId: baseline.remoteComponentId,
|
|
389
|
+
remoteVersion: baseline.remoteVersion,
|
|
390
|
+
remoteHash: baseline.remoteHash,
|
|
391
|
+
pulledAt: baseline.syncedAt,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
export function getComponentLockEntries(lock, identity, environmentName) {
|
|
395
|
+
if (!componentLockMatchesIdentity(lock, identity)) {
|
|
396
|
+
return {};
|
|
397
|
+
}
|
|
398
|
+
if (!environmentName) {
|
|
399
|
+
return lock.components;
|
|
400
|
+
}
|
|
401
|
+
return Object.fromEntries(Object.entries(lock.components).flatMap(([key, entry]) => {
|
|
402
|
+
const baseline = entry.environments?.[environmentName];
|
|
403
|
+
if (!baseline) {
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
return [[key, {
|
|
407
|
+
...entry,
|
|
408
|
+
remoteComponentId: baseline.remoteComponentId,
|
|
409
|
+
remoteVersion: baseline.remoteVersion,
|
|
410
|
+
remoteHash: baseline.remoteHash,
|
|
411
|
+
pulledAt: baseline.syncedAt,
|
|
412
|
+
}]];
|
|
413
|
+
}));
|
|
414
|
+
}
|
|
415
|
+
export function upsertComponentLockEntry(projectRoot, entry, identity = COMPONENT_IDENTITY_BY_ID, environmentName) {
|
|
416
|
+
const normalizedIdentity = normalizeComponentIdentityConfig(identity);
|
|
103
417
|
const lock = readComponentLock(projectRoot);
|
|
104
|
-
|
|
418
|
+
if (!componentLockMatchesIdentity(lock, normalizedIdentity)) {
|
|
419
|
+
lock.componentIdentity = normalizedIdentity;
|
|
420
|
+
lock.components = {};
|
|
421
|
+
}
|
|
422
|
+
const remoteComponentId = entry.remoteComponentId || entry.componentId;
|
|
423
|
+
const key = normalizedIdentity.mode === 'stableKey'
|
|
424
|
+
? entry.stableKey
|
|
425
|
+
: remoteComponentId;
|
|
426
|
+
if (!key) {
|
|
427
|
+
throw new Error(`Cannot write component lock entry without ${normalizedIdentity.mode === 'stableKey' ? normalizedIdentity.metadataProperty : 'componentId'}.`);
|
|
428
|
+
}
|
|
429
|
+
const normalizedEntry = {
|
|
430
|
+
...entry,
|
|
431
|
+
identityMode: normalizedIdentity.mode,
|
|
432
|
+
remoteComponentId,
|
|
433
|
+
...(normalizedIdentity.mode === 'stableKey'
|
|
434
|
+
? {
|
|
435
|
+
metadataProperty: normalizedIdentity.metadataProperty,
|
|
436
|
+
stableKey: key,
|
|
437
|
+
}
|
|
438
|
+
: {}),
|
|
439
|
+
};
|
|
440
|
+
const existing = lock.components[key];
|
|
441
|
+
const storedEntry = environmentName
|
|
442
|
+
? {
|
|
443
|
+
...normalizedEntry,
|
|
444
|
+
remoteComponentId: existing?.remoteComponentId || normalizedEntry.remoteComponentId,
|
|
445
|
+
remoteVersion: existing?.remoteVersion ?? normalizedEntry.remoteVersion,
|
|
446
|
+
remoteHash: existing?.remoteHash || normalizedEntry.remoteHash,
|
|
447
|
+
environments: {
|
|
448
|
+
...existing?.environments,
|
|
449
|
+
[environmentName]: {
|
|
450
|
+
remoteComponentId: normalizedEntry.remoteComponentId,
|
|
451
|
+
remoteVersion: normalizedEntry.remoteVersion,
|
|
452
|
+
remoteHash: normalizedEntry.remoteHash,
|
|
453
|
+
syncedAt: normalizedEntry.pulledAt,
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
}
|
|
457
|
+
: {
|
|
458
|
+
...normalizedEntry,
|
|
459
|
+
...(existing?.environments ? { environments: existing.environments } : {}),
|
|
460
|
+
};
|
|
105
461
|
if (existing
|
|
106
|
-
&& existing.
|
|
107
|
-
&& existing.
|
|
108
|
-
&& existing.
|
|
109
|
-
&& existing.
|
|
110
|
-
&& existing.
|
|
111
|
-
&& existing.
|
|
462
|
+
&& existing.identityMode === storedEntry.identityMode
|
|
463
|
+
&& existing.metadataProperty === storedEntry.metadataProperty
|
|
464
|
+
&& existing.stableKey === storedEntry.stableKey
|
|
465
|
+
&& existing.componentId === storedEntry.componentId
|
|
466
|
+
&& existing.remoteComponentId === storedEntry.remoteComponentId
|
|
467
|
+
&& existing.componentName === storedEntry.componentName
|
|
468
|
+
&& existing.category === storedEntry.category
|
|
469
|
+
&& existing.path === storedEntry.path
|
|
470
|
+
&& existing.remoteVersion === storedEntry.remoteVersion
|
|
471
|
+
&& existing.remoteHash === storedEntry.remoteHash
|
|
472
|
+
&& existing.sourceHash === storedEntry.sourceHash
|
|
473
|
+
&& JSON.stringify(existing.environments || {}) === JSON.stringify(storedEntry.environments || {})) {
|
|
112
474
|
return;
|
|
113
475
|
}
|
|
114
|
-
lock.
|
|
476
|
+
lock.componentIdentity = normalizedIdentity;
|
|
477
|
+
lock.components[key] = storedEntry;
|
|
115
478
|
writeComponentLock(projectRoot, lock);
|
|
116
479
|
}
|
package/dist/src/config.d.ts
CHANGED
|
@@ -4,14 +4,24 @@ export type RuntimeConfig = {
|
|
|
4
4
|
baseUrl: string;
|
|
5
5
|
instance: string;
|
|
6
6
|
token: string;
|
|
7
|
+
production?: true;
|
|
7
8
|
};
|
|
8
9
|
export type RuntimeConfigOptions = {
|
|
9
10
|
baseUrl?: string;
|
|
10
11
|
instance?: string;
|
|
11
12
|
token?: string;
|
|
13
|
+
envName?: string;
|
|
14
|
+
};
|
|
15
|
+
export type StoredEnvironmentProfile = {
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
token: string;
|
|
18
|
+
instance?: string;
|
|
19
|
+
production?: true;
|
|
12
20
|
};
|
|
13
21
|
type StoredConfig = Omit<RuntimeConfig, 'instance'> & {
|
|
14
22
|
instance?: string;
|
|
23
|
+
environments?: Record<string, StoredEnvironmentProfile>;
|
|
24
|
+
activeEnvironment?: string;
|
|
15
25
|
};
|
|
16
26
|
export type AuthValidationState = {
|
|
17
27
|
key: string;
|
|
@@ -45,11 +55,21 @@ export declare function loadStoredConfigIndex(): {
|
|
|
45
55
|
export declare function loadStoredConfig(options?: {
|
|
46
56
|
allowLegacy?: boolean;
|
|
47
57
|
}): StoredConfig;
|
|
58
|
+
export declare function listEnvironmentProfiles(): Record<string, StoredEnvironmentProfile>;
|
|
59
|
+
export declare function getEnvironmentProfile(name: string): StoredEnvironmentProfile | null;
|
|
60
|
+
export declare const DEFAULT_ENV_NAME = "default";
|
|
61
|
+
export declare function getActiveEnvironmentName(): string;
|
|
62
|
+
export declare function setActiveEnvironmentName(name: string): void;
|
|
63
|
+
export declare function saveEnvironmentProfile(name: string, profile: StoredEnvironmentProfile, options?: {
|
|
64
|
+
activate?: boolean;
|
|
65
|
+
}): void;
|
|
66
|
+
export declare function removeEnvironmentProfile(name: string): boolean;
|
|
48
67
|
export declare function buildAuthValidationKey(runtime: RuntimeConfigOptions): string;
|
|
49
68
|
export declare function readAuthValidationState(key?: string): AuthValidationState;
|
|
50
69
|
export declare function saveAuthValidationState(state: AuthValidationState): void;
|
|
51
70
|
export declare function clearAuthValidationState(key?: string): void;
|
|
52
71
|
export declare function resolveRuntimeConfig(options?: RuntimeConfigOptions): {
|
|
72
|
+
production?: true | undefined;
|
|
53
73
|
baseUrl: string;
|
|
54
74
|
instance: string;
|
|
55
75
|
token: string;
|