@neocompose/cli 0.10.7 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/neo.mjs +935 -154
- package/package.json +1 -1
package/dist/neo.mjs
CHANGED
|
@@ -11837,12 +11837,13 @@ var init_project_source_parser = __esm({
|
|
|
11837
11837
|
});
|
|
11838
11838
|
|
|
11839
11839
|
// ../packages/neoscript-language/src/project-schema-contract.generated.ts
|
|
11840
|
-
var PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION, PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION, NEO_PROJECT_SOURCE_RECORD_CONTRACT;
|
|
11840
|
+
var PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION, PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION, PROJECT_FILE_UPLOAD_BATCH_SIZE, NEO_PROJECT_SOURCE_RECORD_CONTRACT;
|
|
11841
11841
|
var init_project_schema_contract_generated = __esm({
|
|
11842
11842
|
"../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
|
|
11843
11843
|
"use strict";
|
|
11844
11844
|
PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
|
|
11845
11845
|
PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.5";
|
|
11846
|
+
PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
|
|
11846
11847
|
NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
|
|
11847
11848
|
"recordFields": {
|
|
11848
11849
|
"member": [
|
|
@@ -12101,6 +12102,7 @@ var init_project_schema_contract_generated = __esm({
|
|
|
12101
12102
|
"ObjectPlacementTile",
|
|
12102
12103
|
"TileInstance",
|
|
12103
12104
|
"ObjectCollider",
|
|
12105
|
+
"SortingGroup",
|
|
12104
12106
|
"SortingLayer",
|
|
12105
12107
|
"SmartTile",
|
|
12106
12108
|
"SmartTileRule",
|
|
@@ -19506,8 +19508,8 @@ function memberSymbol(member, schemaKey, environment, field) {
|
|
|
19506
19508
|
`${field}.source`
|
|
19507
19509
|
);
|
|
19508
19510
|
const overrideOf = nullableString(member.overrideOf, `${field}.overrideOf`);
|
|
19509
|
-
const
|
|
19510
|
-
const inheritedOwner =
|
|
19511
|
+
const inheritedMember2 = overrideOf ? environment.members.get(overrideOf) : void 0;
|
|
19512
|
+
const inheritedOwner = inheritedMember2 ? optionalRecord(inheritedMember2.owner) : void 0;
|
|
19511
19513
|
const inheritedTypeId = inheritedOwner?.kind === "classMember" && typeof inheritedOwner.classId === "string" ? inheritedOwner.classId : void 0;
|
|
19512
19514
|
const inheritedType = inheritedTypeId ? environment.classes.get(inheritedTypeId) : void 0;
|
|
19513
19515
|
const common = {
|
|
@@ -23439,6 +23441,7 @@ function isSchemaSystemMetadata(value) {
|
|
|
23439
23441
|
"objectPlacementTile",
|
|
23440
23442
|
"tileInstance",
|
|
23441
23443
|
"objectCollider",
|
|
23444
|
+
"sortingGroup",
|
|
23442
23445
|
"sortingLayer",
|
|
23443
23446
|
"smartTile",
|
|
23444
23447
|
"smartTileRule",
|
|
@@ -26740,6 +26743,7 @@ var init_validate = __esm({
|
|
|
26740
26743
|
"objectPlacementTile",
|
|
26741
26744
|
"tileInstance",
|
|
26742
26745
|
"objectCollider",
|
|
26746
|
+
"sortingGroup",
|
|
26743
26747
|
"sortingLayer",
|
|
26744
26748
|
"smartTile",
|
|
26745
26749
|
"smartTileRule",
|
|
@@ -29257,6 +29261,7 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
|
|
|
29257
29261
|
const fieldType = partial ? requiredTypeArgument(declaration.type, 0) : declaration.type;
|
|
29258
29262
|
const storedStatic = declaration.modifiers.includes("static") && !declaration.modifiers.includes("readonly");
|
|
29259
29263
|
const settings = annotation(declaration.annotations, "settings");
|
|
29264
|
+
const inherited = inheritedMember(context, commonInput.overrideOf);
|
|
29260
29265
|
const storesSelectionArray = context.enumIdsByName.has(fieldType.name) || fieldType.name === "Dialogue" || Boolean(settings && argument(settings, "collection"));
|
|
29261
29266
|
const common = {
|
|
29262
29267
|
...commonInput,
|
|
@@ -29288,11 +29293,12 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
|
|
|
29288
29293
|
return { ...common, kind: name };
|
|
29289
29294
|
}
|
|
29290
29295
|
if (name === "int") {
|
|
29296
|
+
const inheritedInt = inherited?.kind === "int" ? inherited : void 0;
|
|
29291
29297
|
return {
|
|
29292
29298
|
...common,
|
|
29293
29299
|
kind: "int",
|
|
29294
|
-
min: numberArgument(settings, "min"),
|
|
29295
|
-
max: numberArgument(settings, "max")
|
|
29300
|
+
min: numberArgument(settings, "min") ?? inheritedInt?.min ?? null,
|
|
29301
|
+
max: numberArgument(settings, "max") ?? inheritedInt?.max ?? null
|
|
29296
29302
|
};
|
|
29297
29303
|
}
|
|
29298
29304
|
if (name === "string") {
|
|
@@ -29307,20 +29313,24 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
|
|
|
29307
29313
|
const min = numberTextArgument(settings, "min");
|
|
29308
29314
|
const max = numberTextArgument(settings, "max");
|
|
29309
29315
|
if (name === "decimal") {
|
|
29316
|
+
const inheritedDecimal = inherited?.kind === "decimal" ? inherited : void 0;
|
|
29310
29317
|
return {
|
|
29311
29318
|
...common,
|
|
29312
29319
|
kind: "decimal",
|
|
29313
|
-
min,
|
|
29314
|
-
max,
|
|
29315
|
-
decimalPoints: numberArgument(settings, "decimalPoints")
|
|
29320
|
+
min: min ?? inheritedDecimal?.min ?? null,
|
|
29321
|
+
max: max ?? inheritedDecimal?.max ?? null,
|
|
29322
|
+
decimalPoints: numberArgument(settings, "decimalPoints") ?? inheritedDecimal?.decimalPoints ?? null
|
|
29316
29323
|
};
|
|
29317
29324
|
}
|
|
29325
|
+
const inheritedFloat = inherited?.kind === "float" ? inherited : void 0;
|
|
29326
|
+
const numericMin = min === null ? null : Number(min);
|
|
29327
|
+
const numericMax = max === null ? null : Number(max);
|
|
29318
29328
|
return {
|
|
29319
29329
|
...common,
|
|
29320
29330
|
kind: "float",
|
|
29321
|
-
min:
|
|
29322
|
-
max:
|
|
29323
|
-
decimalPoints: numberArgument(settings, "decimalPoints")
|
|
29331
|
+
min: numericMin ?? inheritedFloat?.min ?? null,
|
|
29332
|
+
max: numericMax ?? inheritedFloat?.max ?? null,
|
|
29333
|
+
decimalPoints: numberArgument(settings, "decimalPoints") ?? inheritedFloat?.decimalPoints ?? null
|
|
29324
29334
|
};
|
|
29325
29335
|
}
|
|
29326
29336
|
const primitive3 = primitiveMemberKind(name);
|
|
@@ -29440,6 +29450,10 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
|
|
|
29440
29450
|
`Unsupported field type ${JSON.stringify(name)} on ${ownerClass.name}.${declaration.name}.`
|
|
29441
29451
|
);
|
|
29442
29452
|
}
|
|
29453
|
+
function inheritedMember(context, memberId) {
|
|
29454
|
+
if (memberId === null) return void 0;
|
|
29455
|
+
return context.loweredMembers.get(memberId) ?? context.baseMembers.get(memberId);
|
|
29456
|
+
}
|
|
29443
29457
|
function lowerListIndexes(ownerClass, declaration) {
|
|
29444
29458
|
const declared = /* @__PURE__ */ new Set();
|
|
29445
29459
|
return declaration.annotations.filter((entry) => entry.name === "index").map((entry) => {
|
|
@@ -29633,7 +29647,6 @@ function lowerInterface(context, declaration) {
|
|
|
29633
29647
|
function lowerEnum(context, declaration) {
|
|
29634
29648
|
const id2 = materializedId(declaration, "enum", declaration.name);
|
|
29635
29649
|
const base = context.baseEnums.get(id2);
|
|
29636
|
-
const baseOptions = new Map(base?.options.map((entry) => [entry.id, entry]));
|
|
29637
29650
|
return {
|
|
29638
29651
|
id: id2,
|
|
29639
29652
|
source: sourceIdentity2(declaration, "enum", declaration.name),
|
|
@@ -29641,13 +29654,15 @@ function lowerEnum(context, declaration) {
|
|
|
29641
29654
|
...declaration.docsText === void 0 ? {} : { docsText: declaration.docsText },
|
|
29642
29655
|
options: declaration.options.map((option) => {
|
|
29643
29656
|
const optionId = materializedId(option, "enum-option", option.name);
|
|
29644
|
-
const baseOption = baseOptions.get(optionId);
|
|
29645
29657
|
return {
|
|
29646
29658
|
id: optionId,
|
|
29647
29659
|
key: optionId,
|
|
29648
29660
|
name: option.name,
|
|
29649
29661
|
...option.docsText === void 0 ? {} : { docsText: option.docsText },
|
|
29650
|
-
|
|
29662
|
+
// An option with no `= "..."` is labelled by its own name. Preserving
|
|
29663
|
+
// the pulled record's text existed to carry a localized-text id
|
|
29664
|
+
// through a lowering; P39 section 1.3 removed that shape.
|
|
29665
|
+
text: option.textExpression === null ? option.name : stringExpression(option.textExpression),
|
|
29651
29666
|
source: sourceIdentity2(option, "enumOption", option.name)
|
|
29652
29667
|
};
|
|
29653
29668
|
}),
|
|
@@ -31185,7 +31200,7 @@ ${members.map((member) => indentNeoSourceNonEmptyLines(member, 2)).join("\n\n")}
|
|
|
31185
31200
|
}
|
|
31186
31201
|
function emitEnum(value) {
|
|
31187
31202
|
const options = value.options.map(
|
|
31188
|
-
(option) => `${emitDocsText(option.docsText)}${id(option.id)}${option.name}${option.text
|
|
31203
|
+
(option) => `${emitDocsText(option.docsText)}${id(option.id)}${option.name}${option.text === option.name ? "" : ` = ${quote(option.text)}`},`
|
|
31189
31204
|
);
|
|
31190
31205
|
return `${emitDocsText(value.docsText)}${id(value.id)}enum ${value.name} {
|
|
31191
31206
|
${options.map((option) => indentNeoSourceNonEmptyLines(option, 2)).join("\n")}
|
|
@@ -31989,11 +32004,6 @@ function assertUniqueEmittedPaths(files) {
|
|
|
31989
32004
|
paths.set(key, file);
|
|
31990
32005
|
}
|
|
31991
32006
|
}
|
|
31992
|
-
function looksLikeId(value) {
|
|
31993
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
|
|
31994
|
-
value
|
|
31995
|
-
);
|
|
31996
|
-
}
|
|
31997
32007
|
function assertIdentifier(value, kind) {
|
|
31998
32008
|
if (!isValidNeoIdentifier(value)) {
|
|
31999
32009
|
throw new Error(
|
|
@@ -33730,6 +33740,7 @@ var init_world_system_kinds_generated = __esm({
|
|
|
33730
33740
|
Tile: "tile",
|
|
33731
33741
|
ObjectBase: "objectBase",
|
|
33732
33742
|
ObjectCollider: "objectCollider",
|
|
33743
|
+
SortingGroup: "sortingGroup",
|
|
33733
33744
|
LayerGroupBase: "layerGroupBase",
|
|
33734
33745
|
SpriteObject: "spriteObject",
|
|
33735
33746
|
ObjectPlacementTile: "objectPlacementTile",
|
|
@@ -36085,6 +36096,22 @@ var init_world_system_classes_generated = __esm({
|
|
|
36085
36096
|
],
|
|
36086
36097
|
worldKind: "objectCollider"
|
|
36087
36098
|
},
|
|
36099
|
+
{
|
|
36100
|
+
classId: "system_69150540-b653-4bd0-a4fa-43a9f39da72b",
|
|
36101
|
+
name: "NeoSortingGroup",
|
|
36102
|
+
isAbstract: false,
|
|
36103
|
+
schemaFields: [
|
|
36104
|
+
{
|
|
36105
|
+
memberId: "system_fb90f48f-fcc0-4c98-bc22-70a8ea01170e",
|
|
36106
|
+
memberKind: "bool",
|
|
36107
|
+
defaultValue: false,
|
|
36108
|
+
docsText: "Sort this group against the scene root, ignoring any enclosing sorting group. Maps to SortingGroup.sortAtRoot.",
|
|
36109
|
+
required: true,
|
|
36110
|
+
schemaKey: "SortAtRoot"
|
|
36111
|
+
}
|
|
36112
|
+
],
|
|
36113
|
+
worldKind: "sortingGroup"
|
|
36114
|
+
},
|
|
36088
36115
|
{
|
|
36089
36116
|
classId: "system_bf076e9b-c8da-47dc-bae3-7527d0c307a8",
|
|
36090
36117
|
name: "NeoLayerGroupBase",
|
|
@@ -36111,6 +36138,42 @@ var init_world_system_classes_generated = __esm({
|
|
|
36111
36138
|
memberKind: "sprite",
|
|
36112
36139
|
required: true,
|
|
36113
36140
|
schemaKey: "Sprite"
|
|
36141
|
+
},
|
|
36142
|
+
{
|
|
36143
|
+
memberId: "system_9fcab37a-9743-4e35-8eee-80cb560f1433",
|
|
36144
|
+
memberKind: "bool",
|
|
36145
|
+
defaultValue: false,
|
|
36146
|
+
docsText: "Mirrors the sprite horizontally about its own centre. Maps to SpriteRenderer.flipX.",
|
|
36147
|
+
required: true,
|
|
36148
|
+
schemaKey: "FlipX"
|
|
36149
|
+
},
|
|
36150
|
+
{
|
|
36151
|
+
memberId: "system_ddd09f08-1656-4404-b36b-5570a4c01fcf",
|
|
36152
|
+
memberKind: "bool",
|
|
36153
|
+
defaultValue: false,
|
|
36154
|
+
docsText: "Mirrors the sprite vertically about its own centre. Maps to SpriteRenderer.flipY.",
|
|
36155
|
+
required: true,
|
|
36156
|
+
schemaKey: "FlipY"
|
|
36157
|
+
},
|
|
36158
|
+
{
|
|
36159
|
+
memberId: "system_f2a8c86d-ace5-421b-9475-0f3f6f97b2a6",
|
|
36160
|
+
memberKind: "enum",
|
|
36161
|
+
defaultValue: ["system_9d607a4f-60c3-4347-94fc-f24b538bf468"],
|
|
36162
|
+
docsText: "How this sprite reacts to sprite masks. Maps to SpriteRenderer.maskInteraction. The web canvas has no real sprite mask, so anything other than None previews as a distinguishable treatment rather than as the mask itself \u2014 only Unity renders the real thing.",
|
|
36163
|
+
enumId: "system_4e6c4d6f-1d0b-402a-ad3a-be92242dceec",
|
|
36164
|
+
multiselect: false,
|
|
36165
|
+
required: true,
|
|
36166
|
+
schemaKey: "MaskInteraction"
|
|
36167
|
+
},
|
|
36168
|
+
{
|
|
36169
|
+
memberId: "system_6f32f1f2-83ea-42fc-8647-34ed0946b7f1",
|
|
36170
|
+
memberKind: "int",
|
|
36171
|
+
defaultValue: null,
|
|
36172
|
+
docsText: "Nudges this sprite's draw order within its object. Added to the order derived from the object's layer group \u2014 it does not replace it. Leave unset for the default order.",
|
|
36173
|
+
minValue: -32768,
|
|
36174
|
+
maxValue: 32767,
|
|
36175
|
+
required: false,
|
|
36176
|
+
schemaKey: "SortingOrder"
|
|
36114
36177
|
}
|
|
36115
36178
|
],
|
|
36116
36179
|
worldKind: "spriteObject"
|
|
@@ -49650,7 +49713,6 @@ var init_localization_types = __esm({
|
|
|
49650
49713
|
LOCALIZED_TEXT_LINK_KINDS = [
|
|
49651
49714
|
"member-value",
|
|
49652
49715
|
"member-default-value",
|
|
49653
|
-
"member-enum-option",
|
|
49654
49716
|
"dialogue-description",
|
|
49655
49717
|
"dialogue-node-text",
|
|
49656
49718
|
"dialogue-choice-text",
|
|
@@ -51426,7 +51488,7 @@ var init_http = __esm({
|
|
|
51426
51488
|
}
|
|
51427
51489
|
return new _NeoApiClient(apiBaseUrl, token);
|
|
51428
51490
|
}
|
|
51429
|
-
async post(path, body, headers) {
|
|
51491
|
+
async post(path, body, headers, options = {}) {
|
|
51430
51492
|
const url = new URL(path, this.apiBaseUrl).toString();
|
|
51431
51493
|
const response = await fetch(url, {
|
|
51432
51494
|
method: "POST",
|
|
@@ -51435,7 +51497,8 @@ var init_http = __esm({
|
|
|
51435
51497
|
"Content-Type": "application/json",
|
|
51436
51498
|
...headers
|
|
51437
51499
|
},
|
|
51438
|
-
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
51500
|
+
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
51501
|
+
signal: options.signal
|
|
51439
51502
|
});
|
|
51440
51503
|
const text = await response.text();
|
|
51441
51504
|
let parsed = null;
|
|
@@ -59521,13 +59584,13 @@ function ownedObjectChildMember(row, sourceMember, key, ctx) {
|
|
|
59521
59584
|
return memberForCustomSchemaValue(classId, key, ctx);
|
|
59522
59585
|
}
|
|
59523
59586
|
function freshCloneValueId() {
|
|
59524
|
-
const
|
|
59525
|
-
if (
|
|
59587
|
+
const randomUUID7 = globalThis.crypto?.randomUUID;
|
|
59588
|
+
if (randomUUID7 === void 0) {
|
|
59526
59589
|
throw new NSGetterRuntimeError(
|
|
59527
59590
|
"Class.Clone cannot mint a value id because crypto.randomUUID is unavailable."
|
|
59528
59591
|
);
|
|
59529
59592
|
}
|
|
59530
|
-
return
|
|
59593
|
+
return randomUUID7.call(globalThis.crypto);
|
|
59531
59594
|
}
|
|
59532
59595
|
function parseDialogueMemoryPointer(pointer) {
|
|
59533
59596
|
if (typeof pointer !== "string") return null;
|
|
@@ -66453,80 +66516,154 @@ function ensureProjectFileBinaryChangesV4(args) {
|
|
|
66453
66516
|
});
|
|
66454
66517
|
}
|
|
66455
66518
|
}
|
|
66519
|
+
function prepareProjectFilePushesV4(args) {
|
|
66520
|
+
const prepared = [];
|
|
66521
|
+
for (const binary of args.binaryChanges) {
|
|
66522
|
+
if (binary.action !== "create" && binary.action !== "upload") continue;
|
|
66523
|
+
const recordId = args.assignedIds.get(binary.fileId) ?? binary.fileId;
|
|
66524
|
+
const change = args.changes.find(
|
|
66525
|
+
(candidate) => candidate.recordKind === "project-file" && candidate.recordId === recordId
|
|
66526
|
+
);
|
|
66527
|
+
if (change === void 0) {
|
|
66528
|
+
throw new Error(
|
|
66529
|
+
`Project file ${recordId} has upload bytes but no source change.`
|
|
66530
|
+
);
|
|
66531
|
+
}
|
|
66532
|
+
if (!isObjectRecord2(change.nextData)) {
|
|
66533
|
+
throw new Error(
|
|
66534
|
+
`Project file ${recordId} has upload bytes but its source change has no record data.`
|
|
66535
|
+
);
|
|
66536
|
+
}
|
|
66537
|
+
const absolute = join14(args.workspace.root, binary.path);
|
|
66538
|
+
const bytes = new Uint8Array(readFileSync12(absolute));
|
|
66539
|
+
const digest = sha256Bytes(bytes);
|
|
66540
|
+
if (binary.localSha256 !== null && digest !== binary.localSha256) {
|
|
66541
|
+
throw new Error(
|
|
66542
|
+
`Project file ${binary.path} changed after status was computed; run push again.`
|
|
66543
|
+
);
|
|
66544
|
+
}
|
|
66545
|
+
const mimeType = binary.mimeType;
|
|
66546
|
+
if (mimeType === null) {
|
|
66547
|
+
throw new Error(`Project file ${binary.path} has no MIME type.`);
|
|
66548
|
+
}
|
|
66549
|
+
prepared.push({
|
|
66550
|
+
uploadToken: `${recordId}-${prepared.length}`,
|
|
66551
|
+
recordId,
|
|
66552
|
+
replaceFileId: binary.action === "upload" ? recordId : null,
|
|
66553
|
+
name: basename2(binary.path),
|
|
66554
|
+
fileType: binary.kind,
|
|
66555
|
+
mimeType,
|
|
66556
|
+
byteLength: bytes.byteLength,
|
|
66557
|
+
contentSha256: digest,
|
|
66558
|
+
audioDurationSeconds: binary.kind === "audio" && typeof change.nextData.audioDurationSeconds === "number" ? change.nextData.audioDurationSeconds : null,
|
|
66559
|
+
bytes
|
|
66560
|
+
});
|
|
66561
|
+
}
|
|
66562
|
+
return prepared;
|
|
66563
|
+
}
|
|
66456
66564
|
async function stageProjectFilePushesV4(args) {
|
|
66565
|
+
const prepared = args.prepared ?? prepareProjectFilePushesV4({
|
|
66566
|
+
workspace: args.workspace,
|
|
66567
|
+
changes: args.changes,
|
|
66568
|
+
binaryChanges: args.binaryChanges,
|
|
66569
|
+
assignedIds: args.assignedIds
|
|
66570
|
+
});
|
|
66457
66571
|
const staged = [];
|
|
66458
66572
|
const cleanupKeys = [];
|
|
66459
66573
|
const put = args.put ?? fetch;
|
|
66574
|
+
const interruptController = new AbortController();
|
|
66575
|
+
const interrupt = () => interruptController.abort(new ProjectFilePushCancelledError());
|
|
66576
|
+
process.once("SIGINT", interrupt);
|
|
66577
|
+
const signal = combineSignals(args.signal, interruptController.signal);
|
|
66578
|
+
const totalBytes = prepared.reduce((sum, file) => sum + file.byteLength, 0);
|
|
66579
|
+
let completedBytes = 0;
|
|
66580
|
+
let completedFiles = 0;
|
|
66581
|
+
const report = () => args.onProgress?.({
|
|
66582
|
+
completedFiles,
|
|
66583
|
+
totalFiles: prepared.length,
|
|
66584
|
+
completedBytes,
|
|
66585
|
+
totalBytes
|
|
66586
|
+
});
|
|
66587
|
+
report();
|
|
66460
66588
|
try {
|
|
66461
|
-
for (
|
|
66462
|
-
|
|
66463
|
-
|
|
66464
|
-
|
|
66465
|
-
(candidate) => candidate.recordKind === "project-file" && candidate.recordId === recordId
|
|
66589
|
+
for (let offset = 0; offset < prepared.length; offset += PROJECT_FILE_UPLOAD_BATCH_SIZE) {
|
|
66590
|
+
const batch = prepared.slice(
|
|
66591
|
+
offset,
|
|
66592
|
+
offset + PROJECT_FILE_UPLOAD_BATCH_SIZE
|
|
66466
66593
|
);
|
|
66467
|
-
|
|
66468
|
-
|
|
66469
|
-
`Project file ${recordId} has upload bytes but no source change.`
|
|
66470
|
-
);
|
|
66471
|
-
}
|
|
66472
|
-
const absolute = join14(args.workspace.root, binary.path);
|
|
66473
|
-
const bytes = new Uint8Array(readFileSync12(absolute));
|
|
66474
|
-
const digest = sha256Bytes(bytes);
|
|
66475
|
-
if (binary.localSha256 !== null && digest !== binary.localSha256) {
|
|
66476
|
-
throw new Error(
|
|
66477
|
-
`Project file ${binary.path} changed after status was computed; run push again.`
|
|
66478
|
-
);
|
|
66479
|
-
}
|
|
66480
|
-
const mimeType = binary.mimeType;
|
|
66481
|
-
if (mimeType === null) {
|
|
66482
|
-
throw new Error(`Project file ${binary.path} has no MIME type.`);
|
|
66483
|
-
}
|
|
66484
|
-
const name = basename2(binary.path);
|
|
66485
|
-
const replaceFileId = binary.action === "upload" ? recordId : null;
|
|
66486
|
-
const presign = await args.client.post(
|
|
66594
|
+
const presign = await postWithTimeout(
|
|
66595
|
+
args.client,
|
|
66487
66596
|
versionPath2(args.workspace, "upload"),
|
|
66488
66597
|
{
|
|
66489
66598
|
route: "projectFile",
|
|
66490
66599
|
metadata: {
|
|
66491
|
-
|
|
66492
|
-
|
|
66493
|
-
|
|
66494
|
-
|
|
66600
|
+
deferredSourceCommit: true,
|
|
66601
|
+
uploads: batch.map((file) => ({
|
|
66602
|
+
uploadToken: file.uploadToken,
|
|
66603
|
+
projectFileId: file.recordId,
|
|
66604
|
+
replaceFileId: file.replaceFileId,
|
|
66605
|
+
name: file.name,
|
|
66606
|
+
contentSha256: file.contentSha256
|
|
66607
|
+
}))
|
|
66495
66608
|
},
|
|
66496
|
-
files:
|
|
66497
|
-
|
|
66609
|
+
files: batch.map((file) => ({
|
|
66610
|
+
name: file.uploadToken,
|
|
66611
|
+
size: file.byteLength,
|
|
66612
|
+
type: file.mimeType
|
|
66613
|
+
}))
|
|
66614
|
+
},
|
|
66615
|
+
signal
|
|
66498
66616
|
);
|
|
66499
|
-
const
|
|
66500
|
-
const
|
|
66501
|
-
const
|
|
66502
|
-
|
|
66503
|
-
|
|
66617
|
+
const entries = readPresignEntries(presign, batch);
|
|
66618
|
+
for (const entry of entries) cleanupKeys.push(entry.storageKey);
|
|
66619
|
+
const batchController = new AbortController();
|
|
66620
|
+
try {
|
|
66621
|
+
await mapWithConcurrency(entries, UPLOAD_CONCURRENCY, async (entry) => {
|
|
66622
|
+
try {
|
|
66623
|
+
await putWithRetry(
|
|
66624
|
+
put,
|
|
66625
|
+
entry,
|
|
66626
|
+
combineSignals(signal, batchController.signal)
|
|
66627
|
+
);
|
|
66628
|
+
} catch (error) {
|
|
66629
|
+
batchController.abort(error);
|
|
66630
|
+
throw error;
|
|
66631
|
+
}
|
|
66632
|
+
staged.push({
|
|
66633
|
+
uploadToken: entry.file.uploadToken,
|
|
66634
|
+
file: {
|
|
66635
|
+
recordId: entry.file.recordId,
|
|
66636
|
+
replaceFileId: entry.file.replaceFileId,
|
|
66637
|
+
name: entry.file.name,
|
|
66638
|
+
fileType: entry.file.fileType,
|
|
66639
|
+
mimeType: entry.file.mimeType,
|
|
66640
|
+
byteLength: entry.file.byteLength,
|
|
66641
|
+
storageKey: entry.storageKey,
|
|
66642
|
+
contentSha256: entry.file.contentSha256,
|
|
66643
|
+
audioDurationSeconds: entry.file.audioDurationSeconds
|
|
66644
|
+
}
|
|
66645
|
+
});
|
|
66646
|
+
completedFiles += 1;
|
|
66647
|
+
completedBytes += entry.file.byteLength;
|
|
66648
|
+
report();
|
|
66649
|
+
});
|
|
66650
|
+
} catch (error) {
|
|
66651
|
+
batchController.abort(error);
|
|
66652
|
+
throw error;
|
|
66504
66653
|
}
|
|
66505
|
-
|
|
66506
|
-
|
|
66507
|
-
|
|
66508
|
-
|
|
66509
|
-
|
|
66510
|
-
|
|
66511
|
-
|
|
66512
|
-
if (!response.ok) {
|
|
66654
|
+
}
|
|
66655
|
+
const byUploadToken = new Map(
|
|
66656
|
+
staged.map((entry) => [entry.uploadToken, entry.file])
|
|
66657
|
+
);
|
|
66658
|
+
return prepared.map((file) => {
|
|
66659
|
+
const result = byUploadToken.get(file.uploadToken);
|
|
66660
|
+
if (result === void 0) {
|
|
66513
66661
|
throw new Error(
|
|
66514
|
-
`
|
|
66662
|
+
`Uploaded project file ${file.name} (${file.uploadToken}) is missing from the staged result.`
|
|
66515
66663
|
);
|
|
66516
66664
|
}
|
|
66517
|
-
|
|
66518
|
-
|
|
66519
|
-
replaceFileId,
|
|
66520
|
-
name,
|
|
66521
|
-
fileType: binary.kind,
|
|
66522
|
-
mimeType,
|
|
66523
|
-
byteLength: bytes.byteLength,
|
|
66524
|
-
storageKey: objectInfo.key,
|
|
66525
|
-
contentSha256: digest,
|
|
66526
|
-
audioDurationSeconds: binary.kind === "audio" && typeof change.nextData.audioDurationSeconds === "number" ? change.nextData.audioDurationSeconds : null
|
|
66527
|
-
});
|
|
66528
|
-
}
|
|
66529
|
-
return staged;
|
|
66665
|
+
return result;
|
|
66666
|
+
});
|
|
66530
66667
|
} catch (error) {
|
|
66531
66668
|
if (cleanupKeys.length > 0) {
|
|
66532
66669
|
try {
|
|
@@ -66537,8 +66674,145 @@ async function stageProjectFilePushesV4(args) {
|
|
|
66537
66674
|
} catch {
|
|
66538
66675
|
}
|
|
66539
66676
|
}
|
|
66677
|
+
if (interruptController.signal.aborted || args.signal?.aborted === true) {
|
|
66678
|
+
throw new ProjectFilePushCancelledError();
|
|
66679
|
+
}
|
|
66540
66680
|
throw error;
|
|
66681
|
+
} finally {
|
|
66682
|
+
process.removeListener("SIGINT", interrupt);
|
|
66683
|
+
}
|
|
66684
|
+
}
|
|
66685
|
+
function readPresignEntries(presign, batch) {
|
|
66686
|
+
const entries = Array.isArray(presign.files) ? presign.files.filter(isObjectRecord2) : [];
|
|
66687
|
+
return batch.map((file) => {
|
|
66688
|
+
const entry = entries.find((candidate) => {
|
|
66689
|
+
const info = isObjectRecord2(candidate.file) ? candidate.file : {};
|
|
66690
|
+
return info.name === file.uploadToken;
|
|
66691
|
+
});
|
|
66692
|
+
const fileInfo = isObjectRecord2(entry?.file) ? entry.file : {};
|
|
66693
|
+
const objectInfo = isObjectRecord2(fileInfo.objectInfo) ? fileInfo.objectInfo : {};
|
|
66694
|
+
if (typeof entry?.signedUrl !== "string") {
|
|
66695
|
+
throw new Error(
|
|
66696
|
+
`Upload presign response is missing signedUrl for ${file.name}.`
|
|
66697
|
+
);
|
|
66698
|
+
}
|
|
66699
|
+
if (typeof objectInfo.key !== "string") {
|
|
66700
|
+
throw new Error(
|
|
66701
|
+
`Upload presign response is missing a storage key for ${file.name}.`
|
|
66702
|
+
);
|
|
66703
|
+
}
|
|
66704
|
+
return {
|
|
66705
|
+
file,
|
|
66706
|
+
signedUrl: entry.signedUrl,
|
|
66707
|
+
storageKey: objectInfo.key,
|
|
66708
|
+
headers: uploadHeaders(entry, objectInfo, file.mimeType)
|
|
66709
|
+
};
|
|
66710
|
+
});
|
|
66711
|
+
}
|
|
66712
|
+
async function postWithTimeout(client, path, body, signal) {
|
|
66713
|
+
for (let attempt = 1; attempt <= PRESIGN_ATTEMPTS; attempt += 1) {
|
|
66714
|
+
try {
|
|
66715
|
+
return await client.post(path, body, void 0, {
|
|
66716
|
+
signal: combineSignals(signal, AbortSignal.timeout(PRESIGN_TIMEOUT_MS))
|
|
66717
|
+
});
|
|
66718
|
+
} catch (error) {
|
|
66719
|
+
if (signal.aborted || !isRetryableRequestError(error) || attempt === PRESIGN_ATTEMPTS) {
|
|
66720
|
+
throw error;
|
|
66721
|
+
}
|
|
66722
|
+
await waitForRetry(attempt, signal);
|
|
66723
|
+
}
|
|
66724
|
+
}
|
|
66725
|
+
throw new Error("Upload presign failed after all retry attempts.");
|
|
66726
|
+
}
|
|
66727
|
+
async function putWithRetry(put, entry, signal) {
|
|
66728
|
+
let lastError;
|
|
66729
|
+
for (let attempt = 1; attempt <= STORAGE_PUT_ATTEMPTS; attempt += 1) {
|
|
66730
|
+
let response;
|
|
66731
|
+
try {
|
|
66732
|
+
response = await put(entry.signedUrl, {
|
|
66733
|
+
method: "PUT",
|
|
66734
|
+
headers: entry.headers,
|
|
66735
|
+
body: Buffer.from(entry.file.bytes),
|
|
66736
|
+
signal: combineSignals(
|
|
66737
|
+
signal,
|
|
66738
|
+
AbortSignal.timeout(STORAGE_PUT_TIMEOUT_MS)
|
|
66739
|
+
)
|
|
66740
|
+
});
|
|
66741
|
+
} catch (error) {
|
|
66742
|
+
if (signal.aborted || attempt === STORAGE_PUT_ATTEMPTS) throw error;
|
|
66743
|
+
lastError = error;
|
|
66744
|
+
await waitForRetry(attempt, signal);
|
|
66745
|
+
continue;
|
|
66746
|
+
}
|
|
66747
|
+
if (response.ok) return;
|
|
66748
|
+
if (isRetryableStatus(response.status) && attempt < STORAGE_PUT_ATTEMPTS) {
|
|
66749
|
+
lastError = new Error(`Storage PUT failed (${response.status}).`);
|
|
66750
|
+
await waitForRetry(attempt, signal);
|
|
66751
|
+
continue;
|
|
66752
|
+
}
|
|
66753
|
+
throw new Error(
|
|
66754
|
+
`Storage PUT failed (${response.status}): ${await response.text()}`
|
|
66755
|
+
);
|
|
66756
|
+
}
|
|
66757
|
+
throw lastError instanceof Error ? lastError : new Error(`Storage PUT failed for ${entry.file.name}.`);
|
|
66758
|
+
}
|
|
66759
|
+
function isRetryableStatus(status) {
|
|
66760
|
+
return status === 408 || status === 429 || status >= 500;
|
|
66761
|
+
}
|
|
66762
|
+
function isRetryableRequestError(error) {
|
|
66763
|
+
if (isObjectRecord2(error) && typeof error.status === "number") {
|
|
66764
|
+
return isRetryableStatus(error.status);
|
|
66765
|
+
}
|
|
66766
|
+
if (isObjectRecord2(error) && error.name === "TimeoutError") return true;
|
|
66767
|
+
if (!(error instanceof TypeError) || error.message !== "fetch failed") {
|
|
66768
|
+
return false;
|
|
66769
|
+
}
|
|
66770
|
+
if (!isObjectRecord2(error.cause) || typeof error.cause.code !== "string") {
|
|
66771
|
+
return false;
|
|
66541
66772
|
}
|
|
66773
|
+
return RETRYABLE_NETWORK_ERROR_CODES.has(error.cause.code);
|
|
66774
|
+
}
|
|
66775
|
+
async function waitForRetry(attempt, signal) {
|
|
66776
|
+
await new Promise((resolve4, reject) => {
|
|
66777
|
+
const abort = () => {
|
|
66778
|
+
clearTimeout(timeout);
|
|
66779
|
+
reject(signal.reason);
|
|
66780
|
+
};
|
|
66781
|
+
const timeout = setTimeout(
|
|
66782
|
+
() => {
|
|
66783
|
+
signal.removeEventListener("abort", abort);
|
|
66784
|
+
resolve4();
|
|
66785
|
+
},
|
|
66786
|
+
200 * 2 ** (attempt - 1)
|
|
66787
|
+
);
|
|
66788
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
66789
|
+
});
|
|
66790
|
+
}
|
|
66791
|
+
async function mapWithConcurrency(values, concurrency, run) {
|
|
66792
|
+
let nextIndex = 0;
|
|
66793
|
+
let firstError;
|
|
66794
|
+
const worker = async () => {
|
|
66795
|
+
while (firstError === void 0) {
|
|
66796
|
+
const index = nextIndex;
|
|
66797
|
+
nextIndex += 1;
|
|
66798
|
+
if (index >= values.length) return;
|
|
66799
|
+
try {
|
|
66800
|
+
await run(values[index]);
|
|
66801
|
+
} catch (error) {
|
|
66802
|
+
firstError ??= error;
|
|
66803
|
+
}
|
|
66804
|
+
}
|
|
66805
|
+
};
|
|
66806
|
+
await Promise.all(
|
|
66807
|
+
Array.from({ length: Math.min(concurrency, values.length) }, worker)
|
|
66808
|
+
);
|
|
66809
|
+
if (firstError !== void 0) throw firstError;
|
|
66810
|
+
}
|
|
66811
|
+
function combineSignals(...signals) {
|
|
66812
|
+
const defined = signals.filter(
|
|
66813
|
+
(signal) => signal !== void 0
|
|
66814
|
+
);
|
|
66815
|
+
return defined.length === 1 ? defined[0] : AbortSignal.any(defined);
|
|
66542
66816
|
}
|
|
66543
66817
|
function uploadHeaders(entry, objectInfo, mimeType) {
|
|
66544
66818
|
const headers = { "Content-Type": mimeType };
|
|
@@ -66560,11 +66834,431 @@ function uploadHeaders(entry, objectInfo, mimeType) {
|
|
|
66560
66834
|
function versionPath2(workspace, suffix) {
|
|
66561
66835
|
return `/api/projects/${workspace.config.projectId}/versions/${workspace.config.versionId}/${suffix}`;
|
|
66562
66836
|
}
|
|
66837
|
+
var UPLOAD_CONCURRENCY, PRESIGN_TIMEOUT_MS, PRESIGN_ATTEMPTS, STORAGE_PUT_TIMEOUT_MS, STORAGE_PUT_ATTEMPTS, ProjectFilePushCancelledError, RETRYABLE_NETWORK_ERROR_CODES;
|
|
66563
66838
|
var init_project_file_push = __esm({
|
|
66564
66839
|
"src/project-source/project-file-push.ts"() {
|
|
66565
66840
|
"use strict";
|
|
66566
66841
|
init_project_files();
|
|
66567
66842
|
init_projection();
|
|
66843
|
+
init_src();
|
|
66844
|
+
UPLOAD_CONCURRENCY = 6;
|
|
66845
|
+
PRESIGN_TIMEOUT_MS = 3e4;
|
|
66846
|
+
PRESIGN_ATTEMPTS = 3;
|
|
66847
|
+
STORAGE_PUT_TIMEOUT_MS = 12e4;
|
|
66848
|
+
STORAGE_PUT_ATTEMPTS = 3;
|
|
66849
|
+
ProjectFilePushCancelledError = class extends Error {
|
|
66850
|
+
constructor() {
|
|
66851
|
+
super("Project file upload was cancelled.");
|
|
66852
|
+
this.name = "ProjectFilePushCancelledError";
|
|
66853
|
+
}
|
|
66854
|
+
};
|
|
66855
|
+
RETRYABLE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
66856
|
+
"ECONNRESET",
|
|
66857
|
+
"ECONNREFUSED",
|
|
66858
|
+
"EHOSTUNREACH",
|
|
66859
|
+
"ENETUNREACH",
|
|
66860
|
+
"ENOTFOUND",
|
|
66861
|
+
"EPIPE",
|
|
66862
|
+
"ETIMEDOUT"
|
|
66863
|
+
]);
|
|
66864
|
+
}
|
|
66865
|
+
});
|
|
66866
|
+
|
|
66867
|
+
// src/project-source/trusted-commit-verification.ts
|
|
66868
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
66869
|
+
import { tmpdir } from "node:os";
|
|
66870
|
+
import { join as join15 } from "node:path";
|
|
66871
|
+
function verifyProjectSourceCommitAgainstStateV4(args) {
|
|
66872
|
+
const root = join15(tmpdir(), `neo-source-verify-virtual-${randomUUID5()}`);
|
|
66873
|
+
const workspace = {
|
|
66874
|
+
root,
|
|
66875
|
+
config: {
|
|
66876
|
+
formatVersion: 4,
|
|
66877
|
+
apiBaseUrl: "https://trusted-server.invalid",
|
|
66878
|
+
projectId: args.projectId,
|
|
66879
|
+
versionId: args.versionId,
|
|
66880
|
+
profile: "editor"
|
|
66881
|
+
},
|
|
66882
|
+
state: { records: { ...args.stateRecords } }
|
|
66883
|
+
};
|
|
66884
|
+
const assignments = validateAssignments(args.pendingIdAssignments);
|
|
66885
|
+
const pendingIdByAssignedId = new Map(
|
|
66886
|
+
[...assignments].map(([pendingId2, assignedId]) => [assignedId, pendingId2])
|
|
66887
|
+
);
|
|
66888
|
+
const trustedPendingProjectFiles = /* @__PURE__ */ new Map();
|
|
66889
|
+
const stagedRecordIds = /* @__PURE__ */ new Set();
|
|
66890
|
+
for (const file of args.stagedFiles) {
|
|
66891
|
+
if (stagedRecordIds.has(file.recordId)) {
|
|
66892
|
+
throw new ProjectSourceCommitVerificationError(
|
|
66893
|
+
"Source commit contains duplicate verified staged project files."
|
|
66894
|
+
);
|
|
66895
|
+
}
|
|
66896
|
+
stagedRecordIds.add(file.recordId);
|
|
66897
|
+
const metadata = {
|
|
66898
|
+
mimeType: file.mimeType,
|
|
66899
|
+
byteLength: file.byteLength,
|
|
66900
|
+
sha256: file.contentSha256
|
|
66901
|
+
};
|
|
66902
|
+
trustedPendingProjectFiles.set(file.recordId, metadata);
|
|
66903
|
+
const pendingId2 = pendingIdByAssignedId.get(file.recordId);
|
|
66904
|
+
if (pendingId2 !== void 0) {
|
|
66905
|
+
trustedPendingProjectFiles.set(pendingId2, metadata);
|
|
66906
|
+
}
|
|
66907
|
+
}
|
|
66908
|
+
const status = computeWorkspaceStatus(workspace, {
|
|
66909
|
+
skipProjectBinaryInspection: true,
|
|
66910
|
+
writeProjectAnalysisCache: () => void 0,
|
|
66911
|
+
trustedPendingProjectFiles,
|
|
66912
|
+
virtualSourceFiles: args.files
|
|
66913
|
+
});
|
|
66914
|
+
const blockingErrors = status.parseErrors.filter(isBlockingSchemaSourceError);
|
|
66915
|
+
if (status.conflictedFiles.length > 0 || blockingErrors.length > 0) {
|
|
66916
|
+
const first = blockingErrors[0];
|
|
66917
|
+
throw new ProjectSourceCommitVerificationError(
|
|
66918
|
+
first ? `Trusted source lowering failed: ${first.file}:${first.line}:${first.column} ${first.message}` : `Trusted source lowering found conflict markers in ${status.conflictedFiles[0]}.`
|
|
66919
|
+
);
|
|
66920
|
+
}
|
|
66921
|
+
const usedAssignments = /* @__PURE__ */ new Set();
|
|
66922
|
+
const expectedChanges = status.changes.map((change) => {
|
|
66923
|
+
const rewrittenData = change.nextData === void 0 ? void 0 : rewritePending(change.nextData, assignments, usedAssignments);
|
|
66924
|
+
return {
|
|
66925
|
+
recordKind: change.recordKind,
|
|
66926
|
+
recordId: rewritePending(change.recordId, assignments, usedAssignments),
|
|
66927
|
+
operation: change.kind,
|
|
66928
|
+
// Source syntax does not author project ownership. The CLI stamps the
|
|
66929
|
+
// authenticated project id on creates immediately before transport;
|
|
66930
|
+
// reproduce that server-known field instead of comparing the
|
|
66931
|
+
// lowerer's empty construction placeholder.
|
|
66932
|
+
nextData: change.kind === "create" && isObjectRecord2(rewrittenData) ? { ...rewrittenData, projectId: args.projectId } : rewrittenData,
|
|
66933
|
+
expectedBaseContentHash: change.kind === "create" ? null : change.casBaseHash ?? null
|
|
66934
|
+
};
|
|
66935
|
+
});
|
|
66936
|
+
const expectedSeeds = [...status.staticValueSeeds].map(
|
|
66937
|
+
([memberId, seed]) => ({
|
|
66938
|
+
memberId: rewritePending(memberId, assignments, usedAssignments),
|
|
66939
|
+
value: rewritePending(seed.value, assignments, usedAssignments),
|
|
66940
|
+
classId: seed.classId === null ? null : rewritePending(seed.classId, assignments, usedAssignments),
|
|
66941
|
+
...seed.valueId === void 0 ? {} : {
|
|
66942
|
+
valueId: rewritePending(seed.valueId, assignments, usedAssignments)
|
|
66943
|
+
},
|
|
66944
|
+
...seed.values === void 0 ? {} : {
|
|
66945
|
+
values: rewritePending(seed.values, assignments, usedAssignments)
|
|
66946
|
+
},
|
|
66947
|
+
...seed.bindingMembers === void 0 ? {} : {
|
|
66948
|
+
bindingMembers: rewritePending(
|
|
66949
|
+
seed.bindingMembers,
|
|
66950
|
+
assignments,
|
|
66951
|
+
usedAssignments
|
|
66952
|
+
)
|
|
66953
|
+
},
|
|
66954
|
+
...seed.localizedTexts === void 0 ? {} : {
|
|
66955
|
+
localizedTexts: rewritePending(
|
|
66956
|
+
seed.localizedTexts,
|
|
66957
|
+
assignments,
|
|
66958
|
+
usedAssignments
|
|
66959
|
+
)
|
|
66960
|
+
}
|
|
66961
|
+
})
|
|
66962
|
+
);
|
|
66963
|
+
for (const pendingId2 of assignments.keys()) {
|
|
66964
|
+
if (!usedAssignments.has(pendingId2)) {
|
|
66965
|
+
throw new ProjectSourceCommitVerificationError(
|
|
66966
|
+
`Pending id assignment ${pendingId2} is not present in the verified source manifest.`
|
|
66967
|
+
);
|
|
66968
|
+
}
|
|
66969
|
+
}
|
|
66970
|
+
compareChanges(expectedChanges, args.changes);
|
|
66971
|
+
compareSeeds(expectedSeeds, args.staticValueSeeds);
|
|
66972
|
+
}
|
|
66973
|
+
function validateAssignments(value) {
|
|
66974
|
+
const assignments = /* @__PURE__ */ new Map();
|
|
66975
|
+
const assignedIds = /* @__PURE__ */ new Set();
|
|
66976
|
+
for (const [pendingId2, assignedId] of Object.entries(value)) {
|
|
66977
|
+
if (!pendingId2.startsWith("__pending__:")) {
|
|
66978
|
+
throw new ProjectSourceCommitVerificationError(
|
|
66979
|
+
`Pending id assignment key ${pendingId2} is not a pending identity.`
|
|
66980
|
+
);
|
|
66981
|
+
}
|
|
66982
|
+
if (pendingMemberValueMemberId(pendingId2) === null) {
|
|
66983
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(
|
|
66984
|
+
assignedId
|
|
66985
|
+
)) {
|
|
66986
|
+
throw new ProjectSourceCommitVerificationError(
|
|
66987
|
+
`Pending id assignment for ${pendingId2} is not a UUID v4.`
|
|
66988
|
+
);
|
|
66989
|
+
}
|
|
66990
|
+
}
|
|
66991
|
+
if (assignedIds.has(assignedId)) {
|
|
66992
|
+
throw new ProjectSourceCommitVerificationError(
|
|
66993
|
+
`Pending id assignments reuse durable id ${assignedId}.`
|
|
66994
|
+
);
|
|
66995
|
+
}
|
|
66996
|
+
assignments.set(pendingId2, assignedId);
|
|
66997
|
+
assignedIds.add(assignedId);
|
|
66998
|
+
}
|
|
66999
|
+
assertMemberValueAssignmentsAreDerived(assignments);
|
|
67000
|
+
return assignments;
|
|
67001
|
+
}
|
|
67002
|
+
function assertMemberValueAssignmentsAreDerived(assignments) {
|
|
67003
|
+
for (const [pendingId2, assignedId] of assignments) {
|
|
67004
|
+
const memberLocator = pendingMemberValueMemberId(pendingId2);
|
|
67005
|
+
if (memberLocator === null) continue;
|
|
67006
|
+
const memberId = memberLocator.startsWith("__pending__:") ? assignments.get(memberLocator) : memberLocator;
|
|
67007
|
+
if (memberId === void 0) {
|
|
67008
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67009
|
+
`Member value assignment ${pendingId2} names member ${memberLocator}, which has no pending id assignment.`
|
|
67010
|
+
);
|
|
67011
|
+
}
|
|
67012
|
+
const derived = derivedMemberValueId(memberId);
|
|
67013
|
+
if (assignedId !== derived) {
|
|
67014
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67015
|
+
`Member value assignment ${pendingId2} is ${assignedId}, but member ${memberId} owns value ${derived}.`
|
|
67016
|
+
);
|
|
67017
|
+
}
|
|
67018
|
+
}
|
|
67019
|
+
}
|
|
67020
|
+
function positionIndependentPendingKey(pendingId2) {
|
|
67021
|
+
const parts = pendingId2.split(":");
|
|
67022
|
+
if (parts.length !== 6) return null;
|
|
67023
|
+
const [prefix, kind, uri, line, character, label] = parts;
|
|
67024
|
+
if (prefix !== "__pending__") return null;
|
|
67025
|
+
if (!/^\d+$/u.test(line) || !/^\d+$/u.test(character)) return null;
|
|
67026
|
+
return `${prefix}:${kind}:${uri}:${label}`;
|
|
67027
|
+
}
|
|
67028
|
+
function positionIndependentAssignments(assignments) {
|
|
67029
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
67030
|
+
for (const pendingId2 of assignments.keys()) {
|
|
67031
|
+
const key = positionIndependentPendingKey(pendingId2);
|
|
67032
|
+
if (key === null) continue;
|
|
67033
|
+
candidates.set(key, [...candidates.get(key) ?? [], pendingId2]);
|
|
67034
|
+
}
|
|
67035
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
67036
|
+
for (const [key, pendingIds] of candidates) {
|
|
67037
|
+
if (pendingIds.length !== 1) continue;
|
|
67038
|
+
resolved.set(key, pendingIds[0]);
|
|
67039
|
+
}
|
|
67040
|
+
return resolved;
|
|
67041
|
+
}
|
|
67042
|
+
function rewritePending(value, assignments, used, byPosition) {
|
|
67043
|
+
const positionless = byPosition ?? positionIndependentAssignments(assignments);
|
|
67044
|
+
if (typeof value === "string") {
|
|
67045
|
+
const exact = assignments.get(value);
|
|
67046
|
+
if (exact !== void 0) {
|
|
67047
|
+
used.add(value);
|
|
67048
|
+
return exact;
|
|
67049
|
+
}
|
|
67050
|
+
if (value.startsWith("__pending__:")) {
|
|
67051
|
+
const key = positionIndependentPendingKey(value);
|
|
67052
|
+
const relocated = key === null ? void 0 : positionless.get(key);
|
|
67053
|
+
if (relocated !== void 0) {
|
|
67054
|
+
used.add(relocated);
|
|
67055
|
+
return assignments.get(relocated);
|
|
67056
|
+
}
|
|
67057
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67058
|
+
`Verified source identity ${value} has no pending id assignment.`
|
|
67059
|
+
);
|
|
67060
|
+
}
|
|
67061
|
+
let rewritten = value;
|
|
67062
|
+
for (const [pendingId2, assignedId] of assignments) {
|
|
67063
|
+
if (!rewritten.includes(pendingId2)) continue;
|
|
67064
|
+
rewritten = rewritten.replaceAll(pendingId2, assignedId);
|
|
67065
|
+
used.add(pendingId2);
|
|
67066
|
+
}
|
|
67067
|
+
return rewritten;
|
|
67068
|
+
}
|
|
67069
|
+
if (Array.isArray(value)) {
|
|
67070
|
+
return value.map(
|
|
67071
|
+
(entry) => rewritePending(entry, assignments, used, positionless)
|
|
67072
|
+
);
|
|
67073
|
+
}
|
|
67074
|
+
if (isObjectRecord2(value)) {
|
|
67075
|
+
const result = {};
|
|
67076
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
67077
|
+
const rewrittenKey = key.startsWith("__pending__:") ? rewritePending(key, assignments, used, positionless) : key;
|
|
67078
|
+
result[rewrittenKey] = rewritePending(
|
|
67079
|
+
entry,
|
|
67080
|
+
assignments,
|
|
67081
|
+
used,
|
|
67082
|
+
positionless
|
|
67083
|
+
);
|
|
67084
|
+
}
|
|
67085
|
+
return result;
|
|
67086
|
+
}
|
|
67087
|
+
return value;
|
|
67088
|
+
}
|
|
67089
|
+
function compareChanges(expected, received) {
|
|
67090
|
+
const expectedByKey = new Map(
|
|
67091
|
+
expected.map((change) => [
|
|
67092
|
+
`${change.recordKind}:${change.recordId}`,
|
|
67093
|
+
change
|
|
67094
|
+
])
|
|
67095
|
+
);
|
|
67096
|
+
const receivedByKey = new Map(
|
|
67097
|
+
received.map((change) => [
|
|
67098
|
+
`${change.recordKind}:${change.recordId}`,
|
|
67099
|
+
change
|
|
67100
|
+
])
|
|
67101
|
+
);
|
|
67102
|
+
if (expectedByKey.size !== expected.length || receivedByKey.size !== received.length) {
|
|
67103
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67104
|
+
"Source commit contains duplicate semantic record changes."
|
|
67105
|
+
);
|
|
67106
|
+
}
|
|
67107
|
+
for (const [key, expectedChange] of expectedByKey) {
|
|
67108
|
+
const actual = receivedByKey.get(key);
|
|
67109
|
+
if (actual === void 0) {
|
|
67110
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67111
|
+
`Source commit omitted semantic change ${key}.`
|
|
67112
|
+
);
|
|
67113
|
+
}
|
|
67114
|
+
if (actual.operation !== expectedChange.operation || (actual.expectedBaseContentHash ?? null) !== expectedChange.expectedBaseContentHash) {
|
|
67115
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67116
|
+
`Source commit changed operation or CAS base for ${key}.`
|
|
67117
|
+
);
|
|
67118
|
+
}
|
|
67119
|
+
const expectedData = comparisonData(
|
|
67120
|
+
expectedChange.recordKind,
|
|
67121
|
+
expectedChange.nextData
|
|
67122
|
+
);
|
|
67123
|
+
const actualData = comparisonData(actual.recordKind, actual.nextData);
|
|
67124
|
+
if (canonicalStringify(expectedData) !== canonicalStringify(actualData)) {
|
|
67125
|
+
const difference = firstDifference(expectedData, actualData);
|
|
67126
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67127
|
+
`Source commit nextData for ${key} does not match trusted lowering${difference === null ? "." : ` at ${difference.path}: trusted ${formatDifferenceValue(difference.trusted)}, submitted ${formatDifferenceValue(difference.submitted)}.`}`
|
|
67128
|
+
);
|
|
67129
|
+
}
|
|
67130
|
+
if (!isObjectRecord2(actual.intent) || actual.intent.type !== `${actual.recordKind}.${actual.operation}`) {
|
|
67131
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67132
|
+
`Source commit intent for ${key} does not match its semantic operation.`
|
|
67133
|
+
);
|
|
67134
|
+
}
|
|
67135
|
+
receivedByKey.delete(key);
|
|
67136
|
+
}
|
|
67137
|
+
const extra = receivedByKey.keys().next().value;
|
|
67138
|
+
if (extra !== void 0) {
|
|
67139
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67140
|
+
`Source commit added semantic change ${extra} absent from trusted lowering.`
|
|
67141
|
+
);
|
|
67142
|
+
}
|
|
67143
|
+
}
|
|
67144
|
+
function firstDifference(trusted, submitted, path = "$") {
|
|
67145
|
+
if (Object.is(trusted, submitted)) return null;
|
|
67146
|
+
if (Array.isArray(trusted) && Array.isArray(submitted)) {
|
|
67147
|
+
const count = Math.max(trusted.length, submitted.length);
|
|
67148
|
+
for (let index = 0; index < count; index += 1) {
|
|
67149
|
+
if (index >= trusted.length) {
|
|
67150
|
+
return {
|
|
67151
|
+
path: `${path}[${index}]`,
|
|
67152
|
+
trusted: ABSENT_DIFFERENCE_VALUE,
|
|
67153
|
+
submitted: submitted[index]
|
|
67154
|
+
};
|
|
67155
|
+
}
|
|
67156
|
+
if (index >= submitted.length) {
|
|
67157
|
+
return {
|
|
67158
|
+
path: `${path}[${index}]`,
|
|
67159
|
+
trusted: trusted[index],
|
|
67160
|
+
submitted: ABSENT_DIFFERENCE_VALUE
|
|
67161
|
+
};
|
|
67162
|
+
}
|
|
67163
|
+
const difference = firstDifference(
|
|
67164
|
+
trusted[index],
|
|
67165
|
+
submitted[index],
|
|
67166
|
+
`${path}[${index}]`
|
|
67167
|
+
);
|
|
67168
|
+
if (difference !== null) return difference;
|
|
67169
|
+
}
|
|
67170
|
+
}
|
|
67171
|
+
if (isObjectRecord2(trusted) && isObjectRecord2(submitted)) {
|
|
67172
|
+
const keys = [
|
|
67173
|
+
.../* @__PURE__ */ new Set([...Object.keys(trusted), ...Object.keys(submitted)])
|
|
67174
|
+
].sort();
|
|
67175
|
+
for (const key of keys) {
|
|
67176
|
+
const trustedHasKey = Object.hasOwn(trusted, key);
|
|
67177
|
+
const submittedHasKey = Object.hasOwn(submitted, key);
|
|
67178
|
+
const childPath = `${path}.${key}`;
|
|
67179
|
+
if (!trustedHasKey || !submittedHasKey) {
|
|
67180
|
+
return {
|
|
67181
|
+
path: childPath,
|
|
67182
|
+
trusted: trustedHasKey ? trusted[key] : ABSENT_DIFFERENCE_VALUE,
|
|
67183
|
+
submitted: submittedHasKey ? submitted[key] : ABSENT_DIFFERENCE_VALUE
|
|
67184
|
+
};
|
|
67185
|
+
}
|
|
67186
|
+
const difference = firstDifference(
|
|
67187
|
+
trusted[key],
|
|
67188
|
+
submitted[key],
|
|
67189
|
+
childPath
|
|
67190
|
+
);
|
|
67191
|
+
if (difference !== null) return difference;
|
|
67192
|
+
}
|
|
67193
|
+
}
|
|
67194
|
+
return { path, trusted, submitted };
|
|
67195
|
+
}
|
|
67196
|
+
function formatDifferenceValue(value) {
|
|
67197
|
+
if (value === ABSENT_DIFFERENCE_VALUE) return "<absent>";
|
|
67198
|
+
const serialized = JSON.stringify(value);
|
|
67199
|
+
const rendered = serialized === void 0 ? String(value) : serialized;
|
|
67200
|
+
return rendered.length <= 160 ? rendered : `${rendered.slice(0, 157)}...`;
|
|
67201
|
+
}
|
|
67202
|
+
function comparisonData(recordKind, value) {
|
|
67203
|
+
if (!isObjectRecord2(value)) return value;
|
|
67204
|
+
const result = { ...value };
|
|
67205
|
+
delete result.createdAt;
|
|
67206
|
+
delete result.updatedAt;
|
|
67207
|
+
if (recordKind === "member") {
|
|
67208
|
+
delete result.getter;
|
|
67209
|
+
delete result.setter;
|
|
67210
|
+
if (result.kind === 23) delete result.action;
|
|
67211
|
+
}
|
|
67212
|
+
if (recordKind === "migration") delete result.action;
|
|
67213
|
+
return result;
|
|
67214
|
+
}
|
|
67215
|
+
function compareSeeds(expected, received) {
|
|
67216
|
+
const normalize = (values) => values.map(normalizeSeedForComparison).sort((left, right) => {
|
|
67217
|
+
if (left.memberId < right.memberId) return -1;
|
|
67218
|
+
if (left.memberId > right.memberId) return 1;
|
|
67219
|
+
return 0;
|
|
67220
|
+
});
|
|
67221
|
+
if (canonicalStringify(normalize(expected)) !== canonicalStringify(normalize(received))) {
|
|
67222
|
+
throw new ProjectSourceCommitVerificationError(
|
|
67223
|
+
"Source commit static value seeds do not match trusted lowering."
|
|
67224
|
+
);
|
|
67225
|
+
}
|
|
67226
|
+
}
|
|
67227
|
+
function normalizeSeedForComparison(seed) {
|
|
67228
|
+
const normalized = { ...seed };
|
|
67229
|
+
if (seed.values !== void 0) {
|
|
67230
|
+
normalized.values = sortSeedRows(seed.values);
|
|
67231
|
+
}
|
|
67232
|
+
if (seed.bindingMembers !== void 0) {
|
|
67233
|
+
normalized.bindingMembers = sortSeedRows(seed.bindingMembers);
|
|
67234
|
+
}
|
|
67235
|
+
if (seed.localizedTexts !== void 0) {
|
|
67236
|
+
normalized.localizedTexts = sortSeedRows(seed.localizedTexts);
|
|
67237
|
+
}
|
|
67238
|
+
return normalized;
|
|
67239
|
+
}
|
|
67240
|
+
function sortSeedRows(values) {
|
|
67241
|
+
return [...values].sort((left, right) => {
|
|
67242
|
+
if (left.id < right.id) return -1;
|
|
67243
|
+
if (left.id > right.id) return 1;
|
|
67244
|
+
return 0;
|
|
67245
|
+
});
|
|
67246
|
+
}
|
|
67247
|
+
var ProjectSourceCommitVerificationError, ABSENT_DIFFERENCE_VALUE;
|
|
67248
|
+
var init_trusted_commit_verification = __esm({
|
|
67249
|
+
"src/project-source/trusted-commit-verification.ts"() {
|
|
67250
|
+
"use strict";
|
|
67251
|
+
init_workspace_status();
|
|
67252
|
+
init_source_diagnostics();
|
|
67253
|
+
init_projection();
|
|
67254
|
+
init_member_value_id();
|
|
67255
|
+
ProjectSourceCommitVerificationError = class extends Error {
|
|
67256
|
+
constructor(message) {
|
|
67257
|
+
super(message);
|
|
67258
|
+
this.name = "ProjectSourceCommitVerificationError";
|
|
67259
|
+
}
|
|
67260
|
+
};
|
|
67261
|
+
ABSENT_DIFFERENCE_VALUE = /* @__PURE__ */ Symbol("absent-difference-value");
|
|
66568
67262
|
}
|
|
66569
67263
|
});
|
|
66570
67264
|
|
|
@@ -66609,7 +67303,7 @@ __export(push_exports, {
|
|
|
66609
67303
|
stripServerDerivedNeoScript: () => stripServerDerivedNeoScript,
|
|
66610
67304
|
workspaceChangesRequireCompleteBodySweep: () => workspaceChangesRequireCompleteBodySweep
|
|
66611
67305
|
});
|
|
66612
|
-
import { randomUUID as
|
|
67306
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
66613
67307
|
import {
|
|
66614
67308
|
mkdirSync as mkdirSync11,
|
|
66615
67309
|
writeFileSync as writeFileSync11,
|
|
@@ -66617,7 +67311,7 @@ import {
|
|
|
66617
67311
|
existsSync as existsSync12,
|
|
66618
67312
|
readFileSync as readFileSync13
|
|
66619
67313
|
} from "node:fs";
|
|
66620
|
-
import { dirname as dirname7, join as
|
|
67314
|
+
import { dirname as dirname7, join as join16, relative as relative5, sep as sep5 } from "node:path";
|
|
66621
67315
|
function assignPendingIds(changes, staticValueSeeds, reconstructed3) {
|
|
66622
67316
|
const assigned = /* @__PURE__ */ new Map();
|
|
66623
67317
|
const assign = (pendingId2) => {
|
|
@@ -66630,7 +67324,7 @@ function assignPendingIds(changes, staticValueSeeds, reconstructed3) {
|
|
|
66630
67324
|
assigned.set(pendingId2, derived);
|
|
66631
67325
|
return derived;
|
|
66632
67326
|
}
|
|
66633
|
-
const fresh =
|
|
67327
|
+
const fresh = randomUUID6();
|
|
66634
67328
|
assigned.set(pendingId2, fresh);
|
|
66635
67329
|
return fresh;
|
|
66636
67330
|
};
|
|
@@ -66941,6 +67635,10 @@ function createPushProgressReporter(json) {
|
|
|
66941
67635
|
};
|
|
66942
67636
|
}
|
|
66943
67637
|
function projectTransactionProgressLabel(event) {
|
|
67638
|
+
if (event.type === "push-progress") {
|
|
67639
|
+
if (event.phase === "preparing") return "Preparing push\u2026";
|
|
67640
|
+
return `Uploading files\u2026 ${event.completedFiles.toLocaleString("en-US")}/${event.totalFiles.toLocaleString("en-US")} (${formatByteProgress(event.completedBytes)}/${formatByteProgress(event.totalBytes)})`;
|
|
67641
|
+
}
|
|
66944
67642
|
if (event.phase === "submitting") return "Pushing\u2026";
|
|
66945
67643
|
if (event.phase === "preparing") return "Preparing push\u2026";
|
|
66946
67644
|
if (event.phase === "waiting") return "Waiting to apply project transaction\u2026";
|
|
@@ -66958,6 +67656,11 @@ function projectTransactionProgressLabel(event) {
|
|
|
66958
67656
|
}
|
|
66959
67657
|
return "Finalizing project transaction\u2026";
|
|
66960
67658
|
}
|
|
67659
|
+
function formatByteProgress(bytes) {
|
|
67660
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
67661
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
67662
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
67663
|
+
}
|
|
66961
67664
|
function progressEventFromAccepted(accepted) {
|
|
66962
67665
|
return {
|
|
66963
67666
|
type: "project-transaction-progress",
|
|
@@ -67230,46 +67933,111 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
67230
67933
|
console.log("Push cancelled.");
|
|
67231
67934
|
return;
|
|
67232
67935
|
}
|
|
67233
|
-
|
|
67234
|
-
|
|
67235
|
-
|
|
67236
|
-
|
|
67237
|
-
|
|
67238
|
-
|
|
67239
|
-
|
|
67240
|
-
|
|
67241
|
-
status.reconstructed
|
|
67242
|
-
);
|
|
67243
|
-
const operations = new Set(status.changes.map((change) => change.kind));
|
|
67244
|
-
const transactionOperation = operations.size === 1 ? status.changes[0].kind : "update";
|
|
67245
|
-
const client = NeoApiClient.forBaseUrl(workspace.config.apiBaseUrl);
|
|
67246
|
-
let stagedFiles = await stageProjectFilePushesV4({
|
|
67247
|
-
workspace,
|
|
67248
|
-
changes: status.changes,
|
|
67249
|
-
binaryChanges: status.binaryChanges ?? [],
|
|
67250
|
-
assignedIds: pendingAssignment.assigned,
|
|
67251
|
-
client
|
|
67936
|
+
let progress = createPushProgressReporter(options.json === true);
|
|
67937
|
+
progress.report({
|
|
67938
|
+
type: "push-progress",
|
|
67939
|
+
phase: "preparing",
|
|
67940
|
+
completedFiles: 0,
|
|
67941
|
+
totalFiles: status.binaryChanges?.length ?? 0,
|
|
67942
|
+
completedBytes: 0,
|
|
67943
|
+
totalBytes: 0
|
|
67252
67944
|
});
|
|
67945
|
+
const prepareAndStage = async () => {
|
|
67946
|
+
const source2 = await createPendingProjectSourceBundleV4(
|
|
67947
|
+
workspace,
|
|
67948
|
+
status,
|
|
67949
|
+
status.staticValueSeeds
|
|
67950
|
+
);
|
|
67951
|
+
const pendingAssignment2 = assignPendingIds(
|
|
67952
|
+
status.changes,
|
|
67953
|
+
status.staticValueSeeds,
|
|
67954
|
+
status.reconstructed
|
|
67955
|
+
);
|
|
67956
|
+
const operations = new Set(status.changes.map((change) => change.kind));
|
|
67957
|
+
const transactionOperation2 = operations.size === 1 ? status.changes[0].kind : "update";
|
|
67958
|
+
const client2 = NeoApiClient.forBaseUrl(workspace.config.apiBaseUrl);
|
|
67959
|
+
const transportChanges2 = status.changes.map((change) => ({
|
|
67960
|
+
recordKind: change.recordKind,
|
|
67961
|
+
recordId: change.recordId,
|
|
67962
|
+
operation: change.kind,
|
|
67963
|
+
nextData: change.kind === "delete" ? void 0 : stripServerDerivedNeoScript(change.nextData),
|
|
67964
|
+
deleted: change.kind === "delete" ? true : void 0,
|
|
67965
|
+
intent: createNeoCliPushIntent(change),
|
|
67966
|
+
expectedBaseContentHash: change.kind === "create" ? null : change.casBaseHash ?? null
|
|
67967
|
+
}));
|
|
67968
|
+
const transportSeeds2 = [...pendingAssignment2.staticValueSeeds].map(
|
|
67969
|
+
([memberId, seed]) => ({ memberId, ...seed })
|
|
67970
|
+
);
|
|
67971
|
+
const files = prepareProjectFilePushesV4({
|
|
67972
|
+
workspace,
|
|
67973
|
+
changes: status.changes,
|
|
67974
|
+
binaryChanges: status.binaryChanges ?? [],
|
|
67975
|
+
assignedIds: pendingAssignment2.assigned
|
|
67976
|
+
});
|
|
67977
|
+
verifyProjectSourceCommitAgainstStateV4({
|
|
67978
|
+
projectId: workspace.config.projectId,
|
|
67979
|
+
versionId: workspace.config.versionId,
|
|
67980
|
+
stateRecords: workspace.state.records,
|
|
67981
|
+
files: source2.files,
|
|
67982
|
+
changes: transportChanges2,
|
|
67983
|
+
staticValueSeeds: transportSeeds2,
|
|
67984
|
+
pendingIdAssignments: Object.fromEntries(pendingAssignment2.assigned),
|
|
67985
|
+
stagedFiles: files
|
|
67986
|
+
});
|
|
67987
|
+
const stagedFiles2 = await stageProjectFilePushesV4({
|
|
67988
|
+
workspace,
|
|
67989
|
+
changes: status.changes,
|
|
67990
|
+
binaryChanges: status.binaryChanges ?? [],
|
|
67991
|
+
assignedIds: pendingAssignment2.assigned,
|
|
67992
|
+
client: client2,
|
|
67993
|
+
prepared: files,
|
|
67994
|
+
onProgress: (upload) => progress.report({
|
|
67995
|
+
type: "push-progress",
|
|
67996
|
+
phase: "uploading",
|
|
67997
|
+
...upload
|
|
67998
|
+
})
|
|
67999
|
+
});
|
|
68000
|
+
return {
|
|
68001
|
+
source: source2,
|
|
68002
|
+
pendingAssignment: pendingAssignment2,
|
|
68003
|
+
transactionOperation: transactionOperation2,
|
|
68004
|
+
client: client2,
|
|
68005
|
+
transportChanges: transportChanges2,
|
|
68006
|
+
transportSeeds: transportSeeds2,
|
|
68007
|
+
preparedFiles: files,
|
|
68008
|
+
stagedFiles: stagedFiles2
|
|
68009
|
+
};
|
|
68010
|
+
};
|
|
68011
|
+
let preparedPush;
|
|
68012
|
+
try {
|
|
68013
|
+
preparedPush = await prepareAndStage();
|
|
68014
|
+
} catch (error) {
|
|
68015
|
+
progress.stop();
|
|
68016
|
+
if (error instanceof ProjectFilePushCancelledError) {
|
|
68017
|
+
if (options.json !== true) console.error("Push cancelled.");
|
|
68018
|
+
process.exitCode = 130;
|
|
68019
|
+
return;
|
|
68020
|
+
}
|
|
68021
|
+
throw error;
|
|
68022
|
+
}
|
|
68023
|
+
const {
|
|
68024
|
+
source,
|
|
68025
|
+
pendingAssignment,
|
|
68026
|
+
transactionOperation,
|
|
68027
|
+
client,
|
|
68028
|
+
transportChanges,
|
|
68029
|
+
transportSeeds,
|
|
68030
|
+
preparedFiles
|
|
68031
|
+
} = preparedPush;
|
|
68032
|
+
let { stagedFiles } = preparedPush;
|
|
67253
68033
|
const commit = async (force) => await client.post(
|
|
67254
68034
|
`/api/projects/${workspace.config.projectId}/versions/${workspace.config.versionId}/schema/commit`,
|
|
67255
68035
|
{
|
|
67256
68036
|
operation: transactionOperation,
|
|
67257
|
-
changes:
|
|
67258
|
-
|
|
67259
|
-
recordKind: change.recordKind,
|
|
67260
|
-
recordId: change.recordId,
|
|
67261
|
-
operation: change.kind,
|
|
67262
|
-
nextData: change.kind === "delete" ? void 0 : stripServerDerivedNeoScript(change.nextData),
|
|
67263
|
-
deleted: change.kind === "delete" ? true : void 0,
|
|
67264
|
-
intent: createNeoCliPushIntent(change),
|
|
67265
|
-
expectedBaseContentHash: change.kind === "create" ? null : change.casBaseHash ?? null
|
|
67266
|
-
};
|
|
67267
|
-
}),
|
|
67268
|
-
staticValueSeeds: [...pendingAssignment.staticValueSeeds].map(
|
|
67269
|
-
([memberId, seed]) => ({ memberId, ...seed })
|
|
67270
|
-
),
|
|
68037
|
+
changes: transportChanges,
|
|
68038
|
+
staticValueSeeds: transportSeeds,
|
|
67271
68039
|
stagedFiles,
|
|
67272
|
-
sourceBundle,
|
|
68040
|
+
sourceBundle: source.bundle,
|
|
67273
68041
|
pendingIdAssignments: Object.fromEntries(pendingAssignment.assigned),
|
|
67274
68042
|
summary: options.summary ?? "neo push"
|
|
67275
68043
|
},
|
|
@@ -67383,7 +68151,6 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
67383
68151
|
if (options.json !== true) success("Push complete.");
|
|
67384
68152
|
return true;
|
|
67385
68153
|
};
|
|
67386
|
-
let progress = createPushProgressReporter(options.json === true);
|
|
67387
68154
|
progress.report({
|
|
67388
68155
|
type: "project-transaction-progress",
|
|
67389
68156
|
transactionId: null,
|
|
@@ -67416,28 +68183,39 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
67416
68183
|
fallback: false
|
|
67417
68184
|
})) {
|
|
67418
68185
|
progress = createPushProgressReporter(options.json === true);
|
|
67419
|
-
progress.report({
|
|
67420
|
-
type: "project-transaction-progress",
|
|
67421
|
-
transactionId: null,
|
|
67422
|
-
phase: "submitting",
|
|
67423
|
-
totalChangeCount: status.changes.length,
|
|
67424
|
-
appliedChangeCount: 0,
|
|
67425
|
-
totalChunkCount: null,
|
|
67426
|
-
appliedChunkCount: 0,
|
|
67427
|
-
errorCode: null,
|
|
67428
|
-
errorMessage: null
|
|
67429
|
-
});
|
|
67430
68186
|
try {
|
|
67431
68187
|
stagedFiles = await stageProjectFilePushesV4({
|
|
67432
68188
|
workspace,
|
|
67433
68189
|
changes: status.changes,
|
|
67434
68190
|
binaryChanges: status.binaryChanges ?? [],
|
|
67435
68191
|
assignedIds: pendingAssignment.assigned,
|
|
67436
|
-
client
|
|
68192
|
+
client,
|
|
68193
|
+
prepared: preparedFiles,
|
|
68194
|
+
onProgress: (upload) => progress.report({
|
|
68195
|
+
type: "push-progress",
|
|
68196
|
+
phase: "uploading",
|
|
68197
|
+
...upload
|
|
68198
|
+
})
|
|
68199
|
+
});
|
|
68200
|
+
progress.report({
|
|
68201
|
+
type: "project-transaction-progress",
|
|
68202
|
+
transactionId: null,
|
|
68203
|
+
phase: "submitting",
|
|
68204
|
+
totalChangeCount: status.changes.length,
|
|
68205
|
+
appliedChangeCount: 0,
|
|
68206
|
+
totalChunkCount: null,
|
|
68207
|
+
appliedChunkCount: 0,
|
|
68208
|
+
errorCode: null,
|
|
68209
|
+
errorMessage: null
|
|
67437
68210
|
});
|
|
67438
68211
|
result = await commit(true);
|
|
67439
68212
|
} catch (retryError) {
|
|
67440
68213
|
progress.stop();
|
|
68214
|
+
if (retryError instanceof ProjectFilePushCancelledError) {
|
|
68215
|
+
if (options.json !== true) console.error("Push cancelled.");
|
|
68216
|
+
process.exitCode = 130;
|
|
68217
|
+
return;
|
|
68218
|
+
}
|
|
67441
68219
|
if (retryError instanceof NeoApiError) {
|
|
67442
68220
|
reportPushRejection(retryError.status, retryError.body);
|
|
67443
68221
|
process.exitCode = 1;
|
|
@@ -67566,17 +68344,19 @@ async function createPendingProjectSourceBundleV4(workspace, status, staticValue
|
|
|
67566
68344
|
}
|
|
67567
68345
|
}
|
|
67568
68346
|
const emission = emitProjectDocumentFilesV4(records2);
|
|
67569
|
-
|
|
67570
|
-
|
|
67571
|
-
|
|
67572
|
-
|
|
67573
|
-
|
|
67574
|
-
|
|
67575
|
-
|
|
67576
|
-
|
|
67577
|
-
|
|
67578
|
-
|
|
67579
|
-
|
|
68347
|
+
const files = emission.files.map((file) => {
|
|
68348
|
+
const kind = neoProjectSourceKind(file.path);
|
|
68349
|
+
if (kind === null) {
|
|
68350
|
+
throw new Error(
|
|
68351
|
+
`Emitted project source bundle file ${JSON.stringify(file.path)} is not a recognized Neo source path.`
|
|
68352
|
+
);
|
|
68353
|
+
}
|
|
68354
|
+
return { path: file.path, kind, content: file.content };
|
|
68355
|
+
});
|
|
68356
|
+
return {
|
|
68357
|
+
files,
|
|
68358
|
+
bundle: await createProjectSourceBundle(files)
|
|
68359
|
+
};
|
|
67580
68360
|
}
|
|
67581
68361
|
function staticSeedBindingMemberRecord(projectId, bindingMember, timestamp) {
|
|
67582
68362
|
return {
|
|
@@ -67967,11 +68747,11 @@ ${finalErrors.map(
|
|
|
67967
68747
|
for (const recordState of Object.values(workspace.state.records)) {
|
|
67968
68748
|
const previousPath = recordState.file;
|
|
67969
68749
|
if (previousPath === void 0 || emittedPaths.has(previousPath)) continue;
|
|
67970
|
-
const absolute =
|
|
68750
|
+
const absolute = join16(workspace.root, previousPath);
|
|
67971
68751
|
if (existsSync12(absolute)) rmSync6(absolute);
|
|
67972
68752
|
}
|
|
67973
68753
|
for (const file of files) {
|
|
67974
|
-
const absolute =
|
|
68754
|
+
const absolute = join16(workspace.root, file.path);
|
|
67975
68755
|
mkdirSync11(dirname7(absolute), { recursive: true });
|
|
67976
68756
|
const existing = existsSync12(absolute) ? readFileSync13(absolute, "utf8") : null;
|
|
67977
68757
|
if (existing !== file.content)
|
|
@@ -68651,6 +69431,7 @@ var init_push = __esm({
|
|
|
68651
69431
|
init_source_diagnostics();
|
|
68652
69432
|
init_projection();
|
|
68653
69433
|
init_project_file_push();
|
|
69434
|
+
init_trusted_commit_verification();
|
|
68654
69435
|
init_world_system_classes();
|
|
68655
69436
|
init_project_manifest();
|
|
68656
69437
|
init_merge();
|
|
@@ -68693,7 +69474,7 @@ __export(dev_exports, {
|
|
|
68693
69474
|
runDev: () => runDev
|
|
68694
69475
|
});
|
|
68695
69476
|
import { watch } from "node:fs";
|
|
68696
|
-
import { join as
|
|
69477
|
+
import { join as join17 } from "node:path";
|
|
68697
69478
|
import { emitKeypressEvents } from "node:readline";
|
|
68698
69479
|
import { ConvexClient } from "convex/browser";
|
|
68699
69480
|
function isSchemaSignal(value) {
|
|
@@ -68800,7 +69581,7 @@ async function runDev(workspace, options) {
|
|
|
68800
69581
|
};
|
|
68801
69582
|
for (const dir of ["Classes", "Enums"]) {
|
|
68802
69583
|
try {
|
|
68803
|
-
watch(
|
|
69584
|
+
watch(join17(workspace.root, dir), { persistent: true }, onFileChange);
|
|
68804
69585
|
} catch {
|
|
68805
69586
|
}
|
|
68806
69587
|
}
|
|
@@ -68856,7 +69637,7 @@ __export(resolve_exports, {
|
|
|
68856
69637
|
workspaceFilePath: () => workspaceFilePath
|
|
68857
69638
|
});
|
|
68858
69639
|
import { readFileSync as readFileSync14, rmSync as rmSync7, writeFileSync as writeFileSync12 } from "node:fs";
|
|
68859
|
-
import { join as
|
|
69640
|
+
import { join as join18 } from "node:path";
|
|
68860
69641
|
function runResolve(workspace, side) {
|
|
68861
69642
|
let resolvedFiles = 0;
|
|
68862
69643
|
for (const filePath of listProjectSourceFilesV4(workspace.root)) {
|
|
@@ -68871,12 +69652,12 @@ function runResolve(workspace, side) {
|
|
|
68871
69652
|
const binary = state.projectBinary;
|
|
68872
69653
|
const conflict2 = binary?.conflict;
|
|
68873
69654
|
if (binary === void 0 || conflict2 === void 0) continue;
|
|
68874
|
-
const destination =
|
|
69655
|
+
const destination = join18(workspace.root, binary.path);
|
|
68875
69656
|
if (side === "theirs") {
|
|
68876
69657
|
if (conflict2.remoteSha256 !== null && conflict2.artifactPath !== void 0) {
|
|
68877
69658
|
writeVerifiedBinaryDownloadV4(
|
|
68878
69659
|
destination,
|
|
68879
|
-
readFileSync14(
|
|
69660
|
+
readFileSync14(join18(workspace.root, conflict2.artifactPath)),
|
|
68880
69661
|
conflict2.remoteSha256
|
|
68881
69662
|
);
|
|
68882
69663
|
binary.sha256 = conflict2.remoteSha256;
|
|
@@ -68886,7 +69667,7 @@ function runResolve(workspace, side) {
|
|
|
68886
69667
|
}
|
|
68887
69668
|
}
|
|
68888
69669
|
if (conflict2.artifactPath !== void 0) {
|
|
68889
|
-
rmSync7(
|
|
69670
|
+
rmSync7(join18(workspace.root, conflict2.artifactPath), { force: true });
|
|
68890
69671
|
}
|
|
68891
69672
|
delete binary.conflict;
|
|
68892
69673
|
resolvedBinaries += 1;
|
|
@@ -68939,7 +69720,7 @@ function resolveMarkers(source, side) {
|
|
|
68939
69720
|
return output.join("\n");
|
|
68940
69721
|
}
|
|
68941
69722
|
function workspaceFilePath(workspace, file) {
|
|
68942
|
-
return
|
|
69723
|
+
return join18(workspace.root, file);
|
|
68943
69724
|
}
|
|
68944
69725
|
var init_resolve = __esm({
|
|
68945
69726
|
"src/commands/resolve.ts"() {
|