@happyvertical/smrt-core 0.57.46 → 0.57.47

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 (189) hide show
  1. package/AGENTS.md +11 -3
  2. package/agents/browser-entry.md +16 -0
  3. package/agents/build-knowledge.md +58 -14
  4. package/agents/change-feed.md +20 -0
  5. package/agents/generators.md +69 -3
  6. package/agents/schema-paths.md +82 -0
  7. package/dist/_virtual/_rolldown/runtime.js +22 -1
  8. package/dist/browser.d.ts +2 -2
  9. package/dist/browser.d.ts.map +1 -1
  10. package/dist/browser.js +2 -2
  11. package/dist/cascade.d.ts +46 -0
  12. package/dist/cascade.d.ts.map +1 -1
  13. package/dist/cascade.js +96 -7
  14. package/dist/cascade.js.map +1 -1
  15. package/dist/change-feed.d.ts.map +1 -1
  16. package/dist/change-feed.js +7 -4
  17. package/dist/change-feed.js.map +1 -1
  18. package/dist/class.d.ts.map +1 -1
  19. package/dist/class.js +3 -3
  20. package/dist/class.js.map +1 -1
  21. package/dist/consumer-plugin/index.d.ts +13 -0
  22. package/dist/consumer-plugin/index.d.ts.map +1 -1
  23. package/dist/consumer-plugin/index.js +69 -13
  24. package/dist/consumer-plugin/index.js.map +1 -1
  25. package/dist/consumer-plugin.js +2 -2
  26. package/dist/database.d.ts.map +1 -1
  27. package/dist/database.js +3 -3
  28. package/dist/database.js.map +1 -1
  29. package/dist/dispatch/bus.d.ts.map +1 -1
  30. package/dist/dispatch/bus.js +1 -4
  31. package/dist/dispatch/bus.js.map +1 -1
  32. package/dist/dispatch/index.d.ts +1 -1
  33. package/dist/dispatch/index.d.ts.map +1 -1
  34. package/dist/dispatch/types.d.ts +22 -3
  35. package/dist/dispatch/types.d.ts.map +1 -1
  36. package/dist/generators/changes-route.d.ts.map +1 -1
  37. package/dist/generators/changes-route.js +2 -2
  38. package/dist/generators/changes-route.js.map +1 -1
  39. package/dist/generators/custom-action.d.ts +11 -0
  40. package/dist/generators/custom-action.d.ts.map +1 -1
  41. package/dist/generators/custom-action.js +23 -4
  42. package/dist/generators/custom-action.js.map +1 -1
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +3 -2
  46. package/dist/lazy-config.d.ts +120 -3
  47. package/dist/lazy-config.d.ts.map +1 -1
  48. package/dist/lazy-config.js +81 -10
  49. package/dist/lazy-config.js.map +1 -1
  50. package/dist/manifest/generator.d.ts +8 -2
  51. package/dist/manifest/generator.d.ts.map +1 -1
  52. package/dist/manifest/generator.js +6 -5
  53. package/dist/manifest/generator.js.map +1 -1
  54. package/dist/manifest/index.d.ts +1 -0
  55. package/dist/manifest/index.d.ts.map +1 -1
  56. package/dist/manifest/index.js +2 -1
  57. package/dist/manifest/index.js.map +1 -1
  58. package/dist/manifest/local-manifest-reader.d.ts +13 -2
  59. package/dist/manifest/local-manifest-reader.d.ts.map +1 -1
  60. package/dist/manifest/local-manifest-reader.js +38 -6
  61. package/dist/manifest/local-manifest-reader.js.map +1 -1
  62. package/dist/manifest/manifest-loader.d.ts +9 -8
  63. package/dist/manifest/manifest-loader.d.ts.map +1 -1
  64. package/dist/manifest/manifest-loader.js +67 -27
  65. package/dist/manifest/manifest-loader.js.map +1 -1
  66. package/dist/manifest/object-declarations.d.ts +116 -0
  67. package/dist/manifest/object-declarations.d.ts.map +1 -0
  68. package/dist/manifest/object-declarations.js +161 -0
  69. package/dist/manifest/object-declarations.js.map +1 -0
  70. package/dist/manifest/static-manifest.d.ts.map +1 -1
  71. package/dist/manifest/static-manifest.js +5 -3
  72. package/dist/manifest/static-manifest.js.map +1 -1
  73. package/dist/manifest/store.d.ts.map +1 -1
  74. package/dist/manifest/store.js +18 -2
  75. package/dist/manifest/store.js.map +1 -1
  76. package/dist/manifest/test-artifacts.d.ts +57 -0
  77. package/dist/manifest/test-artifacts.d.ts.map +1 -0
  78. package/dist/manifest/test-artifacts.js +111 -0
  79. package/dist/manifest/test-artifacts.js.map +1 -0
  80. package/dist/manifest.js +2 -1
  81. package/dist/manifest.json +5 -3
  82. package/dist/migrations/differ.d.ts.map +1 -1
  83. package/dist/migrations/differ.js +11 -3
  84. package/dist/migrations/differ.js.map +1 -1
  85. package/dist/migrations/index.d.ts +2 -0
  86. package/dist/migrations/index.d.ts.map +1 -1
  87. package/dist/migrations/index.js +3 -1
  88. package/dist/migrations/qualified-name-aliases.d.ts.map +1 -1
  89. package/dist/migrations/qualified-name-aliases.js +1 -1
  90. package/dist/migrations/qualified-name-aliases.js.map +1 -1
  91. package/dist/migrations.js +3 -1
  92. package/dist/object.d.ts.map +1 -1
  93. package/dist/object.js +2 -2
  94. package/dist/object.js.map +1 -1
  95. package/dist/postgres-permissions.d.ts.map +1 -1
  96. package/dist/postgres-permissions.js +4 -3
  97. package/dist/postgres-permissions.js.map +1 -1
  98. package/dist/postgres-timeouts.d.ts +30 -3
  99. package/dist/postgres-timeouts.d.ts.map +1 -1
  100. package/dist/postgres-timeouts.js +39 -2
  101. package/dist/postgres-timeouts.js.map +1 -1
  102. package/dist/prebuild/index.d.ts.map +1 -1
  103. package/dist/prebuild/index.js +14 -11
  104. package/dist/prebuild/index.js.map +1 -1
  105. package/dist/registry/class-registration.d.ts.map +1 -1
  106. package/dist/registry/class-registration.js +24 -2
  107. package/dist/registry/class-registration.js.map +1 -1
  108. package/dist/registry/collection-exposure.d.ts +27 -0
  109. package/dist/registry/collection-exposure.d.ts.map +1 -1
  110. package/dist/registry/collection-exposure.js +74 -1
  111. package/dist/registry/collection-exposure.js.map +1 -1
  112. package/dist/registry/collection-resolution.d.ts.map +1 -1
  113. package/dist/registry/collection-resolution.js +1 -0
  114. package/dist/registry/collection-resolution.js.map +1 -1
  115. package/dist/registry/framework-base-classes.d.ts.map +1 -1
  116. package/dist/registry/framework-base-classes.js +5 -0
  117. package/dist/registry/framework-base-classes.js.map +1 -1
  118. package/dist/registry/schema-builder.d.ts +8 -1
  119. package/dist/registry/schema-builder.d.ts.map +1 -1
  120. package/dist/registry/schema-builder.js +17 -4
  121. package/dist/registry/schema-builder.js.map +1 -1
  122. package/dist/registry/types.d.ts +12 -0
  123. package/dist/registry/types.d.ts.map +1 -1
  124. package/dist/registry.d.ts +2 -1
  125. package/dist/registry.d.ts.map +1 -1
  126. package/dist/registry.js +30 -10
  127. package/dist/registry.js.map +1 -1
  128. package/dist/scanner/manifest-generator.d.ts.map +1 -1
  129. package/dist/scanner/manifest-generator.js +10 -8
  130. package/dist/scanner/manifest-generator.js.map +1 -1
  131. package/dist/scanner/types.d.ts +29 -0
  132. package/dist/scanner/types.d.ts.map +1 -1
  133. package/dist/scanner/types.js.map +1 -1
  134. package/dist/schema/generator.d.ts +32 -0
  135. package/dist/schema/generator.d.ts.map +1 -1
  136. package/dist/schema/generator.js +59 -0
  137. package/dist/schema/generator.js.map +1 -1
  138. package/dist/schema/live-parity.d.ts.map +1 -1
  139. package/dist/schema/live-parity.js +4 -2
  140. package/dist/schema/live-parity.js.map +1 -1
  141. package/dist/scripts/browser-unbundled-dev.mjs +90 -0
  142. package/dist/scripts/generate-test-manifest.js +9 -49
  143. package/dist/smrt-knowledge.json +16 -16
  144. package/dist/system/compatibility.d.ts.map +1 -1
  145. package/dist/system/compatibility.js +12 -4
  146. package/dist/system/compatibility.js.map +1 -1
  147. package/dist/system/schema.d.ts +70 -8
  148. package/dist/system/schema.d.ts.map +1 -1
  149. package/dist/system/schema.js +231 -24
  150. package/dist/system/schema.js.map +1 -1
  151. package/dist/testing/database.d.ts.map +1 -1
  152. package/dist/testing/database.js +14 -2
  153. package/dist/testing/database.js.map +1 -1
  154. package/dist/tools/tool-generator.d.ts.map +1 -1
  155. package/dist/tools/tool-generator.js +2 -2
  156. package/dist/tools/tool-generator.js.map +1 -1
  157. package/dist/utils/import-workspace-module.d.ts.map +1 -1
  158. package/dist/utils/import-workspace-module.js +23 -0
  159. package/dist/utils/import-workspace-module.js.map +1 -1
  160. package/dist/utils/naming.js +5 -3
  161. package/dist/utils/naming.js.map +1 -1
  162. package/dist/vendor/pluralize/pluralize.js +421 -0
  163. package/dist/vendor/pluralize/pluralize.js.map +1 -0
  164. package/dist/vite-plugin/api-client-entries.d.ts +5 -1
  165. package/dist/vite-plugin/api-client-entries.d.ts.map +1 -1
  166. package/dist/vite-plugin/api-client-entries.js +11 -6
  167. package/dist/vite-plugin/api-client-entries.js.map +1 -1
  168. package/dist/vite-plugin/consumer-import.d.ts +28 -0
  169. package/dist/vite-plugin/consumer-import.d.ts.map +1 -0
  170. package/dist/vite-plugin/consumer-import.js +42 -0
  171. package/dist/vite-plugin/consumer-import.js.map +1 -0
  172. package/dist/vite-plugin/dev-plane-route.d.ts +6 -1
  173. package/dist/vite-plugin/dev-plane-route.d.ts.map +1 -1
  174. package/dist/vite-plugin/dev-plane-route.js +8 -9
  175. package/dist/vite-plugin/dev-plane-route.js.map +1 -1
  176. package/dist/vite-plugin/index.d.ts.map +1 -1
  177. package/dist/vite-plugin/index.js +12 -9
  178. package/dist/vite-plugin/index.js.map +1 -1
  179. package/dist/vite-plugin/resources-route.d.ts.map +1 -1
  180. package/dist/vite-plugin/resources-route.js +3 -8
  181. package/dist/vite-plugin/resources-route.js.map +1 -1
  182. package/dist/vite-plugin/sveltekit-generator.d.ts.map +1 -1
  183. package/dist/vite-plugin/sveltekit-generator.js +7 -11
  184. package/dist/vite-plugin/sveltekit-generator.js.map +1 -1
  185. package/dist/vite-plugin/sync-apply-route.d.ts +16 -0
  186. package/dist/vite-plugin/sync-apply-route.d.ts.map +1 -1
  187. package/dist/vite-plugin/sync-apply-route.js +48 -6
  188. package/dist/vite-plugin/sync-apply-route.js.map +1 -1
  189. package/package.json +12 -12
