@neocompose/cli 0.59.1 → 0.59.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/dist/neo.mjs CHANGED
@@ -31503,9 +31503,8 @@ var init_project_source_construction_quick_fixes = __esm({
31503
31503
  });
31504
31504
 
31505
31505
  // ../packages/neoscript-language/src/project-source-manifest.ts
31506
- function compileNeoProjectSources(inputs, options = {}) {
31507
- const analysis = analyzeNeoProjectSources(inputs, options.parsedDocuments);
31508
- options.onDocuments?.(analysis.documents);
31506
+ function compileNeoProjectSources(inputs) {
31507
+ const analysis = analyzeNeoProjectSources(inputs);
31509
31508
  const schemaClasses = [];
31510
31509
  const schemaInterfaces = [];
31511
31510
  const schemaEnums = [];
@@ -87808,6 +87807,15 @@ var init_project_document_read = __esm({
87808
87807
  });
87809
87808
 
87810
87809
  // ../src/models/search/universal-search-projection.ts
87810
+ function valueSearchClassName(name) {
87811
+ const trimmed = typeof name === "string" ? nonEmptyTrimmed(name) : void 0;
87812
+ return trimmed === void 0 ? null : truncateUtf8(trimmed, UNIVERSAL_SEARCH_MAX_SUBTITLE_BYTES);
87813
+ }
87814
+ function nonEmptyTrimmed(value) {
87815
+ if (value === void 0 || value === null) return void 0;
87816
+ const trimmed = value.trim();
87817
+ return trimmed.length === 0 ? void 0 : trimmed;
87818
+ }
87811
87819
  function truncateUtf8(value, maxBytes) {
87812
87820
  if (value === void 0) return "";
87813
87821
  if (!Number.isInteger(maxBytes) || maxBytes < 0) {
@@ -87833,11 +87841,12 @@ function isAscii(value) {
87833
87841
  }
87834
87842
  return true;
87835
87843
  }
87836
- var utf8Encoder;
87844
+ var UNIVERSAL_SEARCH_MAX_SUBTITLE_BYTES, utf8Encoder;
87837
87845
  var init_universal_search_projection = __esm({
87838
87846
  "../src/models/search/universal-search-projection.ts"() {
87839
87847
  "use strict";
87840
87848
  init_classes();
87849
+ UNIVERSAL_SEARCH_MAX_SUBTITLE_BYTES = 512;
87841
87850
  utf8Encoder = new TextEncoder();
87842
87851
  }
87843
87852
  });
@@ -87993,7 +88002,7 @@ function projectValueHeadPlacementGraph(args) {
87993
88002
  valueOwnerId: ownerId,
87994
88003
  valueRootMemberId: item.rootMemberId,
87995
88004
  valueClassId: classId,
87996
- valueSearchClassName: schemaClass2 !== void 0 && typeof schemaClass2.name === "string" ? truncateUtf8(schemaClass2.name, 512) : null,
88005
+ valueSearchClassName: valueSearchClassName(schemaClass2?.name),
87997
88006
  valueSearchPlacementPath: item.path,
87998
88007
  ...item.constructorParameterId === void 0 ? {} : { constructorParameterId: item.constructorParameterId },
87999
88008
  ...item.constructorSchemaKey === void 0 ? {} : { constructorSchemaKey: item.constructorSchemaKey }
@@ -88120,7 +88129,7 @@ function projectValueHeadPlacementGraph(args) {
88120
88129
  valueOwnerId: classId === null ? null : valueId,
88121
88130
  valueRootMemberId: null,
88122
88131
  valueClassId: classId,
88123
- valueSearchClassName: schemaClass2 !== void 0 && typeof schemaClass2.name === "string" ? truncateUtf8(schemaClass2.name, 512) : null,
88132
+ valueSearchClassName: valueSearchClassName(schemaClass2?.name),
88124
88133
  valueSearchPlacementPath: null
88125
88134
  });
88126
88135
  }
@@ -92743,7 +92752,7 @@ function planCommitPreparationLoadedClosureScope(args) {
92743
92752
  function animationValidationScope(memberIds) {
92744
92753
  return memberIds.size === 0 ? {} : { animationValidationMemberIds: [...memberIds].sort() };
92745
92754
  }
92746
- function withCommitPreparationInMemoryPlacement(records2) {
92755
+ function placeInMemoryRecords(records2, extractions) {
92747
92756
  const recordKeys = new Set(records2.map(commitPreparationRecordKey));
92748
92757
  const parentByChild = /* @__PURE__ */ new Map();
92749
92758
  const ambiguousParentsByChild = /* @__PURE__ */ new Map();
@@ -92781,7 +92790,7 @@ function withCommitPreparationInMemoryPlacement(records2) {
92781
92790
  }
92782
92791
  parentByChild.set(childKey, { ...parent, authority });
92783
92792
  };
92784
- for (const record6 of records2) {
92793
+ for (const [index, record6] of records2.entries()) {
92785
92794
  const sourceKey = commitPreparationRecordKey(record6);
92786
92795
  if (record6.parentRecordKind !== void 0 && record6.parentRecordKind !== null && record6.parentRecordId !== void 0 && record6.parentRecordId !== null) {
92787
92796
  rememberParent(
@@ -92806,7 +92815,7 @@ function withCommitPreparationInMemoryPlacement(records2) {
92806
92815
  );
92807
92816
  }
92808
92817
  }
92809
- for (const edge of extractProjectSnapshotDerivedEdges(record6).edges) {
92818
+ for (const edge of extractions[index].edges) {
92810
92819
  if (edge.edgeKind !== "containment-child" || edge.targetAddressing !== "record") {
92811
92820
  continue;
92812
92821
  }
@@ -92862,33 +92871,13 @@ function commitPreparationPackedRootIds(records2) {
92862
92871
  }
92863
92872
  return rootIdByChildId;
92864
92873
  }
92865
- function readCommitPreparationScopeInMemory(args) {
92866
- const records2 = withCommitPreparationInMemoryPlacement(args.records);
92867
- const recordsByKey = new Map(
92874
+ function createCommitPreparationInMemoryScopeReader(args) {
92875
+ const extractions = args.records.map(extractProjectSnapshotDerivedEdges);
92876
+ const records2 = placeInMemoryRecords(args.records, extractions);
92877
+ const recordByKey = new Map(
92868
92878
  records2.map((record6) => [commitPreparationRecordKey(record6), record6])
92869
92879
  );
92870
92880
  const packedRootIdByChildId = commitPreparationPackedRootIds(records2);
92871
- const exactStates = /* @__PURE__ */ new Map();
92872
- const packedRootKeyByExactKey = /* @__PURE__ */ new Map();
92873
- for (const record6 of args.request.exactRecords) {
92874
- const key = commitPreparationRecordKey(record6);
92875
- if (recordsByKey.has(key)) {
92876
- exactStates.set(key, "live");
92877
- continue;
92878
- }
92879
- const rootId = record6.recordKind === "value" ? packedRootIdByChildId.get(record6.recordId) : void 0;
92880
- if (rootId === void 0) {
92881
- exactStates.set(key, "absent");
92882
- continue;
92883
- }
92884
- const rootKey = commitPreparationRecordKey({
92885
- recordKind: "value",
92886
- recordId: rootId
92887
- });
92888
- exactStates.set(key, "live");
92889
- exactStates.set(rootKey, "live");
92890
- packedRootKeyByExactKey.set(key, rootKey);
92891
- }
92892
92881
  const keysByKind = /* @__PURE__ */ new Map();
92893
92882
  const sourceOnlyKeys = [];
92894
92883
  const valueKeysByMemberId = /* @__PURE__ */ new Map();
@@ -92959,63 +92948,113 @@ function readCommitPreparationScopeInMemory(args) {
92959
92948
  rememberChild(parentKey, sourceKey);
92960
92949
  }
92961
92950
  }
92962
- const rangeRecordKeys = /* @__PURE__ */ new Map();
92963
- for (const request of args.request.ranges) {
92964
- const matching = request.rangeKind === "record-kind" ? keysByKind.get(request.targetKey) ?? [] : request.rangeKind === "source-only" ? sourceOnlyKeys : request.rangeKind === "value-member" ? valueKeysByMemberId.get(request.targetKey) ?? [] : request.rangeKind === "value-class" ? valueKeysByClassId.get(request.targetKey) ?? [] : request.rangeKind === "container-members" ? valueKeysByContainerId.get(request.targetKey) ?? [] : request.rangeKind === "children" ? childKeysByParentKey.get(request.targetKey) ?? [] : request.rangeKind === "world-kind" ? valueKeysByWorldKind.get(request.targetKey) ?? [] : keysByKind.get("value") ?? [];
92965
- if (matching.length > request.limit) {
92966
- return {
92967
- kind: "fallback",
92968
- reason: {
92969
- code: "range-row-cap-exceeded",
92970
- requestKey: commitPreparationRangeRequestKey(request),
92971
- observed: matching.length,
92972
- limit: request.limit
92973
- }
92974
- };
92951
+ for (const index of [
92952
+ keysByKind,
92953
+ valueKeysByMemberId,
92954
+ valueKeysByClassId,
92955
+ valueKeysByContainerId,
92956
+ valueKeysByWorldKind,
92957
+ childKeysByParentKey
92958
+ ]) {
92959
+ for (const keys of index.values()) keys.sort();
92960
+ }
92961
+ sourceOnlyKeys.sort();
92962
+ const persistedByPostingKey = /* @__PURE__ */ new Map();
92963
+ let incompleteRecordKey;
92964
+ for (const [index, record6] of records2.entries()) {
92965
+ const extraction = extractions[index];
92966
+ if (!extraction.complete)
92967
+ incompleteRecordKey ??= commitPreparationRecordKey(record6);
92968
+ for (const edge of extraction.edges) {
92969
+ const postingKey = commitPreparationPostingRequestKey(edge);
92970
+ const edges = persistedByPostingKey.get(postingKey) ?? [];
92971
+ edges.push({
92972
+ recordKind: record6.recordKind,
92973
+ recordId: record6.recordId,
92974
+ ...edge
92975
+ });
92976
+ persistedByPostingKey.set(postingKey, edges);
92975
92977
  }
92976
- rangeRecordKeys.set(
92977
- commitPreparationRangeRequestKey(request),
92978
- [...matching].sort()
92979
- );
92980
92978
  }
92981
- const persisted = [];
92982
- for (const record6 of records2) {
92983
- const extraction = extractProjectSnapshotDerivedEdges(record6);
92984
- if (!extraction.complete && args.request.postings.some(
92985
- (request) => request.edgeKind === "constructor-aggregate"
92979
+ const read = (request, prepared) => {
92980
+ const exactStates = /* @__PURE__ */ new Map();
92981
+ const packedRootKeyByExactKey = /* @__PURE__ */ new Map();
92982
+ for (const record6 of request.exactRecords) {
92983
+ const key = commitPreparationRecordKey(record6);
92984
+ if (recordByKey.has(key)) {
92985
+ exactStates.set(key, "live");
92986
+ continue;
92987
+ }
92988
+ const rootId = record6.recordKind === "value" ? packedRootIdByChildId.get(record6.recordId) : void 0;
92989
+ if (rootId === void 0) {
92990
+ exactStates.set(key, "absent");
92991
+ continue;
92992
+ }
92993
+ const rootKey = commitPreparationRecordKey({
92994
+ recordKind: "value",
92995
+ recordId: rootId
92996
+ });
92997
+ exactStates.set(key, "live");
92998
+ exactStates.set(rootKey, "live");
92999
+ packedRootKeyByExactKey.set(key, rootKey);
93000
+ }
93001
+ const rangeRecordKeys = /* @__PURE__ */ new Map();
93002
+ for (const range2 of request.ranges) {
93003
+ const matching = range2.rangeKind === "record-kind" ? keysByKind.get(range2.targetKey) ?? [] : range2.rangeKind === "source-only" ? sourceOnlyKeys : range2.rangeKind === "value-member" ? valueKeysByMemberId.get(range2.targetKey) ?? [] : range2.rangeKind === "value-class" ? valueKeysByClassId.get(range2.targetKey) ?? [] : range2.rangeKind === "container-members" ? valueKeysByContainerId.get(range2.targetKey) ?? [] : range2.rangeKind === "children" ? childKeysByParentKey.get(range2.targetKey) ?? [] : range2.rangeKind === "world-kind" ? valueKeysByWorldKind.get(range2.targetKey) ?? [] : keysByKind.get("value") ?? [];
93004
+ if (matching.length > range2.limit) {
93005
+ return {
93006
+ kind: "fallback",
93007
+ reason: {
93008
+ code: "range-row-cap-exceeded",
93009
+ requestKey: commitPreparationRangeRequestKey(range2),
93010
+ observed: matching.length,
93011
+ limit: range2.limit
93012
+ }
93013
+ };
93014
+ }
93015
+ rangeRecordKeys.set(commitPreparationRangeRequestKey(range2), matching);
93016
+ }
93017
+ if (incompleteRecordKey !== void 0 && request.postings.some(
93018
+ (posting) => posting.edgeKind === "constructor-aggregate"
92986
93019
  )) {
92987
93020
  return {
92988
93021
  kind: "fallback",
92989
93022
  reason: {
92990
93023
  code: "derived-edge-extraction-incomplete",
92991
- recordKey: commitPreparationRecordKey(record6)
93024
+ recordKey: incompleteRecordKey
92992
93025
  }
92993
93026
  };
92994
93027
  }
92995
- for (const edge of extraction.edges) {
92996
- persisted.push({ ...record6, ...edge });
92997
- }
92998
- }
92999
- const overlaid = overlayCommitPreparationDerivedEdgePostings({
93000
- requests: args.request.postings,
93001
- persisted,
93002
- prepared: args.prepared
93003
- });
93004
- if (overlaid.kind === "fallback") return overlaid;
93005
- return {
93006
- kind: "complete",
93007
- value: {
93008
- exactStates,
93009
- packedRootKeyByExactKey,
93010
- rangeRecordKeys,
93011
- postingSourceKeys: new Map(
93012
- [...overlaid.value].map(([key, edges]) => [
93013
- key,
93014
- edges.map(commitPreparationRecordKey)
93015
- ])
93016
- )
93028
+ const persisted = [];
93029
+ for (const postingKey of new Set(
93030
+ request.postings.map(commitPreparationPostingRequestKey)
93031
+ )) {
93032
+ for (const edge of persistedByPostingKey.get(postingKey) ?? []) {
93033
+ persisted.push(edge);
93034
+ }
93017
93035
  }
93036
+ const overlaid = overlayCommitPreparationDerivedEdgePostings({
93037
+ requests: request.postings,
93038
+ persisted,
93039
+ prepared
93040
+ });
93041
+ if (overlaid.kind === "fallback") return overlaid;
93042
+ return {
93043
+ kind: "complete",
93044
+ value: {
93045
+ exactStates,
93046
+ packedRootKeyByExactKey,
93047
+ rangeRecordKeys,
93048
+ postingSourceKeys: new Map(
93049
+ [...overlaid.value].map(([key, edges]) => [
93050
+ key,
93051
+ edges.map(commitPreparationRecordKey)
93052
+ ])
93053
+ )
93054
+ }
93055
+ };
93018
93056
  };
93057
+ return { recordByKey, read };
93019
93058
  }
93020
93059
  function commitPreparationRecordKey(record6) {
93021
93060
  return `${record6.recordKind}:${record6.recordId}`;
@@ -97754,12 +97793,12 @@ var init_project_version_transaction_planning = __esm({
97754
97793
  };
97755
97794
  CHUNK_FIXED_COST = addProjectVersionTransactionBudgets(CHUNK_GRAPH_VALIDATION_RESERVE, {
97756
97795
  argumentBytes: 256,
97757
- bytesRead: 32 * KIB,
97758
- bytesWritten: 48 * KIB,
97759
- documentsRead: 4,
97760
- documentsWritten: 5,
97761
- databaseQueries: 97,
97762
- indexRanges: 105,
97796
+ bytesRead: 266 * KIB,
97797
+ bytesWritten: 195 * KIB,
97798
+ documentsRead: 81,
97799
+ documentsWritten: 59,
97800
+ databaseQueries: 83,
97801
+ indexRanges: 83,
97763
97802
  functionsScheduled: 2,
97764
97803
  scheduledFunctionArgsBytes: 2 * KIB,
97765
97804
  returnBytes: 2 * KIB
@@ -97783,7 +97822,7 @@ var init_project_version_transaction_planning = __esm({
97783
97822
  databaseQueries: 410,
97784
97823
  indexRanges: 410
97785
97824
  };
97786
- CHANGE_BYTES_READ_OVERHEAD = 4 * KIB;
97825
+ CHANGE_BYTES_READ_OVERHEAD = 7 * KIB;
97787
97826
  CHANGE_BYTES_WRITTEN_OVERHEAD = 4 * KIB;
97788
97827
  }
97789
97828
  });
@@ -117901,7 +117940,7 @@ function computeWorkspaceStatus(workspace, options) {
117901
117940
  "Format-4 status requires a pulled schema base; run `neo pull --reset`."
117902
117941
  );
117903
117942
  }
117904
- const analysis = options.readProjectAnalysisCache?.(workspace.root, compilationSources) ?? options.compileProjectAnalysis?.(workspace.root, compilationSources) ?? compileNeoProjectSources(compilationSources);
117943
+ const analysis = options.readProjectAnalysisCache?.(workspace.root, compilationSources) ?? compileNeoProjectSources(compilationSources);
117905
117944
  projectAnalysisV4 = analysis;
117906
117945
  for (const diagnostic of analysis.diagnostics) {
117907
117946
  const positioned = new SchemaSourceError(
@@ -120385,7 +120424,7 @@ function prepareAgainstPulledBase(args, base) {
120385
120424
  changes,
120386
120425
  timestamp: serverTimestamp
120387
120426
  });
120388
- const placedRecords = () => {
120427
+ const scopeReader = () => {
120389
120428
  const canonicalPlacementByValueId = projectValueHeadPlacementGraph({
120390
120429
  rootMembers: [
120391
120430
  { id: document.project.rootAssetsMemberId, label: "Assets" },
@@ -120400,8 +120439,9 @@ function prepareAgainstPulledBase(args, base) {
120400
120439
  classes: document.classes,
120401
120440
  values: document.values
120402
120441
  });
120403
- return withCommitPreparationInMemoryPlacement(
120404
- Object.values(args.workspace.state.records).map((record6) => {
120442
+ return createCommitPreparationInMemoryScopeReader({
120443
+ document,
120444
+ records: Object.values(args.workspace.state.records).map((record6) => {
120405
120445
  const recordKind = narrowRecordKind(
120406
120446
  record6.recordKind,
120407
120447
  `${record6.recordKind}:${record6.recordId}`
@@ -120417,7 +120457,7 @@ function prepareAgainstPulledBase(args, base) {
120417
120457
  }
120418
120458
  };
120419
120459
  })
120420
- );
120460
+ });
120421
120461
  };
120422
120462
  const preparationArgs = {
120423
120463
  document,
@@ -120457,7 +120497,7 @@ function prepareAgainstPulledBase(args, base) {
120457
120497
  }
120458
120498
  return prepareWithScopedSafetyValve({
120459
120499
  prepareScoped: () => {
120460
- const records2 = placedRecords();
120500
+ const reader = scopeReader();
120461
120501
  const initialScope = planCommitPreparationInitialScope({
120462
120502
  pass: COMMIT_PREPARATION_PASS_ORDER[0],
120463
120503
  document,
@@ -120467,12 +120507,7 @@ function prepareAgainstPulledBase(args, base) {
120467
120507
  postingLimit: COMMIT_PREPARATION_SCOPE_POSTING_ROW_LIMIT
120468
120508
  });
120469
120509
  if (initialScope.fullContentDimension) return null;
120470
- const scopeAnswer = readCommitPreparationScopeInMemory({
120471
- request: initialScope,
120472
- records: records2,
120473
- prepared: changes,
120474
- document
120475
- });
120510
+ const scopeAnswer = reader.read(initialScope, changes);
120476
120511
  if (scopeAnswer.kind === "fallback") return null;
120477
120512
  const selectedContentKeys = /* @__PURE__ */ new Set();
120478
120513
  const descendantRootKeys = /* @__PURE__ */ new Set();
@@ -120486,7 +120521,7 @@ function prepareAgainstPulledBase(args, base) {
120486
120521
  absentExactKeys
120487
120522
  );
120488
120523
  const initialClosed = closeInMemoryLoadedScope({
120489
- records: records2,
120524
+ reader,
120490
120525
  selected: selectedContentKeys,
120491
120526
  descendantRoots: descendantRootKeys,
120492
120527
  absentExactKeys,
@@ -120525,12 +120560,10 @@ function prepareAgainstPulledBase(args, base) {
120525
120560
  postingLimit: COMMIT_PREPARATION_SCOPE_POSTING_ROW_LIMIT
120526
120561
  });
120527
120562
  if (topUpRequest.fullContentDimension) return null;
120528
- const topUpAnswer = readCommitPreparationScopeInMemory({
120529
- request: topUpRequest,
120530
- records: records2,
120531
- prepared: step.value.preparedChanges,
120532
- document
120533
- });
120563
+ const topUpAnswer = reader.read(
120564
+ topUpRequest,
120565
+ step.value.preparedChanges
120566
+ );
120534
120567
  if (topUpAnswer.kind === "fallback") return null;
120535
120568
  absorbInMemoryScopeAnswer(
120536
120569
  selectedContentKeys,
@@ -120546,7 +120579,7 @@ function prepareAgainstPulledBase(args, base) {
120546
120579
  descendantRootKeys.add(`${change.recordKind}:${change.recordId}`);
120547
120580
  }
120548
120581
  if (!closeInMemoryLoadedScope({
120549
- records: records2,
120582
+ reader,
120550
120583
  selected: selectedContentKeys,
120551
120584
  descendantRoots: descendantRootKeys,
120552
120585
  absentExactKeys,
@@ -120608,14 +120641,14 @@ function absorbInMemoryScopeAnswer(selected, answer, descendantRoots, descendant
120608
120641
  function closeInMemoryLoadedScope(args) {
120609
120642
  const animationSchema = commitPreparationAnimationSchema(args.document);
120610
120643
  for (; ; ) {
120611
- const closureRecords = args.records.filter(
120612
- (record6) => args.selected.has(`${record6.recordKind}:${record6.recordId}`)
120613
- ).map((record6) => ({
120614
- ...record6,
120615
- includeDescendants: args.descendantRoots.has(
120616
- `${record6.recordKind}:${record6.recordId}`
120617
- )
120618
- }));
120644
+ const closureRecords = selectedRecords(args.reader, args.selected).map(
120645
+ (record6) => ({
120646
+ ...record6,
120647
+ includeDescendants: args.descendantRoots.has(
120648
+ `${record6.recordKind}:${record6.recordId}`
120649
+ )
120650
+ })
120651
+ );
120619
120652
  const request = planCommitPreparationLoadedClosureScope({
120620
120653
  pass: args.pass,
120621
120654
  records: closureRecords,
@@ -120624,12 +120657,7 @@ function closeInMemoryLoadedScope(args) {
120624
120657
  animationSchema,
120625
120658
  placementCreationScope: createdWorldPlacementIds(args.prepared) !== null
120626
120659
  });
120627
- const answer = readCommitPreparationScopeInMemory({
120628
- request,
120629
- records: args.records,
120630
- prepared: args.prepared,
120631
- document: args.document
120632
- });
120660
+ const answer = args.reader.read(request, args.prepared);
120633
120661
  if (answer.kind === "fallback") return false;
120634
120662
  const priorSelectedSize = args.selected.size;
120635
120663
  const priorDescendantSize = args.descendantRoots.size;
@@ -120643,20 +120671,26 @@ function closeInMemoryLoadedScope(args) {
120643
120671
  );
120644
120672
  if (args.selected.size === priorSelectedSize && args.descendantRoots.size === priorDescendantSize) {
120645
120673
  return selectedAncestorPathsIntact(
120646
- args.records,
120674
+ args.reader,
120647
120675
  args.selected,
120648
120676
  args.absentExactKeys
120649
120677
  );
120650
120678
  }
120651
120679
  }
120652
120680
  }
120653
- function selectedAncestorPathsIntact(records2, selected, absentExactKeys) {
120681
+ function selectedRecords(reader, selected) {
120682
+ const records2 = [];
120683
+ for (const key of selected) {
120684
+ const record6 = reader.recordByKey.get(key);
120685
+ if (record6 !== void 0) records2.push(record6);
120686
+ }
120687
+ return records2;
120688
+ }
120689
+ function selectedAncestorPathsIntact(reader, selected, absentExactKeys) {
120654
120690
  if (absentExactKeys.size === 0) return true;
120655
- const selectedRecords = records2.filter(
120656
- (record6) => selected.has(`${record6.recordKind}:${record6.recordId}`)
120657
- );
120658
- const packedRootIdByChildId = commitPreparationPackedRootIds(selectedRecords);
120659
- for (const record6 of selectedRecords) {
120691
+ const records2 = selectedRecords(reader, selected);
120692
+ const packedRootIdByChildId = commitPreparationPackedRootIds(records2);
120693
+ for (const record6 of records2) {
120660
120694
  if (record6.recordKind !== "value") continue;
120661
120695
  if (record6.parentRecordKind !== "value") continue;
120662
120696
  const parentId = record6.parentRecordId;
@@ -129001,6 +129035,34 @@ function retainAuthoredDefinitionGroupingV4(files, recordFiles) {
129001
129035
  };
129002
129036
  }
129003
129037
  function emitProjectDocumentFilesV4(records2, options = {}) {
129038
+ const emission = emitProjectDocumentSourcesV4(records2, options);
129039
+ const analysis = compileNeoProjectSources(
129040
+ emission.files.map((file) => {
129041
+ const kind = neoProjectSourceKind(file.path, file.content);
129042
+ if (kind === null || !isNeoProjectProductionSourceKind(kind)) {
129043
+ throw new Error(
129044
+ `Canonical projection emitted non-production source ${JSON.stringify(file.path)}.`
129045
+ );
129046
+ }
129047
+ return { uri: file.path, kind, text: file.content };
129048
+ })
129049
+ );
129050
+ const errors = analysis.diagnostics.filter(
129051
+ (diagnostic) => diagnostic.severity === "error" && // Pull must expose incomplete stored objects so source can repair them.
129052
+ // Status, tests, and push still reject these construction errors.
129053
+ diagnostic.code !== "unsettled-required-member" && !isPullRecoveryDiagnosticCode(diagnostic.code)
129054
+ );
129055
+ if (errors.length > 0) {
129056
+ throw new Error(
129057
+ `Canonical format-4 projection produced invalid source:
129058
+ ${errors.map(
129059
+ (diagnostic) => ` ${diagnostic.uri}:${diagnostic.range.start.line + 1}:${diagnostic.range.start.character + 1} ${diagnostic.message}`
129060
+ ).join("\n")}`
129061
+ );
129062
+ }
129063
+ return { ...emission, analysis };
129064
+ }
129065
+ function emitProjectDocumentSourcesV4(records2, options = {}) {
129004
129066
  const schemaRecords = [];
129005
129067
  for (const record6 of records2.values()) {
129006
129068
  if (record6.deleted || !isSchemaRecordKindV4(record6.recordKind)) continue;
@@ -129129,34 +129191,9 @@ function emitProjectDocumentFilesV4(records2, options = {}) {
129129
129191
  STATIC_MEMBER_OWNERSHIP_RECOVERY_SOURCE
129130
129192
  );
129131
129193
  }
129132
- const analysis = compileNeoProjectSources(
129133
- files.map((file) => {
129134
- const kind = neoProjectSourceKind(file.path, file.content);
129135
- if (kind === null || !isNeoProjectProductionSourceKind(kind)) {
129136
- throw new Error(
129137
- `Canonical projection emitted non-production source ${JSON.stringify(file.path)}.`
129138
- );
129139
- }
129140
- return { uri: file.path, kind, text: file.content };
129141
- })
129142
- );
129143
- const errors = analysis.diagnostics.filter(
129144
- (diagnostic) => diagnostic.severity === "error" && // Pull must expose incomplete stored objects so source can repair them.
129145
- // Status, tests, and push still reject these construction errors.
129146
- diagnostic.code !== "unsettled-required-member" && !isPullRecoveryDiagnosticCode(diagnostic.code)
129147
- );
129148
- if (errors.length > 0) {
129149
- throw new Error(
129150
- `Canonical format-4 projection produced invalid source:
129151
- ${errors.map(
129152
- (diagnostic) => ` ${diagnostic.uri}:${diagnostic.range.start.line + 1}:${diagnostic.range.start.character + 1} ${diagnostic.message}`
129153
- ).join("\n")}`
129154
- );
129155
- }
129156
129194
  return {
129157
129195
  files,
129158
129196
  recordFiles,
129159
- analysis,
129160
129197
  materializedConstructors,
129161
129198
  materializedConstructorOverrideKeys,
129162
129199
  formAlternates: source.formAlternates.map((alternate) => ({
@@ -129278,98 +129315,6 @@ function writeProjectSourceAnalysisCacheV4(root, analysis, sources) {
129278
129315
  );
129279
129316
  renameSync5(temporary, buildFile);
129280
129317
  }
129281
- function compileProjectSourceAnalysisWithBuildCacheV4(root, sources) {
129282
- const parsedDocuments = readProjectSourceDocumentBuildCacheV1(root, sources);
129283
- let documents;
129284
- try {
129285
- const analysis = compileNeoProjectSources(sources, {
129286
- parsedDocuments,
129287
- onDocuments: (result) => {
129288
- documents = result;
129289
- }
129290
- });
129291
- if (documents !== void 0) {
129292
- writeProjectSourceDocumentBuildCacheV1(root, sources, documents);
129293
- }
129294
- return analysis;
129295
- } catch (error) {
129296
- if (parsedDocuments.size === 0) throw error;
129297
- documents = void 0;
129298
- const analysis = compileNeoProjectSources(sources, {
129299
- onDocuments: (result) => {
129300
- documents = result;
129301
- }
129302
- });
129303
- if (documents !== void 0) {
129304
- writeProjectSourceDocumentBuildCacheV1(root, sources, documents);
129305
- }
129306
- return analysis;
129307
- }
129308
- }
129309
- function readProjectSourceDocumentBuildCacheV1(root, sources) {
129310
- try {
129311
- const parsed = JSON.parse(
129312
- readFileSync6(
129313
- join5(root, PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_PATH),
129314
- "utf8"
129315
- )
129316
- );
129317
- if (parsed === null || typeof parsed !== "object") return /* @__PURE__ */ new Map();
129318
- const cache = parsed;
129319
- if (cache.revision !== PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_REVISION || cache.compilerRevision !== NEOSCRIPT_COMPILER_REVISION || cache.files === null || typeof cache.files !== "object" || Array.isArray(cache.files)) {
129320
- return /* @__PURE__ */ new Map();
129321
- }
129322
- const files = cache.files;
129323
- const documents = /* @__PURE__ */ new Map();
129324
- for (const source of sources) {
129325
- const cached = files[source.uri];
129326
- if (cached?.fingerprint !== projectSourceFileFingerprint(source) || !isCachedProjectSourceDocument(cached.document, source)) {
129327
- continue;
129328
- }
129329
- documents.set(source.uri, cached.document);
129330
- }
129331
- return documents;
129332
- } catch {
129333
- return /* @__PURE__ */ new Map();
129334
- }
129335
- }
129336
- function writeProjectSourceDocumentBuildCacheV1(root, sources, documents) {
129337
- const file = join5(root, PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_PATH);
129338
- mkdirSync6(dirname6(file), { recursive: true });
129339
- const temporary = `${file}.${process.pid}.tmp`;
129340
- writeFileSync6(
129341
- temporary,
129342
- `${JSON.stringify({
129343
- revision: PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_REVISION,
129344
- compilerRevision: NEOSCRIPT_COMPILER_REVISION,
129345
- files: Object.fromEntries(
129346
- sources.flatMap((source) => {
129347
- const document = documents.get(source.uri);
129348
- return document === void 0 ? [] : [
129349
- [
129350
- source.uri,
129351
- {
129352
- fingerprint: projectSourceFileFingerprint(source),
129353
- document
129354
- }
129355
- ]
129356
- ];
129357
- })
129358
- )
129359
- })}
129360
- `,
129361
- "utf8"
129362
- );
129363
- renameSync5(temporary, file);
129364
- }
129365
- function projectSourceFileFingerprint(source) {
129366
- return createHash6("sha256").update(String(PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_REVISION)).update("\0").update(String(NEOSCRIPT_COMPILER_REVISION)).update("\0").update(source.kind).update("\0").update(source.text).digest("hex");
129367
- }
129368
- function isCachedProjectSourceDocument(value, source) {
129369
- if (value === null || typeof value !== "object") return false;
129370
- const document = value;
129371
- return document.kind === source.kind && document.sourceText === source.text && Array.isArray(document.declarations) && Array.isArray(document.diagnostics);
129372
- }
129373
129318
  function projectSourceFingerprint(sources) {
129374
129319
  const hash = createHash6("sha256");
129375
129320
  hash.update(String(PROJECT_SOURCE_BUILD_CACHE_REVISION));
@@ -129385,7 +129330,7 @@ function projectSourceFingerprint(sources) {
129385
129330
  }
129386
129331
  return hash.digest("hex");
129387
129332
  }
129388
- var PROJECT_SOURCE_BUILD_CACHE_PATH, PROJECT_SOURCE_BUILD_CACHE_REVISION, PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_PATH, PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_REVISION;
129333
+ var PROJECT_SOURCE_BUILD_CACHE_PATH, PROJECT_SOURCE_BUILD_CACHE_REVISION;
129389
129334
  var init_project_document_cache = __esm({
129390
129335
  "src/project-source/project-document-cache.ts"() {
129391
129336
  "use strict";
@@ -129393,8 +129338,6 @@ var init_project_document_cache = __esm({
129393
129338
  init_project_documents();
129394
129339
  PROJECT_SOURCE_BUILD_CACHE_PATH = ".neo/build/project-source-analysis-v4.json";
129395
129340
  PROJECT_SOURCE_BUILD_CACHE_REVISION = 2;
129396
- PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_PATH = ".neo/build/project-source-documents-v1.json";
129397
- PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_REVISION = 1;
129398
129341
  }
129399
129342
  });
129400
129343
 
@@ -129984,7 +129927,6 @@ function computeWorkspaceStatus2(workspace, options = {}) {
129984
129927
  virtualSourceFiles,
129985
129928
  writeProjectAnalysisCache: options.writeProjectAnalysisCache ?? writeProjectSourceAnalysisCacheV4,
129986
129929
  readProjectAnalysisCache: options.readProjectAnalysisCache ?? readProjectSourceAnalysisBuildCacheV4,
129987
- compileProjectAnalysis: options.compileProjectAnalysis ?? compileProjectSourceAnalysisWithBuildCacheV4,
129988
129930
  inspectProjectBinaries: inspectProjectBinaryStatusV4,
129989
129931
  lowerSupplementalRecords: (state, analysis, trustedPendingFiles) => lowerSupplementalProjectSourcesV4(workspace.root, state, analysis, {
129990
129932
  ...trustedPendingFiles === void 0 ? {} : { trustedPendingFiles }
@@ -130292,6 +130234,60 @@ var init_schema_commit_transport = __esm({
130292
130234
  }
130293
130235
  });
130294
130236
 
130237
+ // src/off-thread-fetch.ts
130238
+ import { Worker as Worker2 } from "node:worker_threads";
130239
+ async function fetchOffThread(url, headers, signal) {
130240
+ signal?.throwIfAborted();
130241
+ const worker = new Worker2(REQUEST, {
130242
+ eval: true,
130243
+ execArgv: [],
130244
+ workerData: { url: url.href, headers }
130245
+ });
130246
+ let abort = () => void 0;
130247
+ try {
130248
+ const message = await new Promise((resolve5, reject) => {
130249
+ abort = () => reject(signal?.reason);
130250
+ signal?.addEventListener("abort", abort, { once: true });
130251
+ worker.once("message", resolve5);
130252
+ worker.once("error", reject);
130253
+ worker.once(
130254
+ "exit",
130255
+ (code) => reject(new Error(`The request worker exited with code ${code}.`))
130256
+ );
130257
+ });
130258
+ if (typeof message !== "object" || message === null)
130259
+ throw new Error("The request worker posted a non-object result.");
130260
+ if ("error" in message && typeof message.error === "string")
130261
+ throw new Error(
130262
+ message.error,
130263
+ "cause" in message && typeof message.cause === "string" ? { cause: message.cause } : void 0
130264
+ );
130265
+ if (!("ok" in message) || typeof message.ok !== "boolean")
130266
+ throw new Error('The request worker result is missing boolean "ok".');
130267
+ if (!("status" in message) || typeof message.status !== "number")
130268
+ throw new Error('The request worker result is missing numeric "status".');
130269
+ if (!("body" in message) || typeof message.body !== "string")
130270
+ throw new Error('The request worker result is missing string "body".');
130271
+ return { ok: message.ok, status: message.status, body: message.body };
130272
+ } finally {
130273
+ signal?.removeEventListener("abort", abort);
130274
+ void worker.terminate();
130275
+ }
130276
+ }
130277
+ var REQUEST;
130278
+ var init_off_thread_fetch = __esm({
130279
+ "src/off-thread-fetch.ts"() {
130280
+ "use strict";
130281
+ REQUEST = `
130282
+ const { workerData, parentPort } = require("node:worker_threads");
130283
+ fetch(workerData.url, { headers: workerData.headers, redirect: "error" }).then(
130284
+ async (response) => parentPort.postMessage({ ok: response.ok, status: response.status, body: await response.text() }),
130285
+ (error) => parentPort.postMessage({ error: String(error), cause: error?.cause === undefined ? null : String(error.cause) }),
130286
+ );
130287
+ `;
130288
+ }
130289
+ });
130290
+
130295
130291
  // ../convex/_generated/api.js
130296
130292
  var api_exports = {};
130297
130293
  __export(api_exports, {
@@ -130325,20 +130321,22 @@ async function mintConvexJwt(apiBaseUrl, signal, convexSiteUrl) {
130325
130321
  }
130326
130322
  const pinnedSite = loadTrustedConvexSite(apiBaseUrl);
130327
130323
  const direct = convexSiteUrl !== void 0 && pinnedSite === convexSiteUrl;
130328
- const response = await fetch(
130324
+ const response = await fetchOffThread(
130329
130325
  new URL("/api/auth/convex/token", direct ? convexSiteUrl : apiBaseUrl),
130330
- {
130331
- headers: { Authorization: `Bearer ${sessionToken}` },
130332
- redirect: "error",
130333
- signal
130334
- }
130326
+ { Authorization: `Bearer ${sessionToken}` },
130327
+ signal
130335
130328
  );
130336
- const body = await response.json();
130337
130329
  if (!response.ok) {
130338
130330
  throw new Error(
130339
- `Convex JWT mint failed with status ${response.status}: ${JSON.stringify(body).slice(0, 200)}`
130331
+ `Convex JWT mint failed with status ${response.status}: ${response.body.slice(0, 200)}`
130340
130332
  );
130341
130333
  }
130334
+ let body;
130335
+ try {
130336
+ body = JSON.parse(response.body);
130337
+ } catch {
130338
+ throw new Error("Convex token response is not JSON.");
130339
+ }
130342
130340
  if (typeof body !== "object" || body === null || !("token" in body) || typeof body.token !== "string")
130343
130341
  throw new Error('Convex token response is missing a string "token".');
130344
130342
  const payload = convexJwtPayload(body.token);
@@ -130520,11 +130518,45 @@ function convexHttpActionUrl(convexUrl) {
130520
130518
  async function createConvexPushConnection(workspace) {
130521
130519
  const convexUrl = await resolveConvexUrl(workspace);
130522
130520
  const siteUrl = convexHttpActionUrl(convexUrl);
130521
+ const lifetime = new AbortController();
130523
130522
  const tokenCache = new ConvexJwtCache(
130524
130523
  workspace.config.apiBaseUrl,
130525
- void 0,
130524
+ lifetime.signal,
130526
130525
  siteUrl
130527
130526
  );
130527
+ void tokenCache.getToken().catch(() => void 0);
130528
+ let subscriber;
130529
+ let authFailed = false;
130530
+ const fail2 = (error) => {
130531
+ if (lifetime.signal.aborted) return;
130532
+ if (subscriber === void 0) authFailed = true;
130533
+ else subscriber(error);
130534
+ };
130535
+ const authenticate = (client) => client.setAuth(
130536
+ async ({ forceRefreshToken }) => {
130537
+ try {
130538
+ return await tokenCache.getToken(forceRefreshToken);
130539
+ } catch (error) {
130540
+ fail2(error instanceof Error ? error : new Error(String(error)));
130541
+ return null;
130542
+ }
130543
+ },
130544
+ (authenticated) => {
130545
+ if (!authenticated)
130546
+ fail2(new Error("Convex rejected the session authentication."));
130547
+ }
130548
+ );
130549
+ let socket;
130550
+ const connect = () => {
130551
+ if (socket !== void 0) return socket;
130552
+ socket = new ConvexClient(convexUrl, {
130553
+ initialAuthTokenReuse: true,
130554
+ logger: false
130555
+ });
130556
+ authenticate(socket);
130557
+ return socket;
130558
+ };
130559
+ let closing;
130528
130560
  return {
130529
130561
  async submit(body, force) {
130530
130562
  const json = JSON.stringify(body);
@@ -130554,6 +130586,7 @@ async function createConvexPushConnection(workspace) {
130554
130586
  limitBytes: SCHEMA_COMMIT_HTTP_MAX_BYTES
130555
130587
  }
130556
130588
  );
130589
+ connect();
130557
130590
  const client = new NeoApiClient(siteUrl, await tokenCache.getToken());
130558
130591
  const path = `${SCHEMA_COMMIT_HTTP_PATH}?${new URLSearchParams({ projectId: workspace.config.projectId, versionId: workspace.config.versionId })}`;
130559
130592
  const finish = startPerformanceSpan("commit-transport", {
@@ -130573,28 +130606,26 @@ async function createConvexPushConnection(workspace) {
130573
130606
  finish();
130574
130607
  }
130575
130608
  },
130576
- async subscribe(signal, onError) {
130577
- await tokenCache.getToken(false, signal);
130609
+ /** Routes the socket's authentication failures to `onError` until `signal` aborts. */
130610
+ subscribe(signal, onError) {
130578
130611
  signal.throwIfAborted();
130579
- const client = new ConvexClient(convexUrl, {
130580
- initialAuthTokenReuse: true,
130581
- logger: false
130582
- });
130583
- client.setAuth(
130584
- async ({ forceRefreshToken }) => {
130585
- try {
130586
- return await tokenCache.getToken(forceRefreshToken, signal);
130587
- } catch (error) {
130588
- onError(error instanceof Error ? error : new Error(String(error)));
130589
- return null;
130590
- }
130591
- },
130592
- (authenticated) => {
130593
- if (!authenticated && !signal.aborted)
130594
- onError(new Error("Convex rejected the session authentication."));
130595
- }
130596
- );
130612
+ subscriber = (error) => {
130613
+ if (!signal.aborted) onError(error);
130614
+ };
130615
+ const client = connect();
130616
+ if (authFailed) {
130617
+ authFailed = false;
130618
+ authenticate(client);
130619
+ }
130597
130620
  return client;
130621
+ },
130622
+ /** Idempotent; cancels an in-flight mint and closes the socket. */
130623
+ close() {
130624
+ if (closing === void 0) {
130625
+ lifetime.abort();
130626
+ closing = socket?.close() ?? Promise.resolve();
130627
+ }
130628
+ return closing;
130598
130629
  }
130599
130630
  };
130600
130631
  }
@@ -130605,6 +130636,7 @@ var init_convex = __esm({
130605
130636
  init_http();
130606
130637
  init_schema_commit_transport();
130607
130638
  init_performance();
130639
+ init_off_thread_fetch();
130608
130640
  init_api();
130609
130641
  init_token_store();
130610
130642
  init_workspace();
@@ -132527,9 +132559,9 @@ async function commitProjectVersionChanges(args) {
132527
132559
  errorCode: null,
132528
132560
  errorMessage: null
132529
132561
  });
132562
+ const connection = createConvexPushConnection(workspace);
132530
132563
  try {
132531
- const connection = await createConvexPushConnection(workspace);
132532
- const response = await connection.submit(body, false);
132564
+ const response = await (await connection).submit(body, false);
132533
132565
  const accepted = readAcceptedProjectVersionCommitResponse(response);
132534
132566
  if (accepted === null) {
132535
132567
  if (!isObjectRecord2(response) || typeof response.kind !== "string") {
@@ -132546,7 +132578,7 @@ async function commitProjectVersionChanges(args) {
132546
132578
  workspace,
132547
132579
  accepted,
132548
132580
  reporter,
132549
- connection
132581
+ connection: await connection
132550
132582
  });
132551
132583
  return {
132552
132584
  kind: completed.totalChangeCount === 0 ? "noop" : "committed",
@@ -132554,8 +132586,15 @@ async function commitProjectVersionChanges(args) {
132554
132586
  };
132555
132587
  } finally {
132556
132588
  reporter.stop();
132589
+ await closePushConnection(connection);
132557
132590
  }
132558
132591
  }
132592
+ async function closePushConnection(connection) {
132593
+ await connection.then(
132594
+ (opened) => opened.close(),
132595
+ () => void 0
132596
+ );
132597
+ }
132559
132598
  function clientPreparedCommitBody(args) {
132560
132599
  return {
132561
132600
  operation: args.operation,
@@ -132579,7 +132618,7 @@ function readAcceptedProjectVersionCommitResponse(value) {
132579
132618
  throw new Error("Accepted project transaction is missing transactionId.");
132580
132619
  }
132581
132620
  const rawStatus = value.commitStatus ?? value.status;
132582
- if (rawStatus !== "preparing" && rawStatus !== "waiting" && rawStatus !== "queued" && rawStatus !== "applying" && rawStatus !== "reverting" && rawStatus !== "committed" && rawStatus !== "failed") {
132621
+ if (!isProjectVersionTransactionCommitStatus(rawStatus)) {
132583
132622
  throw new Error(
132584
132623
  `Accepted project transaction "${value.transactionId}" has invalid commitStatus ${JSON.stringify(rawStatus)}.`
132585
132624
  );
@@ -132607,7 +132646,70 @@ function readAcceptedProjectVersionCommitResponse(value) {
132607
132646
  totalChangeCount,
132608
132647
  appliedChangeCount,
132609
132648
  totalChunkCount,
132610
- appliedChunkCount
132649
+ appliedChunkCount,
132650
+ ...value.completion === void 0 ? {} : {
132651
+ completion: readAcceptedCompletion(
132652
+ value.completion,
132653
+ value.transactionId
132654
+ )
132655
+ }
132656
+ };
132657
+ }
132658
+ function readAcceptedCompletion(value, transactionId) {
132659
+ const status = readProjectVersionTransactionStatus(value, transactionId);
132660
+ if (status.commitStatus !== "committed" && status.commitStatus !== "noop" && status.commitStatus !== "failed") {
132661
+ throw new Error(
132662
+ `Accepted project transaction "${transactionId}" reported a completion with commitStatus "${status.commitStatus}".`
132663
+ );
132664
+ }
132665
+ const resultPage = isObjectRecord2(value) ? value.resultPage : void 0;
132666
+ return resultPage === void 0 ? { status } : {
132667
+ status,
132668
+ resultPage: readStoredResultPage(resultPage, transactionId)
132669
+ };
132670
+ }
132671
+ function readStoredResultPage(value, transactionId) {
132672
+ const label = `Project transaction "${transactionId}" completion result page`;
132673
+ if (!isObjectRecord2(value)) {
132674
+ throw new Error(`${label} must be an object.`);
132675
+ }
132676
+ if (value.transactionId !== transactionId) {
132677
+ throw new Error(
132678
+ `${label} expected transactionId "${transactionId}"; received ${JSON.stringify(value.transactionId)}.`
132679
+ );
132680
+ }
132681
+ if (!Array.isArray(value.chunks)) {
132682
+ throw new Error(`${label} chunks must be an array.`);
132683
+ }
132684
+ const chunks = [];
132685
+ for (const [index, chunk] of value.chunks.entries()) {
132686
+ const chunkLabel = `${label} chunk ${index}`;
132687
+ if (!isObjectRecord2(chunk)) {
132688
+ throw new Error(`${chunkLabel} must be an object.`);
132689
+ }
132690
+ if (typeof chunk.assignmentsJson !== "string") {
132691
+ throw new Error(`${chunkLabel} assignmentsJson must be a string.`);
132692
+ }
132693
+ if (typeof chunk.changedRecordsJson !== "string") {
132694
+ throw new Error(`${chunkLabel} changedRecordsJson must be a string.`);
132695
+ }
132696
+ chunks.push({
132697
+ chunkIndex: readCount(chunk.chunkIndex, `${chunkLabel} chunkIndex`),
132698
+ assignmentsJson: chunk.assignmentsJson,
132699
+ changedRecordsJson: chunk.changedRecordsJson
132700
+ });
132701
+ }
132702
+ if (typeof value.isDone !== "boolean") {
132703
+ throw new Error(`${label} isDone must be a boolean.`);
132704
+ }
132705
+ return {
132706
+ transactionId,
132707
+ chunks,
132708
+ continueCursor: readNullableString(
132709
+ value.continueCursor,
132710
+ `${label} continueCursor`
132711
+ ),
132712
+ isDone: value.isDone
132611
132713
  };
132612
132714
  }
132613
132715
  function readProjectVersionTransactionStatus(value, transactionId) {
@@ -132876,24 +132978,20 @@ function progressEventFromStatus(status) {
132876
132978
  };
132877
132979
  }
132878
132980
  async function waitForAcceptedProjectVersionTransaction(args) {
132879
- const { workspace, accepted, reporter } = args;
132981
+ const { workspace, accepted, reporter, connection } = args;
132880
132982
  const { projectId, versionId } = workspace.config;
132881
132983
  const controller = new AbortController();
132882
132984
  const interrupt = () => controller.abort(
132883
132985
  new ProjectTransactionInterruptedError(accepted.transactionId)
132884
132986
  );
132885
132987
  process.once("SIGINT", interrupt);
132886
- reporter.report(progressEventFromAccepted(accepted));
132988
+ if (accepted.completion === void 0)
132989
+ reporter.report(progressEventFromAccepted(accepted));
132887
132990
  const finishWait = startPerformanceSpan("transaction-wait");
132888
- let client;
132889
132991
  let unsubscribe;
132890
132992
  let progressTimer;
132891
132993
  let settled = false;
132892
132994
  try {
132893
- const connection = args.connection ?? await withTransactionAbort(
132894
- createConvexPushConnection(workspace),
132895
- controller.signal
132896
- );
132897
132995
  let failed = () => void 0;
132898
132996
  let updated = () => void 0;
132899
132997
  let firstResultPage;
@@ -132928,24 +133026,19 @@ async function waitForAcceptedProjectVersionTransaction(args) {
132928
133026
  };
132929
133027
  }
132930
133028
  );
132931
- void terminal2.catch(() => void 0);
132932
- client = await connection.subscribe(controller.signal, (error) => {
133029
+ const client = connection.subscribe(controller.signal, (error) => {
132933
133030
  controller.abort(error);
132934
133031
  failed(error);
132935
133032
  });
132936
- const progressClient = client;
132937
133033
  const refreshProgress = async () => {
132938
133034
  if (settled || controller.signal.aborted) return;
132939
133035
  try {
132940
133036
  const response = await withTransactionAbort(
132941
- progressClient.query(
132942
- api2.projectVersionTransactionJobs.getTransactionStatus,
132943
- {
132944
- projectId,
132945
- versionId,
132946
- transactionId: accepted.transactionId
132947
- }
132948
- ),
133037
+ client.query(api2.projectVersionTransactionJobs.getTransactionStatus, {
133038
+ projectId,
133039
+ versionId,
133040
+ transactionId: accepted.transactionId
133041
+ }),
132949
133042
  controller.signal
132950
133043
  );
132951
133044
  if (settled || controller.signal.aborted) return;
@@ -132965,29 +133058,36 @@ async function waitForAcceptedProjectVersionTransaction(args) {
132965
133058
  const finishFirstStatus = startPerformanceSpan("transaction-first-status");
132966
133059
  let firstStatus = true;
132967
133060
  try {
132968
- unsubscribe = client.onUpdate(
132969
- api2.projectVersionTransactionJobs.getTransactionCompletion,
132970
- {
132971
- projectId,
132972
- versionId,
132973
- transactionId: accepted.transactionId,
132974
- includeResultPage: true
132975
- },
132976
- (response) => {
132977
- if (firstStatus) {
132978
- firstStatus = false;
132979
- finishFirstStatus();
132980
- }
132981
- if (settled) return;
132982
- firstResultPage = response?.resultPage;
132983
- updated(response);
132984
- },
132985
- failed
132986
- );
133061
+ if (accepted.completion === void 0) {
133062
+ unsubscribe = client.onUpdate(
133063
+ api2.projectVersionTransactionJobs.getTransactionCompletion,
133064
+ {
133065
+ projectId,
133066
+ versionId,
133067
+ transactionId: accepted.transactionId,
133068
+ includeResultPage: true
133069
+ },
133070
+ (response) => {
133071
+ if (firstStatus) {
133072
+ firstStatus = false;
133073
+ finishFirstStatus();
133074
+ }
133075
+ if (settled) return;
133076
+ firstResultPage = response?.resultPage;
133077
+ updated(response);
133078
+ },
133079
+ failed
133080
+ );
133081
+ } else {
133082
+ firstStatus = false;
133083
+ finishFirstStatus();
133084
+ firstResultPage = accepted.completion.resultPage;
133085
+ updated(accepted.completion.status);
133086
+ }
132987
133087
  if (!settled)
132988
133088
  progressTimer = setTimeout(() => void refreshProgress(), 5e3);
132989
133089
  const status = await withTransactionAbort(terminal2, controller.signal);
132990
- unsubscribe();
133090
+ unsubscribe?.();
132991
133091
  unsubscribe = void 0;
132992
133092
  const finishDownload = startPerformanceSpan("result-download");
132993
133093
  try {
@@ -133011,7 +133111,6 @@ async function waitForAcceptedProjectVersionTransaction(args) {
133011
133111
  clearTimeout(progressTimer);
133012
133112
  unsubscribe?.();
133013
133113
  controller.abort();
133014
- if (client !== void 0) await client.close();
133015
133114
  finishWait();
133016
133115
  process.removeListener("SIGINT", interrupt);
133017
133116
  }
@@ -133202,6 +133301,19 @@ async function runPush(workspace, options, preparationOverride) {
133202
133301
  `neo push cannot run from configured hook ${JSON.stringify(process.env.NEO_HOOK)}. Nested pushes are always blocked; run the intended validation command directly.`
133203
133302
  );
133204
133303
  }
133304
+ if (options.dryRun) {
133305
+ await pushWorkspace(workspace, options, preparationOverride, void 0);
133306
+ return;
133307
+ }
133308
+ const connection = createConvexPushConnection(workspace);
133309
+ await connection.catch(() => void 0);
133310
+ try {
133311
+ await pushWorkspace(workspace, options, preparationOverride, connection);
133312
+ } finally {
133313
+ await closePushConnection(connection);
133314
+ }
133315
+ }
133316
+ async function pushWorkspace(workspace, options, preparationOverride, connection) {
133205
133317
  const configuredHook = options.dryRun ? workspace.config.prePushDryRunHook : workspace.config.prePushHook;
133206
133318
  const verifiesConfiguredHook = options.noVerify !== true && configuredHook !== void 0;
133207
133319
  const preparedInputFingerprint = verifiesConfiguredHook ? fingerprintPushInputs(workspace) : void 0;
@@ -133354,6 +133466,8 @@ async function runPush(workspace, options, preparationOverride) {
133354
133466
  }
133355
133467
  }
133356
133468
  if (options.dryRun) return;
133469
+ if (connection === void 0)
133470
+ throw new Error("A committing push has no connection to commit through.");
133357
133471
  if (isInteractive() && !await promptConfirm({
133358
133472
  message: `Push ${status.changes.length} change(s)?`,
133359
133473
  fallback: true
@@ -133435,7 +133549,6 @@ async function runPush(workspace, options, preparationOverride) {
133435
133549
  stagedUploadSessionId
133436
133550
  } = preparedPush;
133437
133551
  const { stagedFiles } = preparedPush;
133438
- let pushConnection;
133439
133552
  const commit = async (force) => {
133440
133553
  const body = clientPreparedCommitBody({
133441
133554
  workspace,
@@ -133447,8 +133560,7 @@ async function runPush(workspace, options, preparationOverride) {
133447
133560
  pendingIdAssignments: Object.fromEntries(pendingAssignment.assigned),
133448
133561
  summary: options.summary ?? "neo push"
133449
133562
  });
133450
- pushConnection ??= await createConvexPushConnection(workspace);
133451
- return await pushConnection.submit(body, force);
133563
+ return await (await connection).submit(body, force);
133452
133564
  };
133453
133565
  const finishCommitResponse = async (response, reporter) => {
133454
133566
  let accepted;
@@ -133494,13 +133606,14 @@ async function runPush(workspace, options, preparationOverride) {
133494
133606
  if (options.json !== true) success("Push complete.");
133495
133607
  return true;
133496
133608
  }
133609
+ const opened = await connection;
133497
133610
  let completed;
133498
133611
  try {
133499
133612
  completed = await waitForAcceptedProjectVersionTransaction({
133500
133613
  workspace,
133501
133614
  accepted,
133502
133615
  reporter,
133503
- connection: pushConnection
133616
+ connection: opened
133504
133617
  });
133505
133618
  } catch (error) {
133506
133619
  if (error instanceof ProjectTransactionInterruptedError) {
@@ -133545,6 +133658,7 @@ async function runPush(workspace, options, preparationOverride) {
133545
133658
  reporter.stop();
133546
133659
  throw error;
133547
133660
  }
133661
+ void opened.close();
133548
133662
  try {
133549
133663
  const finishApply = startPerformanceSpan("apply-result");
133550
133664
  try {
@@ -134500,7 +134614,8 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
134500
134614
  valueIds: binding.valueIds.map(
134501
134615
  (id2) => rewriteAssignedString(id2, replacements)
134502
134616
  )
134503
- }))
134617
+ })),
134618
+ localStatus.sourceSnapshot
134504
134619
  );
134505
134620
  } catch (error) {
134506
134621
  workspace.state = {
@@ -134787,8 +134902,8 @@ function rewriteFilesFromState(workspace, records2 = new Map(
134787
134902
  data: recordState.data
134788
134903
  }
134789
134904
  ])
134790
- ), preservedSourceFiles = /* @__PURE__ */ new Map(), recordFiles = /* @__PURE__ */ new Map(), localValues = workspace.state.localValues) {
134791
- const result = emitProjectDocumentFilesV4(
134905
+ ), preservedSourceFiles = /* @__PURE__ */ new Map(), recordFiles = /* @__PURE__ */ new Map(), localValues = workspace.state.localValues, sourceSnapshot) {
134906
+ const result = emitProjectDocumentSourcesV4(
134792
134907
  candidateValueRecordsForEmissionV4(
134793
134908
  records2,
134794
134909
  workspace.state.records,
@@ -134827,11 +134942,15 @@ function rewriteFilesFromState(workspace, records2 = new Map(
134827
134942
  }
134828
134943
  return { uri: file.path, kind, text: file.content };
134829
134944
  });
134830
- const finalAnalysis = files.every(
134831
- (file, index) => file.content === result.files[index]?.content
134832
- ) ? result.analysis : compileNeoProjectSources(finalInputs);
134945
+ const unchanged = sourceSnapshot !== void 0 && sameCompilationInputs(finalInputs, sourceSnapshot.inputs);
134946
+ const finalAnalysis = unchanged ? sourceSnapshot.analysis : compileNeoProjectSources(finalInputs);
134833
134947
  assertAssignedIdSourceRewriteValid(finalAnalysis);
134834
- writeProjectSourceAnalysisCacheV4(workspace.root, finalAnalysis, finalInputs);
134948
+ if (!unchanged)
134949
+ writeProjectSourceAnalysisCacheV4(
134950
+ workspace.root,
134951
+ finalAnalysis,
134952
+ finalInputs
134953
+ );
134835
134954
  const resolveSourcePath = createWorkspaceSourcePathResolver(workspace.root);
134836
134955
  const emittedEntries = new Set(
134837
134956
  files.map((file) => fileSystemEntryKey(resolveSourcePath(file.path)))
@@ -134839,12 +134958,10 @@ function rewriteFilesFromState(workspace, records2 = new Map(
134839
134958
  const output = new Map(
134840
134959
  files.map((file) => [file.path, file.content])
134841
134960
  );
134842
- const previousPaths = [
134843
- ...Object.values(workspace.state.records).flatMap(
134844
- (record6) => record6.file === void 0 ? [] : [record6.file]
134845
- ),
134846
- ...preservedSourceFiles.keys()
134847
- ];
134961
+ const previousPaths = new Set(preservedSourceFiles.keys());
134962
+ for (const record6 of Object.values(workspace.state.records)) {
134963
+ if (record6.file !== void 0) previousPaths.add(record6.file);
134964
+ }
134848
134965
  for (const path of previousPaths) {
134849
134966
  const absolute = resolveSourcePath(path);
134850
134967
  if (!existsSync10(absolute) || emittedEntries.has(fileSystemEntryKey(absolute)))
@@ -134881,6 +134998,13 @@ function rewriteFilesFromState(workspace, records2 = new Map(
134881
134998
  writeWorkspaceState(workspace.root, workspace.state);
134882
134999
  finishCommittedPushProjection(workspace);
134883
135000
  }
135001
+ function sameCompilationInputs(left, right) {
135002
+ if (left.length !== right.length) return false;
135003
+ return left.every((input, index) => {
135004
+ const other = right[index];
135005
+ return input.uri === other?.uri && input.kind === other.kind && input.text === other.text;
135006
+ });
135007
+ }
134884
135008
  function assertAssignedIdSourceRewriteValid(analysis) {
134885
135009
  const finalErrors = analysis.diagnostics.filter(
134886
135010
  (diagnostic) => diagnostic.severity === "error" && !isPullRecoveryDiagnosticCode(diagnostic.code)
@@ -138362,7 +138486,16 @@ function auditProjectIntegrity(workspace) {
138362
138486
  const storedPlacements = buildStoredValuePlacementIndexV4(
138363
138487
  Object.values(records2)
138364
138488
  );
138365
- const placements = collectPlacements(values, storedPlacements);
138489
+ const lookupValueIds = collectLookupValueIds(
138490
+ records2,
138491
+ values,
138492
+ storedPlacements
138493
+ );
138494
+ const placements = collectPlacements(
138495
+ values,
138496
+ storedPlacements,
138497
+ lookupValueIds
138498
+ );
138366
138499
  const memberIdBySchemaKey = collectClassSchemas(records2);
138367
138500
  const storageKeyByMemberId = collectMemberStorageKeys(records2);
138368
138501
  const findings = [];
@@ -138579,7 +138712,7 @@ function collectValueRows(records2) {
138579
138712
  }
138580
138713
  return values;
138581
138714
  }
138582
- function collectPlacements(values, storedPlacements) {
138715
+ function collectPlacements(values, storedPlacements, lookupValueIds) {
138583
138716
  const placements = /* @__PURE__ */ new Map();
138584
138717
  const claim = (childId, placement) => {
138585
138718
  if (values.has(childId) && !placements.has(childId)) {
@@ -138595,6 +138728,7 @@ function collectPlacements(values, storedPlacements) {
138595
138728
  continue;
138596
138729
  }
138597
138730
  if (!Array.isArray(body)) continue;
138731
+ if (lookupValueIds.has(parent.id)) continue;
138598
138732
  for (const childId of body) {
138599
138733
  if (typeof childId === "string") {
138600
138734
  claim(childId, { parent, schemaKey: UNORDERED_MEMBERSHIP_KEY });
@@ -138615,6 +138749,57 @@ function collectPlacements(values, storedPlacements) {
138615
138749
  }
138616
138750
  return placements;
138617
138751
  }
138752
+ function collectLookupValueIds(records2, values, storedPlacements) {
138753
+ const members = /* @__PURE__ */ new Map();
138754
+ const pending = [];
138755
+ for (const record6 of Object.values(records2)) {
138756
+ if (record6.recordKind !== "member" || !isObjectRecord2(record6.data))
138757
+ continue;
138758
+ members.set(record6.recordId, record6.data);
138759
+ if (typeof record6.data.valueId === "string") {
138760
+ pending.push({ valueId: record6.data.valueId, memberId: record6.recordId });
138761
+ }
138762
+ }
138763
+ for (const edge of storedPlacements.placementByChildValueId.values()) {
138764
+ if (edge.memberId !== null) {
138765
+ pending.push({ valueId: edge.childValueId, memberId: edge.memberId });
138766
+ }
138767
+ }
138768
+ const contained = /* @__PURE__ */ new Map();
138769
+ for (const value of values.values()) {
138770
+ if (value.containerId === null) continue;
138771
+ const siblings = contained.get(value.containerId);
138772
+ if (siblings === void 0) contained.set(value.containerId, [value.id]);
138773
+ else siblings.push(value.id);
138774
+ }
138775
+ const lookups = /* @__PURE__ */ new Set();
138776
+ const visited = /* @__PURE__ */ new Set();
138777
+ for (let next = pending.pop(); next !== void 0; next = pending.pop()) {
138778
+ if (visited.has(next.valueId)) continue;
138779
+ visited.add(next.valueId);
138780
+ const member = members.get(next.memberId);
138781
+ if (member === void 0) continue;
138782
+ if (member.kind === 9 /* Lookup */ || member.kind === 18 /* DialogueLookup */) {
138783
+ lookups.add(next.valueId);
138784
+ continue;
138785
+ }
138786
+ if (member.kind !== 6 /* List */ && member.kind !== 5 /* Dictionary */)
138787
+ continue;
138788
+ const memberId = member.entryMemberId;
138789
+ if (typeof memberId !== "string") continue;
138790
+ const body = values.get(next.valueId)?.value;
138791
+ const children = isObjectRecord2(body) ? Object.values(body) : body;
138792
+ if (Array.isArray(children)) {
138793
+ for (const valueId of children) {
138794
+ if (typeof valueId === "string") pending.push({ valueId, memberId });
138795
+ }
138796
+ }
138797
+ for (const valueId of contained.get(next.valueId) ?? []) {
138798
+ pending.push({ valueId, memberId });
138799
+ }
138800
+ }
138801
+ return lookups;
138802
+ }
138618
138803
  function collectClassSchemas(records2) {
138619
138804
  const schemas = /* @__PURE__ */ new Map();
138620
138805
  for (const record6 of Object.values(records2)) {
@@ -138684,6 +138869,7 @@ var init_project_integrity = __esm({
138684
138869
  "use strict";
138685
138870
  init_member_storage_key();
138686
138871
  init_system_record_id();
138872
+ init_member_kind_enum();
138687
138873
  init_projection();
138688
138874
  init_stored_value_placements();
138689
138875
  UNORDERED_MEMBERSHIP_KEY = "(container)";
@@ -140757,7 +140943,7 @@ var init_registry2 = __esm({
140757
140943
  "schema-contract/registry.mjs"() {
140758
140944
  "use strict";
140759
140945
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
140760
- cliVersion: "0.59.1",
140946
+ cliVersion: "0.59.3",
140761
140947
  projectFileUploadBatchSize: 32,
140762
140948
  documentRecords: {
140763
140949
  member: {
@@ -148578,7 +148764,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
148578
148764
  async function main() {
148579
148765
  const args = parseArgs(process.argv.slice(2));
148580
148766
  if (args.command === "--version") {
148581
- console.log("0.59.1");
148767
+ console.log("0.59.3");
148582
148768
  return;
148583
148769
  }
148584
148770
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {