@neocompose/cli 0.19.1 → 0.19.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.
Files changed (2) hide show
  1. package/dist/neo.mjs +369 -40
  2. package/package.json +1 -1
package/dist/neo.mjs CHANGED
@@ -21593,6 +21593,14 @@ var init_project_source_type_checker = __esm({
21593
21593
  });
21594
21594
 
21595
21595
  // ../packages/neoscript-language/src/project-source-analysis.ts
21596
+ function isSystemReservedRecordId(id2) {
21597
+ if (id2 === null) return false;
21598
+ if (id2.startsWith(SYSTEM_RECORD_ID_PREFIX)) return true;
21599
+ if (QUARANTINED_LEGACY_SYSTEM_RECORD_IDS.has(id2)) return true;
21600
+ return QUARANTINED_LEGACY_SYSTEM_ID_PREFIXES.some(
21601
+ (prefix) => id2.startsWith(prefix)
21602
+ );
21603
+ }
21596
21604
  function isEnumOptionId(id2) {
21597
21605
  if (isPendingId(id2)) return true;
21598
21606
  if (id2.startsWith(SYSTEM_RECORD_ID_PREFIX)) {
@@ -21637,6 +21645,7 @@ function analyzeNeoProjectSources(inputs) {
21637
21645
  }
21638
21646
  }
21639
21647
  validateSymbolUniqueness(symbols, diagnostics);
21648
+ validateSystemAnnotationAuthoring(documents, diagnostics);
21640
21649
  validateTypeReferences(documents, symbols, diagnostics);
21641
21650
  diagnostics.push(...validateProjectSourceTypes(documents));
21642
21651
  diagnostics.push(...validateProjectSourceSettlement(documents));
@@ -21930,6 +21939,124 @@ function sourceId(uri, annotations, diagnostics) {
21930
21939
  }
21931
21940
  return id2;
21932
21941
  }
21942
+ function declaredIdValue(annotations) {
21943
+ const annotation2 = annotations.find((entry) => entry.name === "id");
21944
+ if (annotation2 === void 0) return null;
21945
+ if (annotation2.arguments.length !== 1) return null;
21946
+ const id2 = decodeStringLiteral(annotation2.arguments[0].text);
21947
+ if (id2 === null || id2.length === 0) return null;
21948
+ return id2;
21949
+ }
21950
+ function systemAnnotation(annotations) {
21951
+ return annotations.find((entry) => entry.name === "system");
21952
+ }
21953
+ function validateSystemAnnotationAuthoring(documents, diagnostics) {
21954
+ const owners = /* @__PURE__ */ new Map();
21955
+ for (const [uri, document] of documents) {
21956
+ for (const declaration of document.declarations) {
21957
+ if (declaration.kind !== "class" && declaration.kind !== "interface") {
21958
+ continue;
21959
+ }
21960
+ const key = declaration.name.toLowerCase();
21961
+ if (!owners.has(key)) owners.set(key, { uri, declaration });
21962
+ }
21963
+ }
21964
+ for (const [uri, document] of documents) {
21965
+ for (const declaration of document.declarations) {
21966
+ const declarationAnnotation = systemAnnotation(declaration.annotations);
21967
+ const declarationId = declaredIdValue(declaration.annotations);
21968
+ if (declarationAnnotation !== void 0 && !isSystemReservedRecordId(declarationId)) {
21969
+ diagnostics.push(
21970
+ authoredSystemDiagnostic(
21971
+ uri,
21972
+ declarationAnnotation,
21973
+ declaration.name,
21974
+ declarationId
21975
+ )
21976
+ );
21977
+ }
21978
+ if (declaration.kind !== "class" && declaration.kind !== "interface") {
21979
+ continue;
21980
+ }
21981
+ for (const member of declaration.members) {
21982
+ const annotation2 = systemAnnotation(member.annotations);
21983
+ if (annotation2 === void 0) continue;
21984
+ const memberId = declaredIdValue(member.annotations);
21985
+ if (isSystemReservedRecordId(memberId)) continue;
21986
+ const label = `${declaration.name}.${member.name}`;
21987
+ const inherited = inheritedSystemMember(
21988
+ declaration,
21989
+ member.name,
21990
+ owners
21991
+ );
21992
+ if (inherited === null) {
21993
+ diagnostics.push(
21994
+ authoredSystemDiagnostic(uri, annotation2, label, memberId)
21995
+ );
21996
+ continue;
21997
+ }
21998
+ diagnostics.push({
21999
+ uri,
22000
+ range: annotation2.range,
22001
+ severity: "error",
22002
+ source: "neo-project",
22003
+ code: "authored-system-annotation-on-override",
22004
+ message: `@system on '${label}' is platform protection metadata Neo Compose sets on its own records. '${inherited.site.declaration.name}.${inherited.member.name}' carries it because the platform owns that record; carrying it on your own override would lock you out of editing or deleting it. Remove @system from the override.`,
22005
+ relatedInformation: [
22006
+ {
22007
+ location: {
22008
+ uri: inherited.site.uri,
22009
+ range: inherited.member.nameRange
22010
+ },
22011
+ message: "The protected base member is declared here."
22012
+ }
22013
+ ]
22014
+ });
22015
+ }
22016
+ }
22017
+ }
22018
+ }
22019
+ function authoredSystemDiagnostic(uri, annotation2, label, id2) {
22020
+ return {
22021
+ uri,
22022
+ range: annotation2.range,
22023
+ severity: "error",
22024
+ source: "neo-project",
22025
+ code: "authored-system-annotation",
22026
+ message: `@system on '${label}' is platform protection metadata Neo Compose sets on its own records, and ${systemIdentityClause(label, id2)}. Remove @system.`
22027
+ };
22028
+ }
22029
+ function systemIdentityClause(label, id2) {
22030
+ if (id2 === null) {
22031
+ return `'${label}' declares no @id, so it is a project record this push would create`;
22032
+ }
22033
+ return `@id '${id2}' is not in the reserved '${SYSTEM_RECORD_ID_PREFIX}' namespace`;
22034
+ }
22035
+ function inheritedSystemMember(declaration, memberName, owners) {
22036
+ const target = memberName.toLowerCase();
22037
+ const seen = /* @__PURE__ */ new Set([declaration.name.toLowerCase()]);
22038
+ const queue = baseSites(declaration, owners);
22039
+ while (queue.length > 0) {
22040
+ const site = queue.shift();
22041
+ const key = site.declaration.name.toLowerCase();
22042
+ if (seen.has(key)) continue;
22043
+ seen.add(key);
22044
+ const member = site.declaration.members.find(
22045
+ (entry) => entry.name.toLowerCase() === target && systemAnnotation(entry.annotations) !== void 0
22046
+ );
22047
+ if (member !== void 0) return { site, member };
22048
+ queue.push(...baseSites(site.declaration, owners));
22049
+ }
22050
+ return null;
22051
+ }
22052
+ function baseSites(declaration, owners) {
22053
+ const sites = [];
22054
+ for (const base of declaration.baseTypes) {
22055
+ const site = owners.get(base.name.toLowerCase());
22056
+ if (site !== void 0) sites.push(site);
22057
+ }
22058
+ return sites;
22059
+ }
21933
22060
  function validateSymbolUniqueness(symbols, diagnostics) {
21934
22061
  const names = /* @__PURE__ */ new Map();
21935
22062
  const ids = /* @__PURE__ */ new Map();
@@ -22115,7 +22242,7 @@ function emptyRange2() {
22115
22242
  end: { line: 0, character: 0 }
22116
22243
  };
22117
22244
  }
22118
- var BUILTIN_TYPE_NAMES, RESERVED_NAMES3, SYSTEM_RECORD_ID_PREFIX, RFC_4122_UUID;
22245
+ var BUILTIN_TYPE_NAMES, RESERVED_NAMES3, SYSTEM_RECORD_ID_PREFIX, RFC_4122_UUID, QUARANTINED_LEGACY_SYSTEM_ID_PREFIXES, QUARANTINED_LEGACY_SYSTEM_RECORD_IDS;
22119
22246
  var init_project_source_analysis = __esm({
22120
22247
  "../packages/neoscript-language/src/project-source-analysis.ts"() {
22121
22248
  "use strict";
@@ -22150,6 +22277,23 @@ var init_project_source_analysis = __esm({
22150
22277
  RESERVED_NAMES3 = new Set(NEOSCRIPT_KEYWORDS);
22151
22278
  SYSTEM_RECORD_ID_PREFIX = "system_";
22152
22279
  RFC_4122_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
22280
+ QUARANTINED_LEGACY_SYSTEM_ID_PREFIXES = [
22281
+ "neo-tile-grid-record-relations-v1-member-"
22282
+ ];
22283
+ QUARANTINED_LEGACY_SYSTEM_RECORD_IDS = /* @__PURE__ */ new Set([
22284
+ "430fca56-b45a-4896-9ab2-795a3faf57f6",
22285
+ // VaultPlaqueObject.PlacementTiles
22286
+ "47c21aa5-e852-41d2-882c-b4f555aee9dd",
22287
+ // PlayerSpawnObject.PlacementTiles
22288
+ "571a0e0b-b36c-45f3-ae9a-5fde39045c11",
22289
+ // ExitPromptObject.PlacementTiles
22290
+ "8e8c5ddf-6273-4440-869e-f1f9ca5dc51b",
22291
+ // ExitPromptObject.Size
22292
+ "94472662-a3a9-4c02-8abb-6229442e1e49",
22293
+ // RecoveryCacheObject.Collider
22294
+ "d8e9ad0e-157f-4709-96a7-8775efa3dd11"
22295
+ // RecoveryCacheObject.PlacementTiles
22296
+ ]);
22153
22297
  }
22154
22298
  });
22155
22299
 
@@ -36559,33 +36703,33 @@ var MemberKind;
36559
36703
  var init_member_kind_enum = __esm({
36560
36704
  "../src/models/members/member-kind-enum.ts"() {
36561
36705
  "use strict";
36562
- MemberKind = /* @__PURE__ */ ((MemberKind10) => {
36563
- MemberKind10[MemberKind10["Null"] = 0] = "Null";
36564
- MemberKind10[MemberKind10["Bool"] = 1] = "Bool";
36565
- MemberKind10[MemberKind10["Int"] = 2] = "Int";
36566
- MemberKind10[MemberKind10["String"] = 3] = "String";
36567
- MemberKind10[MemberKind10["Float"] = 4] = "Float";
36568
- MemberKind10[MemberKind10["Dictionary"] = 5] = "Dictionary";
36569
- MemberKind10[MemberKind10["List"] = 6] = "List";
36570
- MemberKind10[MemberKind10["Class"] = 7] = "Class";
36571
- MemberKind10[MemberKind10["Enum"] = 8] = "Enum";
36572
- MemberKind10[MemberKind10["Lookup"] = 9] = "Lookup";
36573
- MemberKind10[MemberKind10["NSProperty"] = 10] = "NSProperty";
36574
- MemberKind10[MemberKind10["Sprite"] = 11] = "Sprite";
36575
- MemberKind10[MemberKind10["Audio"] = 12] = "Audio";
36576
- MemberKind10[MemberKind10["Function"] = 13] = "Function";
36577
- MemberKind10[MemberKind10["Vector2"] = 14] = "Vector2";
36578
- MemberKind10[MemberKind10["Vector2Int"] = 15] = "Vector2Int";
36579
- MemberKind10[MemberKind10["Vector3"] = 16] = "Vector3";
36580
- MemberKind10[MemberKind10["Vector3Int"] = 17] = "Vector3Int";
36581
- MemberKind10[MemberKind10["DialogueLookup"] = 18] = "DialogueLookup";
36582
- MemberKind10[MemberKind10["Color"] = 19] = "Color";
36583
- MemberKind10[MemberKind10["Decimal"] = 20] = "Decimal";
36584
- MemberKind10[MemberKind10["Generic"] = 21] = "Generic";
36585
- MemberKind10[MemberKind10["Interface"] = 22] = "Interface";
36586
- MemberKind10[MemberKind10["NSFunction"] = 23] = "NSFunction";
36587
- MemberKind10[MemberKind10["FunctionRef"] = 24] = "FunctionRef";
36588
- return MemberKind10;
36706
+ MemberKind = /* @__PURE__ */ ((MemberKind11) => {
36707
+ MemberKind11[MemberKind11["Null"] = 0] = "Null";
36708
+ MemberKind11[MemberKind11["Bool"] = 1] = "Bool";
36709
+ MemberKind11[MemberKind11["Int"] = 2] = "Int";
36710
+ MemberKind11[MemberKind11["String"] = 3] = "String";
36711
+ MemberKind11[MemberKind11["Float"] = 4] = "Float";
36712
+ MemberKind11[MemberKind11["Dictionary"] = 5] = "Dictionary";
36713
+ MemberKind11[MemberKind11["List"] = 6] = "List";
36714
+ MemberKind11[MemberKind11["Class"] = 7] = "Class";
36715
+ MemberKind11[MemberKind11["Enum"] = 8] = "Enum";
36716
+ MemberKind11[MemberKind11["Lookup"] = 9] = "Lookup";
36717
+ MemberKind11[MemberKind11["NSProperty"] = 10] = "NSProperty";
36718
+ MemberKind11[MemberKind11["Sprite"] = 11] = "Sprite";
36719
+ MemberKind11[MemberKind11["Audio"] = 12] = "Audio";
36720
+ MemberKind11[MemberKind11["Function"] = 13] = "Function";
36721
+ MemberKind11[MemberKind11["Vector2"] = 14] = "Vector2";
36722
+ MemberKind11[MemberKind11["Vector2Int"] = 15] = "Vector2Int";
36723
+ MemberKind11[MemberKind11["Vector3"] = 16] = "Vector3";
36724
+ MemberKind11[MemberKind11["Vector3Int"] = 17] = "Vector3Int";
36725
+ MemberKind11[MemberKind11["DialogueLookup"] = 18] = "DialogueLookup";
36726
+ MemberKind11[MemberKind11["Color"] = 19] = "Color";
36727
+ MemberKind11[MemberKind11["Decimal"] = 20] = "Decimal";
36728
+ MemberKind11[MemberKind11["Generic"] = 21] = "Generic";
36729
+ MemberKind11[MemberKind11["Interface"] = 22] = "Interface";
36730
+ MemberKind11[MemberKind11["NSFunction"] = 23] = "NSFunction";
36731
+ MemberKind11[MemberKind11["FunctionRef"] = 24] = "FunctionRef";
36732
+ return MemberKind11;
36589
36733
  })(MemberKind || {});
36590
36734
  }
36591
36735
  });
@@ -40457,14 +40601,18 @@ function isEnumOptionsRecord(value) {
40457
40601
  }
40458
40602
  return true;
40459
40603
  }
40604
+ function isOptionalOptionKeyOrder(value) {
40605
+ if (value === void 0) return true;
40606
+ if (!Array.isArray(value)) return false;
40607
+ return value.every((key) => typeof key === "string");
40608
+ }
40460
40609
  function isEnumBase(value) {
40461
40610
  const v = value;
40462
40611
  if (!v) return false;
40463
40612
  if (typeof v.name !== "string") return false;
40464
40613
  if (!isValidDocsText(v.docsText)) return false;
40465
40614
  if (!isEnumOptionsRecord(v.options)) return false;
40466
- if (!Array.isArray(v.optionKeyOrder)) return false;
40467
- if (!v.optionKeyOrder.every((key) => typeof key === "string")) return false;
40615
+ if (!isOptionalOptionKeyOrder(v.optionKeyOrder)) return false;
40468
40616
  if (v.system !== void 0 && v.system !== null) {
40469
40617
  return isSystemMetadata(v.system);
40470
40618
  }
@@ -40473,7 +40621,7 @@ function isEnumBase(value) {
40473
40621
  function getEnumOptionKeyOrder(enumDef) {
40474
40622
  const seen = /* @__PURE__ */ new Set();
40475
40623
  const result = [];
40476
- for (const optionId of enumDef.optionKeyOrder) {
40624
+ for (const optionId of enumDef.optionKeyOrder ?? []) {
40477
40625
  if (!Object.prototype.hasOwnProperty.call(enumDef.options, optionId)) {
40478
40626
  continue;
40479
40627
  }
@@ -45114,7 +45262,7 @@ ${namedArguments(
45114
45262
  function emitLocalizationStatus(status, identifier2, names) {
45115
45263
  const annotations = [
45116
45264
  id(status.id).trimEnd(),
45117
- ...status.system ? [systemAnnotation(status.system)] : []
45265
+ ...status.system ? [systemAnnotation2(status.system)] : []
45118
45266
  ];
45119
45267
  const statusReference = (value) => value === null ? "null" : names.get(value) ?? `Reference<LocalizationStatus>(id: ${quote(value)})`;
45120
45268
  return `${annotations.join("\n")}
@@ -45158,7 +45306,7 @@ function emitClass(context, schemaClass2, memberIds) {
45158
45306
  ...schemaClass2.targetMemberId ? [
45159
45307
  `@settings(target: ${qualifiedMember(context, schemaClass2.targetMemberId)})`
45160
45308
  ] : [],
45161
- ...schemaClass2.system ? [systemAnnotation(schemaClass2.system)] : [],
45309
+ ...schemaClass2.system ? [systemAnnotation2(schemaClass2.system)] : [],
45162
45310
  ...relationsAnnotations(context, schemaClass2)
45163
45311
  ];
45164
45312
  const modifier = schemaClass2.declarationModifier === "abstract" ? "abstract " : "";
@@ -45373,7 +45521,7 @@ function emitMember(context, member, enclosingClassId) {
45373
45521
  ] : [],
45374
45522
  ...memberSettings(context, member),
45375
45523
  ...listAnnotations(member),
45376
- ...member.system ? [systemAnnotation(member.system)] : []
45524
+ ...member.system ? [systemAnnotation2(member.system)] : []
45377
45525
  ];
45378
45526
  const prefix = memberModifier3(member);
45379
45527
  if (member.kind === "computed") {
@@ -46173,7 +46321,7 @@ function genericName(context, idValue) {
46173
46321
  }
46174
46322
  throw new Error(`Unknown generic parameter ${quote(idValue)}.`);
46175
46323
  }
46176
- function systemAnnotation(system) {
46324
+ function systemAnnotation2(system) {
46177
46325
  const args = [
46178
46326
  `kind: .${enumCase(system.kind)}`,
46179
46327
  ...system.worldKind ? [`worldKind: .${enumCase(system.worldKind)}`] : []
@@ -64563,7 +64711,7 @@ function createNeoScriptProject(context) {
64563
64711
  enumHeader,
64564
64712
  enumDefinition.name
64565
64713
  ),
64566
- members: safeEnumOptionOrder(enumDefinition).map((optionId, index) => {
64714
+ members: getEnumOptionKeyOrder(enumDefinition).map((optionId, index) => {
64567
64715
  const option = enumDefinition.options[optionId];
64568
64716
  const optionName = option?.name ?? optionId;
64569
64717
  return {
@@ -64615,9 +64763,6 @@ function virtualCSharpIdentifier(value) {
64615
64763
  const prefixed = /^[A-Za-z_]/.test(replaced) ? replaced : `_${replaced}`;
64616
64764
  return prefixed.length > 0 ? prefixed : "_";
64617
64765
  }
64618
- function safeEnumOptionOrder(enumDefinition) {
64619
- return Array.isArray(enumDefinition.optionKeyOrder) ? getEnumOptionKeyOrder(enumDefinition) : Object.keys(enumDefinition.options);
64620
- }
64621
64766
  function classToLanguageType(schemaClass2, context) {
64622
64767
  let chain;
64623
64768
  try {
@@ -79236,6 +79381,150 @@ var init_trusted_commit_verification = __esm({
79236
79381
  }
79237
79382
  });
79238
79383
 
79384
+ // ../src/models/classes/world-layer-link-target.ts
79385
+ var init_world_layer_link_target = __esm({
79386
+ "../src/models/classes/world-layer-link-target.ts"() {
79387
+ "use strict";
79388
+ init_classes();
79389
+ init_core();
79390
+ init_project2();
79391
+ }
79392
+ });
79393
+
79394
+ // ../src/models/project/world-content-sidecar-validation.ts
79395
+ var init_world_content_sidecar_validation = __esm({
79396
+ "../src/models/project/world-content-sidecar-validation.ts"() {
79397
+ "use strict";
79398
+ init_classes();
79399
+ init_world_layer_link_target();
79400
+ init_core();
79401
+ init_internal_record_relations();
79402
+ }
79403
+ });
79404
+
79405
+ // ../src/models/project-file-authoring-identifiers.ts
79406
+ function isValidProjectFileAuthoringIdentifier(value) {
79407
+ return isValidProjectSourceIdentifier(value);
79408
+ }
79409
+ function assertProjectFileAuthoringIdentifier(value, label) {
79410
+ if (isValidProjectFileAuthoringIdentifier(value)) return;
79411
+ throw new Error(
79412
+ `${label} ${JSON.stringify(value)} must be a valid Neo identifier. Use letters, digits, and underscores, begin with a letter or underscore, and do not use a reserved Neo name.`
79413
+ );
79414
+ }
79415
+ function assertProjectFileAuthoringRecordIdentifiers(recordKind, data) {
79416
+ if (recordKind !== "unity-texture-template" && recordKind !== "unity-audio-clip-template") {
79417
+ return;
79418
+ }
79419
+ if (!isObjectRecord3(data) || typeof data.name !== "string") return;
79420
+ const label = recordKind === "unity-texture-template" ? "Unity texture template name" : "Unity audio clip template name";
79421
+ assertProjectFileAuthoringIdentifier(data.name, label);
79422
+ }
79423
+ function isObjectRecord3(value) {
79424
+ return typeof value === "object" && value !== null && !Array.isArray(value);
79425
+ }
79426
+ var init_project_file_authoring_identifiers = __esm({
79427
+ "../src/models/project-file-authoring-identifiers.ts"() {
79428
+ "use strict";
79429
+ init_project_source_identifiers();
79430
+ }
79431
+ });
79432
+
79433
+ // ../src/database/project-version-validation.ts
79434
+ function validateProjectRecordByKind(recordKind, data) {
79435
+ if (recordKind === ProjectRecordKind.Project) {
79436
+ if (isProject(data)) return;
79437
+ }
79438
+ if (recordKind === ProjectRecordKind.Member) {
79439
+ if (isAnyMember(data)) return;
79440
+ }
79441
+ if (recordKind === ProjectRecordKind.Value) {
79442
+ if (isMemberValue(data)) return;
79443
+ }
79444
+ if (recordKind === ProjectRecordKind.Class) {
79445
+ if (isNeoSchemaClass(data)) return;
79446
+ }
79447
+ if (recordKind === ProjectRecordKind.Constructor) {
79448
+ if (isNeoClassConstructor(data)) return;
79449
+ if (isNeoClassConstructorBase(data)) return;
79450
+ }
79451
+ if (recordKind === ProjectRecordKind.InternalRecordRelation) {
79452
+ if (isInternalRecordRelation(data)) return;
79453
+ }
79454
+ if (recordKind === ProjectRecordKind.Enum) {
79455
+ if (isEnum(data)) return;
79456
+ }
79457
+ if (recordKind === ProjectRecordKind.Interface) {
79458
+ if (isNeoInterface(data)) return;
79459
+ }
79460
+ if (recordKind === ProjectRecordKind.Dialogue) {
79461
+ if (isDialogueRecord(data)) return;
79462
+ if (isDialogue(data)) return;
79463
+ }
79464
+ if (recordKind === ProjectRecordKind.DialogueNode) {
79465
+ if (isDialogueNodeRecord(data)) return;
79466
+ }
79467
+ if (recordKind === ProjectRecordKind.DialogueGroup) {
79468
+ if (isAnyDialogueGroup(data)) return;
79469
+ }
79470
+ if (recordKind === ProjectRecordKind.PriorityGroup) {
79471
+ if (isPriorityGroup(data)) return;
79472
+ }
79473
+ if (recordKind === ProjectRecordKind.ProjectFile) {
79474
+ if (isProjectFile(data)) return;
79475
+ }
79476
+ if (recordKind === ProjectRecordKind.UnityTextureTemplate) {
79477
+ if (isUnityTexture2DImportSettingsTemplate(data)) {
79478
+ assertProjectFileAuthoringRecordIdentifiers(recordKind, data);
79479
+ return;
79480
+ }
79481
+ }
79482
+ if (recordKind === ProjectRecordKind.UnityAudioClipTemplate) {
79483
+ if (isUnityAudioClipImportSettingsTemplate(data)) {
79484
+ assertProjectFileAuthoringRecordIdentifiers(recordKind, data);
79485
+ return;
79486
+ }
79487
+ }
79488
+ if (recordKind === ProjectRecordKind.LocalizationConfig) {
79489
+ if (isProjectLocalizationConfig(data)) return;
79490
+ }
79491
+ if (recordKind === ProjectRecordKind.LocalizationStatus) {
79492
+ if (isLocalizationStatus(data)) return;
79493
+ }
79494
+ if (recordKind === ProjectRecordKind.LocalizedText) {
79495
+ if (isLocalizedText(data)) return;
79496
+ }
79497
+ if (recordKind === ProjectRecordKind.Migration) {
79498
+ if (isProjectMigration(data)) return;
79499
+ }
79500
+ const shape = typeof data === "object" && data !== null ? `keys [${Object.keys(data).sort().join(", ")}]` : `type ${typeof data}`;
79501
+ throw new Error(
79502
+ `Project record data failed validation for record kind "${recordKind}" (${shape}).`
79503
+ );
79504
+ }
79505
+ var init_project_version_validation = __esm({
79506
+ "../src/database/project-version-validation.ts"() {
79507
+ "use strict";
79508
+ init_project2();
79509
+ init_internal_record_relations();
79510
+ init_world_content_sidecar_validation();
79511
+ init_members();
79512
+ init_classes();
79513
+ init_constructors2();
79514
+ init_inheritance();
79515
+ init_generics();
79516
+ init_enum2();
79517
+ init_interfaces();
79518
+ init_dialogue();
79519
+ init_project2();
79520
+ init_files();
79521
+ init_localization2();
79522
+ init_unity();
79523
+ init_project_file_authoring_identifiers();
79524
+ init_animation_clips();
79525
+ }
79526
+ });
79527
+
79239
79528
  // src/commands/push-change-intent.ts
79240
79529
  function createNeoCliPushIntent(change) {
79241
79530
  const intentType = `${change.recordKind}.${change.kind}`;
@@ -80247,6 +80536,7 @@ async function prepareLocalPushArtifactsV4(workspace, status) {
80247
80536
  binaryChanges: status.binaryChanges ?? [],
80248
80537
  assignedIds: pendingAssignment.assigned
80249
80538
  });
80539
+ assertPushedRecordsPassDomainGuards(status.changes);
80250
80540
  verifyProjectSourceCommitAgainstStateV4({
80251
80541
  projectId: workspace.config.projectId,
80252
80542
  versionId: workspace.config.versionId,
@@ -80266,6 +80556,37 @@ async function prepareLocalPushArtifactsV4(workspace, status) {
80266
80556
  preparedFiles
80267
80557
  };
80268
80558
  }
80559
+ function assertPushedRecordsPassDomainGuards(changes) {
80560
+ for (const change of changes) {
80561
+ if (change.kind === "delete") continue;
80562
+ if (change.nextData === void 0) continue;
80563
+ if (SERVER_MINTED_PUSH_RECORD_KINDS.has(change.recordKind)) continue;
80564
+ if (change.kind === "create" && SERVER_COMPLETED_PUSH_RECORD_CREATE_KINDS.has(change.recordKind)) {
80565
+ continue;
80566
+ }
80567
+ if (!isProjectRecordKind(change.recordKind)) {
80568
+ throw new Error(
80569
+ `Cannot push ${change.recordKind} "${change.recordId}"${describeChangeOrigin(change)}: "${change.recordKind}" is not a project record kind.`
80570
+ );
80571
+ }
80572
+ try {
80573
+ validateProjectRecordByKind(change.recordKind, change.nextData);
80574
+ } catch (error) {
80575
+ const detail = error instanceof Error ? error.message : String(error);
80576
+ throw new Error(
80577
+ `Cannot push ${change.kind} ${change.recordKind} "${change.recordId}"${describeChangeOrigin(change)}: ${detail}`
80578
+ );
80579
+ }
80580
+ }
80581
+ }
80582
+ function describeChangeOrigin(change) {
80583
+ const name = change.nextData?.name;
80584
+ const parts = [];
80585
+ if (typeof name === "string" && name.length > 0) parts.push(name);
80586
+ if (change.file !== null) parts.push(change.file);
80587
+ if (parts.length === 0) return "";
80588
+ return ` (${parts.join(" in ")})`;
80589
+ }
80269
80590
  function cloneStatusForDryRun(status) {
80270
80591
  return {
80271
80592
  ...status,
@@ -81545,7 +81866,7 @@ function compileMigrationAction(schema, migrationData, locator) {
81545
81866
  locator
81546
81867
  );
81547
81868
  }
81548
- var compileNSAction2, compileNSFunction2, compileNSGetter2, compileNSSetter2, ProjectTransactionInterruptedError, ProjectTransactionFailedError, PROJECT_TRANSACTION_POLL_DELAYS_MS;
81869
+ var compileNSAction2, compileNSFunction2, compileNSGetter2, compileNSSetter2, ProjectTransactionInterruptedError, ProjectTransactionFailedError, PROJECT_TRANSACTION_POLL_DELAYS_MS, SERVER_MINTED_PUSH_RECORD_KINDS, SERVER_COMPLETED_PUSH_RECORD_CREATE_KINDS;
81549
81870
  var init_push = __esm({
81550
81871
  "src/commands/push.ts"() {
81551
81872
  "use strict";
@@ -81568,6 +81889,8 @@ var init_push = __esm({
81568
81889
  init_projection();
81569
81890
  init_project_file_push();
81570
81891
  init_trusted_commit_verification();
81892
+ init_project_version_validation();
81893
+ init_project2();
81571
81894
  init_world_system_classes();
81572
81895
  init_project_manifest();
81573
81896
  init_merge();
@@ -81602,6 +81925,12 @@ var init_push = __esm({
81602
81925
  4e3,
81603
81926
  5e3
81604
81927
  ];
81928
+ SERVER_MINTED_PUSH_RECORD_KINDS = /* @__PURE__ */ new Set([
81929
+ "project-file"
81930
+ ]);
81931
+ SERVER_COMPLETED_PUSH_RECORD_CREATE_KINDS = /* @__PURE__ */ new Set([
81932
+ "localized-text"
81933
+ ]);
81605
81934
  }
81606
81935
  });
81607
81936
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.19.1",
3
+ "version": "0.19.3",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",