@@ -1,3 +1,4 @@
1
+ import { SMRT_TEST_MANIFEST_PATHS_ENV_KEY, isActiveTestManifestPath, isRefusedTestArtifact, isTestArtifactManifest, registerActiveTestManifestPath, resolveActiveTestManifestPath } from "./test-artifacts.js";
1
2
  import { discoverManifestEntry, findManifestEntryByQualifiedName, loadExternalManifest, loadExternalManifestSync, loadLocalTestManifestSync, loadManifestFromPathSync } from "./manifest-loader.js";
2
3
  import { ManifestGenerator } from "../scanner/manifest-generator.js";
3
4
  import { ManifestManager } from "./manager.js";
@@ -41,6 +42,6 @@ function getManifest() {
41
42
  return Promise.resolve(manifest);
42
43
  }
43
44
  //#endregion
44
- export { ManifestBuilder, ManifestGenerator, ManifestManager, manifest as default, manifest, discoverManifestEntry, findManifestEntryByQualifiedName, getManifest, loadExternalManifest, loadExternalManifestSync, loadLocalTestManifestSync, loadManifestFromPathSync, staticManifest };
45
+ export { ManifestBuilder, ManifestGenerator, ManifestManager, SMRT_TEST_MANIFEST_PATHS_ENV_KEY, manifest as default, manifest, discoverManifestEntry, findManifestEntryByQualifiedName, getManifest, isActiveTestManifestPath, isRefusedTestArtifact, isTestArtifactManifest, loadExternalManifest, loadExternalManifestSync, loadLocalTestManifestSync, loadManifestFromPathSync, registerActiveTestManifestPath, resolveActiveTestManifestPath, staticManifest };
45
46
 
