@neocompose/cli 0.6.1 → 0.6.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/CHANGELOG.md +17 -0
- package/README.md +3 -0
- package/dist/neo.mjs +1059 -80
- package/package.json +1 -1
package/dist/neo.mjs
CHANGED
|
@@ -26173,6 +26173,9 @@ var init_merge = __esm({
|
|
|
26173
26173
|
});
|
|
26174
26174
|
|
|
26175
26175
|
// src/project-manifest/merge.ts
|
|
26176
|
+
function isSchemaDocumentRecordKind(recordKind) {
|
|
26177
|
+
return Object.hasOwn(SCHEMA_DOCUMENT_FIELD_CONTRACTS, recordKind);
|
|
26178
|
+
}
|
|
26176
26179
|
function schemaDocumentSemanticallyEqual(recordKind, left, right) {
|
|
26177
26180
|
return canonicallyEqual(
|
|
26178
26181
|
normalizeDocumentForComparison(recordKind, left, "left"),
|
|
@@ -38036,8 +38039,9 @@ function regenerateDialogueSourceNamesV4(records2) {
|
|
|
38036
38039
|
const nodeNames = regeneratedNodeNames(nodes, triggerId, classMembers);
|
|
38037
38040
|
const dialogueLinks = regenerateBindingSourceNames(
|
|
38038
38041
|
dialogue.linkedValues,
|
|
38039
|
-
|
|
38040
|
-
placements
|
|
38042
|
+
classMembers,
|
|
38043
|
+
placements,
|
|
38044
|
+
"pascal"
|
|
38041
38045
|
);
|
|
38042
38046
|
const dialogueBindingNames = new Map(
|
|
38043
38047
|
dialogueLinks.map((link) => [
|
|
@@ -38045,9 +38049,6 @@ function regenerateDialogueSourceNamesV4(records2) {
|
|
|
38045
38049
|
stringField(link, "sourceName")
|
|
38046
38050
|
])
|
|
38047
38051
|
);
|
|
38048
|
-
for (const link of dialogueLinks) {
|
|
38049
|
-
classMembers.reserve(stringField(link, "sourceName"));
|
|
38050
|
-
}
|
|
38051
38052
|
const functionNames = regeneratedSourceFunctionNames(nodes, classMembers);
|
|
38052
38053
|
const nextDialogue = rewriteFunctionSourceNames(
|
|
38053
38054
|
{ ...dialogue, sourceName: className, linkedValues: dialogueLinks },
|
|
@@ -38120,7 +38121,7 @@ function regeneratedNodeNames(nodes, triggerId, allocator) {
|
|
|
38120
38121
|
}
|
|
38121
38122
|
return result;
|
|
38122
38123
|
}
|
|
38123
|
-
function regenerateBindingSourceNames(rawLinks, allocator, placements) {
|
|
38124
|
+
function regenerateBindingSourceNames(rawLinks, allocator, placements, casing) {
|
|
38124
38125
|
if (!Array.isArray(rawLinks)) return [];
|
|
38125
38126
|
return rawLinks.map((rawLink, index) => {
|
|
38126
38127
|
if (!isObjectRecord2(rawLink) || typeof rawLink.valueId !== "string") {
|
|
@@ -38128,7 +38129,8 @@ function regenerateBindingSourceNames(rawLinks, allocator, placements) {
|
|
|
38128
38129
|
}
|
|
38129
38130
|
const preferred = placements.preferredBindingName(
|
|
38130
38131
|
rawLink.valueId,
|
|
38131
|
-
optionalString2(rawLink.declaredTypeName) ?? `value${index + 1}
|
|
38132
|
+
optionalString2(rawLink.declaredTypeName) ?? `value${index + 1}`,
|
|
38133
|
+
casing
|
|
38132
38134
|
);
|
|
38133
38135
|
return { ...rawLink, sourceName: allocator.claim(preferred) };
|
|
38134
38136
|
});
|
|
@@ -38141,25 +38143,47 @@ function regenerateNodeBindingSourceNames(rawLinks, placements, dialogueNamesByV
|
|
|
38141
38143
|
}
|
|
38142
38144
|
return rawLink;
|
|
38143
38145
|
});
|
|
38146
|
+
const inheritedValueIds = new Set(
|
|
38147
|
+
links.flatMap((link) => {
|
|
38148
|
+
const valueId = stringField(link, "valueId");
|
|
38149
|
+
return dialogueNamesByValueId.has(valueId) ? [valueId] : [];
|
|
38150
|
+
})
|
|
38151
|
+
);
|
|
38144
38152
|
const allocator = new DialogueSourceNameAllocator(
|
|
38145
|
-
dialogueNamesByValueId.
|
|
38153
|
+
[...dialogueNamesByValueId].filter(([valueId]) => !inheritedValueIds.has(valueId)).map(([, name]) => name)
|
|
38146
38154
|
);
|
|
38147
|
-
|
|
38155
|
+
const namesByValueId = /* @__PURE__ */ new Map();
|
|
38156
|
+
const allocate = (link, index) => {
|
|
38148
38157
|
const valueId = stringField(link, "valueId");
|
|
38149
|
-
|
|
38150
|
-
|
|
38151
|
-
|
|
38152
|
-
}
|
|
38153
|
-
return {
|
|
38154
|
-
...link,
|
|
38155
|
-
sourceName: allocator.claim(
|
|
38158
|
+
namesByValueId.set(
|
|
38159
|
+
valueId,
|
|
38160
|
+
allocator.claim(
|
|
38156
38161
|
placements.preferredBindingName(
|
|
38157
38162
|
valueId,
|
|
38158
|
-
optionalString2(link.declaredTypeName) ?? `value${index + 1}
|
|
38163
|
+
optionalString2(link.declaredTypeName) ?? `value${index + 1}`,
|
|
38164
|
+
"camel"
|
|
38159
38165
|
)
|
|
38160
38166
|
)
|
|
38161
|
-
|
|
38167
|
+
);
|
|
38168
|
+
};
|
|
38169
|
+
links.forEach((link, index) => {
|
|
38170
|
+
if (dialogueNamesByValueId.has(stringField(link, "valueId"))) {
|
|
38171
|
+
allocate(link, index);
|
|
38172
|
+
}
|
|
38162
38173
|
});
|
|
38174
|
+
links.forEach((link, index) => {
|
|
38175
|
+
if (!dialogueNamesByValueId.has(stringField(link, "valueId"))) {
|
|
38176
|
+
allocate(link, index);
|
|
38177
|
+
}
|
|
38178
|
+
});
|
|
38179
|
+
return links.map((link) => ({
|
|
38180
|
+
...link,
|
|
38181
|
+
sourceName: requiredMap(
|
|
38182
|
+
namesByValueId,
|
|
38183
|
+
stringField(link, "valueId"),
|
|
38184
|
+
"dialogue-node linked value"
|
|
38185
|
+
)
|
|
38186
|
+
}));
|
|
38163
38187
|
}
|
|
38164
38188
|
function regenerateTextChildren(node) {
|
|
38165
38189
|
if (!isObjectRecord2(node.optionSettings)) return node;
|
|
@@ -39190,6 +39214,12 @@ function lowerIdentifier(value) {
|
|
|
39190
39214
|
const result = pascalIdentifier2(value);
|
|
39191
39215
|
return `${result[0]?.toLowerCase() ?? "v"}${result.slice(1)}`;
|
|
39192
39216
|
}
|
|
39217
|
+
function bindingIdentifier(value, casing) {
|
|
39218
|
+
const cased = casing === "camel" ? lowerIdentifier(value) : value;
|
|
39219
|
+
if (isDialogueSourceIdentifier(cased)) return cased;
|
|
39220
|
+
const escaped = `_${cased}`;
|
|
39221
|
+
return isDialogueSourceIdentifier(escaped) ? escaped : "_Value";
|
|
39222
|
+
}
|
|
39193
39223
|
function ensureStatement(value) {
|
|
39194
39224
|
const trimmed = value.trim();
|
|
39195
39225
|
return trimmed.endsWith(";") ? trimmed : `${trimmed};`;
|
|
@@ -39271,8 +39301,10 @@ var init_dialogue_sources = __esm({
|
|
|
39271
39301
|
classes = /* @__PURE__ */ new Map();
|
|
39272
39302
|
classesByName = /* @__PURE__ */ new Map();
|
|
39273
39303
|
values = /* @__PURE__ */ new Map();
|
|
39304
|
+
localizedTexts = /* @__PURE__ */ new Map();
|
|
39274
39305
|
ownerClassIdsByMemberId = /* @__PURE__ */ new Map();
|
|
39275
39306
|
parentValueIdsByChildId = /* @__PURE__ */ new Map();
|
|
39307
|
+
mainLocale;
|
|
39276
39308
|
constructor(records2) {
|
|
39277
39309
|
for (const record3 of records2) {
|
|
39278
39310
|
if (record3.recordKind === "member")
|
|
@@ -39281,7 +39313,13 @@ var init_dialogue_sources = __esm({
|
|
|
39281
39313
|
this.classes.set(record3.recordId, recordData2(record3));
|
|
39282
39314
|
else if (record3.recordKind === "value")
|
|
39283
39315
|
this.values.set(record3.recordId, recordData2(record3));
|
|
39316
|
+
else if (record3.recordKind === "localized-text")
|
|
39317
|
+
this.localizedTexts.set(record3.recordId, recordData2(record3));
|
|
39284
39318
|
}
|
|
39319
|
+
const localization = records2.find(
|
|
39320
|
+
(record3) => record3.recordKind === "localization-config"
|
|
39321
|
+
);
|
|
39322
|
+
this.mainLocale = localization ? optionalString2(recordData2(localization).mainLocale) ?? "en-US" : "en-US";
|
|
39285
39323
|
for (const schemaClass2 of this.classes.values()) {
|
|
39286
39324
|
const name = optionalString2(schemaClass2.name);
|
|
39287
39325
|
if (name && !this.classesByName.has(name)) {
|
|
@@ -39336,34 +39374,48 @@ var init_dialogue_sources = __esm({
|
|
|
39336
39374
|
get(valueId) {
|
|
39337
39375
|
return this.symbols.get(valueId) ?? this.inferClassStamped(valueId) ?? this.inferDetached(valueId);
|
|
39338
39376
|
}
|
|
39339
|
-
preferredBindingName(valueId, fallback) {
|
|
39340
|
-
const
|
|
39377
|
+
preferredBindingName(valueId, fallback, casing) {
|
|
39378
|
+
const symbol = this.get(valueId);
|
|
39379
|
+
const displayName = this.valueDisplayName(
|
|
39380
|
+
valueId,
|
|
39381
|
+
symbol?.type ?? fallback
|
|
39382
|
+
);
|
|
39341
39383
|
if (displayName !== null) {
|
|
39342
|
-
return
|
|
39343
|
-
dialogueSourceNameFromDisplayName(displayName, fallback)
|
|
39384
|
+
return bindingIdentifier(
|
|
39385
|
+
dialogueSourceNameFromDisplayName(displayName, fallback),
|
|
39386
|
+
casing
|
|
39344
39387
|
);
|
|
39345
39388
|
}
|
|
39346
|
-
const symbol = this.get(valueId);
|
|
39347
39389
|
const placedName = symbol?.expression.includes(".") === true ? symbol.expression.split(".").at(-1) : null;
|
|
39348
|
-
return
|
|
39349
|
-
dialogueSourceNameFromDisplayName(placedName, symbol?.type ?? fallback)
|
|
39390
|
+
return bindingIdentifier(
|
|
39391
|
+
dialogueSourceNameFromDisplayName(placedName, symbol?.type ?? fallback),
|
|
39392
|
+
casing
|
|
39350
39393
|
);
|
|
39351
39394
|
}
|
|
39352
|
-
valueDisplayName(valueId) {
|
|
39395
|
+
valueDisplayName(valueId, typeName) {
|
|
39353
39396
|
const value = this.values.get(valueId);
|
|
39354
39397
|
if (!value || !isObjectRecord2(value.value)) return null;
|
|
39355
39398
|
const classId = optionalString2(value.classId);
|
|
39356
|
-
const schemaClass2 = classId ? this.classes.get(classId) :
|
|
39399
|
+
const schemaClass2 = classId ? this.classes.get(classId) : this.classesByName.get(typeName);
|
|
39357
39400
|
if (!schemaClass2 || !isObjectRecord2(schemaClass2.schema)) return null;
|
|
39358
39401
|
const nameEntry = Object.entries(schemaClass2.schema).find(
|
|
39359
39402
|
([memberName2]) => memberName2.toLocaleLowerCase("en-US") === "name"
|
|
39360
39403
|
);
|
|
39361
39404
|
if (nameEntry === void 0) return null;
|
|
39362
|
-
const [memberName] = nameEntry;
|
|
39405
|
+
const [memberName, memberId] = nameEntry;
|
|
39406
|
+
if (typeof memberId !== "string") return null;
|
|
39407
|
+
const nameMember = this.members.get(memberId);
|
|
39408
|
+
if (nameMember?.kind !== 3) return null;
|
|
39363
39409
|
const childValueId = value.value[memberName];
|
|
39364
39410
|
if (typeof childValueId !== "string") return null;
|
|
39365
39411
|
const child = this.values.get(childValueId);
|
|
39366
|
-
|
|
39412
|
+
if (typeof child?.value !== "string") return null;
|
|
39413
|
+
const localizedText = this.localizedTexts.get(child.value);
|
|
39414
|
+
const localeValues = isObjectRecord2(localizedText?.localeValues) ? localizedText.localeValues : null;
|
|
39415
|
+
const mainLocaleEntry = localeValues?.[this.mainLocale];
|
|
39416
|
+
const mainLocaleValue = isObjectRecord2(mainLocaleEntry) ? mainLocaleEntry.value : null;
|
|
39417
|
+
const displayName = typeof mainLocaleValue === "string" ? mainLocaleValue : child.value;
|
|
39418
|
+
return displayName.trim().length > 0 ? displayName : null;
|
|
39367
39419
|
}
|
|
39368
39420
|
inferClassStamped(valueId) {
|
|
39369
39421
|
const value = this.values.get(valueId);
|
|
@@ -45473,6 +45525,7 @@ __export(project_document_read_exports, {
|
|
|
45473
45525
|
readOptionalArrayField: () => readOptionalArrayField,
|
|
45474
45526
|
readProjectDocument: () => readProjectDocument,
|
|
45475
45527
|
readProjectDocumentContentHashHeads: () => readProjectDocumentContentHashHeads,
|
|
45528
|
+
readProjectDocumentManifestPageRecords: () => readProjectDocumentManifestPageRecords,
|
|
45476
45529
|
readProjectDocumentManifestRecords: () => readProjectDocumentManifestRecords,
|
|
45477
45530
|
readProjectDocumentRevisionMarker: () => readProjectDocumentRevisionMarker
|
|
45478
45531
|
});
|
|
@@ -45678,6 +45731,12 @@ function readProjectDocumentManifestRecords(value) {
|
|
|
45678
45731
|
};
|
|
45679
45732
|
});
|
|
45680
45733
|
}
|
|
45734
|
+
function readProjectDocumentManifestPageRecords(value) {
|
|
45735
|
+
if (!isObject3(value)) {
|
|
45736
|
+
throw new Error("Convex project document manifest page must be an object.");
|
|
45737
|
+
}
|
|
45738
|
+
return readProjectDocumentManifestRecords(value.records);
|
|
45739
|
+
}
|
|
45681
45740
|
async function fetchProjectDocumentSnapshots(fetchBatch, snapshotIds) {
|
|
45682
45741
|
const chunks = [];
|
|
45683
45742
|
for (let offset = 0; offset < snapshotIds.length; offset += DOCUMENT_SNAPSHOT_FETCH_CHUNK_SIZE) {
|
|
@@ -46639,6 +46698,32 @@ var init_http = __esm({
|
|
|
46639
46698
|
}
|
|
46640
46699
|
return parsed;
|
|
46641
46700
|
}
|
|
46701
|
+
async get(path, options = {}) {
|
|
46702
|
+
const url = new URL(path, this.apiBaseUrl).toString();
|
|
46703
|
+
const response = await fetch(url, {
|
|
46704
|
+
method: "GET",
|
|
46705
|
+
headers: { Authorization: `Bearer ${this.token}` },
|
|
46706
|
+
signal: options.signal
|
|
46707
|
+
});
|
|
46708
|
+
const text = await response.text();
|
|
46709
|
+
let parsed = null;
|
|
46710
|
+
if (text.length > 0) {
|
|
46711
|
+
try {
|
|
46712
|
+
parsed = JSON.parse(text);
|
|
46713
|
+
} catch {
|
|
46714
|
+
parsed = text;
|
|
46715
|
+
}
|
|
46716
|
+
}
|
|
46717
|
+
if (!response.ok) {
|
|
46718
|
+
const detail = typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "string" ? parsed.error : text.slice(0, 300);
|
|
46719
|
+
throw new NeoApiError(
|
|
46720
|
+
`GET ${path} failed with status ${response.status}: ${detail}`,
|
|
46721
|
+
response.status,
|
|
46722
|
+
parsed
|
|
46723
|
+
);
|
|
46724
|
+
}
|
|
46725
|
+
return parsed;
|
|
46726
|
+
}
|
|
46642
46727
|
async getBytes(path) {
|
|
46643
46728
|
const url = new URL(path, this.apiBaseUrl).toString();
|
|
46644
46729
|
const response = await fetch(url, {
|
|
@@ -59063,11 +59148,32 @@ async function runMerge(workspace, sourceRef, dryRun, runMigrations = false) {
|
|
|
59063
59148
|
}
|
|
59064
59149
|
}
|
|
59065
59150
|
try {
|
|
59066
|
-
|
|
59151
|
+
let result = await client.post(mergePath, {
|
|
59067
59152
|
sourceVersionId: source.id,
|
|
59068
59153
|
dryRun,
|
|
59069
59154
|
resolutions: resolutions.length > 0 ? resolutions : void 0
|
|
59070
59155
|
});
|
|
59156
|
+
const accepted = readAcceptedMergeTransaction(result);
|
|
59157
|
+
if (accepted !== null) {
|
|
59158
|
+
const progress = spinner("Preparing merge\u2026");
|
|
59159
|
+
try {
|
|
59160
|
+
await waitForMergeTransaction({
|
|
59161
|
+
client,
|
|
59162
|
+
projectId: workspace.config.projectId,
|
|
59163
|
+
versionId: workspace.config.versionId,
|
|
59164
|
+
accepted,
|
|
59165
|
+
update: (label) => progress.update(label)
|
|
59166
|
+
});
|
|
59167
|
+
progress.succeed("Merge transaction committed.");
|
|
59168
|
+
} catch (error) {
|
|
59169
|
+
progress.fail("Merge transaction failed.");
|
|
59170
|
+
throw error;
|
|
59171
|
+
}
|
|
59172
|
+
result = { ...result, commitStatus: "committed" };
|
|
59173
|
+
if (result.sourceArchivePending === true) {
|
|
59174
|
+
console.log("Source branch archival is finishing in the background.");
|
|
59175
|
+
}
|
|
59176
|
+
}
|
|
59071
59177
|
const merged = typeof result.merged === "number" ? result.merged : 0;
|
|
59072
59178
|
if (dryRun) {
|
|
59073
59179
|
console.log(`Merge dry-run: ${merged} record(s) would merge cleanly.`);
|
|
@@ -59135,6 +59241,104 @@ async function runMerge(workspace, sourceRef, dryRun, runMigrations = false) {
|
|
|
59135
59241
|
throw error;
|
|
59136
59242
|
}
|
|
59137
59243
|
}
|
|
59244
|
+
function readAcceptedMergeTransaction(value) {
|
|
59245
|
+
if (!isObjectRecord2(value)) {
|
|
59246
|
+
throw new Error("Merge response must be an object.");
|
|
59247
|
+
}
|
|
59248
|
+
if (value.kind !== "accepted") return null;
|
|
59249
|
+
if (typeof value.transactionId !== "string") {
|
|
59250
|
+
throw new Error("Accepted merge is missing transactionId.");
|
|
59251
|
+
}
|
|
59252
|
+
if (!isMergeTransactionStatus(value.commitStatus)) {
|
|
59253
|
+
throw new Error("Accepted merge has an invalid commitStatus.");
|
|
59254
|
+
}
|
|
59255
|
+
const totalChangeCount = value.totalChangeCount === null ? null : readMergeProgressCount(value.totalChangeCount, "totalChangeCount");
|
|
59256
|
+
const appliedChangeCount = readMergeProgressCount(
|
|
59257
|
+
value.appliedChangeCount,
|
|
59258
|
+
"appliedChangeCount"
|
|
59259
|
+
);
|
|
59260
|
+
return {
|
|
59261
|
+
transactionId: value.transactionId,
|
|
59262
|
+
commitStatus: value.commitStatus,
|
|
59263
|
+
totalChangeCount,
|
|
59264
|
+
appliedChangeCount
|
|
59265
|
+
};
|
|
59266
|
+
}
|
|
59267
|
+
async function waitForMergeTransaction(args) {
|
|
59268
|
+
const transactionPath = `/api/projects/${encodeURIComponent(args.projectId)}/versions/${encodeURIComponent(args.versionId)}/schema/transactions/${encodeURIComponent(args.accepted.transactionId)}`;
|
|
59269
|
+
let status = args.accepted;
|
|
59270
|
+
let delayMs = 250;
|
|
59271
|
+
for (; ; ) {
|
|
59272
|
+
args.update(mergeTransactionProgressLabel(status));
|
|
59273
|
+
if (status.commitStatus === "committed") return;
|
|
59274
|
+
if (status.commitStatus === "failed") {
|
|
59275
|
+
throw new Error(
|
|
59276
|
+
`Merge transaction "${status.transactionId}" failed after rollback.`
|
|
59277
|
+
);
|
|
59278
|
+
}
|
|
59279
|
+
const response = await args.client.get(transactionPath);
|
|
59280
|
+
status = readMergeTransactionStatus(response, status.transactionId);
|
|
59281
|
+
if (status.commitStatus === "committed") continue;
|
|
59282
|
+
if (status.commitStatus === "failed") continue;
|
|
59283
|
+
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
|
|
59284
|
+
delayMs = Math.min(delayMs * 2, 5e3);
|
|
59285
|
+
}
|
|
59286
|
+
}
|
|
59287
|
+
function readMergeTransactionStatus(value, transactionId) {
|
|
59288
|
+
if (!isObjectRecord2(value)) {
|
|
59289
|
+
throw new Error(
|
|
59290
|
+
`Merge transaction "${transactionId}" status must be an object.`
|
|
59291
|
+
);
|
|
59292
|
+
}
|
|
59293
|
+
if (value.transactionId !== transactionId) {
|
|
59294
|
+
throw new Error(
|
|
59295
|
+
`Merge transaction status expected "${transactionId}", received ${JSON.stringify(value.transactionId)}.`
|
|
59296
|
+
);
|
|
59297
|
+
}
|
|
59298
|
+
if (!isMergeTransactionStatus(value.commitStatus)) {
|
|
59299
|
+
throw new Error(
|
|
59300
|
+
`Merge transaction "${transactionId}" has an invalid commitStatus.`
|
|
59301
|
+
);
|
|
59302
|
+
}
|
|
59303
|
+
const totalChangeCount = value.totalChangeCount === null ? null : readMergeProgressCount(value.totalChangeCount, "totalChangeCount");
|
|
59304
|
+
const appliedChangeCount = readMergeProgressCount(
|
|
59305
|
+
value.appliedChangeCount,
|
|
59306
|
+
"appliedChangeCount"
|
|
59307
|
+
);
|
|
59308
|
+
return {
|
|
59309
|
+
transactionId,
|
|
59310
|
+
commitStatus: value.commitStatus,
|
|
59311
|
+
totalChangeCount,
|
|
59312
|
+
appliedChangeCount
|
|
59313
|
+
};
|
|
59314
|
+
}
|
|
59315
|
+
function readMergeProgressCount(value, field) {
|
|
59316
|
+
if (typeof value !== "number") {
|
|
59317
|
+
throw new Error(`Merge transaction ${field} must be a number.`);
|
|
59318
|
+
}
|
|
59319
|
+
if (!Number.isSafeInteger(value)) {
|
|
59320
|
+
throw new Error(`Merge transaction ${field} must be a safe integer.`);
|
|
59321
|
+
}
|
|
59322
|
+
if (value < 0) {
|
|
59323
|
+
throw new Error(`Merge transaction ${field} must not be negative.`);
|
|
59324
|
+
}
|
|
59325
|
+
return value;
|
|
59326
|
+
}
|
|
59327
|
+
function isMergeTransactionStatus(value) {
|
|
59328
|
+
return value === "preparing" || value === "waiting" || value === "queued" || value === "applying" || value === "reverting" || value === "committed" || value === "failed";
|
|
59329
|
+
}
|
|
59330
|
+
function mergeTransactionProgressLabel(status) {
|
|
59331
|
+
if (status.commitStatus === "preparing") return "Preparing merge\u2026";
|
|
59332
|
+
if (status.commitStatus === "waiting") return "Waiting to apply merge\u2026";
|
|
59333
|
+
if (status.commitStatus === "queued") return "Queueing merge\u2026";
|
|
59334
|
+
if (status.commitStatus === "reverting") return "Reverting merge\u2026";
|
|
59335
|
+
if (status.commitStatus === "committed") return "Merge committed.";
|
|
59336
|
+
if (status.commitStatus === "failed") return "Merge failed.";
|
|
59337
|
+
if (status.totalChangeCount !== null) {
|
|
59338
|
+
return `Applying merge\u2026 ${status.appliedChangeCount.toLocaleString("en-US")}/${status.totalChangeCount.toLocaleString("en-US")} changes`;
|
|
59339
|
+
}
|
|
59340
|
+
return "Applying merge\u2026";
|
|
59341
|
+
}
|
|
59138
59342
|
async function runRefresh(workspace, dryRun) {
|
|
59139
59343
|
const { versions } = await loadVersionMetadata(workspace);
|
|
59140
59344
|
const current = versions.find(
|
|
@@ -61726,6 +61930,345 @@ function assignPendingIds(changes, staticValueSeeds, reconstructed3) {
|
|
|
61726
61930
|
}
|
|
61727
61931
|
return { assigned, staticValueSeeds: rewrittenSeeds };
|
|
61728
61932
|
}
|
|
61933
|
+
function readAcceptedProjectVersionCommitResponse(value) {
|
|
61934
|
+
if (!isObjectRecord2(value) || value.kind !== "accepted") return null;
|
|
61935
|
+
if (typeof value.transactionId !== "string") {
|
|
61936
|
+
throw new Error("Accepted project transaction is missing transactionId.");
|
|
61937
|
+
}
|
|
61938
|
+
const rawStatus = value.commitStatus ?? value.status;
|
|
61939
|
+
if (rawStatus !== "preparing" && rawStatus !== "waiting" && rawStatus !== "queued" && rawStatus !== "applying" && rawStatus !== "reverting" && rawStatus !== "committed" && rawStatus !== "failed") {
|
|
61940
|
+
throw new Error(
|
|
61941
|
+
`Accepted project transaction "${value.transactionId}" has invalid commitStatus ${JSON.stringify(rawStatus)}.`
|
|
61942
|
+
);
|
|
61943
|
+
}
|
|
61944
|
+
const totalChangeCount = readNullableCount(
|
|
61945
|
+
value.totalChangeCount,
|
|
61946
|
+
"accepted totalChangeCount"
|
|
61947
|
+
);
|
|
61948
|
+
const appliedChangeCount = readCount(
|
|
61949
|
+
value.appliedChangeCount,
|
|
61950
|
+
"accepted appliedChangeCount"
|
|
61951
|
+
);
|
|
61952
|
+
const totalChunkCount = readNullableCount(
|
|
61953
|
+
value.totalChunkCount,
|
|
61954
|
+
"accepted totalChunkCount"
|
|
61955
|
+
);
|
|
61956
|
+
const appliedChunkCount = readCount(
|
|
61957
|
+
value.appliedChunkCount,
|
|
61958
|
+
"accepted appliedChunkCount"
|
|
61959
|
+
);
|
|
61960
|
+
return {
|
|
61961
|
+
kind: "accepted",
|
|
61962
|
+
transactionId: value.transactionId,
|
|
61963
|
+
commitStatus: rawStatus,
|
|
61964
|
+
totalChangeCount,
|
|
61965
|
+
appliedChangeCount,
|
|
61966
|
+
totalChunkCount,
|
|
61967
|
+
appliedChunkCount
|
|
61968
|
+
};
|
|
61969
|
+
}
|
|
61970
|
+
function readProjectVersionTransactionStatus(value, transactionId) {
|
|
61971
|
+
if (!isObjectRecord2(value)) {
|
|
61972
|
+
throw new Error(
|
|
61973
|
+
`Project transaction "${transactionId}" status response must be an object.`
|
|
61974
|
+
);
|
|
61975
|
+
}
|
|
61976
|
+
if (value.transactionId !== transactionId) {
|
|
61977
|
+
throw new Error(
|
|
61978
|
+
`Project transaction status response expected transactionId "${transactionId}"; received ${JSON.stringify(value.transactionId)}.`
|
|
61979
|
+
);
|
|
61980
|
+
}
|
|
61981
|
+
if (!isProjectVersionTransactionCommitStatus(value.commitStatus)) {
|
|
61982
|
+
throw new Error(
|
|
61983
|
+
`Project transaction "${transactionId}" has invalid commitStatus ${JSON.stringify(value.commitStatus)}.`
|
|
61984
|
+
);
|
|
61985
|
+
}
|
|
61986
|
+
const errorCode = readNullableString(
|
|
61987
|
+
value.errorCode,
|
|
61988
|
+
`Project transaction "${transactionId}" errorCode`
|
|
61989
|
+
);
|
|
61990
|
+
const errorMessage3 = readNullableString(
|
|
61991
|
+
value.errorMessage,
|
|
61992
|
+
`Project transaction "${transactionId}" errorMessage`
|
|
61993
|
+
);
|
|
61994
|
+
const resultCursor = readNullableString(
|
|
61995
|
+
value.resultCursor,
|
|
61996
|
+
`Project transaction "${transactionId}" resultCursor`
|
|
61997
|
+
);
|
|
61998
|
+
return {
|
|
61999
|
+
transactionId,
|
|
62000
|
+
commitStatus: value.commitStatus,
|
|
62001
|
+
totalChangeCount: readNullableCount(
|
|
62002
|
+
value.totalChangeCount,
|
|
62003
|
+
`Project transaction "${transactionId}" totalChangeCount`
|
|
62004
|
+
),
|
|
62005
|
+
appliedChangeCount: readCount(
|
|
62006
|
+
value.appliedChangeCount,
|
|
62007
|
+
`Project transaction "${transactionId}" appliedChangeCount`
|
|
62008
|
+
),
|
|
62009
|
+
totalChunkCount: readNullableCount(
|
|
62010
|
+
value.totalChunkCount,
|
|
62011
|
+
`Project transaction "${transactionId}" totalChunkCount`
|
|
62012
|
+
),
|
|
62013
|
+
appliedChunkCount: readCount(
|
|
62014
|
+
value.appliedChunkCount,
|
|
62015
|
+
`Project transaction "${transactionId}" appliedChunkCount`
|
|
62016
|
+
),
|
|
62017
|
+
errorCode,
|
|
62018
|
+
errorMessage: errorMessage3,
|
|
62019
|
+
resultCursor
|
|
62020
|
+
};
|
|
62021
|
+
}
|
|
62022
|
+
function readProjectVersionTransactionResultPage(value, transactionId) {
|
|
62023
|
+
if (!isObjectRecord2(value)) {
|
|
62024
|
+
throw new Error(
|
|
62025
|
+
`Project transaction "${transactionId}" result page must be an object.`
|
|
62026
|
+
);
|
|
62027
|
+
}
|
|
62028
|
+
if (value.transactionId !== transactionId) {
|
|
62029
|
+
throw new Error(
|
|
62030
|
+
`Project transaction result page expected transactionId "${transactionId}"; received ${JSON.stringify(value.transactionId)}.`
|
|
62031
|
+
);
|
|
62032
|
+
}
|
|
62033
|
+
if (!isObjectRecord2(value.assignments)) {
|
|
62034
|
+
throw new Error(
|
|
62035
|
+
`Project transaction "${transactionId}" result page assignments must be an object.`
|
|
62036
|
+
);
|
|
62037
|
+
}
|
|
62038
|
+
const assignments = {};
|
|
62039
|
+
for (const [pendingId2, assignedId] of Object.entries(value.assignments)) {
|
|
62040
|
+
if (typeof assignedId !== "string") {
|
|
62041
|
+
throw new Error(
|
|
62042
|
+
`Project transaction "${transactionId}" result assignment ${JSON.stringify(pendingId2)} must be a string.`
|
|
62043
|
+
);
|
|
62044
|
+
}
|
|
62045
|
+
assignments[pendingId2] = assignedId;
|
|
62046
|
+
}
|
|
62047
|
+
if (!Array.isArray(value.changedRecords)) {
|
|
62048
|
+
throw new Error(
|
|
62049
|
+
`Project transaction "${transactionId}" result page changedRecords must be an array.`
|
|
62050
|
+
);
|
|
62051
|
+
}
|
|
62052
|
+
const continueCursor = readNullableString(
|
|
62053
|
+
value.continueCursor,
|
|
62054
|
+
`Project transaction "${transactionId}" result page continueCursor`
|
|
62055
|
+
);
|
|
62056
|
+
if (typeof value.isDone !== "boolean") {
|
|
62057
|
+
throw new Error(
|
|
62058
|
+
`Project transaction "${transactionId}" result page isDone must be a boolean.`
|
|
62059
|
+
);
|
|
62060
|
+
}
|
|
62061
|
+
return {
|
|
62062
|
+
transactionId,
|
|
62063
|
+
assignments,
|
|
62064
|
+
changedRecords: value.changedRecords,
|
|
62065
|
+
continueCursor,
|
|
62066
|
+
isDone: value.isDone
|
|
62067
|
+
};
|
|
62068
|
+
}
|
|
62069
|
+
function readCount(value, field) {
|
|
62070
|
+
if (typeof value !== "number") {
|
|
62071
|
+
throw new Error(`${field} must be a number.`);
|
|
62072
|
+
}
|
|
62073
|
+
if (!Number.isSafeInteger(value)) {
|
|
62074
|
+
throw new Error(`${field} must be a safe integer.`);
|
|
62075
|
+
}
|
|
62076
|
+
if (value < 0) {
|
|
62077
|
+
throw new Error(`${field} must not be negative.`);
|
|
62078
|
+
}
|
|
62079
|
+
return value;
|
|
62080
|
+
}
|
|
62081
|
+
function readNullableCount(value, field) {
|
|
62082
|
+
if (value === null) return null;
|
|
62083
|
+
return readCount(value, field);
|
|
62084
|
+
}
|
|
62085
|
+
function readNullableString(value, field) {
|
|
62086
|
+
if (value === null) return null;
|
|
62087
|
+
if (typeof value !== "string") {
|
|
62088
|
+
throw new Error(`${field} must be a string or null.`);
|
|
62089
|
+
}
|
|
62090
|
+
return value;
|
|
62091
|
+
}
|
|
62092
|
+
function isProjectVersionTransactionCommitStatus(value) {
|
|
62093
|
+
return value === "preparing" || value === "waiting" || value === "queued" || value === "applying" || value === "reverting" || value === "committed" || value === "failed";
|
|
62094
|
+
}
|
|
62095
|
+
function createPushProgressReporter(json) {
|
|
62096
|
+
const animated = process.stdout.isTTY === true && !json;
|
|
62097
|
+
const indicator = animated ? spinner("Pushing\u2026") : null;
|
|
62098
|
+
let lastStructuredEvent = "";
|
|
62099
|
+
return {
|
|
62100
|
+
report(event) {
|
|
62101
|
+
if (indicator !== null) {
|
|
62102
|
+
indicator.update(projectTransactionProgressLabel(event));
|
|
62103
|
+
return;
|
|
62104
|
+
}
|
|
62105
|
+
const encoded = JSON.stringify(event);
|
|
62106
|
+
if (encoded === lastStructuredEvent) return;
|
|
62107
|
+
lastStructuredEvent = encoded;
|
|
62108
|
+
console.log(encoded);
|
|
62109
|
+
},
|
|
62110
|
+
stop() {
|
|
62111
|
+
indicator?.stop();
|
|
62112
|
+
}
|
|
62113
|
+
};
|
|
62114
|
+
}
|
|
62115
|
+
function projectTransactionProgressLabel(event) {
|
|
62116
|
+
if (event.phase === "submitting") return "Pushing\u2026";
|
|
62117
|
+
if (event.phase === "preparing") return "Preparing push\u2026";
|
|
62118
|
+
if (event.phase === "waiting") return "Waiting to apply project transaction\u2026";
|
|
62119
|
+
if (event.phase === "reverting") return "Reverting project transaction\u2026";
|
|
62120
|
+
if (event.phase === "finalizing") return "Finalizing project transaction\u2026";
|
|
62121
|
+
if (event.phase === "committed") return "Push complete.";
|
|
62122
|
+
if (event.phase === "failed") return "Project transaction failed.";
|
|
62123
|
+
if (event.phase === "interrupted")
|
|
62124
|
+
return "Project transaction still running.";
|
|
62125
|
+
if (event.totalChangeCount !== null && event.appliedChangeCount < event.totalChangeCount) {
|
|
62126
|
+
return `Applying project transaction\u2026 ${event.appliedChangeCount.toLocaleString("en-US")}/${event.totalChangeCount.toLocaleString("en-US")} changes`;
|
|
62127
|
+
}
|
|
62128
|
+
if (event.totalChunkCount !== null && event.appliedChunkCount < event.totalChunkCount) {
|
|
62129
|
+
return `Applying project transaction\u2026 ${event.appliedChunkCount.toLocaleString("en-US")}/${event.totalChunkCount.toLocaleString("en-US")} chunks`;
|
|
62130
|
+
}
|
|
62131
|
+
return "Finalizing project transaction\u2026";
|
|
62132
|
+
}
|
|
62133
|
+
function progressEventFromAccepted(accepted) {
|
|
62134
|
+
return {
|
|
62135
|
+
type: "project-transaction-progress",
|
|
62136
|
+
transactionId: accepted.transactionId,
|
|
62137
|
+
phase: accepted.commitStatus,
|
|
62138
|
+
totalChangeCount: accepted.totalChangeCount,
|
|
62139
|
+
appliedChangeCount: accepted.appliedChangeCount,
|
|
62140
|
+
totalChunkCount: accepted.totalChunkCount,
|
|
62141
|
+
appliedChunkCount: accepted.appliedChunkCount,
|
|
62142
|
+
errorCode: null,
|
|
62143
|
+
errorMessage: null
|
|
62144
|
+
};
|
|
62145
|
+
}
|
|
62146
|
+
function progressEventFromStatus(status) {
|
|
62147
|
+
const phase = status.commitStatus === "committed" || status.commitStatus === "applying" && status.totalChunkCount !== null && status.appliedChunkCount === status.totalChunkCount ? "finalizing" : status.commitStatus;
|
|
62148
|
+
return {
|
|
62149
|
+
type: "project-transaction-progress",
|
|
62150
|
+
transactionId: status.transactionId,
|
|
62151
|
+
phase,
|
|
62152
|
+
totalChangeCount: status.totalChangeCount,
|
|
62153
|
+
appliedChangeCount: status.appliedChangeCount,
|
|
62154
|
+
totalChunkCount: status.totalChunkCount,
|
|
62155
|
+
appliedChunkCount: status.appliedChunkCount,
|
|
62156
|
+
errorCode: status.errorCode,
|
|
62157
|
+
errorMessage: status.errorMessage
|
|
62158
|
+
};
|
|
62159
|
+
}
|
|
62160
|
+
async function waitForAcceptedProjectVersionTransaction(args) {
|
|
62161
|
+
const { client, projectId, versionId, accepted, reporter } = args;
|
|
62162
|
+
const transactionPath = `/api/projects/${projectId}/versions/${versionId}/schema/transactions/${accepted.transactionId}`;
|
|
62163
|
+
const controller = new AbortController();
|
|
62164
|
+
let interrupted = false;
|
|
62165
|
+
const interrupt = () => {
|
|
62166
|
+
interrupted = true;
|
|
62167
|
+
controller.abort();
|
|
62168
|
+
};
|
|
62169
|
+
process.once("SIGINT", interrupt);
|
|
62170
|
+
reporter.report(progressEventFromAccepted(accepted));
|
|
62171
|
+
let pollIndex = 0;
|
|
62172
|
+
try {
|
|
62173
|
+
for (; ; ) {
|
|
62174
|
+
const rawStatus = await client.get(transactionPath, {
|
|
62175
|
+
signal: controller.signal
|
|
62176
|
+
});
|
|
62177
|
+
const status = readProjectVersionTransactionStatus(
|
|
62178
|
+
rawStatus,
|
|
62179
|
+
accepted.transactionId
|
|
62180
|
+
);
|
|
62181
|
+
reporter.report(progressEventFromStatus(status));
|
|
62182
|
+
if (status.commitStatus === "committed") {
|
|
62183
|
+
return await downloadProjectVersionTransactionResult({
|
|
62184
|
+
client,
|
|
62185
|
+
transactionPath,
|
|
62186
|
+
transactionId: accepted.transactionId,
|
|
62187
|
+
status,
|
|
62188
|
+
signal: controller.signal
|
|
62189
|
+
});
|
|
62190
|
+
}
|
|
62191
|
+
if (status.commitStatus === "failed") {
|
|
62192
|
+
throw new ProjectTransactionFailedError(status);
|
|
62193
|
+
}
|
|
62194
|
+
const delay = PROJECT_TRANSACTION_POLL_DELAYS_MS[Math.min(pollIndex, PROJECT_TRANSACTION_POLL_DELAYS_MS.length - 1)];
|
|
62195
|
+
pollIndex += 1;
|
|
62196
|
+
await waitForPollDelay(delay, controller.signal);
|
|
62197
|
+
}
|
|
62198
|
+
} catch (error) {
|
|
62199
|
+
if (interrupted) {
|
|
62200
|
+
throw new ProjectTransactionInterruptedError(accepted.transactionId);
|
|
62201
|
+
}
|
|
62202
|
+
throw error;
|
|
62203
|
+
} finally {
|
|
62204
|
+
process.removeListener("SIGINT", interrupt);
|
|
62205
|
+
}
|
|
62206
|
+
}
|
|
62207
|
+
async function waitForPollDelay(delayMs, signal) {
|
|
62208
|
+
if (signal.aborted) {
|
|
62209
|
+
throw new Error("Project transaction polling was interrupted.");
|
|
62210
|
+
}
|
|
62211
|
+
await new Promise((resolve4, reject) => {
|
|
62212
|
+
const aborted = () => {
|
|
62213
|
+
clearTimeout(timer);
|
|
62214
|
+
reject(new Error("Project transaction polling was interrupted."));
|
|
62215
|
+
};
|
|
62216
|
+
const timer = setTimeout(() => {
|
|
62217
|
+
signal.removeEventListener("abort", aborted);
|
|
62218
|
+
resolve4();
|
|
62219
|
+
}, delayMs);
|
|
62220
|
+
signal.addEventListener("abort", aborted, { once: true });
|
|
62221
|
+
});
|
|
62222
|
+
}
|
|
62223
|
+
async function downloadProjectVersionTransactionResult(args) {
|
|
62224
|
+
const assignments = {};
|
|
62225
|
+
const changedRecords = [];
|
|
62226
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
62227
|
+
let cursor = args.status.resultCursor ?? "";
|
|
62228
|
+
for (; ; ) {
|
|
62229
|
+
if (seenCursors.has(cursor)) {
|
|
62230
|
+
throw new Error(
|
|
62231
|
+
`Project transaction "${args.transactionId}" result pagination repeated cursor ${JSON.stringify(cursor)}.`
|
|
62232
|
+
);
|
|
62233
|
+
}
|
|
62234
|
+
seenCursors.add(cursor);
|
|
62235
|
+
const query = new URLSearchParams({ cursor });
|
|
62236
|
+
const rawPage = await args.client.get(
|
|
62237
|
+
`${args.transactionPath}/results?${query.toString()}`,
|
|
62238
|
+
{ signal: args.signal }
|
|
62239
|
+
);
|
|
62240
|
+
const page = readProjectVersionTransactionResultPage(
|
|
62241
|
+
rawPage,
|
|
62242
|
+
args.transactionId
|
|
62243
|
+
);
|
|
62244
|
+
for (const [pendingId2, assignedId] of Object.entries(page.assignments)) {
|
|
62245
|
+
const existing = assignments[pendingId2];
|
|
62246
|
+
if (existing !== void 0 && existing !== assignedId) {
|
|
62247
|
+
throw new Error(
|
|
62248
|
+
`Project transaction "${args.transactionId}" returned conflicting assignments for ${JSON.stringify(pendingId2)}.`
|
|
62249
|
+
);
|
|
62250
|
+
}
|
|
62251
|
+
assignments[pendingId2] = assignedId;
|
|
62252
|
+
}
|
|
62253
|
+
changedRecords.push(...page.changedRecords);
|
|
62254
|
+
if (page.isDone) {
|
|
62255
|
+
return {
|
|
62256
|
+
kind: "committed",
|
|
62257
|
+
transactionId: args.transactionId,
|
|
62258
|
+
totalChangeCount: args.status.totalChangeCount ?? changedRecords.length,
|
|
62259
|
+
totalChunkCount: args.status.totalChunkCount ?? 0,
|
|
62260
|
+
assignments,
|
|
62261
|
+
changedRecords
|
|
62262
|
+
};
|
|
62263
|
+
}
|
|
62264
|
+
if (page.continueCursor === null) {
|
|
62265
|
+
throw new Error(
|
|
62266
|
+
`Project transaction "${args.transactionId}" result page is not done but has no continueCursor.`
|
|
62267
|
+
);
|
|
62268
|
+
}
|
|
62269
|
+
cursor = page.continueCursor;
|
|
62270
|
+
}
|
|
62271
|
+
}
|
|
61729
62272
|
async function runPush(workspace, options) {
|
|
61730
62273
|
const status = computeWorkspaceStatus(workspace);
|
|
61731
62274
|
if (status.conflictedFiles.length > 0) {
|
|
@@ -61756,7 +62299,19 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
61756
62299
|
binaryChanges: status.binaryChanges ?? []
|
|
61757
62300
|
});
|
|
61758
62301
|
if (status.changes.length === 0) {
|
|
61759
|
-
|
|
62302
|
+
if (options.json === true) {
|
|
62303
|
+
console.log(
|
|
62304
|
+
JSON.stringify({
|
|
62305
|
+
type: "push-plan",
|
|
62306
|
+
dryRun: options.dryRun,
|
|
62307
|
+
changeCount: 0,
|
|
62308
|
+
staticValueSeedCount: 0,
|
|
62309
|
+
changes: []
|
|
62310
|
+
})
|
|
62311
|
+
);
|
|
62312
|
+
} else {
|
|
62313
|
+
console.log("Nothing to push \u2014 working copy is clean.");
|
|
62314
|
+
}
|
|
61760
62315
|
return;
|
|
61761
62316
|
}
|
|
61762
62317
|
prepareNSPropertySetterChanges(workspace, status);
|
|
@@ -61802,23 +62357,42 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
61802
62357
|
change.nextData = { ...change.nextData, updatedAt: now };
|
|
61803
62358
|
}
|
|
61804
62359
|
}
|
|
61805
|
-
|
|
61806
|
-
`${options.dryRun ? "Would push" : "Pushing"} ${color.bold(String(status.changes.length))} change(s):`
|
|
61807
|
-
);
|
|
61808
|
-
for (const change of status.changes) {
|
|
62360
|
+
if (options.json === true) {
|
|
61809
62361
|
console.log(
|
|
61810
|
-
|
|
62362
|
+
JSON.stringify({
|
|
62363
|
+
type: "push-plan",
|
|
62364
|
+
dryRun: options.dryRun,
|
|
62365
|
+
changeCount: status.changes.length,
|
|
62366
|
+
staticValueSeedCount: status.staticValueSeeds.size,
|
|
62367
|
+
changes: status.changes.map((change) => ({
|
|
62368
|
+
kind: change.kind,
|
|
62369
|
+
recordKind: change.recordKind,
|
|
62370
|
+
recordId: change.recordId
|
|
62371
|
+
}))
|
|
62372
|
+
})
|
|
61811
62373
|
);
|
|
61812
|
-
|
|
61813
|
-
for (const line of summarizeFieldDiff(change.baseData, change.nextData)) {
|
|
61814
|
-
console.log(color.dim(` ${line}`));
|
|
61815
|
-
}
|
|
61816
|
-
}
|
|
61817
|
-
}
|
|
61818
|
-
if (status.staticValueSeeds.size > 0) {
|
|
62374
|
+
} else {
|
|
61819
62375
|
console.log(
|
|
61820
|
-
|
|
62376
|
+
`${options.dryRun ? "Would push" : "Pushing"} ${color.bold(String(status.changes.length))} change(s):`
|
|
61821
62377
|
);
|
|
62378
|
+
for (const change of status.changes) {
|
|
62379
|
+
console.log(
|
|
62380
|
+
` ${paintChangeKind(change.kind)} ${describeChange(change).replace(`${change.kind} `, "")}`
|
|
62381
|
+
);
|
|
62382
|
+
if (change.kind === "update") {
|
|
62383
|
+
for (const line of summarizeFieldDiff(
|
|
62384
|
+
change.baseData,
|
|
62385
|
+
change.nextData
|
|
62386
|
+
)) {
|
|
62387
|
+
console.log(color.dim(` ${line}`));
|
|
62388
|
+
}
|
|
62389
|
+
}
|
|
62390
|
+
}
|
|
62391
|
+
if (status.staticValueSeeds.size > 0) {
|
|
62392
|
+
console.log(
|
|
62393
|
+
` ${color.dim(`create ${status.staticValueSeeds.size} member value seed(s)`)}`
|
|
62394
|
+
);
|
|
62395
|
+
}
|
|
61822
62396
|
}
|
|
61823
62397
|
if (options.dryRun) return;
|
|
61824
62398
|
if (isInteractive() && !await promptConfirm({
|
|
@@ -61882,12 +62456,131 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
61882
62456
|
},
|
|
61883
62457
|
force ? { "x-neo-force-project-version-write": "true" } : void 0
|
|
61884
62458
|
);
|
|
61885
|
-
const
|
|
62459
|
+
const finishCommitResponse = async (response, reporter) => {
|
|
62460
|
+
let accepted;
|
|
62461
|
+
try {
|
|
62462
|
+
accepted = readAcceptedProjectVersionCommitResponse(response);
|
|
62463
|
+
} catch (error) {
|
|
62464
|
+
reporter.stop();
|
|
62465
|
+
throw error;
|
|
62466
|
+
}
|
|
62467
|
+
if (accepted === null) {
|
|
62468
|
+
try {
|
|
62469
|
+
applyPushResult(workspace, response);
|
|
62470
|
+
} catch (error) {
|
|
62471
|
+
reporter.stop();
|
|
62472
|
+
throw error;
|
|
62473
|
+
}
|
|
62474
|
+
reporter.report({
|
|
62475
|
+
type: "project-transaction-progress",
|
|
62476
|
+
transactionId: immediateTransactionId(response),
|
|
62477
|
+
phase: "committed",
|
|
62478
|
+
totalChangeCount: status.changes.length,
|
|
62479
|
+
appliedChangeCount: status.changes.length,
|
|
62480
|
+
totalChunkCount: null,
|
|
62481
|
+
appliedChunkCount: 0,
|
|
62482
|
+
errorCode: null,
|
|
62483
|
+
errorMessage: null
|
|
62484
|
+
});
|
|
62485
|
+
reporter.stop();
|
|
62486
|
+
if (options.json !== true) success("Push complete.");
|
|
62487
|
+
return true;
|
|
62488
|
+
}
|
|
62489
|
+
let completed;
|
|
62490
|
+
try {
|
|
62491
|
+
completed = await waitForAcceptedProjectVersionTransaction({
|
|
62492
|
+
client,
|
|
62493
|
+
projectId: workspace.config.projectId,
|
|
62494
|
+
versionId: workspace.config.versionId,
|
|
62495
|
+
accepted,
|
|
62496
|
+
reporter
|
|
62497
|
+
});
|
|
62498
|
+
} catch (error) {
|
|
62499
|
+
if (error instanceof ProjectTransactionInterruptedError) {
|
|
62500
|
+
reporter.report({
|
|
62501
|
+
type: "project-transaction-progress",
|
|
62502
|
+
transactionId: error.transactionId,
|
|
62503
|
+
phase: "interrupted",
|
|
62504
|
+
totalChangeCount: accepted.totalChangeCount,
|
|
62505
|
+
appliedChangeCount: accepted.appliedChangeCount,
|
|
62506
|
+
totalChunkCount: accepted.totalChunkCount,
|
|
62507
|
+
appliedChunkCount: accepted.appliedChunkCount,
|
|
62508
|
+
errorCode: null,
|
|
62509
|
+
errorMessage: error.message
|
|
62510
|
+
});
|
|
62511
|
+
reporter.stop();
|
|
62512
|
+
if (options.json !== true) console.error(error.message);
|
|
62513
|
+
process.exitCode = 130;
|
|
62514
|
+
return false;
|
|
62515
|
+
}
|
|
62516
|
+
if (error instanceof ProjectTransactionFailedError) {
|
|
62517
|
+
const failed = error.status;
|
|
62518
|
+
reporter.report({
|
|
62519
|
+
type: "project-transaction-progress",
|
|
62520
|
+
transactionId: failed.transactionId,
|
|
62521
|
+
phase: "failed",
|
|
62522
|
+
totalChangeCount: failed.totalChangeCount,
|
|
62523
|
+
appliedChangeCount: failed.appliedChangeCount,
|
|
62524
|
+
totalChunkCount: failed.totalChunkCount,
|
|
62525
|
+
appliedChunkCount: failed.appliedChunkCount,
|
|
62526
|
+
errorCode: failed.errorCode,
|
|
62527
|
+
errorMessage: error.message
|
|
62528
|
+
});
|
|
62529
|
+
reporter.stop();
|
|
62530
|
+
if (options.json !== true) {
|
|
62531
|
+
console.error(
|
|
62532
|
+
`Push failed (${failed.errorCode ?? "project-transaction-failed"}, transaction ${failed.transactionId}): ${error.message}`
|
|
62533
|
+
);
|
|
62534
|
+
}
|
|
62535
|
+
process.exitCode = 1;
|
|
62536
|
+
return false;
|
|
62537
|
+
}
|
|
62538
|
+
reporter.stop();
|
|
62539
|
+
throw error;
|
|
62540
|
+
}
|
|
62541
|
+
try {
|
|
62542
|
+
applyCommittedProjectTransactionResult({
|
|
62543
|
+
workspace,
|
|
62544
|
+
result: completed,
|
|
62545
|
+
submittedChanges: status.changes,
|
|
62546
|
+
candidateAssignments: pendingAssignment.assigned
|
|
62547
|
+
});
|
|
62548
|
+
} catch (error) {
|
|
62549
|
+
reporter.stop();
|
|
62550
|
+
throw error;
|
|
62551
|
+
}
|
|
62552
|
+
reporter.report({
|
|
62553
|
+
type: "project-transaction-progress",
|
|
62554
|
+
transactionId: completed.transactionId,
|
|
62555
|
+
phase: "committed",
|
|
62556
|
+
totalChangeCount: completed.totalChangeCount,
|
|
62557
|
+
appliedChangeCount: completed.totalChangeCount,
|
|
62558
|
+
totalChunkCount: completed.totalChunkCount,
|
|
62559
|
+
appliedChunkCount: completed.totalChunkCount,
|
|
62560
|
+
errorCode: null,
|
|
62561
|
+
errorMessage: null
|
|
62562
|
+
});
|
|
62563
|
+
reporter.stop();
|
|
62564
|
+
if (options.json !== true) success("Push complete.");
|
|
62565
|
+
return true;
|
|
62566
|
+
};
|
|
62567
|
+
let progress = createPushProgressReporter(options.json === true);
|
|
62568
|
+
progress.report({
|
|
62569
|
+
type: "project-transaction-progress",
|
|
62570
|
+
transactionId: null,
|
|
62571
|
+
phase: "submitting",
|
|
62572
|
+
totalChangeCount: status.changes.length,
|
|
62573
|
+
appliedChangeCount: 0,
|
|
62574
|
+
totalChunkCount: null,
|
|
62575
|
+
appliedChunkCount: 0,
|
|
62576
|
+
errorCode: null,
|
|
62577
|
+
errorMessage: null
|
|
62578
|
+
});
|
|
61886
62579
|
let result;
|
|
61887
62580
|
try {
|
|
61888
62581
|
result = await commit(options.acceptBump);
|
|
61889
62582
|
} catch (error) {
|
|
61890
|
-
|
|
62583
|
+
progress.stop();
|
|
61891
62584
|
if (!(error instanceof NeoApiError)) throw error;
|
|
61892
62585
|
const rejection = error.body;
|
|
61893
62586
|
if (isInteractive() && !options.acceptBump && isObjectRecord2(rejection) && rejection.error === "version-bump-required") {
|
|
@@ -61903,7 +62596,18 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
61903
62596
|
message: "Accept the bump and push?",
|
|
61904
62597
|
fallback: false
|
|
61905
62598
|
})) {
|
|
61906
|
-
|
|
62599
|
+
progress = createPushProgressReporter(options.json === true);
|
|
62600
|
+
progress.report({
|
|
62601
|
+
type: "project-transaction-progress",
|
|
62602
|
+
transactionId: null,
|
|
62603
|
+
phase: "submitting",
|
|
62604
|
+
totalChangeCount: status.changes.length,
|
|
62605
|
+
appliedChangeCount: 0,
|
|
62606
|
+
totalChunkCount: null,
|
|
62607
|
+
appliedChunkCount: 0,
|
|
62608
|
+
errorCode: null,
|
|
62609
|
+
errorMessage: null
|
|
62610
|
+
});
|
|
61907
62611
|
try {
|
|
61908
62612
|
stagedFiles = await stageProjectFilePushesV4({
|
|
61909
62613
|
workspace,
|
|
@@ -61914,7 +62618,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
61914
62618
|
});
|
|
61915
62619
|
result = await commit(true);
|
|
61916
62620
|
} catch (retryError) {
|
|
61917
|
-
|
|
62621
|
+
progress.stop();
|
|
61918
62622
|
if (retryError instanceof NeoApiError) {
|
|
61919
62623
|
reportPushRejection(retryError.body);
|
|
61920
62624
|
process.exitCode = 1;
|
|
@@ -61922,9 +62626,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
61922
62626
|
}
|
|
61923
62627
|
throw retryError;
|
|
61924
62628
|
}
|
|
61925
|
-
|
|
61926
|
-
applyPushResult(workspace, result);
|
|
61927
|
-
success("Push complete.");
|
|
62629
|
+
await finishCommitResponse(result, progress);
|
|
61928
62630
|
return;
|
|
61929
62631
|
}
|
|
61930
62632
|
console.log("Push cancelled.");
|
|
@@ -61935,9 +62637,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
61935
62637
|
process.exitCode = 1;
|
|
61936
62638
|
return;
|
|
61937
62639
|
}
|
|
61938
|
-
|
|
61939
|
-
applyPushResult(workspace, result);
|
|
61940
|
-
success("Push complete.");
|
|
62640
|
+
await finishCommitResponse(result, progress);
|
|
61941
62641
|
}
|
|
61942
62642
|
async function createPendingProjectSourceBundleV4(workspace, status, staticValueSeeds) {
|
|
61943
62643
|
const records2 = /* @__PURE__ */ new Map();
|
|
@@ -62084,52 +62784,298 @@ function reportPushRejection(body) {
|
|
|
62084
62784
|
}
|
|
62085
62785
|
console.error(`Push rejected (409): ${JSON.stringify(body)}`);
|
|
62086
62786
|
}
|
|
62087
|
-
function
|
|
62088
|
-
if (!isObjectRecord2(result)
|
|
62089
|
-
|
|
62787
|
+
function immediateTransactionId(result) {
|
|
62788
|
+
if (!isObjectRecord2(result)) return null;
|
|
62789
|
+
if (typeof result.transactionId === "string") return result.transactionId;
|
|
62790
|
+
if (!isObjectRecord2(result.transaction)) return null;
|
|
62791
|
+
return typeof result.transaction.id === "string" ? result.transaction.id : null;
|
|
62792
|
+
}
|
|
62793
|
+
function applyCommittedProjectTransactionResult(args) {
|
|
62794
|
+
const { workspace, result, submittedChanges, candidateAssignments } = args;
|
|
62795
|
+
const localStatus = computeWorkspaceStatus(workspace);
|
|
62796
|
+
const blockingErrors = localStatus.parseErrors.filter(
|
|
62797
|
+
isBlockingSchemaSourceError
|
|
62798
|
+
);
|
|
62799
|
+
if (blockingErrors.length > 0) {
|
|
62800
|
+
throw new Error(
|
|
62801
|
+
`Project transaction "${result.transactionId}" committed, but its result cannot be applied while the working copy has parse errors. Fix the source and run the same neo push again:
|
|
62802
|
+
${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
62803
|
+
);
|
|
62804
|
+
}
|
|
62805
|
+
if (localStatus.conflictedFiles.length > 0) {
|
|
62806
|
+
throw new Error(
|
|
62807
|
+
`Project transaction "${result.transactionId}" committed, but its result cannot be applied while conflict markers remain in ${localStatus.conflictedFiles.join(", ")}. Resolve them and run the same neo push again.`
|
|
62808
|
+
);
|
|
62090
62809
|
}
|
|
62810
|
+
const replacements = projectTransactionResultReplacements(
|
|
62811
|
+
candidateAssignments,
|
|
62812
|
+
result.assignments
|
|
62813
|
+
);
|
|
62814
|
+
const localRecords = rewriteReconstructedRecords(
|
|
62815
|
+
localStatus.reconstructed,
|
|
62816
|
+
replacements
|
|
62817
|
+
);
|
|
62818
|
+
const submittedByKey = /* @__PURE__ */ new Map();
|
|
62819
|
+
for (const change of submittedChanges) {
|
|
62820
|
+
if (change.nextData === void 0) continue;
|
|
62821
|
+
const recordId = rewriteAssignedString(change.recordId, replacements);
|
|
62822
|
+
const nextData = rewriteAssignedValue(change.nextData, replacements);
|
|
62823
|
+
if (!isObjectRecord2(nextData)) {
|
|
62824
|
+
throw new Error(
|
|
62825
|
+
`Submitted ${change.recordKind} "${recordId}" did not rewrite to an object.`
|
|
62826
|
+
);
|
|
62827
|
+
}
|
|
62828
|
+
submittedByKey.set(recordStateKey(change.recordKind, recordId), nextData);
|
|
62829
|
+
}
|
|
62830
|
+
const previousRecords = workspace.state.records;
|
|
62831
|
+
const nextRecords = foldChangedRecords(
|
|
62832
|
+
previousRecords,
|
|
62833
|
+
result.changedRecords
|
|
62834
|
+
);
|
|
62835
|
+
const changedKeys = /* @__PURE__ */ new Set();
|
|
62091
62836
|
for (const changed of result.changedRecords) {
|
|
62092
|
-
|
|
62093
|
-
|
|
62837
|
+
const identity2 = readChangedRecordIdentity(changed);
|
|
62838
|
+
changedKeys.add(recordStateKey(identity2.recordKind, identity2.recordId));
|
|
62839
|
+
}
|
|
62840
|
+
const emitRecords = /* @__PURE__ */ new Map();
|
|
62841
|
+
for (const [key, state] of Object.entries(nextRecords)) {
|
|
62842
|
+
const prior = previousRecords[key];
|
|
62843
|
+
const local = localRecords.get(key);
|
|
62844
|
+
if (local === void 0 && prior?.file !== void 0) continue;
|
|
62845
|
+
const submitted = submittedByKey.get(key);
|
|
62846
|
+
const emitData = local === void 0 ? state.data : changedKeys.has(key) && submitted !== void 0 ? mergeCommittedRecordWithLaterLocalEdits(
|
|
62847
|
+
state.recordKind,
|
|
62848
|
+
submitted,
|
|
62849
|
+
state.data,
|
|
62850
|
+
local.fullData
|
|
62851
|
+
) : local.fullData;
|
|
62852
|
+
emitRecords.set(key, {
|
|
62853
|
+
recordKind: state.recordKind,
|
|
62854
|
+
recordId: state.recordId,
|
|
62855
|
+
contentHash: state.contentHash,
|
|
62856
|
+
deleted: false,
|
|
62857
|
+
data: emitData
|
|
62858
|
+
});
|
|
62859
|
+
}
|
|
62860
|
+
for (const [key, local] of localRecords) {
|
|
62861
|
+
if (emitRecords.has(key)) continue;
|
|
62862
|
+
if (changedKeys.has(key)) continue;
|
|
62863
|
+
emitRecords.set(key, {
|
|
62864
|
+
recordKind: local.recordKind,
|
|
62865
|
+
recordId: local.recordId,
|
|
62866
|
+
contentHash: "",
|
|
62867
|
+
deleted: false,
|
|
62868
|
+
data: local.fullData
|
|
62869
|
+
});
|
|
62870
|
+
}
|
|
62871
|
+
const previousState = workspace.state;
|
|
62872
|
+
workspace.state = { ...previousState, records: nextRecords };
|
|
62873
|
+
try {
|
|
62874
|
+
rewriteFilesFromState(workspace, emitRecords);
|
|
62875
|
+
writeWorkspaceState(workspace.root, workspace.state);
|
|
62876
|
+
} catch (error) {
|
|
62877
|
+
workspace.state = previousState;
|
|
62878
|
+
throw error;
|
|
62879
|
+
}
|
|
62880
|
+
}
|
|
62881
|
+
function projectTransactionResultReplacements(candidateAssignments, resultAssignments) {
|
|
62882
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
62883
|
+
for (const [pendingId2, assignedId] of Object.entries(resultAssignments)) {
|
|
62884
|
+
replacements.set(pendingId2, assignedId);
|
|
62885
|
+
const candidateId = candidateAssignments.get(pendingId2);
|
|
62886
|
+
if (candidateId !== void 0) replacements.set(candidateId, assignedId);
|
|
62887
|
+
}
|
|
62888
|
+
return {
|
|
62889
|
+
exact: replacements,
|
|
62890
|
+
embedded: [...replacements].sort(
|
|
62891
|
+
([left], [right]) => right.length - left.length
|
|
62892
|
+
)
|
|
62893
|
+
};
|
|
62894
|
+
}
|
|
62895
|
+
function rewriteReconstructedRecords(records2, replacements) {
|
|
62896
|
+
const rewritten = /* @__PURE__ */ new Map();
|
|
62897
|
+
for (const record3 of records2.values()) {
|
|
62898
|
+
const recordId = rewriteAssignedString(record3.recordId, replacements);
|
|
62899
|
+
const fileFields = rewriteAssignedValue(record3.fileFields, replacements);
|
|
62900
|
+
if (!isObjectRecord2(fileFields)) {
|
|
62901
|
+
throw new Error(
|
|
62902
|
+
`Local ${record3.recordKind} "${recordId}" file fields did not rewrite to an object.`
|
|
62903
|
+
);
|
|
62904
|
+
}
|
|
62905
|
+
const fullData = rewriteAssignedValue(record3.fullData, replacements);
|
|
62906
|
+
if (!isObjectRecord2(fullData)) {
|
|
62907
|
+
throw new Error(
|
|
62908
|
+
`Local ${record3.recordKind} "${recordId}" full data did not rewrite to an object.`
|
|
62909
|
+
);
|
|
62910
|
+
}
|
|
62911
|
+
const key = recordStateKey(record3.recordKind, recordId);
|
|
62912
|
+
if (rewritten.has(key)) {
|
|
62913
|
+
throw new Error(
|
|
62914
|
+
`Project transaction assignments collapse multiple local records onto "${key}".`
|
|
62915
|
+
);
|
|
62916
|
+
}
|
|
62917
|
+
rewritten.set(key, { ...record3, recordId, fileFields, fullData });
|
|
62918
|
+
}
|
|
62919
|
+
return rewritten;
|
|
62920
|
+
}
|
|
62921
|
+
function rewriteAssignedString(value, replacements) {
|
|
62922
|
+
const exact = replacements.exact.get(value);
|
|
62923
|
+
if (exact !== void 0) return exact;
|
|
62924
|
+
let result = value;
|
|
62925
|
+
for (const [source, target] of replacements.embedded) {
|
|
62926
|
+
if (result.includes(source)) result = result.replaceAll(source, target);
|
|
62927
|
+
}
|
|
62928
|
+
return result;
|
|
62929
|
+
}
|
|
62930
|
+
function rewriteAssignedValue(value, replacements) {
|
|
62931
|
+
if (typeof value === "string") {
|
|
62932
|
+
return rewriteAssignedString(value, replacements);
|
|
62933
|
+
}
|
|
62934
|
+
if (Array.isArray(value)) {
|
|
62935
|
+
return value.map((entry) => rewriteAssignedValue(entry, replacements));
|
|
62936
|
+
}
|
|
62937
|
+
if (!isObjectRecord2(value)) return value;
|
|
62938
|
+
const rewritten = {};
|
|
62939
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
62940
|
+
rewritten[rewriteAssignedString(key, replacements)] = rewriteAssignedValue(
|
|
62941
|
+
entry,
|
|
62942
|
+
replacements
|
|
62943
|
+
);
|
|
62944
|
+
}
|
|
62945
|
+
return rewritten;
|
|
62946
|
+
}
|
|
62947
|
+
function mergeCommittedRecordWithLaterLocalEdits(recordKind, submitted, committed, local) {
|
|
62948
|
+
if (!isObjectRecord2(committed)) return local;
|
|
62949
|
+
if (isSchemaDocumentRecordKind(recordKind)) {
|
|
62950
|
+
if (schemaDocumentAuthoredSemanticallyEqual(recordKind, submitted, local)) {
|
|
62951
|
+
return committed;
|
|
62952
|
+
}
|
|
62953
|
+
const merged2 = mergeSchemaDocumentRecord(
|
|
62954
|
+
recordKind,
|
|
62955
|
+
submitted,
|
|
62956
|
+
committed,
|
|
62957
|
+
local
|
|
62958
|
+
);
|
|
62959
|
+
return merged2.conflictFields.length === 0 ? merged2.merged : local;
|
|
62960
|
+
}
|
|
62961
|
+
const comparison = {
|
|
62962
|
+
base: sourceComparableRecordForPush(recordKind, submitted),
|
|
62963
|
+
server: sourceComparableRecordForPush(recordKind, committed),
|
|
62964
|
+
local: sourceComparableRecordForPush(recordKind, local)
|
|
62965
|
+
};
|
|
62966
|
+
if (canonicallyEqual(comparison.base, comparison.local)) return committed;
|
|
62967
|
+
const merged = threeWayMergeRecord(submitted, committed, local, {
|
|
62968
|
+
comparison,
|
|
62969
|
+
serverWinsFields: /* @__PURE__ */ new Set([
|
|
62970
|
+
"projectId",
|
|
62971
|
+
"createdAt",
|
|
62972
|
+
"updatedAt",
|
|
62973
|
+
"getter",
|
|
62974
|
+
"setter",
|
|
62975
|
+
"action",
|
|
62976
|
+
"layout"
|
|
62977
|
+
]),
|
|
62978
|
+
recursive: true
|
|
62979
|
+
});
|
|
62980
|
+
return merged.conflictFields.length === 0 ? merged.merged : local;
|
|
62981
|
+
}
|
|
62982
|
+
function sourceComparableRecordForPush(recordKind, value) {
|
|
62983
|
+
const result = {};
|
|
62984
|
+
const hasAuthoredCode = typeof value.code === "string" || typeof value.setterCode === "string";
|
|
62985
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
62986
|
+
if (key === "projectId" || key === "createdAt" || key === "updatedAt") {
|
|
62987
|
+
continue;
|
|
62094
62988
|
}
|
|
62095
|
-
|
|
62096
|
-
|
|
62097
|
-
|
|
62098
|
-
throw new Error("Changed record is missing recordKind/recordId.");
|
|
62989
|
+
if (recordKind === "dialogue-node" && key === "layout") continue;
|
|
62990
|
+
if (hasAuthoredCode && (key === "getter" || key === "setter" || key === "action")) {
|
|
62991
|
+
continue;
|
|
62099
62992
|
}
|
|
62993
|
+
result[key] = sourceComparableValueForPush(recordKind, entry);
|
|
62994
|
+
}
|
|
62995
|
+
return result;
|
|
62996
|
+
}
|
|
62997
|
+
function sourceComparableValueForPush(recordKind, value) {
|
|
62998
|
+
if (Array.isArray(value)) {
|
|
62999
|
+
return value.map(
|
|
63000
|
+
(entry) => sourceComparableValueForPush(recordKind, entry)
|
|
63001
|
+
);
|
|
63002
|
+
}
|
|
63003
|
+
if (!isObjectRecord2(value)) return value;
|
|
63004
|
+
return sourceComparableRecordForPush(recordKind, value);
|
|
63005
|
+
}
|
|
63006
|
+
function readChangedRecordIdentity(changed) {
|
|
63007
|
+
if (!isObjectRecord2(changed)) {
|
|
63008
|
+
throw new Error("Transaction changedRecords entries must be objects.");
|
|
63009
|
+
}
|
|
63010
|
+
if (typeof changed.recordKind !== "string") {
|
|
63011
|
+
throw new Error(
|
|
63012
|
+
"Changed record is missing recordKind/recordId: recordKind is not a string."
|
|
63013
|
+
);
|
|
63014
|
+
}
|
|
63015
|
+
if (typeof changed.recordId !== "string") {
|
|
63016
|
+
throw new Error(
|
|
63017
|
+
"Changed record is missing recordKind/recordId: recordId is not a string."
|
|
63018
|
+
);
|
|
63019
|
+
}
|
|
63020
|
+
return { recordKind: changed.recordKind, recordId: changed.recordId };
|
|
63021
|
+
}
|
|
63022
|
+
function foldChangedRecords(previous, changedRecords) {
|
|
63023
|
+
const records2 = { ...previous };
|
|
63024
|
+
for (const changed of changedRecords) {
|
|
63025
|
+
const { recordKind, recordId } = readChangedRecordIdentity(changed);
|
|
62100
63026
|
const key = recordStateKey(recordKind, recordId);
|
|
63027
|
+
if (!isObjectRecord2(changed)) {
|
|
63028
|
+
throw new Error(`Changed record "${key}" must be an object.`);
|
|
63029
|
+
}
|
|
62101
63030
|
if (changed.deleted === true) {
|
|
62102
|
-
delete
|
|
63031
|
+
delete records2[key];
|
|
62103
63032
|
continue;
|
|
62104
63033
|
}
|
|
62105
63034
|
const snapshot = changed.snapshot;
|
|
62106
|
-
if (!isObjectRecord2(snapshot)
|
|
63035
|
+
if (!isObjectRecord2(snapshot)) {
|
|
63036
|
+
throw new Error(
|
|
63037
|
+
`Changed record "${key}" response is missing its snapshot.`
|
|
63038
|
+
);
|
|
63039
|
+
}
|
|
63040
|
+
if (typeof snapshot.contentHash !== "string") {
|
|
62107
63041
|
throw new Error(
|
|
62108
63042
|
`Changed record "${key}" response is missing its snapshot content hash.`
|
|
62109
63043
|
);
|
|
62110
63044
|
}
|
|
62111
|
-
|
|
63045
|
+
records2[key] = {
|
|
62112
63046
|
recordKind,
|
|
62113
63047
|
recordId,
|
|
62114
63048
|
contentHash: snapshot.contentHash,
|
|
62115
63049
|
data: changed.data,
|
|
62116
|
-
file:
|
|
63050
|
+
file: records2[key]?.file,
|
|
63051
|
+
projectBinary: records2[key]?.projectBinary
|
|
62117
63052
|
};
|
|
62118
63053
|
}
|
|
63054
|
+
return records2;
|
|
63055
|
+
}
|
|
63056
|
+
function applyPushResult(workspace, result) {
|
|
63057
|
+
if (!isObjectRecord2(result) || !Array.isArray(result.changedRecords)) {
|
|
63058
|
+
throw new Error("Transaction response is missing changedRecords.");
|
|
63059
|
+
}
|
|
63060
|
+
workspace.state.records = foldChangedRecords(
|
|
63061
|
+
workspace.state.records,
|
|
63062
|
+
result.changedRecords
|
|
63063
|
+
);
|
|
62119
63064
|
rewriteFilesFromState(workspace);
|
|
62120
63065
|
writeWorkspaceState(workspace.root, workspace.state);
|
|
62121
63066
|
}
|
|
62122
|
-
function rewriteFilesFromState(workspace
|
|
62123
|
-
|
|
62124
|
-
|
|
62125
|
-
|
|
63067
|
+
function rewriteFilesFromState(workspace, records2 = new Map(
|
|
63068
|
+
Object.entries(workspace.state.records).map(([key, recordState]) => [
|
|
63069
|
+
key,
|
|
63070
|
+
{
|
|
62126
63071
|
recordKind: recordState.recordKind,
|
|
62127
63072
|
recordId: recordState.recordId,
|
|
62128
63073
|
contentHash: recordState.contentHash,
|
|
62129
63074
|
deleted: false,
|
|
62130
63075
|
data: recordState.data
|
|
62131
|
-
}
|
|
62132
|
-
|
|
63076
|
+
}
|
|
63077
|
+
])
|
|
63078
|
+
)) {
|
|
62133
63079
|
const result = emitProjectDocumentFilesV4(records2);
|
|
62134
63080
|
writeProjectSourceAnalysisCacheV4(workspace.root, result.analysis);
|
|
62135
63081
|
const emittedPaths = new Set(result.files.map((file) => file.path));
|
|
@@ -62610,7 +63556,7 @@ function compileMigrationAction(schema, migrationData) {
|
|
|
62610
63556
|
migrationContext: true
|
|
62611
63557
|
});
|
|
62612
63558
|
}
|
|
62613
|
-
var compileNSAction2, compileNSFunction2, compileNSGetter2, compileNSSetter2, createProjectVersionIntent2, isKnownProjectVersionIntentType2;
|
|
63559
|
+
var compileNSAction2, compileNSFunction2, compileNSGetter2, compileNSSetter2, createProjectVersionIntent2, isKnownProjectVersionIntentType2, ProjectTransactionInterruptedError, ProjectTransactionFailedError, PROJECT_TRANSACTION_POLL_DELAYS_MS;
|
|
62614
63560
|
var init_push = __esm({
|
|
62615
63561
|
"src/commands/push.ts"() {
|
|
62616
63562
|
"use strict";
|
|
@@ -62627,8 +63573,38 @@ var init_push = __esm({
|
|
|
62627
63573
|
init_source_diagnostics();
|
|
62628
63574
|
init_projection();
|
|
62629
63575
|
init_project_file_push();
|
|
63576
|
+
init_project_manifest();
|
|
63577
|
+
init_merge();
|
|
62630
63578
|
({ compileNSAction: compileNSAction2, compileNSFunction: compileNSFunction2, compileNSGetter: compileNSGetter2, compileNSSetter: compileNSSetter2 } = compiler_adapter_exports);
|
|
62631
63579
|
({ createProjectVersionIntent: createProjectVersionIntent2, isKnownProjectVersionIntentType: isKnownProjectVersionIntentType2 } = project_version_intents_exports);
|
|
63580
|
+
ProjectTransactionInterruptedError = class extends Error {
|
|
63581
|
+
constructor(transactionId) {
|
|
63582
|
+
super(
|
|
63583
|
+
`Project transaction "${transactionId}" is still running. Run the same neo push again to reconnect.`
|
|
63584
|
+
);
|
|
63585
|
+
this.transactionId = transactionId;
|
|
63586
|
+
this.name = "ProjectTransactionInterruptedError";
|
|
63587
|
+
}
|
|
63588
|
+
transactionId;
|
|
63589
|
+
};
|
|
63590
|
+
ProjectTransactionFailedError = class extends Error {
|
|
63591
|
+
constructor(status) {
|
|
63592
|
+
super(
|
|
63593
|
+
status.errorMessage ?? `Project transaction "${status.transactionId}" failed after rollback.`
|
|
63594
|
+
);
|
|
63595
|
+
this.status = status;
|
|
63596
|
+
this.name = "ProjectTransactionFailedError";
|
|
63597
|
+
}
|
|
63598
|
+
status;
|
|
63599
|
+
};
|
|
63600
|
+
PROJECT_TRANSACTION_POLL_DELAYS_MS = [
|
|
63601
|
+
250,
|
|
63602
|
+
500,
|
|
63603
|
+
1e3,
|
|
63604
|
+
2e3,
|
|
63605
|
+
4e3,
|
|
63606
|
+
5e3
|
|
63607
|
+
];
|
|
62632
63608
|
}
|
|
62633
63609
|
});
|
|
62634
63610
|
|
|
@@ -63368,7 +64344,7 @@ ${h("Start")}
|
|
|
63368
64344
|
whoami ${d("[--api <url>]")}
|
|
63369
64345
|
|
|
63370
64346
|
${h("Working copy")}
|
|
63371
|
-
pull ${d("[--force|--reset] [--regenerate-source-names]")} push ${d("[--dry-run] [--summary <text>] [--accept-bump]")}
|
|
64347
|
+
pull ${d("[--force|--reset] [--regenerate-source-names]")} push ${d("[--dry-run] [--summary <text>] [--accept-bump] [--json]")}
|
|
63372
64348
|
status ${d("[--json]")} diff ${d("[--json]")}
|
|
63373
64349
|
dev ${d("[--push]")} resolve ${d("[--mine|--theirs]")}
|
|
63374
64350
|
doctor ${d("[--json]")} ${d("validate format/compiler/editor/source/file contracts")}
|
|
@@ -63418,16 +64394,18 @@ and tracked project binary from the authoritative server records.
|
|
|
63418
64394
|
return `${h("neo push")} \u2014 commit the working copy to the server
|
|
63419
64395
|
|
|
63420
64396
|
${h("Usage")}
|
|
63421
|
-
neo push ${d("[--dry-run] [--summary <text>] [--accept-bump]")}
|
|
64397
|
+
neo push ${d("[--dry-run] [--summary <text>] [--accept-bump] [--json]")}
|
|
63422
64398
|
|
|
63423
64399
|
${h("Flags")}
|
|
63424
64400
|
--dry-run ${d("Preview the change set; commit nothing.")}
|
|
63425
64401
|
--summary <text> ${d("Attach a summary message to the transaction.")}
|
|
63426
64402
|
--accept-bump ${d("Accept a server-required version bump instead of aborting.")}
|
|
64403
|
+
--json ${d("Emit machine-readable plan and transaction progress events.")}
|
|
63427
64404
|
|
|
63428
|
-
Push sends the ${h("entire")} working copy as one
|
|
63429
|
-
transaction.
|
|
63430
|
-
|
|
64405
|
+
Push sends the ${h("entire")} working copy as one compare-and-swap logical
|
|
64406
|
+
transaction. Large pushes continue as a durable server job; rerun the identical
|
|
64407
|
+
push to reconnect if the terminal closes. Run ${h("neo status")} / ${h("neo diff")}
|
|
64408
|
+
first \u2014 local-ahead changes you did not make this session ride along too.
|
|
63431
64409
|
`;
|
|
63432
64410
|
}
|
|
63433
64411
|
if (command === "script") {
|
|
@@ -63919,7 +64897,8 @@ async function main() {
|
|
|
63919
64897
|
await runPush2(workspace, {
|
|
63920
64898
|
dryRun: boolFlag(args, "dry-run"),
|
|
63921
64899
|
summary: stringFlag(args, "summary"),
|
|
63922
|
-
acceptBump: boolFlag(args, "accept-bump")
|
|
64900
|
+
acceptBump: boolFlag(args, "accept-bump"),
|
|
64901
|
+
json: boolFlag(args, "json")
|
|
63923
64902
|
});
|
|
63924
64903
|
return;
|
|
63925
64904
|
}
|