46
47
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/manifest/index.ts"],"sourcesContent":["/**\n * Static manifest module for runtime use\n * Uses pre-generated manifest from build time instead of runtime scanning\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SmartObjectManifest } from '../scanner/types';\n\n// Re-export utility functions that work with static manifest\nexport { ManifestGenerator } from '../scanner/manifest-generator';\nexport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types';\nexport type { ManifestBuilderOptions } from './generator';\nexport { ManifestBuilder } from './generator';\nexport { ManifestManager } from './manager';\nexport {\n discoverManifestEntry,\n findManifestEntryByQualifiedName,\n loadExternalManifest,\n loadExternalManifestSync,\n loadLocalTestManifestSync,\n loadManifestFromPathSync,\n} from './manifest-loader';\n\nconst EMPTY_STATIC_MANIFEST: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: 0,\n objects: {},\n packageName: '@happyvertical/smrt-core',\n};\n\nfunction loadStaticManifest(): SmartObjectManifest {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const manifestCandidates = [\n join(currentDir, 'static-manifest.json'),\n join(currentDir, '..', 'manifest.json'),\n join(currentDir, '..', '..', 'dist', 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (!existsSync(manifestPath)) {\n continue;\n }\n\n try {\n return JSON.parse(readFileSync(manifestPath, 'utf-8'));\n } catch {\n // Fall through to the next candidate or the empty manifest.\n }\n }\n\n return EMPTY_STATIC_MANIFEST;\n}\n\nexport const manifest = loadStaticManifest();\nexport const staticManifest = manifest;\nexport default manifest;\n\n/**\n * Get manifest data (static at runtime)\n * No longer requires TypeScript compiler or file scanning.\n */\nexport function getManifest() {\n return Promise.resolve(manifest);\n}\n"],"mappings":";;;;;;;;;;;;AA4BA,IAAM,wBAA6C;CACjD,SAAS;CACT,WAAW;CACX,SAAS,CAAC;CACV,aAAa;AACf;AAEA,SAAS,qBAA0C;CACjD,MAAM,aAAa,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CACzD,MAAM,qBAAqB;EACzB,KAAK,YAAY,sBAAsB;EACvC,KAAK,YAAY,MAAM,eAAe;EACtC,KAAK,YAAY,MAAM,MAAM,QAAQ,eAAe;CACtD;CAEA,KAAK,MAAM,gBAAgB,oBAAoB;EAC7C,IAAI,CAAC,WAAW,YAAY,GAC1B;EAGF,IAAI;GACF,OAAO,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;EACvD,QAAQ,CAER;CACF;CAEA,OAAO;AACT;AAEA,IAAa,WAAW,mBAAmB;AAC3C,IAAa,iBAAiB;;;;;AAO9B,SAAgB,cAAc;CAC5B,OAAO,QAAQ,QAAQ,QAAQ;AACjC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/manifest/index.ts"],"sourcesContent":["/**\n * Static manifest module for runtime use\n * Uses pre-generated manifest from build time instead of runtime scanning\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { SmartObjectManifest } from '../scanner/types';\n\n// Re-export utility functions that work with static manifest\nexport { ManifestGenerator } from '../scanner/manifest-generator';\nexport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '../scanner/types';\nexport type { ManifestBuilderOptions } from './generator';\nexport { ManifestBuilder } from './generator';\nexport { ManifestManager } from './manager';\nexport {\n discoverManifestEntry,\n findManifestEntryByQualifiedName,\n loadExternalManifest,\n loadExternalManifestSync,\n loadLocalTestManifestSync,\n loadManifestFromPathSync,\n} from './manifest-loader';\nexport {\n isActiveTestManifestPath,\n isRefusedTestArtifact,\n isTestArtifactManifest,\n registerActiveTestManifestPath,\n resolveActiveTestManifestPath,\n SMRT_TEST_MANIFEST_PATHS_ENV_KEY,\n} from './test-artifacts';\n\nconst EMPTY_STATIC_MANIFEST: SmartObjectManifest = {\n version: '1.0.0',\n timestamp: 0,\n objects: {},\n packageName: '@happyvertical/smrt-core',\n};\n\nfunction loadStaticManifest(): SmartObjectManifest {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const manifestCandidates = [\n join(currentDir, 'static-manifest.json'),\n join(currentDir, '..', 'manifest.json'),\n join(currentDir, '..', '..', 'dist', 'manifest.json'),\n ];\n\n for (const manifestPath of manifestCandidates) {\n if (!existsSync(manifestPath)) {\n continue;\n }\n\n try {\n return JSON.parse(readFileSync(manifestPath, 'utf-8'));\n } catch {\n // Fall through to the next candidate or the empty manifest.\n }\n }\n\n return EMPTY_STATIC_MANIFEST;\n}\n\nexport const manifest = loadStaticManifest();\nexport const staticManifest = manifest;\nexport default manifest;\n\n/**\n * Get manifest data (static at runtime)\n * No longer requires TypeScript compiler or file scanning.\n */\nexport function getManifest() {\n return Promise.resolve(manifest);\n}\n"],"mappings":";;;;;;;;;;;;;AAoCA,IAAM,wBAA6C;CACjD,SAAS;CACT,WAAW;CACX,SAAS,CAAC;CACV,aAAa;AACf;AAEA,SAAS,qBAA0C;CACjD,MAAM,aAAa,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CACzD,MAAM,qBAAqB;EACzB,KAAK,YAAY,sBAAsB;EACvC,KAAK,YAAY,MAAM,eAAe;EACtC,KAAK,YAAY,MAAM,MAAM,QAAQ,eAAe;CACtD;CAEA,KAAK,MAAM,gBAAgB,oBAAoB;EAC7C,IAAI,CAAC,WAAW,YAAY,GAC1B;EAGF,IAAI;GACF,OAAO,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;EACvD,QAAQ,CAER;CACF;CAEA,OAAO;AACT;AAEA,IAAa,WAAW,mBAAmB;AAC3C,IAAa,iBAAiB;;;;;AAO9B,SAAgB,cAAc;CAC5B,OAAO,QAAQ,QAAQ,QAAQ;AACjC"}
@@ -19,6 +19,12 @@ export interface ManifestFileAccess {
19
19
  * `src/manifest/manifest.json`. When loading a local project, the dev path takes
20
20
  * priority; for external packages (dependencies), the build path takes priority
21
21
  * to avoid pulling in test objects.
22
+ *
23
+ * Inside a test run, the run's active test manifest snapshot (see
24
+ * `test-artifacts.ts`, #4128) precedes every local path. A manifest marked
25
+ * `artifactPurpose: 'test'` found anywhere else is skipped (#2760). It is never written
26
+ * to, or read from, the standard locations, so a concurrent build cannot
27
+ * replace it and a process outside the run never reads it.
22
28
  */
23
29
  export declare class LocalManifestReader {
24
30
  protected projectRoot: string;
@@ -29,8 +35,13 @@ export declare class LocalManifestReader {
29
35
  */
30
36
  getOutputPath(mode: 'dev' | 'build' | 'source'): string;
31
37
  /**
32
- * Loads the local manifest from the standard locations.
33
- * Priority: .smrt/manifest.json -> dist/manifest.json -> src/manifest/manifest.json
38
+ * The paths {@link loadLocal} reads, in priority order: the active test
39
+ * manifest snapshot (only inside a test run that registered one), then
40
+ * `.smrt/manifest.json`, `dist/manifest.json`, `src/manifest/manifest.json`.
41
+ */
42
+ getLocalCandidatePaths(): string[];
43
+ /**
44
+ * Loads the local manifest from {@link getLocalCandidatePaths}.
34
45
  */
35
46
  loadLocal(): SmartObjectManifest | null;
36
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"local-manifest-reader.d.ts","sourceRoot":"","sources":["../../src/manifest/local-manifest-reader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;CACvD;AAOD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,mBAAmB;IAE5B,SAAS,CAAC,WAAW,EAAE,MAAM;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADZ,WAAW,EAAE,MAAM,EACZ,KAAK,GAAE,kBAAmC;IAG7D;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM;IAUvD;;;OAGG;IACH,SAAS,IAAI,mBAAmB,GAAG,IAAI;IAQvC;;;;;;;;OAQG;IACH,sBAAsB,IAAI,mBAAmB,GAAG,IAAI;IAQpD,OAAO,CAAC,cAAc;CAgBvB"}
1
+ {"version":3,"file":"local-manifest-reader.d.ts","sourceRoot":"","sources":["../../src/manifest/local-manifest-reader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAO/D,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;CACvD;AAaD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,mBAAmB;IAE5B,SAAS,CAAC,WAAW,EAAE,MAAM;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADZ,WAAW,EAAE,MAAM,EACZ,KAAK,GAAE,kBAAmC;IAG7D;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM;IAUvD;;;;OAIG;IACH,sBAAsB,IAAI,MAAM,EAAE;IAsBlC;;OAEG;IACH,SAAS,IAAI,mBAAmB,GAAG,IAAI;IAIvC;;;;;;;;OAQG;IACH,sBAAsB,IAAI,mBAAmB,GAAG,IAAI;IAQpD,OAAO,CAAC,cAAc;CA4BvB"}
@@ -1,3 +1,4 @@
1
+ import { isRefusedTestArtifact, resolveActiveTestManifestPath } from "./test-artifacts.js";
1
2
  import { existsSync, join, readFileSync } from "./node-host.js";
2
3
  import { createLogger } from "@happyvertical/logger";
3
4
  //#region src/manifest/local-manifest-reader.ts
@@ -7,6 +8,10 @@ var hostFileAccess = {
7
8
  readFileSync
8
9
  };
9
10
  var logger = createLogger({ level: "info" });
11
+ /** Registered test snapshots already reported missing, so each warns once. */
12
+ var reportedMissingTestManifests = /* @__PURE__ */ new Set();
13
+ /** Refused test artifacts already reported, so each warns once. */
14
+ var reportedRefusedTestArtifacts = /* @__PURE__ */ new Set();
10
15
  /**
11
16
  * Reads SMRT manifests for a project from the standard locations.
12
17
  *
@@ -22,6 +27,12 @@ var logger = createLogger({ level: "info" });
22
27
  * `src/manifest/manifest.json`. When loading a local project, the dev path takes
23
28
  * priority; for external packages (dependencies), the build path takes priority
24
29
  * to avoid pulling in test objects.
30
+ *
31
+ * Inside a test run, the run's active test manifest snapshot (see
32
+ * `test-artifacts.ts`, #4128) precedes every local path. A manifest marked
33
+ * `artifactPurpose: 'test'` found anywhere else is skipped (#2760). It is never written
34
+ * to, or read from, the standard locations, so a concurrent build cannot
35
+ * replace it and a process outside the run never reads it.
25
36
  */
26
37
  var LocalManifestReader = class {
27
38
  projectRoot;
@@ -39,15 +50,28 @@ var LocalManifestReader = class {
39
50
  return join(this.projectRoot, "dist/manifest.json");
40
51
  }
41
52
  /**
42
- * Loads the local manifest from the standard locations.
43
- * Priority: .smrt/manifest.json -> dist/manifest.json -> src/manifest/manifest.json
53
+ * The paths {@link loadLocal} reads, in priority order: the active test
54
+ * manifest snapshot (only inside a test run that registered one), then
55
+ * `.smrt/manifest.json`, `dist/manifest.json`, `src/manifest/manifest.json`.
44
56
  */
45
- loadLocal() {
46
- return this._loadFromPaths([
57
+ getLocalCandidatePaths() {
58
+ const activeTestManifest = resolveActiveTestManifestPath(this.projectRoot);
59
+ if (activeTestManifest && !this.files.existsSync(activeTestManifest) && !reportedMissingTestManifests.has(activeTestManifest)) {
60
+ reportedMissingTestManifests.add(activeTestManifest);
61
+ logger.warn(`[ManifestManager] The active test manifest ${activeTestManifest} registered for ${this.projectRoot} is missing; falling back to production manifests, so inline test fixtures are not described`);
62
+ }
63
+ return [
64
+ ...activeTestManifest ? [activeTestManifest] : [],
47
65
  this.getOutputPath("dev"),
48
66
  this.getOutputPath("build"),
49
67
  this.getOutputPath("source")
50
- ]);
68
+ ];
69
+ }
70
+ /**
71
+ * Loads the local manifest from {@link getLocalCandidatePaths}.
72
+ */
73
+ loadLocal() {
74
+ return this._loadFromPaths(this.getLocalCandidatePaths());
51
75
  }
52
76
  /**
53
77
  * Loads the manifest for an external package (dependency).
@@ -68,7 +92,15 @@ var LocalManifestReader = class {
68
92
  _loadFromPaths(paths) {
69
93
  for (const path of paths) if (this.files.existsSync(path)) try {
70
94
  const content = this.files.readFileSync(path, "utf-8");
71
- return JSON.parse(content);
95
+ const manifest = JSON.parse(content);
96
+ if (isRefusedTestArtifact(manifest, path)) {
97
+ if (!reportedRefusedTestArtifacts.has(path)) {
98
+ reportedRefusedTestArtifacts.add(path);
99
+ logger.warn(`[ManifestManager] Skipping test artifact at ${path}: a test run's manifest is not a build output, and this process is not that run (rebuild to replace it)`);
100
+ }
101
+ continue;
102
+ }
103
+ return manifest;
72
104
  } catch (error) {
73
105
  logger.error(`[ManifestManager] Failed to read manifest at ${path}`, { error });
74
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"local-manifest-reader.js","names":[],"sources":["../../src/manifest/local-manifest-reader.ts"],"sourcesContent":["import { createLogger } from '@happyvertical/logger';\nimport type { SmartObjectManifest } from '../scanner/types.js';\nimport { existsSync, join, readFileSync } from './node-host.js';\n\n/** The two filesystem reads a manifest load needs. */\nexport interface ManifestFileAccess {\n existsSync(path: string): boolean;\n readFileSync(path: string, encoding: 'utf-8'): string;\n}\n\n/** Resolved through the lazy Node host: absent files on a host without one. */\nconst hostFileAccess: ManifestFileAccess = { existsSync, readFileSync };\n\nconst logger = createLogger({ level: 'info' });\n\n/**\n * Reads SMRT manifests for a project from the standard locations.\n *\n * @remarks\n * The read half of `ManifestManager`, split out so the registry's manifest\n * discovery does not pull the write and generation half (`node:fs` writes,\n * the AST scanner) into a browser bundle (#2838). Filesystem access goes\n * through `node-host.ts`, so without a Node host every load finds nothing.\n *\n * Manifests are JSON files containing class/field metadata produced by the AST scanner.\n * Dev manifests live at `.smrt/manifest.json`; build manifests at `dist/manifest.json`.\n * Workspace packages may also provide a checked-in source manifest at\n * `src/manifest/manifest.json`. When loading a local project, the dev path takes\n * priority; for external packages (dependencies), the build path takes priority\n * to avoid pulling in test objects.\n */\nexport class LocalManifestReader {\n constructor(\n protected projectRoot: string,\n private readonly files: ManifestFileAccess = hostFileAccess,\n ) {}\n\n /**\n * Get the standard output path for the manifest based on mode.\n */\n getOutputPath(mode: 'dev' | 'build' | 'source'): string {\n if (mode === 'dev') {\n return join(this.projectRoot, '.smrt/manifest.json');\n }\n if (mode === 'source') {\n return join(this.projectRoot, 'src/manifest/manifest.json');\n }\n return join(this.projectRoot, 'dist/manifest.json');\n }\n\n /**\n * Loads the local manifest from the standard locations.\n * Priority: .smrt/manifest.json -> dist/manifest.json -> src/manifest/manifest.json\n */\n loadLocal(): SmartObjectManifest | null {\n return this._loadFromPaths([\n this.getOutputPath('dev'),\n this.getOutputPath('build'),\n this.getOutputPath('source'),\n ]);\n }\n\n /**\n * Loads the manifest for an external package (dependency).\n * Priority: dist/manifest.json -> .smrt/manifest.json -> src/manifest/manifest.json\n *\n * External packages should prefer their production (dist) manifest\n * over the dev/test (.smrt) manifest to avoid pulling in test objects\n * and transitive dependencies. In a workspace, the checked-in source manifest\n * provides the same package metadata even when the sibling package has not been built yet.\n */\n loadForExternalPackage(): SmartObjectManifest | null {\n return this._loadFromPaths([\n this.getOutputPath('build'),\n this.getOutputPath('dev'),\n this.getOutputPath('source'),\n ]);\n }\n\n private _loadFromPaths(paths: string[]): SmartObjectManifest | null {\n for (const path of paths) {\n if (this.files.existsSync(path)) {\n try {\n const content = this.files.readFileSync(path, 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n logger.error(`[ManifestManager] Failed to read manifest at ${path}`, {\n error,\n });\n }\n }\n }\n\n return null;\n }\n}\n"],"mappings":";;;;AAWA,IAAM,iBAAqC;CAAE;CAAY;AAAa;AAEtE,IAAM,SAAS,aAAa,EAAE,OAAO,OAAO,CAAC;;;;;;;;;;;;;;;;;AAkB7C,IAAa,sBAAb,MAAiC;CAEnB;CACO;CAFnB,YACE,aACA,QAA6C,gBAC7C;EAFU,KAAA,cAAA;EACO,KAAA,QAAA;CAChB;;;;CAKH,cAAc,MAA0C;EACtD,IAAI,SAAS,OACX,OAAO,KAAK,KAAK,aAAa,qBAAqB;EAErD,IAAI,SAAS,UACX,OAAO,KAAK,KAAK,aAAa,4BAA4B;EAE5D,OAAO,KAAK,KAAK,aAAa,oBAAoB;CACpD;;;;;CAMA,YAAwC;EACtC,OAAO,KAAK,eAAe;GACzB,KAAK,cAAc,KAAK;GACxB,KAAK,cAAc,OAAO;GAC1B,KAAK,cAAc,QAAQ;EAC7B,CAAC;CACH;;;;;;;;;;CAWA,yBAAqD;EACnD,OAAO,KAAK,eAAe;GACzB,KAAK,cAAc,OAAO;GAC1B,KAAK,cAAc,KAAK;GACxB,KAAK,cAAc,QAAQ;EAC7B,CAAC;CACH;CAEA,eAAuB,OAA6C;EAClE,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,MAAM,WAAW,IAAI,GAC5B,IAAI;GACF,MAAM,UAAU,KAAK,MAAM,aAAa,MAAM,OAAO;GACrD,OAAO,KAAK,MAAM,OAAO;EAC3B,SAAS,OAAO;GACd,OAAO,MAAM,gDAAgD,QAAQ,EACnE,MACF,CAAC;EACH;EAIJ,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"local-manifest-reader.js","names":[],"sources":["../../src/manifest/local-manifest-reader.ts"],"sourcesContent":["import { createLogger } from '@happyvertical/logger';\nimport type { SmartObjectManifest } from '../scanner/types.js';\nimport { existsSync, join, readFileSync } from './node-host.js';\nimport {\n isRefusedTestArtifact,\n resolveActiveTestManifestPath,\n} from './test-artifacts.js';\n\n/** The two filesystem reads a manifest load needs. */\nexport interface ManifestFileAccess {\n existsSync(path: string): boolean;\n readFileSync(path: string, encoding: 'utf-8'): string;\n}\n\n/** Resolved through the lazy Node host: absent files on a host without one. */\nconst hostFileAccess: ManifestFileAccess = { existsSync, readFileSync };\n\nconst logger = createLogger({ level: 'info' });\n\n/** Registered test snapshots already reported missing, so each warns once. */\nconst reportedMissingTestManifests = new Set<string>();\n\n/** Refused test artifacts already reported, so each warns once. */\nconst reportedRefusedTestArtifacts = new Set<string>();\n\n/**\n * Reads SMRT manifests for a project from the standard locations.\n *\n * @remarks\n * The read half of `ManifestManager`, split out so the registry's manifest\n * discovery does not pull the write and generation half (`node:fs` writes,\n * the AST scanner) into a browser bundle (#2838). Filesystem access goes\n * through `node-host.ts`, so without a Node host every load finds nothing.\n *\n * Manifests are JSON files containing class/field metadata produced by the AST scanner.\n * Dev manifests live at `.smrt/manifest.json`; build manifests at `dist/manifest.json`.\n * Workspace packages may also provide a checked-in source manifest at\n * `src/manifest/manifest.json`. When loading a local project, the dev path takes\n * priority; for external packages (dependencies), the build path takes priority\n * to avoid pulling in test objects.\n *\n * Inside a test run, the run's active test manifest snapshot (see\n * `test-artifacts.ts`, #4128) precedes every local path. A manifest marked\n * `artifactPurpose: 'test'` found anywhere else is skipped (#2760). It is never written\n * to, or read from, the standard locations, so a concurrent build cannot\n * replace it and a process outside the run never reads it.\n */\nexport class LocalManifestReader {\n constructor(\n protected projectRoot: string,\n private readonly files: ManifestFileAccess = hostFileAccess,\n ) {}\n\n /**\n * Get the standard output path for the manifest based on mode.\n */\n getOutputPath(mode: 'dev' | 'build' | 'source'): string {\n if (mode === 'dev') {\n return join(this.projectRoot, '.smrt/manifest.json');\n }\n if (mode === 'source') {\n return join(this.projectRoot, 'src/manifest/manifest.json');\n }\n return join(this.projectRoot, 'dist/manifest.json');\n }\n\n /**\n * The paths {@link loadLocal} reads, in priority order: the active test\n * manifest snapshot (only inside a test run that registered one), then\n * `.smrt/manifest.json`, `dist/manifest.json`, `src/manifest/manifest.json`.\n */\n getLocalCandidatePaths(): string[] {\n const activeTestManifest = resolveActiveTestManifestPath(this.projectRoot);\n if (\n activeTestManifest &&\n !this.files.existsSync(activeTestManifest) &&\n !reportedMissingTestManifests.has(activeTestManifest)\n ) {\n // Falling through to the production chain silently would reproduce\n // the #4128 symptom (fixture metadata vanishing) with no signal.\n reportedMissingTestManifests.add(activeTestManifest);\n logger.warn(\n `[ManifestManager] The active test manifest ${activeTestManifest} registered for ${this.projectRoot} is missing; falling back to production manifests, so inline test fixtures are not described`,\n );\n }\n return [\n ...(activeTestManifest ? [activeTestManifest] : []),\n this.getOutputPath('dev'),\n this.getOutputPath('build'),\n this.getOutputPath('source'),\n ];\n }\n\n /**\n * Loads the local manifest from {@link getLocalCandidatePaths}.\n */\n loadLocal(): SmartObjectManifest | null {\n return this._loadFromPaths(this.getLocalCandidatePaths());\n }\n\n /**\n * Loads the manifest for an external package (dependency).\n * Priority: dist/manifest.json -> .smrt/manifest.json -> src/manifest/manifest.json\n *\n * External packages should prefer their production (dist) manifest\n * over the dev/test (.smrt) manifest to avoid pulling in test objects\n * and transitive dependencies. In a workspace, the checked-in source manifest\n * provides the same package metadata even when the sibling package has not been built yet.\n */\n loadForExternalPackage(): SmartObjectManifest | null {\n return this._loadFromPaths([\n this.getOutputPath('build'),\n this.getOutputPath('dev'),\n this.getOutputPath('source'),\n ]);\n }\n\n private _loadFromPaths(paths: string[]): SmartObjectManifest | null {\n for (const path of paths) {\n if (this.files.existsSync(path)) {\n try {\n const content = this.files.readFileSync(path, 'utf-8');\n const manifest = JSON.parse(content);\n // A test artifact is only valid as its own run's active snapshot;\n // anywhere else its inline fixtures are phantom objects (#2760).\n if (isRefusedTestArtifact(manifest, path)) {\n if (!reportedRefusedTestArtifacts.has(path)) {\n reportedRefusedTestArtifacts.add(path);\n logger.warn(\n `[ManifestManager] Skipping test artifact at ${path}: a test run's manifest is not a build output, and this process is not that run (rebuild to replace it)`,\n );\n }\n continue;\n }\n return manifest;\n } catch (error) {\n logger.error(`[ManifestManager] Failed to read manifest at ${path}`, {\n error,\n });\n }\n }\n }\n\n return null;\n }\n}\n"],"mappings":";;;;;AAeA,IAAM,iBAAqC;CAAE;CAAY;AAAa;AAEtE,IAAM,SAAS,aAAa,EAAE,OAAO,OAAO,CAAC;;AAG7C,IAAM,+CAA+B,IAAI,IAAY;;AAGrD,IAAM,+CAA+B,IAAI,IAAY;;;;;;;;;;;;;;;;;;;;;;;AAwBrD,IAAa,sBAAb,MAAiC;CAEnB;CACO;CAFnB,YACE,aACA,QAA6C,gBAC7C;EAFU,KAAA,cAAA;EACO,KAAA,QAAA;CAChB;;;;CAKH,cAAc,MAA0C;EACtD,IAAI,SAAS,OACX,OAAO,KAAK,KAAK,aAAa,qBAAqB;EAErD,IAAI,SAAS,UACX,OAAO,KAAK,KAAK,aAAa,4BAA4B;EAE5D,OAAO,KAAK,KAAK,aAAa,oBAAoB;CACpD;;;;;;CAOA,yBAAmC;EACjC,MAAM,qBAAqB,8BAA8B,KAAK,WAAW;EACzE,IACE,sBACA,CAAC,KAAK,MAAM,WAAW,kBAAkB,KACzC,CAAC,6BAA6B,IAAI,kBAAkB,GACpD;GAGA,6BAA6B,IAAI,kBAAkB;GACnD,OAAO,KACL,8CAA8C,mBAAmB,kBAAkB,KAAK,YAAY,6FACtG;EACF;EACA,OAAO;GACL,GAAI,qBAAqB,CAAC,kBAAkB,IAAI,CAAC;GACjD,KAAK,cAAc,KAAK;GACxB,KAAK,cAAc,OAAO;GAC1B,KAAK,cAAc,QAAQ;EAC7B;CACF;;;;CAKA,YAAwC;EACtC,OAAO,KAAK,eAAe,KAAK,uBAAuB,CAAC;CAC1D;;;;;;;;;;CAWA,yBAAqD;EACnD,OAAO,KAAK,eAAe;GACzB,KAAK,cAAc,OAAO;GAC1B,KAAK,cAAc,KAAK;GACxB,KAAK,cAAc,QAAQ;EAC7B,CAAC;CACH;CAEA,eAAuB,OAA6C;EAClE,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,MAAM,WAAW,IAAI,GAC5B,IAAI;GACF,MAAM,UAAU,KAAK,MAAM,aAAa,MAAM,OAAO;GACrD,MAAM,WAAW,KAAK,MAAM,OAAO;GAGnC,IAAI,sBAAsB,UAAU,IAAI,GAAG;IACzC,IAAI,CAAC,6BAA6B,IAAI,IAAI,GAAG;KAC3C,6BAA6B,IAAI,IAAI;KACrC,OAAO,KACL,+CAA+C,KAAK,wGACtD;IACF;IACA;GACF;GACA,OAAO;EACT,SAAS,OAAO;GACd,OAAO,MAAM,gDAAgD,QAAQ,EACnE,MACF,CAAC;EACH;EAIJ,OAAO;CACT;AACF"}
@@ -65,14 +65,15 @@ export type { FieldDefinition, MethodDefinition };
65
65
  export declare function loadLocalTestManifestSync(): Manifest | null | undefined;
66
66
  /**
67
67
  * The manifest of the project the process runs in (the first of
68
- * `<cwd>/.smrt/manifest.json`, `<cwd>/dist/manifest.json`,
69
- * `<cwd>/src/manifest/manifest.json`, as `LocalManifestReader.loadLocal()` reads
70
- * them), never seeded into the lookup caches. Only consulted to attribute a
71
- * decorated class whose declaring file that manifest describes, when no loaded
72
- * manifest does: a plain Node/tsx script importing an app's workspace-package
73
- * models has not loaded the app's manifest yet (#3109). The read is reused
74
- * only while that file is unchanged, so a dev server that regenerates it is
75
- * seen; a missing manifest is never cached.
68
+ * `LocalManifestReader.getLocalCandidatePaths()`: a test run's active
69
+ * snapshot, then `<cwd>/.smrt/manifest.json`, `<cwd>/dist/manifest.json`,
70
+ * `<cwd>/src/manifest/manifest.json`, skipping a test artifact outside its
71
+ * own run, #2760), never seeded into the lookup caches. Only consulted to
72
+ * attribute a decorated class whose declaring file that manifest describes,
73
+ * when no loaded manifest does: a plain Node/tsx script importing an app's
74
+ * workspace-package models has not loaded the app's manifest yet (#3109).
75
+ * Each read is reused only while that file is unchanged, so a dev server that
76
+ * regenerates it is seen; a missing manifest is never cached.
76
77
  */
77
78
  export declare function readProjectManifestSync(): SmartObjectManifest | null;
78
79
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../../src/manifest/manifest-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../../src/manifest/manifest-loader.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { bumpRegistryGeneration } from "../registry/generation.js";
3
3
  import "../scanner/types.js";
4
4
  import { parse } from "../utils/json.js";
5
5
  import { isDecoratorRuntimeFramePath, isDecoratorRuntimePackageName, isModuleRunnerFramePath, isSmrtCoreFramePath } from "../utils/stack-frames.js";
6
+ import { isRefusedTestArtifact } from "./test-artifacts.js";
6
7
  import { getLocalTestManifestCache as getLocalTestManifestCache$1, getManifestCache, getStaticManifestCache as getStaticManifestCache$1, getTestManifestCache as getTestManifestCache$1, isTestEnvironment as isTestEnvironment$1, shouldLoadCoreTestManifest } from "./store.js";
7
8
  import { dirname, existsSync, join, readFileSync, readdirSync, require, statSync } from "./node-host.js";
8
9
  import { LocalManifestReader } from "./local-manifest-reader.js";
@@ -207,7 +208,9 @@ function loadLocalTestManifestSync() {
207
208
  if (existsSync(testManifestPath)) try {
208
209
  const testManifest = parse(readFileSync(testManifestPath, "utf-8"));
209
210
  const testObjectCount = Object.keys(testManifest.objects).length;
210
- if (testObjectCount > 0) {
211
+ const refused = isRefusedTestArtifact(testManifest, testManifestPath);
212
+ if (refused && testObjectCount > 0) warnRefusedLocalTestManifest(testManifestPath);
213
+ if (testObjectCount > 0 && !refused) {
211
214
  setLocalTestManifestCache(testManifest);
212
215
  debugLog(`[manifest-loader] ✅ Loaded test manifest from ${testManifestPath} (${testObjectCount} objects) - preferred over empty LocalManifestReader result`);
213
216
  return testManifest;
@@ -219,6 +222,10 @@ function loadLocalTestManifestSync() {
219
222
  }
220
223
  if (existsSync(testManifestPath)) try {
221
224
  const testManifest = parse(readFileSync(testManifestPath, "utf-8"));
225
+ if (isRefusedTestArtifact(testManifest, testManifestPath)) {
226
+ warnRefusedLocalTestManifest(testManifestPath);
227
+ return null;
228
+ }
222
229
  setLocalTestManifestCache(testManifest);
223
230
  const objectCount = Object.keys(testManifest.objects).length;
224
231
  debugLog(`[manifest-loader] ✅ Loaded test manifest from ${testManifestPath} (${objectCount} objects)`);
@@ -229,48 +236,65 @@ function loadLocalTestManifestSync() {
229
236
  debugLog("[manifest-loader] ⚠️ No local manifest found (will retry on next call)");
230
237
  return null;
231
238
  }
232
- var projectManifestRead;
239
+ var warnedRefusedLocalTestManifests = /* @__PURE__ */ new Set();
233
240
  /**
234
- * The manifest of the project the process runs in (the first of
235
- * `<cwd>/.smrt/manifest.json`, `<cwd>/dist/manifest.json`,
236
- * `<cwd>/src/manifest/manifest.json`, as `LocalManifestReader.loadLocal()` reads
237
- * them), never seeded into the lookup caches. Only consulted to attribute a
238
- * decorated class whose declaring file that manifest describes, when no loaded
239
- * manifest does: a plain Node/tsx script importing an app's workspace-package
240
- * models has not loaded the app's manifest yet (#3109). The read is reused
241
- * only while that file is unchanged, so a dev server that regenerates it is
242
- * seen; a missing manifest is never cached.
241
+ * Warn once that a local test manifest was refused: outside the test run that
242
+ * registered it, its inline fixtures would be phantom objects (#2760), and
243
+ * inside an unregistered run their metadata is silently missing otherwise.
243
244
  */
244
- function readProjectManifestSync() {
245
- if (typeof process === "undefined" || typeof process.cwd !== "function") return null;
246
- const manager = new LocalManifestReader(process.cwd());
247
- const path = [
248
- manager.getOutputPath("dev"),
249
- manager.getOutputPath("build"),
250
- manager.getOutputPath("source")
251
- ].find((candidate) => existsSync(candidate));
252
- if (!path) return null;
245
+ function warnRefusedLocalTestManifest(path) {
246
+ if (warnedRefusedLocalTestManifests.has(path)) return;
247
+ warnedRefusedLocalTestManifests.add(path);
248
+ logger.warn(`[manifest-loader] Ignoring test manifest ${path}: it is not this process's active test manifest. Run tests under smrtVitestPlugin() (or register it with registerActiveTestManifestPath()) to use it.`);
249
+ }
250
+ var projectManifestReads = /* @__PURE__ */ new Map();
251
+ /** Parse `path`, reusing the previous parse while its mtime is unchanged. */
252
+ function readProjectManifestCandidate(path) {
253
253
  let mtimeMs;
254
254
  try {
255
255
  mtimeMs = statSync(path).mtimeMs;
256
256
  } catch {
257
- return null;
257
+ return;
258
258
  }
259
- if (projectManifestRead?.path === path && projectManifestRead.mtimeMs === mtimeMs) return projectManifestRead.manifest;
259
+ const cached = projectManifestReads.get(path);
260
+ if (cached?.mtimeMs === mtimeMs) return cached.manifest;
260
261
  let manifest = null;
261
262
  try {
262
263
  manifest = parse(readFileSync(path, "utf-8"));
263
264
  } catch {
264
265
  manifest = null;
265
266
  }
266
- projectManifestRead = {
267
- path,
267
+ projectManifestReads.set(path, {
268
268
  mtimeMs,
269
269
  manifest
270
- };
270
+ });
271
271
  return manifest;
272
272
  }
273
273
  /**
274
+ * The manifest of the project the process runs in (the first of
275
+ * `LocalManifestReader.getLocalCandidatePaths()`: a test run's active
276
+ * snapshot, then `<cwd>/.smrt/manifest.json`, `<cwd>/dist/manifest.json`,
277
+ * `<cwd>/src/manifest/manifest.json`, skipping a test artifact outside its
278
+ * own run, #2760), never seeded into the lookup caches. Only consulted to
279
+ * attribute a decorated class whose declaring file that manifest describes,
280
+ * when no loaded manifest does: a plain Node/tsx script importing an app's
281
+ * workspace-package models has not loaded the app's manifest yet (#3109).
282
+ * Each read is reused only while that file is unchanged, so a dev server that
283
+ * regenerates it is seen; a missing manifest is never cached.
284
+ */
285
+ function readProjectManifestSync() {
286
+ if (typeof process === "undefined" || typeof process.cwd !== "function") return null;
287
+ const manager = new LocalManifestReader(process.cwd());
288
+ for (const candidate of manager.getLocalCandidatePaths()) {
289
+ if (!existsSync(candidate)) continue;
290
+ const manifest = readProjectManifestCandidate(candidate);
291
+ if (manifest === void 0) return null;
292
+ if (isRefusedTestArtifact(manifest, candidate)) continue;
293
+ return manifest;
294
+ }
295
+ return null;
296
+ }
297
+ /**
274
298
  * Extract package name from class constructor
275
299
  *
276
300
  * Uses the ObjectRegistry (preferred) or fallback methods to determine
@@ -379,9 +403,17 @@ function resolveWorkspacePackageJsonPath(packageName) {
379
403
  }
380
404
  return null;
381
405
  }
406
+ /** Whether the manifest file at `path` is a refused test artifact (#2760). */
407
+ function isRefusedTestArtifactFile(path) {
408
+ try {
409
+ return isRefusedTestArtifact(parse(readFileSync(path, "utf-8")), path);
410
+ } catch {
411
+ return false;
412
+ }
413
+ }
382
414
  function resolveWorkspaceSourceManifestPath(packageDir) {
383
415
  const candidates = [join(packageDir, "src", "manifest", "manifest.json"), join(packageDir, ".smrt", "manifest.json")];
384
- for (const candidate of candidates) if (existsSync(candidate)) return candidate;
416
+ for (const candidate of candidates) if (existsSync(candidate) && !isRefusedTestArtifactFile(candidate)) return candidate;
385
417
  return null;
386
418
  }
387
419
  function resolveManifestExportPath(packageName, options = {}) {
@@ -450,6 +482,10 @@ function loadExternalManifestSync(packageName, options = {}) {
450
482
  if (options.warn ?? true) logger.warn(`Invalid manifest structure for package ${packageName}`);
451
483
  return null;
452
484
  }
485
+ if (isRefusedTestArtifact(manifest, manifestPath)) {
486
+ if (options.warn ?? true) logger.warn(`Ignoring test artifact ${manifestPath} for package ${packageName}; test manifests are never dependency manifests`);
487
+ return null;
488
+ }
453
489
  const cachedManifest = manifest.packageName ? manifest : {
454
490
  ...manifest,
455
491
  packageName
@@ -479,6 +515,10 @@ function loadManifestFromPathSync(manifestPath) {
479
515
  logger.warn(`Invalid manifest structure at ${manifestPath}`);
480
516
  return null;
481
517
  }
518
+ if (isRefusedTestArtifact(manifest, manifestPath)) {
519
+ logger.warn(`Ignoring test artifact ${manifestPath}; it is not this process's active test manifest`);
520
+ return null;
521
+ }
482
522
  const cacheKey = manifest.packageName || manifestPath;
483
523
  getManifestCacheMap().set(cacheKey, manifest);
484
524
  debugLog(`[manifest-loader] ✅ Loaded manifest from path ${manifestPath} (${Object.keys(manifest.objects).length} objects)`);
@@ -756,7 +796,7 @@ function clearManifestCache() {
756
796
  getManifestCacheMap().clear();
757
797
  getManifestCollisionsMap().clear();
758
798
  getSTISiblingCache().clear();
759
- projectManifestRead = void 0;
799
+ projectManifestReads.clear();
760
800
  }
761
801
  /**
762
802
  * Get all loaded manifests