@salsita-ai/sdk 0.50.0-develop.c33986dc44 → 0.50.0-develop.ca5894b56c

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 (245) hide show
  1. package/README.md +1 -1
  2. package/dist/application-spec/core/enhanced-json-value.d.ts +2 -31
  3. package/dist/application-spec/core/enhanced-json-value.js +1 -1
  4. package/dist/application-spec/core/index.d.ts +1 -3
  5. package/dist/application-spec/core/index.js +1 -1
  6. package/dist/application-spec/core/json-schema.d.ts +2 -52
  7. package/dist/application-spec/core/markers/index.d.ts +1 -1
  8. package/dist/application-spec/core/markers/index.js +1 -1
  9. package/dist/application-spec/core/markers/msg-marker.d.ts +2 -28
  10. package/dist/application-spec/core/markers/msg-marker.js +1 -1
  11. package/dist/application-spec/core/markers/raw-eval-write-marker.d.ts +1 -1
  12. package/dist/application-spec/core/markers/raw-eval-write-marker.js +1 -1
  13. package/dist/application-spec/core/markers/raw-read-write-marker.js +1 -1
  14. package/dist/application-spec/errors/diagnostic-codes.d.ts +1 -0
  15. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  16. package/dist/application-spec/errors/diagnostic-messages.d.ts +1 -0
  17. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  18. package/dist/application-spec/generate-application/code/project-scaffolding.js +2 -2
  19. package/dist/application-spec/generate-application/code/templates/index.d.ts +2 -6
  20. package/dist/application-spec/generate-application/code/templates/index.js +1 -1
  21. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill-bundle.d.ts +10 -0
  22. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill-bundle.js +7 -0
  23. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill.js +1 -1
  24. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +1 -1
  25. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +1 -1
  26. package/dist/application-spec/generate-application/runtime/factory-data/factory-data-runtime.d.ts +2 -2
  27. package/dist/application-spec/generate-application/runtime/factory-data/recipe-defaults.d.ts +1 -1
  28. package/dist/application-spec/generate-application/runtime/factory-data/recipe-defaults.js +1 -1
  29. package/dist/application-spec/generate-application/runtime/factory-data/static-violations.d.ts +1 -1
  30. package/dist/application-spec/generate-application/runtime/factory-data/static-violations.js +1 -1
  31. package/dist/application-spec/generate-application/runtime/generate-runtime-instance.d.ts +1 -1
  32. package/dist/application-spec/generate-application/runtime/generate-runtime-instance.js +1 -1
  33. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.js +1 -1
  34. package/dist/application-spec/generate-application/runtime/sections/expression-runtime.d.ts +1 -1
  35. package/dist/application-spec/generate-application/runtime/sections/expression-runtime.js +1 -1
  36. package/dist/application-spec/generate-application/runtime/sections/generate-memo-eval-plan-runtime.d.ts +1 -1
  37. package/dist/application-spec/generate-application/runtime/sections/generate-memo-eval-plan-runtime.js +1 -1
  38. package/dist/application-spec/generate-application/runtime/sections/preset-runtime.d.ts +2 -3
  39. package/dist/application-spec/generate-application/runtime/sections/reflection-constants-runtime.d.ts +2 -1
  40. package/dist/application-spec/generate-application/runtime/spec-code/resolve-spec-code.d.ts +1 -1
  41. package/dist/application-spec/parse-application-files/parse-application-files.js +1 -1
  42. package/dist/application-spec/parse-application-files/raw-spec/raw-expressions.d.ts +1 -1
  43. package/dist/application-spec/parse-application-files/raw-spec/raw-expressions.js +1 -1
  44. package/dist/application-spec/parse-application-files/spec/model/aliases.d.ts +3 -9
  45. package/dist/application-spec/parse-application-files/spec/model/common-types.d.ts +6 -14
  46. package/dist/application-spec/parse-application-files/spec/model/defaults.d.ts +6 -31
  47. package/dist/application-spec/parse-application-files/spec/model/entity-types.d.ts +3 -8
  48. package/dist/application-spec/parse-application-files/spec/model/model-version-key.d.ts +3 -3
  49. package/dist/application-spec/parse-application-files/spec/model/names/action-name.d.ts +3 -7
  50. package/dist/application-spec/parse-application-files/spec/model/names/alias-name.d.ts +3 -7
  51. package/dist/application-spec/parse-application-files/spec/model/names/entity-or-alias-name.d.ts +3 -8
  52. package/dist/application-spec/parse-application-files/spec/model/names/entity-type-name.d.ts +3 -8
  53. package/dist/application-spec/parse-application-files/spec/model/names/expression-name.d.ts +3 -6
  54. package/dist/application-spec/parse-application-files/spec/model/names/instance-name.d.ts +3 -7
  55. package/dist/application-spec/parse-application-files/spec/model/names/invariant-name.d.ts +3 -3
  56. package/dist/application-spec/parse-application-files/spec/model/names/shape-property-name.d.ts +3 -11
  57. package/dist/application-spec/parse-application-files/spec/model/names/violation-type-name.d.ts +3 -3
  58. package/dist/application-spec/parse-application-files/spec/model/presets.d.ts +6 -29
  59. package/dist/client/authorized-client.d.ts +3 -1
  60. package/dist/client/authorized-client.js +1 -1
  61. package/dist/client/contract.d.ts +17 -0
  62. package/dist/client/index.d.ts +1 -1
  63. package/dist/client/local-authorized-client.d.ts +3 -1
  64. package/dist/client/local-authorized-client.js +1 -1
  65. package/dist/client/memory-authorized-client.d.ts +4 -1
  66. package/dist/client/memory-authorized-client.js +1 -1
  67. package/dist/client/phoenix-api.d.ts +228 -0
  68. package/dist/configurator/ConfiguratorApp.js +1 -1
  69. package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
  70. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +13 -0
  71. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -1
  72. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.d.ts +2 -1
  73. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.js +1 -1
  74. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.d.ts +15 -9
  75. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.js +1 -1
  76. package/dist/configurator/common/configurator-interface.d.ts +2 -2
  77. package/dist/configurator/common/configurator-interface.js +1 -1
  78. package/dist/configurator/configurator-context/ConfiguratorDataProvider.js +1 -1
  79. package/dist/configurator/configurator-context/PresetSelectionProvider.js +1 -1
  80. package/dist/configurator/configurator-context/configurator-hooks/index.d.ts +0 -1
  81. package/dist/configurator/configurator-context/configurator-hooks/index.js +1 -1
  82. package/dist/configurator/configurator-context/index.d.ts +0 -4
  83. package/dist/configurator/configurator-context/index.js +1 -1
  84. package/dist/configurator/pages/ConfiguratorNotFoundPage.js +1 -1
  85. package/dist/configurator/pages/LoadedConfiguratorDetailPage.js +1 -1
  86. package/dist/configurator/pages/error-boundaries/DevContextFallback.js +1 -1
  87. package/dist/configurator/pages/error-boundaries/DevLoadingFallback.js +1 -1
  88. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.d.ts +1 -1
  89. package/dist/configurator/ui/assistant/screenshots/ScreenshotThumbnails.js +1 -1
  90. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.d.ts +12 -4
  91. package/dist/configurator/ui/assistant/screenshots/tool-screenshots.js +1 -1
  92. package/dist/configurator/ui/assistant/screenshots/use-screenshot-src.d.ts +8 -0
  93. package/dist/configurator/ui/assistant/screenshots/use-screenshot-src.js +1 -0
  94. package/dist/configurator/ui/configurator-layout/slots/canvas/GPUAccelerationDisabled.js +1 -1
  95. package/dist/configurator/ui/configurator-layout/slots/canvas/WebGLNotSupported.js +1 -1
  96. package/dist/configurator/ui/configurator-layout/slots/readonly-banner/CloneToEditDialog.js +1 -1
  97. package/dist/configurator/ui/legacy/chat/MobileChat.js +1 -1
  98. package/dist/configurator/ui/legacy/layout/common/CommonTopNavigation.js +1 -1
  99. package/dist/configurator/ui/legacy/layout/simple/SimpleSidebar.js +1 -1
  100. package/dist/configurator/ui/legacy/layout/simple/SimpleTopNavigation.js +1 -1
  101. package/dist/configurator/ui/legacy/layout/steps/StepsNavigation.js +1 -1
  102. package/dist/configurator/ui/legacy/layout/steps/StepsOwnerLayout.js +1 -1
  103. package/dist/configurator/ui/legacy/layout/steps/StepsSideBar.js +1 -1
  104. package/dist/configurator/ui/legacy/layout/tabs/TabsSidebar.js +1 -1
  105. package/dist/configurator/ui/phoenix-layout-elements/header/common/back-button/use-go-back-action.js +1 -1
  106. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/StepsNavigation.js +1 -1
  107. package/dist/configurator/ui/phoenix-layout-elements/sidebar-footer/common/PreviousStepButton.js +1 -1
  108. package/dist/docs/3d-scene/cameras/custom.mdx +4 -2
  109. package/dist/docs/index.json +1 -1
  110. package/dist/docs/phoenix/domain-model.mdx +4 -1
  111. package/dist/docs/phoenix/phoenix-cli.mdx +14 -6
  112. package/dist/docs/phoenix/project-structure.mdx +21 -17
  113. package/dist/docs/phoenix/sdk-builder-workflow.mdx +2 -2
  114. package/dist/docs/phoenix/webhooks.mdx +5 -1
  115. package/dist/domain/application/assistant/build-assistant-manifest.js +1 -1
  116. package/dist/domain/application/assistant/generate-assistant-prompt.js +1 -1
  117. package/dist/domain/index.d.ts +1 -0
  118. package/dist/domain/index.js +1 -1
  119. package/dist/domain/spec/application/index.d.ts +1 -0
  120. package/dist/domain/spec/application/index.js +1 -0
  121. package/dist/{application-spec/core → domain/spec}/components/component-filter.d.ts +3 -2
  122. package/dist/domain/spec/enhanced-json-value.d.ts +30 -0
  123. package/dist/domain/spec/enhanced-json-value.js +1 -0
  124. package/dist/domain/spec/index.d.ts +7 -0
  125. package/dist/domain/spec/index.js +1 -0
  126. package/dist/domain/spec/json-schema.d.ts +52 -0
  127. package/dist/domain/spec/json-schema.js +1 -0
  128. package/dist/domain/spec/markers/index.d.ts +2 -0
  129. package/dist/domain/spec/markers/index.js +1 -0
  130. package/dist/domain/spec/markers/msg-marker.d.ts +28 -0
  131. package/dist/domain/spec/markers/msg-marker.js +1 -0
  132. package/dist/domain/spec/model/aliases.d.ts +9 -0
  133. package/dist/domain/spec/model/aliases.js +1 -0
  134. package/dist/domain/spec/model/common-types.d.ts +15 -0
  135. package/dist/domain/spec/model/common-types.js +1 -0
  136. package/dist/domain/spec/model/defaults.d.ts +33 -0
  137. package/dist/domain/spec/model/defaults.js +1 -0
  138. package/dist/domain/spec/model/entity-types.d.ts +8 -0
  139. package/dist/domain/spec/model/entity-types.js +1 -0
  140. package/dist/domain/spec/model/index.d.ts +7 -0
  141. package/dist/domain/spec/model/index.js +1 -0
  142. package/dist/domain/spec/model/model-version-key.d.ts +3 -0
  143. package/dist/domain/spec/model/model-version-key.js +1 -0
  144. package/dist/domain/spec/model/names/action-name.d.ts +7 -0
  145. package/dist/domain/spec/model/names/action-name.js +1 -0
  146. package/dist/domain/spec/model/names/alias-name.d.ts +7 -0
  147. package/dist/domain/spec/model/names/alias-name.js +1 -0
  148. package/dist/domain/spec/model/names/entity-or-alias-name.d.ts +8 -0
  149. package/dist/domain/spec/model/names/entity-or-alias-name.js +1 -0
  150. package/dist/domain/spec/model/names/entity-type-name.d.ts +8 -0
  151. package/dist/domain/spec/model/names/entity-type-name.js +1 -0
  152. package/dist/domain/spec/model/names/expression-name.d.ts +6 -0
  153. package/dist/domain/spec/model/names/expression-name.js +1 -0
  154. package/dist/domain/spec/model/names/index.d.ts +9 -0
  155. package/dist/domain/spec/model/names/index.js +1 -0
  156. package/dist/domain/spec/model/names/instance-name.d.ts +7 -0
  157. package/dist/domain/spec/model/names/instance-name.js +1 -0
  158. package/dist/domain/spec/model/names/invariant-name.d.ts +3 -0
  159. package/dist/domain/spec/model/names/invariant-name.js +1 -0
  160. package/dist/domain/spec/model/names/shape-property-name.d.ts +11 -0
  161. package/dist/domain/spec/model/names/shape-property-name.js +1 -0
  162. package/dist/domain/spec/model/names/violation-type-name.d.ts +3 -0
  163. package/dist/domain/spec/model/names/violation-type-name.js +1 -0
  164. package/dist/domain/spec/model/presets.d.ts +30 -0
  165. package/dist/domain/spec/model/presets.js +1 -0
  166. package/dist/phoenix/application-spec/generate-application-spec-project.d.ts +1 -0
  167. package/dist/phoenix/application-spec/generate-application-spec-project.js +2 -2
  168. package/dist/phoenix/application-spec/generate-project-files.d.ts +1 -0
  169. package/dist/phoenix/application-spec/index.d.ts +1 -0
  170. package/dist/phoenix/application-spec/index.js +1 -1
  171. package/dist/phoenix/application-spec/resolve-deployment-data.d.ts +11 -0
  172. package/dist/phoenix/application-spec/resolve-deployment-data.js +2 -2
  173. package/dist/phoenix/bin.js +1 -1
  174. package/dist/phoenix/cli.js +1 -1
  175. package/dist/phoenix/commands/build.js +1 -1
  176. package/dist/phoenix/commands/clean.js +1 -1
  177. package/dist/phoenix/commands/deploy.js +1 -1
  178. package/dist/phoenix/commands/dev.js +5 -5
  179. package/dist/phoenix/commands/generated-env-markers.d.ts +1 -0
  180. package/dist/phoenix/commands/generated-env-markers.js +1 -1
  181. package/dist/phoenix/commands/index.d.ts +1 -1
  182. package/dist/phoenix/commands/index.js +1 -1
  183. package/dist/phoenix/commands/sync.js +1 -1
  184. package/dist/phoenix/lingui/index.d.ts +1 -0
  185. package/dist/phoenix/lingui/index.js +1 -0
  186. package/dist/phoenix/{services → lingui}/lingui.d.ts +5 -2
  187. package/dist/phoenix/lingui/lingui.js +1 -0
  188. package/dist/phoenix/services/application-spec-project-watcher.d.ts +3 -1
  189. package/dist/phoenix/services/application-spec-project-watcher.js +2 -2
  190. package/dist/phoenix/services/index.d.ts +1 -0
  191. package/dist/phoenix/services/index.js +1 -1
  192. package/dist/phoenix/services/lingui-watcher.js +1 -1
  193. package/dist/phoenix/services/prepare-development-environment.js +1 -1
  194. package/dist/phoenix/services/vite-config.js +1 -1
  195. package/dist/react-sdk/application-runtime/domain-application-context/chat-system.d.ts +1 -1
  196. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/ConfiguratorRoutingProvider.d.ts +1 -1
  197. package/dist/react-sdk/configurator-routing/ConfiguratorRoutingProvider.js +1 -0
  198. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/OnGoToIndexHandler.d.ts +1 -2
  199. package/dist/react-sdk/configurator-routing/OnGoToIndexHandler.js +1 -0
  200. package/dist/react-sdk/configurator-routing/index.d.ts +3 -0
  201. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/index.js +1 -1
  202. package/dist/{configurator/configurator-context → react-sdk}/configurator-routing/use-power-routing-lifecycle.d.ts +2 -0
  203. package/dist/react-sdk/configurator-routing/use-power-routing-lifecycle.js +1 -0
  204. package/dist/react-sdk/domain-application-context/OnPresetLoadedHandler.js +1 -0
  205. package/dist/react-sdk/domain-application-context/chat-hooks.d.ts +4 -0
  206. package/dist/react-sdk/domain-application-context/chat-hooks.js +1 -0
  207. package/dist/react-sdk/domain-application-context/index.d.ts +2 -0
  208. package/dist/react-sdk/domain-application-context/index.js +1 -1
  209. package/dist/react-sdk/index.d.ts +3 -0
  210. package/dist/react-sdk/index.js +1 -1
  211. package/dist/react-sdk/integration/IntegrationSubscription.js +1 -0
  212. package/dist/react-sdk/integration/index.d.ts +1 -0
  213. package/dist/react-sdk/integration/index.js +1 -0
  214. package/dist/react-sdk/lifecycle-providers/LifecycleProviders.js +1 -0
  215. package/dist/react-sdk/lifecycle-providers/index.d.ts +1 -0
  216. package/dist/react-sdk/lifecycle-providers/index.js +1 -0
  217. package/package.json +3 -3
  218. package/dist/configurator/configurator-context/IntegrationSubscription.js +0 -1
  219. package/dist/configurator/configurator-context/LifecycleProviders.js +0 -1
  220. package/dist/configurator/configurator-context/OnPresetLoadedHandler.js +0 -1
  221. package/dist/configurator/configurator-context/configurator-hooks/chat-hooks.d.ts +0 -1
  222. package/dist/configurator/configurator-context/configurator-hooks/chat-hooks.js +0 -1
  223. package/dist/configurator/configurator-context/configurator-routing/ConfiguratorRoutingProvider.js +0 -1
  224. package/dist/configurator/configurator-context/configurator-routing/OnGoToIndexHandler.js +0 -1
  225. package/dist/configurator/configurator-context/configurator-routing/index.d.ts +0 -2
  226. package/dist/configurator/configurator-context/configurator-routing/use-power-routing-lifecycle.js +0 -1
  227. package/dist/phoenix/services/lingui.js +0 -1
  228. /package/dist/{application-spec/core → domain/spec/application}/application-instance.d.ts +0 -0
  229. /package/dist/{application-spec/core → domain/spec/application}/application-instance.js +0 -0
  230. /package/dist/{application-spec/core → domain/spec}/components/component-filter.js +0 -0
  231. /package/dist/{application-spec/core → domain/spec}/components/index.d.ts +0 -0
  232. /package/dist/{application-spec/core → domain/spec}/components/index.js +0 -0
  233. /package/dist/{application-spec/core → domain/spec}/components/sdk-code-ref.d.ts +0 -0
  234. /package/dist/{application-spec/core → domain/spec}/components/sdk-code-ref.js +0 -0
  235. /package/dist/{application-spec/core → domain/spec}/expressions/index.d.ts +0 -0
  236. /package/dist/{application-spec/core → domain/spec}/expressions/index.js +0 -0
  237. /package/dist/{application-spec/core → domain/spec}/expressions/relation-expression-params.d.ts +0 -0
  238. /package/dist/{application-spec/core → domain/spec}/expressions/relation-expression-params.js +0 -0
  239. /package/dist/{application-spec/core → domain/spec}/expressions/sdk-expression-implementation.d.ts +0 -0
  240. /package/dist/{application-spec/core → domain/spec}/expressions/sdk-expression-implementation.js +0 -0
  241. /package/dist/{application-spec/core → domain/spec}/markers/eval-marker.d.ts +0 -0
  242. /package/dist/{application-spec/core → domain/spec}/markers/eval-marker.js +0 -0
  243. /package/dist/{configurator/configurator-context → react-sdk/domain-application-context}/OnPresetLoadedHandler.d.ts +0 -0
  244. /package/dist/{configurator/configurator-context → react-sdk/integration}/IntegrationSubscription.d.ts +0 -0
  245. /package/dist/{configurator/configurator-context → react-sdk/lifecycle-providers}/LifecycleProviders.d.ts +0 -0
@@ -0,0 +1,10 @@
1
+ import { type AgentSkillReference } from './agent-skill.js';
2
+ import { type PhoenixSkillOptions } from './phoenix-skill.js';
3
+ /** The discoverable entry point and the documents it ships beside it. */
4
+ interface PhoenixSkillBundle {
5
+ readonly content: string;
6
+ readonly references: readonly AgentSkillReference[];
7
+ }
8
+ /** Keeps the existing generators as content owners while changing only discovery and relative routing. */
9
+ export declare const generatePhoenixSkillBundle: (options: PhoenixSkillOptions) => PhoenixSkillBundle;
10
+ export {};
@@ -0,0 +1,7 @@
1
+ import{renderAgentSkill as e}from"./agent-skill.js";import{generatePhoenixCliSkill as t}from"./phoenix-cli-skill.js";import{generatePhoenixCreateConfiguratorSkill as n,generatePhoenixCreateConfiguratorSkillReferences as r}from"./phoenix-create-configurator-skill.js";import{generatePhoenixFeedbackSkill as i}from"./phoenix-feedback-skill.js";import{generatePhoenixReviewSkill as o}from"./phoenix-review-skill.js";import{generatePhoenixSkill as a}from"./phoenix-skill.js";import{generatePhoenixVariantsSkill as s}from"./phoenix-variants-skill.js";let l=(e,t,n)=>n.reduce((e,n)=>{let r="../".repeat(t.split("/").length-2),i=`[${n.title}](${r}${n.path.slice(11)})`;return e.replaceAll(`\`${n.name}\` skill`,i).replaceAll(`${n.name} skill`,i)},e),c=e=>{let t="\n---\n\n",n=e.content.indexOf(t),r=e.content.slice(0,n).split("\n").find(e=>e.startsWith("description: "));if(-1===n||void 0===r)throw Error(`Cannot emit the ${e.name} guide: its skill frontmatter is missing. Render it with renderAgentSkill.`);return{description:r.slice(13),body:e.content.slice(n+t.length)}};export const generatePhoenixSkillBundle=h=>{let p=[{name:"phoenix",title:"Project guidance",path:"references/project.md",content:a(h),references:[]},{name:"phoenix-create-configurator",title:"Configurator workflow",path:"references/create-configurator/guide.md",content:n(),references:r()},{name:"phoenix-cli",title:"CLI guide",path:"references/cli.md",content:t(),references:[]},{name:"phoenix-review",title:"Code review guide",path:"references/review.md",content:o(),references:[]},{name:"phoenix-variants",title:"Variants guide",path:"references/variants.md",content:s(),references:[]},{name:"phoenix-feedback",title:"Feedback guide",path:"references/feedback.md",content:i(),references:[]}];return{content:e({name:"phoenix",description:"Build, change, inspect, deploy or review a Phoenix configurator project. Use for Phoenix project work, visual alternatives, and platform feedback.",sections:[`# Phoenix
2
+
3
+ Load the guides for the work in hand before doing that work. Several may apply. Follow their existing instructions; this entry point only routes to them. Reuse guidance already read in the conversation unless sync or an SDK update changed it.`,`## Choose the relevant guidance
4
+
5
+ | When | Read |
6
+ | --- | --- |
7
+ ${p.map(e=>`| ${c(e).description} | [${e.title}](${e.path}) |`).join("\n")}`,"The workflow guide links to product discovery, asset conversion, UX guidance and appearance review at the stages that use them. An isolated code fix needs project guidance and the applicable CLI/review guides; it does not restart the configurator workflow.\n\nEarlier Phoenix skill names refer to these guides: ask for the same task through `phoenix`. Read linked documents when their task applies, not the whole reference tree."]}),references:p.flatMap(e=>[{path:e.path,content:l(c(e).body,e.path,p)},...e.references.map(t=>{let n=`${e.path.slice(0,e.path.lastIndexOf("/")+1)}${t.path}`;return{path:n,content:l(t.content,n,p)}})])}};
@@ -1 +1 @@
1
- import{renderAgentSkill as e}from"./agent-skill.js";import{sdkGuidanceSections as t}from"./sdk-content.js";export const followsCanaryBuilds=e=>!e.useWorkspace&&e.sdkVersion.includes("-develop.");export const generatePhoenixSkill=({checkLatestCanary:n})=>e({name:"phoenix",description:`Phoenix SDK project conventions, covering project structure, architecture principles, key patterns, file and export rules, webhook membership, versioning the domain model once it is deployed, showing the user the dev preview and the build of a deploy, the run evaluation that follows a live deploy, inspecting the rendered result, and how to search the SDK documentation${n?", and the internal-beta check for the latest canary SDK build":""}. Use before writing or changing specs or source code, or deploying this Phoenix configurator project.`,sections:[t.packageManager,...n?["## Stay on the Latest Canary\nDuring the internal beta this project uses the `canary` build of the SDK, which is published from every change to the platform. Once per conversation, before you change anything, compare the installed version, the `version` in `node_modules/@salsita-ai/sdk/package.json`, with the newest canary:\n```bash\nnpm view @salsita-ai/sdk@canary version\n```\nWhen they differ, tell the user which version you are moving to, then update the SDK, bring the packages it needs next to it in line, and regenerate the project's files:\n```bash\npnpm add @salsita-ai/sdk@canary && pnpm phoenix deps && pnpm install && pnpm phoenix sync\n```\n`sync` rewrites the Phoenix skills, so read the ones you use again after it. When the user runs a globally installed `phoenix`, update that too with `npm install -g @salsita-ai/sdk@canary`. If the project no longer builds after the update, stop and tell the user; the `phoenix-feedback` skill covers reporting it."]:[],t.projectStructure,t.architecturePrinciples,t.keyPatterns,t.fileConventions,t.exportRules,t.webhookMembership,t.doNotEdit,t.modelVersioning,"## Show the Preview While You Work\nThe user should see the configurator change as you build it. Before your first change in a conversation, make sure `pnpm phoenix dev` is running (start it in the background when it is not) and open the address it prints as `Preview: <url>` (also written to `.phoenix/phoenix-dev.log`) in the user's browser: `open '<url>'` on macOS, `xdg-open '<url>'` on Linux, `Start-Process '<url>'` in PowerShell, `start \"\" \"<url>\"` in cmd. Keep the quotes, the shell would otherwise read a `?` in the address as a pattern. The log keeps the lines of earlier runs, so when you have just started dev, wait for the `Preview:` line written after your start and use the last one. Open it once; the preview reloads on every change, so tell the user to keep that tab open instead of opening it again.",t.visualInspection,"## Show the Build After a Deploy\nImmediately before invoking `pnpm phoenix deploy`, refresh `conversation.log` in the project root with the current conversation. Prefer the agent application's native session export when available; do not invent an export command or scan unrelated sessions. Otherwise write the messages still available in context and label the log `reconstructed; incomplete`. Never present a compaction summary as verbatim earlier messages.\n\nUse UTF-8 text with a header naming the agent, export time, source (native export or reconstructed), covered session and known omissions. Preserve user and assistant messages in chronological order, plus tool names, arguments and results when available. Keep each tool result to at most 16 KiB of text, marking truncation explicitly; describe image attachments by reference rather than embedding binary/base64 data, and mark references whose files are not uploaded. Exclude internal instructions, hidden reasoning, credentials and unrelated sensitive content; mark redactions without repeating the removed content. Refresh the current session's log rather than appending duplicate copies or silently carrying over a previous session.\n\nShow the user the exact file to review or redact and obtain approval to include it before deploying; do not ask again when they have already approved that file. If they decline, move it out of the project root before deployment so it cannot be collected. Deploy includes the file in the build's private source archive, downloadable by those authorized to download that build's sources, and leaves it out when extracting build inputs. A missing log warns but does not block deployment. The CLI does not export, redact or validate the transcript's completeness for you.\n\n`pnpm phoenix deploy` starts a build on the server and waits for it to go live. Right after `Build <id> started` it prints `Follow the build in Studio: <url>`. Run the deploy so that you can read its output while it runs, and open that link in the user's browser, quoted as above, as soon as it appears, so they can follow the build they just triggered. When the line is missing, the sign-in is older than the link: tell the user the build is listed under Deployments in Studio, and that `pnpm phoenix login <workspace>` brings the link back.\n\nWhen the deploy reports the configurator live, load the `phoenix-feedback` skill before you write your final message and follow its \"Evaluate the Run\" section, so the user is asked about the run while they are still there. It is asked once per conversation, and only once the user has nothing more to build.","## Code Review\nUse the `phoenix-review` skill to review code changes before committing.",t.sdkDocumentation]});
1
+ import{renderAgentSkill as e}from"./agent-skill.js";import{sdkGuidanceSections as t}from"./sdk-content.js";export const followsCanaryBuilds=e=>!e.useWorkspace&&e.sdkVersion.includes("-develop.");export const generatePhoenixSkill=({checkLatestCanary:n})=>e({name:"phoenix",description:`Phoenix SDK project conventions, covering project structure, architecture principles, key patterns, file and export rules, webhook membership, versioning the domain model once it is deployed, showing the user the dev preview and the build of a deploy, the run evaluation that follows a live deploy, inspecting the rendered result, and how to search the SDK documentation${n?", and the internal-beta check for the latest canary SDK build":""}. Use before writing or changing specs or source code, or deploying this Phoenix configurator project.`,sections:[t.packageManager,...n?["## Stay on the Latest Canary\nDuring the internal beta this project uses the `canary` build of the SDK, which is published from every change to the platform. Once per conversation, before you change anything, compare the installed version, the `version` in `node_modules/@salsita-ai/sdk/package.json`, with the newest canary:\n```bash\nnpm view @salsita-ai/sdk@canary version\n```\nWhen they differ, tell the user which version you are moving to, then update the SDK, bring the packages it needs next to it in line, and regenerate the project's files:\n```bash\npnpm add @salsita-ai/sdk@canary && pnpm phoenix deps && pnpm install && pnpm phoenix sync\n```\n`sync` rewrites the Phoenix skills, so read the ones you use again after it. When the user runs a globally installed `phoenix`, update that too with `npm install -g @salsita-ai/sdk@canary`. If the project no longer builds after the update, stop and tell the user; the `phoenix-feedback` skill covers reporting it."]:[],t.projectStructure,t.architecturePrinciples,t.keyPatterns,t.fileConventions,t.exportRules,t.webhookMembership,t.doNotEdit,t.modelVersioning,"## Show the Preview While You Work\nThe user should see the configurator change as you build it. Before your first change in a conversation, make sure `pnpm phoenix dev` is running (start it in the background when it is not) and open the address it prints as `Preview: <url>` (also written to `.phoenix/phoenix-dev.log`) in the user's browser: `open '<url>'` on macOS, `xdg-open '<url>'` on Linux, `Start-Process '<url>'` in PowerShell, `start \"\" \"<url>\"` in cmd. Keep the quotes, the shell would otherwise read a `?` in the address as a pattern. The log keeps the lines of earlier runs, so when you have just started dev, wait for the `Preview:` line written after your start and use the last one. Open it once; the preview reloads on every change, so tell the user to keep that tab open instead of opening it again. A domain model change is the exception: `pnpm phoenix dev` registers the model with the server only when it starts, and after the change it logs an error that asks for a restart. Restart it, wait for the new `Preview:` line and open that address in place of the old tab, whose address carries the `?cid=` of a configuration saved with the earlier model, which the new model rejects.",t.visualInspection,"## Show the Build After a Deploy\nImmediately before invoking `pnpm phoenix deploy`, refresh `conversation.log` in the project root with the current conversation. Prefer the agent application's native session export when available; do not invent an export command or scan unrelated sessions. Otherwise write the messages still available in context and label the log `reconstructed; incomplete`. Never present a compaction summary as verbatim earlier messages.\n\nUse UTF-8 text with a header naming the agent, export time, source (native export or reconstructed), covered session and known omissions. Preserve user and assistant messages in chronological order, plus tool names, arguments and results when available. Keep each tool result to at most 16 KiB of text, marking truncation explicitly; describe image attachments by reference rather than embedding binary/base64 data, and mark references whose files are not uploaded. Exclude internal instructions, hidden reasoning, credentials and unrelated sensitive content; mark redactions without repeating the removed content. Refresh the current session's log rather than appending duplicate copies or silently carrying over a previous session.\n\nShow the user the exact file to review or redact and obtain approval to include it before deploying; do not ask again when they have already approved that file. If they decline, move it out of the project root before deployment so it cannot be collected. Deploy includes the file in the build's private source archive, downloadable by those authorized to download that build's sources, and leaves it out when extracting build inputs. A missing log warns but does not block deployment. The CLI does not export, redact or validate the transcript's completeness for you.\n\n`pnpm phoenix deploy` starts a build on the server and waits for it to go live. Right after `Build <id> started` it prints `Follow the build in Studio: <url>`. Run the deploy so that you can read its output while it runs, and open that link in the user's browser, quoted as above, as soon as it appears, so they can follow the build they just triggered. When the line is missing, the sign-in is older than the link: tell the user the build is listed under Deployments in Studio, and that `pnpm phoenix login <workspace>` brings the link back.\n\nWhen the deploy reports the configurator live, load the `phoenix-feedback` skill before you write your final message and follow its \"Evaluate the Run\" section, so the user is asked about the run while they are still there. It is asked once per conversation, and only once the user has nothing more to build.","## Code Review\nUse the `phoenix-review` skill to review code changes before committing.",t.sdkDocumentation]});
@@ -54,7 +54,7 @@ Without a lockfile, use the package manager the \`packageManager\` field of \`pa
54
54
  - \`AppLoaderContent\`: \`phx.frontend.createAppLoader(({ phases }) => …)\` replaces what the loading overlay shows (each phase \`{ id, label?, progress? }\`, the list possibly empty); Phoenix keeps the overlay itself
55
55
  - Assistant form elements: an element declared under \`assistant.formElements\` (\`description\`, \`role\`, scalar \`attributes\` beside the built-in \`label\`, a \`value\` included, \`required\`) is the default export \`phx.frontend.createAssistantFormElement('name', Component)\` of one file; the name types the component's props by its role (\`AssistantFormElementProps<'name'>\`): an option reports its answer with \`onSelect(answer)\`, an input with \`onChange(state, answer)\`; and the application does not start while a declared element has no registration or a registration no declaration
56
56
  - \`src/handlers/\` — Event & lifecycle handlers
57
- - \`src/webhooks/\` — Server-side webhook handlers (\`phx.webhooks.*Builder\`); the webhook is the default export of \`src/webhooks/index.ts\`, which you create when the project needs its own handlers — without it the build uses a built-in inert webhook that answers only anonymous auth, so create the file before setting \`useAuthHook\` or \`useClerk\`
57
+ - \`src/webhooks/\` — Server-side webhook handlers (\`phx.webhooks.*Builder\`); the webhook is the default export of \`src/webhooks/index.ts\`, which you create when the project needs its own handlers. Without it, generation continues with a built-in webhook that answers only anonymous auth; enabling \`useAuthHook\` or \`useClerk\` reports \`AUTH_WITHOUT_PROJECT_WEBHOOK\`. Add the entry with the required Clerk or custom auth handlers, or disable unintended auth settings
58
58
  - \`src/migrations/\` — Schema version migrations (v*.ts)
59
59
  - \`src/locales/\` — Locale catalogs (authored .po sources; compiled .ts, do not edit)
60
60
  - \`src/admin/\` — Admin interface (mirrors main src/ structure)
@@ -1,4 +1,4 @@
1
- export const sdkGuidanceSections={packageManager:"## Package Manager\nThe project installs with its own package manager, and the commands in this skill are written for pnpm. Run them through the package manager the project uses, which the lockfile in the project root names:\n- `pnpm-lock.yaml`: `pnpm phoenix <command>`, `pnpm install`, `pnpm add <package>`\n- `package-lock.json`: `npx phoenix <command>`, `npm install`, `npm install <package>`\n- `yarn.lock`: `yarn phoenix <command>`, `yarn install`, `yarn add <package>`\n- `bun.lock` or `bun.lockb`: `bunx phoenix <command>`, `bun install`, `bun add <package>`\n\nWithout a lockfile, use the package manager the `packageManager` field of `package.json` names, or ask the user.",buildCommands:"## Build Commands\n- `pnpm phoenix build` — Full production build\n- `pnpm phoenix dev` — Development mode with hot reload\n- `pnpm phoenix sync` — Sync generated files without full build\n- `pnpm phoenix deps` — Add the SDK's missing peer dependencies to `package.json` and move out-of-range ones into the SDK's range; it installs nothing, so install after it",devLogs:"## Dev Logs\n- `pnpm phoenix dev` writes all logs to `.phoenix/phoenix-dev.log`\n- Contains: spec parse errors, build errors, browser runtime errors, file watcher events\n- After making changes, always check the log for errors: `tail -50 .phoenix/phoenix-dev.log` or `grep ERROR .phoenix/phoenix-dev.log`\n- Rotated automatically at 10MB (`.log.1`, `.log.2` are older rotations)",projectStructure:"## Project Structure\n- `spec/` — Domain YAML specs (entities, relations, expressions, invariants, components, application config)\n- `src/expressions/` — Computed/derived entity properties (`phx.domain.implementCustomExpressions()`)\n- `src/actions/` — Domain operations declared under `actions:` in the spec (`phx.domain.implementActions()`), run by controls and exposed to the assistant\n- `src/invariants/` — Business rule constraints (`phx.domain.implementCustomInvariants()`)\n- `src/transformers/` — Automatic state fixers (`phx.frontend.transformerBuilder`)\n- `src/components/` — ECS system components (`phx.domain.attachComponent.withEntity()`)\n- `src/elements/` — Page-level React components (`phx.frontend.createCustomPhoenixLayoutElement()`)\n - `ConfiguratorLayout`: a layout element with this name replaces everything the built-in layout renders for a loaded configuration, in owner and read mode, finalization included. Prefer arranging the spec's layout components; write one for shell-level changes, such as moving the sidebar or adding an area the built-in layout has no place for\n - Mount `LayoutSlots.SharedCanvas` (from `@salsita-ai/sdk/configurator`) in a positioned root covering the page; put the UI above it, positioned and after it in the markup. With the canvas mounted the app loader waits until the scene has loaded; a layout without a canvas is not held by the loader. Call `phx.frontend.useSceneSafeArea()` and put `containerRef` on the element covering the whole canvas and `safeAreaRef` on the region the UI leaves free, with `pointerEvents: 'none'`, so the camera frames the scene there\n - Sidebar moved, contents as the spec configures them: mount `LayoutSlots.DesktopSidebar` in a positioned container that sets its size, with `side=\"start\"` on the left; `docs/layouts/sidebar/in-a-custom-layout.mdx` is the whole layout\n - Your own UI: \"Hooks for a Project Layout\" in `docs/phoenix/configurator-interface.mdx` lists the hooks with what each returns (`pnpm phoenix docs -r docs/phoenix/configurator-interface.mdx`), `docs/phoenix/layout-slots.mdx` the built-in pieces you can still mount, and `docs/layouts/custom-layout.mdx` is a worked example. Call the hooks as `phx.frontend.useX()`; besides those below, these are often needed: `usePreview()` (`isPreview` while the preview start screen shows), `useCloseAction()` (the host's close action or `null`), `useActiveViewports()` (the container's breakpoints, `null` until measured, `desktop` above 768 px: the desktop/phone switch), `useResolveLocalizable()` and `useLocalizable(text)` (spec texts to strings), `useIsCloningAllowed()` (a read-mode \"edit a copy\" action with `LayoutSlots.CloneToEditDialog`)\n - Undo and redo: `phx.frontend.useUndoRedo()` returns `{ canUndo, canRedo, undo, redo }`; disable each button from `canUndo`/`canRedo`\n - Tabs: `phx.frontend.useTabNavigation()` returns `{ source, tabs, activeTab, select }` for the spec's `sidebarTabs` (of the selected entity) or `horizontalTabs`; render `tabs` (each `{ index, label, icon, state, isActive }`, `icon` a PhxIcon name) and call `select(tab.index)` on click. Pass `{ source: 'sidebarTabs' }` or `{ source: 'horizontalTabs' }` when the layout shows one kind only. Not `LayoutSlots.useSidebarTabs()`: it serves the built-in sidebar and returns no tabs while its summary shows\n - Steps: `phx.frontend.useStepNavigation()` returns `{ steps, activeStep, activeIndex, isFirst, isLast, canGoNext, canGoPrevious, next, previous, goTo }` for the spec's `navigationSteps`; render `steps` (each `{ index, label, state, status }`, `status` `'complete' | 'active' | 'upcoming'`), call `next()`/`previous()` for Back and Next and `goTo(step.index)` from a stepper. It enforces no order and no validity: enable only `'complete'` steps for an \"earlier steps only\" stepper, and to block moving on while the configuration has a problem, require `phx.frontend.useStateValidity().severity !== 'warning'` besides `canGoNext`: a change with a `fixable` or `fatal` violation is rejected, so the configuration is never invalid, and a `warning` is the problem that stays (it blocks finalizing too). `useSteps` and `useHasSteps` from `@salsita-ai/sdk/configurator` are deprecated\n - Messages: mount `LayoutSlots.Services` for the built-in snackbars, or show violations, side-effect hints, errors and failed saves yourself with `phx.frontend.useConfiguratorMessages(onMessage)`, not both. A failed save arrives as `saveError`, the next successful save as `saveRecovery`; a layout that mounts neither shows no sign of a failed save. Either way mount a snackbar root (`LayoutSlots.DesktopSnackbarsRoot` or `LayoutSlots.MobileSnackbarsRoot`): errors of the built-in actions are always snackbars\n - Finalize over the spec's `finalizeAction` components, each naming a handler registered with `phx.frontend.createPhoenixHandler`: `phx.frontend.useFinalizeActions()` returns `{ actions, primary, secondary, disabled, hints }`; render `primary` (and `secondary` in a menu or list) in a loop, each action `{ key, label, title, icon, run, isPending, error, disabled }`, and call `action.run()` on click (its promise never rejects; show `action.error` on failure). The configurator runs the handlers itself, outside the layout, so a handler must not rely on a provider the layout adds. For one known handler, `phx.frontend.useFinalizeAction(handler)` in a component wrapped in `PhoenixHandlerBoundary` (from `@salsita-ai/sdk/react`) works too; `FinalizeActions` (from `@salsita-ai/sdk/configurator`) mounts the built-in buttons. `finalizePage` and `finalizeButton` are legacy\n - Read mode and fullscreen are the layout's job, no hook enforces them (`useUndoRedo`, `useFinalizeActions` and `useStepNavigation` included): hide undo, redo, finalization and whatever else a viewer must not change while `phx.frontend.useAccessService().accessInfo.viewMode` is `true` (tabs are navigation, so a viewer may switch them), and remove panels while `phx.frontend.useIsFullscreenActive()` is set; `phx.frontend.useSetFullscreen()` returns its setter\n - `ConfigurationNotFoundPage`: `phx.frontend.createConfigurationNotFoundPage(({ onBack }) => …)` replaces the \"configuration not accessible\" page; show a way back only when the optional `onBack` is set. The not-authenticated page's default renders it too; only the admin's not-authorized page keeps the built-in page\n - `ConfiguratorErrorPage`: `phx.frontend.createConfiguratorErrorPage(({ reason, onRetry }) => …)` replaces the production error page; `reason` is `uncaughtError` or `presetCreationFailed`. A page that throws falls back to the built-in one, and development keeps the detailed error pages, so the project page shows only in a production build. Register both pages with these helpers: `createCustomPhoenixLayoutElement` with the name works too, but types the component as taking only `children`, so the typed props do not compile there in a strict project\n - `AppLoaderContent`: `phx.frontend.createAppLoader(({ phases }) => …)` replaces what the loading overlay shows (each phase `{ id, label?, progress? }`, the list possibly empty); Phoenix keeps the overlay itself\n - Assistant form elements: an element declared under `assistant.formElements` (`description`, `role`, scalar `attributes` beside the built-in `label`, a `value` included, `required`) is the default export `phx.frontend.createAssistantFormElement('name', Component)` of one file; the name types the component's props by its role (`AssistantFormElementProps<'name'>`): an option reports its answer with `onSelect(answer)`, an input with `onChange(state, answer)`; and the application does not start while a declared element has no registration or a registration no declaration\n- `src/handlers/` — Event & lifecycle handlers\n- `src/webhooks/` — Server-side webhook handlers (`phx.webhooks.*Builder`); the webhook is the default export of `src/webhooks/index.ts`, which you create when the project needs its own handlers — without it the build uses a built-in inert webhook that answers only anonymous auth, so create the file before setting `useAuthHook` or `useClerk`\n- `src/migrations/` — Schema version migrations (v*.ts)\n- `src/locales/` — Locale catalogs (authored .po sources; compiled .ts, do not edit)\n- `src/admin/` — Admin interface (mirrors main src/ structure)\n- `src/_shared/` — Shared utilities (NOT auto-imported, requires explicit imports)\n- `.phoenix/` — Auto-generated files (DO NOT EDIT, except the option files in `.phoenix/variants/`)\n- `public/` — Static assets (3D models, textures, images, HDRI maps, fonts)\n- `assets/` — Uploadable resources (PDF templates, email assets)",architecturePrinciples:"## Architecture Principles\n- YAML-first: 99% of configuration in spec/*.yaml, custom code is last resort\n- ECS pattern: entities (domain objects) + components (behavior/UI) + systems (SDK runtime)\n- Reactive state: immutable domain state flows through RxJS pipelines\n- Data binding: `$read` (read-only), `$write` (write-only), `$bind` (bidirectional) connect components to domain\n- memoEval: all component implementations must use memoEval for stable object references",keyPatterns:"## Key Patterns\n- Expressions = computed properties on entities (prefix: `$`), implemented per-entity in src/expressions/\n- Actions = named domain operations (`actions:` in YAML with `params` and `result` schemas), implemented in src/actions/, prepared through `actionSystem.prepareAction()` and exposed as assistant mutations through `assistant.actions`\n- Invariants = validation rules returning violations, static or dynamic\n- Transformers = auto-fixers maintaining consistency after state changes\n- Components defined in YAML with `$read`/`$bind` bindings, or custom in src/components/ using attachComponent builder\n- Webhooks = server-side finalization tasks (PDF, email, CSV, image rendering)\n- Filters = contextual component activation via navigationStates, viewStates, modes, selectedEntityIds",fileConventions:`## File Conventions
1
+ export const sdkGuidanceSections={packageManager:"## Package Manager\nThe project installs with its own package manager, and the commands in this skill are written for pnpm. Run them through the package manager the project uses, which the lockfile in the project root names:\n- `pnpm-lock.yaml`: `pnpm phoenix <command>`, `pnpm install`, `pnpm add <package>`\n- `package-lock.json`: `npx phoenix <command>`, `npm install`, `npm install <package>`\n- `yarn.lock`: `yarn phoenix <command>`, `yarn install`, `yarn add <package>`\n- `bun.lock` or `bun.lockb`: `bunx phoenix <command>`, `bun install`, `bun add <package>`\n\nWithout a lockfile, use the package manager the `packageManager` field of `package.json` names, or ask the user.",buildCommands:"## Build Commands\n- `pnpm phoenix build` — Full production build\n- `pnpm phoenix dev` — Development mode with hot reload\n- `pnpm phoenix sync` — Sync generated files without full build\n- `pnpm phoenix deps` — Add the SDK's missing peer dependencies to `package.json` and move out-of-range ones into the SDK's range; it installs nothing, so install after it",devLogs:"## Dev Logs\n- `pnpm phoenix dev` writes all logs to `.phoenix/phoenix-dev.log`\n- Contains: spec parse errors, build errors, browser runtime errors, file watcher events\n- After making changes, always check the log for errors: `tail -50 .phoenix/phoenix-dev.log` or `grep ERROR .phoenix/phoenix-dev.log`\n- Rotated automatically at 10MB (`.log.1`, `.log.2` are older rotations)",projectStructure:"## Project Structure\n- `spec/` — Domain YAML specs (entities, relations, expressions, invariants, components, application config)\n- `src/expressions/` — Computed/derived entity properties (`phx.domain.implementCustomExpressions()`)\n- `src/actions/` — Domain operations declared under `actions:` in the spec (`phx.domain.implementActions()`), run by controls and exposed to the assistant\n- `src/invariants/` — Business rule constraints (`phx.domain.implementCustomInvariants()`)\n- `src/transformers/` — Automatic state fixers (`phx.frontend.transformerBuilder`)\n- `src/components/` — ECS system components (`phx.domain.attachComponent.withEntity()`)\n- `src/elements/` — Page-level React components (`phx.frontend.createCustomPhoenixLayoutElement()`)\n - `ConfiguratorLayout`: a layout element with this name replaces everything the built-in layout renders for a loaded configuration, in owner and read mode, finalization included. Prefer arranging the spec's layout components; write one for shell-level changes, such as moving the sidebar or adding an area the built-in layout has no place for\n - Mount `LayoutSlots.SharedCanvas` (from `@salsita-ai/sdk/configurator`) in a positioned root covering the page; put the UI above it, positioned and after it in the markup. With the canvas mounted the app loader waits until the scene has loaded; a layout without a canvas is not held by the loader. Call `phx.frontend.useSceneSafeArea()` and put `containerRef` on the element covering the whole canvas and `safeAreaRef` on the region the UI leaves free, with `pointerEvents: 'none'`, so the camera frames the scene there\n - Sidebar moved, contents as the spec configures them: mount `LayoutSlots.DesktopSidebar` in a positioned container that sets its size, with `side=\"start\"` on the left; `docs/layouts/sidebar/in-a-custom-layout.mdx` is the whole layout\n - Your own UI: \"Hooks for a Project Layout\" in `docs/phoenix/configurator-interface.mdx` lists the hooks with what each returns (`pnpm phoenix docs -r docs/phoenix/configurator-interface.mdx`), `docs/phoenix/layout-slots.mdx` the built-in pieces you can still mount, and `docs/layouts/custom-layout.mdx` is a worked example. Call the hooks as `phx.frontend.useX()`; besides those below, these are often needed: `usePreview()` (`isPreview` while the preview start screen shows), `useCloseAction()` (the host's close action or `null`), `useActiveViewports()` (the container's breakpoints, `null` until measured, `desktop` above 768 px: the desktop/phone switch), `useResolveLocalizable()` and `useLocalizable(text)` (spec texts to strings), `useIsCloningAllowed()` (a read-mode \"edit a copy\" action with `LayoutSlots.CloneToEditDialog`)\n - Undo and redo: `phx.frontend.useUndoRedo()` returns `{ canUndo, canRedo, undo, redo }`; disable each button from `canUndo`/`canRedo`\n - Tabs: `phx.frontend.useTabNavigation()` returns `{ source, tabs, activeTab, select }` for the spec's `sidebarTabs` (of the selected entity) or `horizontalTabs`; render `tabs` (each `{ index, label, icon, state, isActive }`, `icon` a PhxIcon name) and call `select(tab.index)` on click. Pass `{ source: 'sidebarTabs' }` or `{ source: 'horizontalTabs' }` when the layout shows one kind only. Not `LayoutSlots.useSidebarTabs()`: it serves the built-in sidebar and returns no tabs while its summary shows\n - Steps: `phx.frontend.useStepNavigation()` returns `{ steps, activeStep, activeIndex, isFirst, isLast, canGoNext, canGoPrevious, next, previous, goTo }` for the spec's `navigationSteps`; render `steps` (each `{ index, label, state, status }`, `status` `'complete' | 'active' | 'upcoming'`), call `next()`/`previous()` for Back and Next and `goTo(step.index)` from a stepper. It enforces no order and no validity: enable only `'complete'` steps for an \"earlier steps only\" stepper, and to block moving on while the configuration has a problem, require `phx.frontend.useStateValidity().severity !== 'warning'` besides `canGoNext`: a change with a `fixable` or `fatal` violation is rejected, so the configuration is never invalid, and a `warning` is the problem that stays (it blocks finalizing too). `useSteps` and `useHasSteps` from `@salsita-ai/sdk/configurator` are deprecated\n - Messages: mount `LayoutSlots.Services` for the built-in snackbars, or show violations, side-effect hints, errors and failed saves yourself with `phx.frontend.useConfiguratorMessages(onMessage)`, not both. A failed save arrives as `saveError`, the next successful save as `saveRecovery`; a layout that mounts neither shows no sign of a failed save. Either way mount a snackbar root (`LayoutSlots.DesktopSnackbarsRoot` or `LayoutSlots.MobileSnackbarsRoot`): errors of the built-in actions are always snackbars\n - Finalize over the spec's `finalizeAction` components, each naming a handler registered with `phx.frontend.createPhoenixHandler`: `phx.frontend.useFinalizeActions()` returns `{ actions, primary, secondary, disabled, hints }`; render `primary` (and `secondary` in a menu or list) in a loop, each action `{ key, label, title, icon, run, isPending, error, disabled }`, and call `action.run()` on click (its promise never rejects; show `action.error` on failure). The configurator runs the handlers itself, outside the layout, so a handler must not rely on a provider the layout adds. For one known handler, `phx.frontend.useFinalizeAction(handler)` in a component wrapped in `PhoenixHandlerBoundary` (from `@salsita-ai/sdk/react`) works too; `FinalizeActions` (from `@salsita-ai/sdk/configurator`) mounts the built-in buttons. `finalizePage` and `finalizeButton` are legacy\n - Read mode and fullscreen are the layout's job, no hook enforces them (`useUndoRedo`, `useFinalizeActions` and `useStepNavigation` included): hide undo, redo, finalization and whatever else a viewer must not change while `phx.frontend.useAccessService().accessInfo.viewMode` is `true` (tabs are navigation, so a viewer may switch them), and remove panels while `phx.frontend.useIsFullscreenActive()` is set; `phx.frontend.useSetFullscreen()` returns its setter\n - `ConfigurationNotFoundPage`: `phx.frontend.createConfigurationNotFoundPage(({ onBack }) => …)` replaces the \"configuration not accessible\" page; show a way back only when the optional `onBack` is set. The not-authenticated page's default renders it too; only the admin's not-authorized page keeps the built-in page\n - `ConfiguratorErrorPage`: `phx.frontend.createConfiguratorErrorPage(({ reason, onRetry }) => …)` replaces the production error page; `reason` is `uncaughtError` or `presetCreationFailed`. A page that throws falls back to the built-in one, and development keeps the detailed error pages, so the project page shows only in a production build. Register both pages with these helpers: `createCustomPhoenixLayoutElement` with the name works too, but types the component as taking only `children`, so the typed props do not compile there in a strict project\n - `AppLoaderContent`: `phx.frontend.createAppLoader(({ phases }) => …)` replaces what the loading overlay shows (each phase `{ id, label?, progress? }`, the list possibly empty); Phoenix keeps the overlay itself\n - Assistant form elements: an element declared under `assistant.formElements` (`description`, `role`, scalar `attributes` beside the built-in `label`, a `value` included, `required`) is the default export `phx.frontend.createAssistantFormElement('name', Component)` of one file; the name types the component's props by its role (`AssistantFormElementProps<'name'>`): an option reports its answer with `onSelect(answer)`, an input with `onChange(state, answer)`; and the application does not start while a declared element has no registration or a registration no declaration\n- `src/handlers/` — Event & lifecycle handlers\n- `src/webhooks/` — Server-side webhook handlers (`phx.webhooks.*Builder`); the webhook is the default export of `src/webhooks/index.ts`, which you create when the project needs its own handlers. Without it, generation continues with a built-in webhook that answers only anonymous auth; enabling `useAuthHook` or `useClerk` reports `AUTH_WITHOUT_PROJECT_WEBHOOK`. Add the entry with the required Clerk or custom auth handlers, or disable unintended auth settings\n- `src/migrations/` — Schema version migrations (v*.ts)\n- `src/locales/` — Locale catalogs (authored .po sources; compiled .ts, do not edit)\n- `src/admin/` — Admin interface (mirrors main src/ structure)\n- `src/_shared/` — Shared utilities (NOT auto-imported, requires explicit imports)\n- `.phoenix/` — Auto-generated files (DO NOT EDIT, except the option files in `.phoenix/variants/`)\n- `public/` — Static assets (3D models, textures, images, HDRI maps, fonts)\n- `assets/` — Uploadable resources (PDF templates, email assets)",architecturePrinciples:"## Architecture Principles\n- YAML-first: 99% of configuration in spec/*.yaml, custom code is last resort\n- ECS pattern: entities (domain objects) + components (behavior/UI) + systems (SDK runtime)\n- Reactive state: immutable domain state flows through RxJS pipelines\n- Data binding: `$read` (read-only), `$write` (write-only), `$bind` (bidirectional) connect components to domain\n- memoEval: all component implementations must use memoEval for stable object references",keyPatterns:"## Key Patterns\n- Expressions = computed properties on entities (prefix: `$`), implemented per-entity in src/expressions/\n- Actions = named domain operations (`actions:` in YAML with `params` and `result` schemas), implemented in src/actions/, prepared through `actionSystem.prepareAction()` and exposed as assistant mutations through `assistant.actions`\n- Invariants = validation rules returning violations, static or dynamic\n- Transformers = auto-fixers maintaining consistency after state changes\n- Components defined in YAML with `$read`/`$bind` bindings, or custom in src/components/ using attachComponent builder\n- Webhooks = server-side finalization tasks (PDF, email, CSV, image rendering)\n- Filters = contextual component activation via navigationStates, viewStates, modes, selectedEntityIds",fileConventions:`## File Conventions
2
2
  - Components: PascalCase (.tsx)
3
3
  - Utilities: kebab-case (.ts)
4
4
  - Expressions: entity-name.ts
@@ -1,7 +1,7 @@
1
1
  import { Branded } from '@salsita-ai/common/utils';
2
- import type { AnyEntityReflections, DomainEntity, DomainEntityReflection } from '#package/domain';
2
+ import type { AnyEntityReflections, Defaults, DomainEntity, DomainEntityReflection } from '#package/domain';
3
3
  import type { RuntimeReferenceStore } from '../../../caching/index.js';
4
- import type { Defaults, Invariants } from '../../../parse-application-files/index.js';
4
+ import type { Invariants } from '../../../parse-application-files/index.js';
5
5
  import { type RecipeDefaults } from './recipe-defaults.js';
6
6
  import { type StaticViolations } from './static-violations.js';
7
7
  interface FactoryDataRuntimeFields {
@@ -1,4 +1,4 @@
1
- import type { Defaults } from '../../../parse-application-files/index.js';
1
+ import { type Defaults } from '#package/domain';
2
2
  /**
3
3
  * The default property values of each entity type, keyed by entity type: what
4
4
  * `phx.domain.createRecipe` puts into a new recipe before the caller's overrides. Alias entries are
@@ -1 +1 @@
1
- import{createMessageDescriptor as e,isEvalMarker as t,isMsgMarker as r}from"../../../core/index.js";let s=(a,i)=>{if(null===a||"object"!=typeof a)return a;if(r(a))return e(a);if(t(a))throw Error(`The default at ${i} is an $eval expression. Defaults are static values; the parser rejects $eval in them, so the spec given to the runtime was not produced by it. Parse the spec again and pass the result.`);return Array.isArray(a)?a.map((e,t)=>s(e,`${i}[${t}]`)):Object.fromEntries(Object.entries(a).map(([e,t])=>[e,s(t,`${i}.${e}`)]))};export const createRecipeDefaults=e=>Object.fromEntries(Object.entries(e.entries).map(([e,t])=>[e,Object.fromEntries(Object.entries(t).map(([t,r])=>[t,s(r,`${e}.${t}`)]))]));
1
+ import{createMessageDescriptor as e,isEvalMarker as t,isMsgMarker as r}from"#package/domain";let a=(s,i)=>{if(null===s||"object"!=typeof s)return s;if(r(s))return e(s);if(t(s))throw Error(`The default at ${i} is an $eval expression. Defaults are static values; the parser rejects $eval in them, so the spec given to the runtime was not produced by it. Parse the spec again and pass the result.`);return Array.isArray(s)?s.map((e,t)=>a(e,`${i}[${t}]`)):Object.fromEntries(Object.entries(s).map(([e,t])=>[e,a(t,`${i}.${e}`)]))};export const createRecipeDefaults=e=>Object.fromEntries(Object.entries(e.entries).map(([e,t])=>[e,Object.fromEntries(Object.entries(t).map(([t,r])=>[t,a(r,`${e}.${t}`)]))]));
@@ -1,4 +1,4 @@
1
- import type { Violation } from '#package/domain';
1
+ import { type Violation } from '#package/domain';
2
2
  import type { Invariants } from '../../../parse-application-files/index.js';
3
3
  /**
4
4
  * The violation each static invariant of a domain reports when its implementation returns `false`,
@@ -1 +1 @@
1
- import{createMessageDescriptor as t}from"../../../core/index.js";export const createStaticViolations=e=>{let i={};for(let[o,r]of Object.entries(e.entries))for(let e of Object.values(r)){if("static"!==e.kind)continue;let r={type:String(e.violationType),severity:e.severity,message:"string"==typeof e.message?e.message:t(e.message),...void 0===e.controlViolationPriority?{}:{controlViolationPriority:e.controlViolationPriority}};i[o]={...i[o],[String(e.name)]:r}}return i};
1
+ import{createMessageDescriptor as t}from"#package/domain";export const createStaticViolations=e=>{let i={};for(let[o,r]of Object.entries(e.entries))for(let e of Object.values(r)){if("static"!==e.kind)continue;let r={type:String(e.violationType),severity:e.severity,message:"string"==typeof e.message?e.message:t(e.message),...void 0===e.controlViolationPriority?{}:{controlViolationPriority:e.controlViolationPriority}};i[o]={...i[o],[String(e.name)]:r}}return i};
@@ -1,2 +1,2 @@
1
- import { ApplicationInstance } from '../../core/index.js';
1
+ import { ApplicationInstance } from '#package/domain';
2
2
  export declare const generateRuntimeInstance: (applicationInstance: ApplicationInstance) => ApplicationInstance;
@@ -1 +1 @@
1
- import{ApplicationInstance as e}from"../../core/index.js";export const generateRuntimeInstance=n=>e(n.applicationVersion);
1
+ import{ApplicationInstance as e}from"#package/domain";export const generateRuntimeInstance=n=>e(n.applicationVersion);
@@ -1 +1 @@
1
- import{Branded as e}from"@salsita-ai/common/utils";import{DomainComponentOpticBuilder as t,adminSidebarComponent as a,attributeSelectionComponent as i,componentsByName as r,composedOfComponent as n,navigationPageComponent as o,navigationPanelListComponent as d,referenceComponent as c}from"#package/domain";import*as m from"#package/domain";import{FILTER_CRITERION_KEYS as s,isSdkCodeRef as l}from"../../../core/index.js";import{specCodeComponentKey as g,specCodeFilterId as p}from"../../runtime-spec/index.js";import{resolveSpecCode as R}from"../spec-code/index.js";let A=new Map([["reference",c],["composedOf",n],["adminSidebar",a],["attributeSelection",i],["navigationPage",o],["navigationPanelList",d]]),f={createAdminCustomPageRead:m.createAdminCustomPageRead,createAdminCustomSidebarRead:m.createAdminCustomSidebarRead,createAdminDataPageRead:m.createAdminDataPageRead,createAdminDataTableSidebarRead:m.createAdminDataTableSidebarRead,createAdminNavigationPanelRead:m.createAdminNavigationPanelRead,createAdminPresetCategoryPageRead:m.createAdminPresetCategoryPageRead,createAdminPresetCategorySelectionRead:m.createAdminPresetCategorySelectionRead,createAdminPresetCategorySelectionWrite:m.createAdminPresetCategorySelectionWrite,createAdminPresetCategorySidebarRead:m.createAdminPresetCategorySidebarRead,createAdminPresetListPageRead:m.createAdminPresetListPageRead,createAdminPresetSidebarRead:m.createAdminPresetSidebarRead,createAdminRecipeCollectionPageRead:m.createAdminRecipeCollectionPageRead,createAdminRecipeSidebarRead:m.createAdminRecipeSidebarRead},u=(e,t)=>{let a=f[e.sdkFunction]??m[e.sdkFunction];if("function"!=typeof a)throw Error(`SDK factory function "${e.sdkFunction}" not found. Make sure it is exported from the package.`);return a(...e.params.map(e=>{if(l(e)){let a=t.entities[e.$codeRef]??t.aliasReflections[e.$codeRef];if(!a)throw Error(`Reflection "${e.$codeRef}" not found in ModelRuntime. This is a bug — the target was validated at parse time.`);return a}return e}))};export const buildSdkOptic=(a,i,n,o,d)=>{let c=t.from(n),m=r.get(a.componentName)??A.get(a.componentName);if(!m)throw Error(`SDK component "${a.componentName}" not found. This is a bug — the component was validated at parse time.`);let l=c.withComponent(m,a.instanceName,!0),f=a.isAlias?l.withAlias(String(a.typeOrAlias)):l.withEntity(String(a.typeOrAlias)),P=g(String(a.typeOrAlias),String(a.instanceName),a.componentName);for(let[e,t]of i.filters.items.entries()){if("root"===t.kind){let e=t.target,a=t=>t[e];f=f.withFilter(a);continue}let a={};for(let i of s){let r=t[i];void 0!==r&&("dynamic"===r.kind?a[i]=e=>e[r.target]:"eval"===r.kind?a[i]=R(d,p(P,e,i,r.code),r.code):a[i]=r.value)}f=f.withGradualFilter(a)}let S=u(i.readFactory,o),y=u(i.writeFactory,o),b=f.attach(S,y);return e({typeOrAlias:String(a.typeOrAlias),componentName:a.componentName,instanceName:String(a.instanceName),optic:b})};
1
+ import{Branded as e}from"@salsita-ai/common/utils";import{DomainComponentOpticBuilder as t,FILTER_CRITERION_KEYS as a,adminSidebarComponent as i,attributeSelectionComponent as r,componentsByName as n,composedOfComponent as o,isSdkCodeRef as d,navigationPageComponent as c,navigationPanelListComponent as m,referenceComponent as s}from"#package/domain";import*as l from"#package/domain";import{specCodeComponentKey as g,specCodeFilterId as p}from"../../runtime-spec/index.js";import{resolveSpecCode as R}from"../spec-code/index.js";let A=new Map([["reference",s],["composedOf",o],["adminSidebar",i],["attributeSelection",r],["navigationPage",c],["navigationPanelList",m]]),f={createAdminCustomPageRead:l.createAdminCustomPageRead,createAdminCustomSidebarRead:l.createAdminCustomSidebarRead,createAdminDataPageRead:l.createAdminDataPageRead,createAdminDataTableSidebarRead:l.createAdminDataTableSidebarRead,createAdminNavigationPanelRead:l.createAdminNavigationPanelRead,createAdminPresetCategoryPageRead:l.createAdminPresetCategoryPageRead,createAdminPresetCategorySelectionRead:l.createAdminPresetCategorySelectionRead,createAdminPresetCategorySelectionWrite:l.createAdminPresetCategorySelectionWrite,createAdminPresetCategorySidebarRead:l.createAdminPresetCategorySidebarRead,createAdminPresetListPageRead:l.createAdminPresetListPageRead,createAdminPresetSidebarRead:l.createAdminPresetSidebarRead,createAdminRecipeCollectionPageRead:l.createAdminRecipeCollectionPageRead,createAdminRecipeSidebarRead:l.createAdminRecipeSidebarRead},u=(e,t)=>{let a=f[e.sdkFunction]??l[e.sdkFunction];if("function"!=typeof a)throw Error(`SDK factory function "${e.sdkFunction}" not found. Make sure it is exported from the package.`);return a(...e.params.map(e=>{if(d(e)){let a=t.entities[e.$codeRef]??t.aliasReflections[e.$codeRef];if(!a)throw Error(`Reflection "${e.$codeRef}" not found in ModelRuntime. This is a bug — the target was validated at parse time.`);return a}return e}))};export const buildSdkOptic=(i,r,o,d,c)=>{let m=t.from(o),s=n.get(i.componentName)??A.get(i.componentName);if(!s)throw Error(`SDK component "${i.componentName}" not found. This is a bug — the component was validated at parse time.`);let l=m.withComponent(s,i.instanceName,!0),f=i.isAlias?l.withAlias(String(i.typeOrAlias)):l.withEntity(String(i.typeOrAlias)),P=g(String(i.typeOrAlias),String(i.instanceName),i.componentName);for(let[e,t]of r.filters.items.entries()){if("root"===t.kind){let e=t.target,a=t=>t[e];f=f.withFilter(a);continue}let i={};for(let r of a){let a=t[r];void 0!==a&&("dynamic"===a.kind?i[r]=e=>e[a.target]:"eval"===a.kind?i[r]=R(c,p(P,e,r,a.code),a.code):i[r]=a.value)}f=f.withGradualFilter(i)}let S=u(r.readFactory,d),y=u(r.writeFactory,d),b=f.attach(S,y);return e({typeOrAlias:String(i.typeOrAlias),componentName:i.componentName,instanceName:String(i.instanceName),optic:b})};
@@ -1,5 +1,5 @@
1
1
  import { Branded } from '@salsita-ai/common/utils';
2
- import type { DomainEntity, Expression as DomainExpression, Invariant as DomainInvariant, ImplementationErrorCollector, ProjectModule } from '#package/domain';
2
+ import { type DomainEntity, type Expression as DomainExpression, type Invariant as DomainInvariant, type ImplementationErrorCollector, type ProjectModule } from '#package/domain';
3
3
  import type { RuntimeReferenceStore } from '../../../caching/index.js';
4
4
  import type { Expressions } from '../../../parse-application-files/index.js';
5
5
  import { type RuntimeModelVersion } from '../../runtime-spec/index.js';
@@ -1 +1 @@
1
- import e from"lodash-es/isEqual.js";import{Branded as t}from"@salsita-ai/common/utils";import{ImplementationError as i,createRelationFactory as n,mergeExpressionModules as a}from"#package/domain";import{canonicalEnhancedJsonValueKey as r,isSdkExpressionImplementation as o}from"../../../core/index.js";import{specCodeExpressionKey as l}from"../../runtime-spec/index.js";import{generateMemoEvalPlanRuntime as s}from"./generate-memo-eval-plan-runtime.js";let p={},m=["0-1","1-1","0-N","1-N"],d={relation:(e,t)=>{let i=t[0];if(!("object"==typeof i&&null!==i&&"kind"in i&&"target"in i&&"string"==typeof i.target&&"cardinality"in i&&m.includes(i.cardinality)&&("allOfType"===i.kind||("direct"===i.kind||"indirect"===i.kind)&&"field"in i&&"string"==typeof i.field)))throw Error("Cannot create the relation expression because its parameter is not a relation declaration. The application spec is inconsistent; rebuild it from a valid relations declaration.");return n(e.aliasMap)(i)},violations:(e,t)=>{let i=t[0];if("object"!=typeof i||null===i||!("entityType"in i)||"string"!=typeof i.entityType)throw Error("Cannot create the violations expression because its entityType parameter is missing. The application spec is inconsistent; rebuild it from a valid invariants declaration.");let n=i.entityType,a=Object.entries(e.invariantImplementations).flatMap(([t,i])=>{let a=e.aliasMap[t];return t===n||a?.includes(n)?i:[]});return{origin:{name:"$violations",typeOrAlias:n},evaluate:(e,t,i)=>a.flatMap(n=>n.evaluate(e,t,i)),meta:{}}}},f=e=>{let t=s(e.plan,l(e.entityOrAlias,e.name),e.code);return{origin:{name:e.name,typeOrAlias:e.entityOrAlias},evaluate:(e,i,n)=>t(n.domain.get$Entity(e,i),i,n),meta:{}}},u=e=>({...(0,d[e.kind])({aliasMap:e.aliasMap,invariantImplementations:e.invariantImplementations},e.params),origin:{name:e.name,typeOrAlias:e.entityOrAlias}});export const ExpressionRuntime=(n,l,s,m,d=p,c,g,y={})=>{let v={};for(let[e,t]of n.latestModel.aliases)v[String(e)]=t.map(String);let x={...y};for(let[e,t]of Object.entries(a(s,v,g,((e,t,i)=>{let n=new Map,a=(e,t)=>{n.set(e,(n.get(e)??new Set).add(t))};for(let[i,n]of e.expressions.expressions)for(let[e,r]of n)if("user"!==r.implementation.kind)for(let n of t[String(i)]??[String(i)])a(n,String(e));for(let[e,t]of Object.entries(i))for(let i of Object.keys(t))a(e,i);return n})(n,v,y))))x[e]={...x[e],...t};let S=l.createBuilder(`${m}/sdk`,{build:u,getKey:e=>`sdk::${e.entityOrAlias}::${e.name}`,compare:(t,i)=>t.kind===i.kind&&e(t.params,i.params)&&e(t.aliasMap,i.aliasMap)&&("violations"!==i.kind||t.invariantImplementations===i.invariantImplementations)}),h=l.createBuilder(`${m}/user`,{build:e=>e.impl,getKey:e=>`user::${e.entityType}::${e.name}`,compare:(e,t)=>{let i,n;return(i=e.impl)===(n=t.impl)||i.evaluate===n.evaluate&&i.meta===n.meta&&i.origin.name===n.origin.name&&i.origin.typeOrAlias===n.origin.typeOrAlias}}),O=l.createBuilder(`${m}/value`,{build:f,getKey:e=>`value::${e.entityOrAlias}::${e.name}`,compare:(e,t)=>e.valueKey===t.valueKey&&e.code===t.code}),b={},k=!1,$=new Set,M=new Set,j=new Set;for(let[e,t]of n.expressions.expressions)for(let[,i]of t){let t=v[String(e)]??[String(e)];if(o(i.implementation)){let n={entityOrAlias:String(e),name:String(i.name),kind:i.implementation.kind,params:i.implementation.params,aliasMap:v,invariantImplementations:d},a=S.build(n);for(let e of(a.changed&&(k=!0),$.add(S.getKey(n)),t))b[e]||(b[e]={}),b[e][String(i.name)]=a.output;continue}if("value"===i.implementation.kind){let n=i.implementation.value,a={entityOrAlias:String(e),name:String(i.name),valueKey:r(n),plan:i.implementation.plan,code:c},o=O.build(a);for(let e of(o.changed&&(k=!0),j.add(O.getKey(a)),t))b[e]||(b[e]={}),b[e][String(i.name)]=o.output;continue}}for(let[e,t]of Object.entries(x))for(let[i,n]of Object.entries(t)){let t={entityType:e,name:i,impl:n},a=h.build(t);a.changed&&(k=!0),M.add(h.getKey(t)),b[e]||(b[e]={}),b[e][i]=a.output}S.cleanup($)&&(k=!0),h.cleanup(M)&&(k=!0),O.cleanup(j)&&(k=!0);let A=[];for(let[e,t]of n.expressions.entityExpressions)for(let i of t.shapeGroups){let t=n.expressions.expressions.get(i);if(t)for(let[i]of t)b[String(e)]?.[String(i)]||A.push({entityType:String(e),exprName:String(i)})}return A.length>0?(A.forEach(e=>g.add(new i({code:"MISSING_IMPLEMENTATION",origin:null,problem:`Missing implementation of expression ${e.entityType}.${e.exprName}`,fix:"The spec declares it without a value of its own ($eval, $msg or a read), so a project file implements it: a default export of phx.domain.implementCustomExpressions({ ... }) in src/expressions/, or of phx.domain.admin.implementCustomExpressions({ ... }) in src/admin/expressions/ for an admin entity type. Implement it, or remove the declaration from the spec."}))),{ok:!1,missing:A}):{ok:!0,runtime:t({merged:b,changed:k})}};
1
+ import e from"lodash-es/isEqual.js";import{Branded as t}from"@salsita-ai/common/utils";import{ImplementationError as i,canonicalEnhancedJsonValueKey as n,createRelationFactory as a,isSdkExpressionImplementation as r,mergeExpressionModules as o}from"#package/domain";import{specCodeExpressionKey as l}from"../../runtime-spec/index.js";import{generateMemoEvalPlanRuntime as s}from"./generate-memo-eval-plan-runtime.js";let p={},m=["0-1","1-1","0-N","1-N"],d={relation:(e,t)=>{let i=t[0];if(!("object"==typeof i&&null!==i&&"kind"in i&&"target"in i&&"string"==typeof i.target&&"cardinality"in i&&m.includes(i.cardinality)&&("allOfType"===i.kind||("direct"===i.kind||"indirect"===i.kind)&&"field"in i&&"string"==typeof i.field)))throw Error("Cannot create the relation expression because its parameter is not a relation declaration. The application spec is inconsistent; rebuild it from a valid relations declaration.");return a(e.aliasMap)(i)},violations:(e,t)=>{let i=t[0];if("object"!=typeof i||null===i||!("entityType"in i)||"string"!=typeof i.entityType)throw Error("Cannot create the violations expression because its entityType parameter is missing. The application spec is inconsistent; rebuild it from a valid invariants declaration.");let n=i.entityType,a=Object.entries(e.invariantImplementations).flatMap(([t,i])=>{let a=e.aliasMap[t];return t===n||a?.includes(n)?i:[]});return{origin:{name:"$violations",typeOrAlias:n},evaluate:(e,t,i)=>a.flatMap(n=>n.evaluate(e,t,i)),meta:{}}}},f=e=>{let t=s(e.plan,l(e.entityOrAlias,e.name),e.code);return{origin:{name:e.name,typeOrAlias:e.entityOrAlias},evaluate:(e,i,n)=>t(n.domain.get$Entity(e,i),i,n),meta:{}}},u=e=>({...(0,d[e.kind])({aliasMap:e.aliasMap,invariantImplementations:e.invariantImplementations},e.params),origin:{name:e.name,typeOrAlias:e.entityOrAlias}});export const ExpressionRuntime=(a,l,s,m,d=p,c,g,y={})=>{let v={};for(let[e,t]of a.latestModel.aliases)v[String(e)]=t.map(String);let x={...y};for(let[e,t]of Object.entries(o(s,v,g,((e,t,i)=>{let n=new Map,a=(e,t)=>{n.set(e,(n.get(e)??new Set).add(t))};for(let[i,n]of e.expressions.expressions)for(let[e,r]of n)if("user"!==r.implementation.kind)for(let n of t[String(i)]??[String(i)])a(n,String(e));for(let[e,t]of Object.entries(i))for(let i of Object.keys(t))a(e,i);return n})(a,v,y))))x[e]={...x[e],...t};let S=l.createBuilder(`${m}/sdk`,{build:u,getKey:e=>`sdk::${e.entityOrAlias}::${e.name}`,compare:(t,i)=>t.kind===i.kind&&e(t.params,i.params)&&e(t.aliasMap,i.aliasMap)&&("violations"!==i.kind||t.invariantImplementations===i.invariantImplementations)}),h=l.createBuilder(`${m}/user`,{build:e=>e.impl,getKey:e=>`user::${e.entityType}::${e.name}`,compare:(e,t)=>{let i,n;return(i=e.impl)===(n=t.impl)||i.evaluate===n.evaluate&&i.meta===n.meta&&i.origin.name===n.origin.name&&i.origin.typeOrAlias===n.origin.typeOrAlias}}),O=l.createBuilder(`${m}/value`,{build:f,getKey:e=>`value::${e.entityOrAlias}::${e.name}`,compare:(e,t)=>e.valueKey===t.valueKey&&e.code===t.code}),b={},k=!1,$=new Set,M=new Set,A=new Set;for(let[e,t]of a.expressions.expressions)for(let[,i]of t){let t=v[String(e)]??[String(e)];if(r(i.implementation)){let n={entityOrAlias:String(e),name:String(i.name),kind:i.implementation.kind,params:i.implementation.params,aliasMap:v,invariantImplementations:d},a=S.build(n);for(let e of(a.changed&&(k=!0),$.add(S.getKey(n)),t))b[e]||(b[e]={}),b[e][String(i.name)]=a.output;continue}if("value"===i.implementation.kind){let a=i.implementation.value,r={entityOrAlias:String(e),name:String(i.name),valueKey:n(a),plan:i.implementation.plan,code:c},o=O.build(r);for(let e of(o.changed&&(k=!0),A.add(O.getKey(r)),t))b[e]||(b[e]={}),b[e][String(i.name)]=o.output;continue}}for(let[e,t]of Object.entries(x))for(let[i,n]of Object.entries(t)){let t={entityType:e,name:i,impl:n},a=h.build(t);a.changed&&(k=!0),M.add(h.getKey(t)),b[e]||(b[e]={}),b[e][i]=a.output}S.cleanup($)&&(k=!0),h.cleanup(M)&&(k=!0),O.cleanup(A)&&(k=!0);let T=[];for(let[e,t]of a.expressions.entityExpressions)for(let i of t.shapeGroups){let t=a.expressions.expressions.get(i);if(t)for(let[i]of t)b[String(e)]?.[String(i)]||T.push({entityType:String(e),exprName:String(i)})}return T.length>0?(T.forEach(e=>g.add(new i({code:"MISSING_IMPLEMENTATION",origin:null,problem:`Missing implementation of expression ${e.entityType}.${e.exprName}`,fix:"The spec declares it without a value of its own ($eval, $msg or a read), so a project file implements it: a default export of phx.domain.implementCustomExpressions({ ... }) in src/expressions/, or of phx.domain.admin.implementCustomExpressions({ ... }) in src/admin/expressions/ for an admin entity type. Implement it, or remove the declaration from the spec."}))),{ok:!1,missing:T}):{ok:!0,runtime:t({merged:b,changed:k})}};
@@ -1,4 +1,4 @@
1
- import type { SelfAccessor } from '../../../core/index.js';
1
+ import { type SelfAccessor } from '#package/domain';
2
2
  import type { MemoEvalPlan } from '../../../parse-application-files/spec/index.js';
3
3
  import { type SpecCodeMap } from '../spec-code/index.js';
4
4
  /**
@@ -1 +1 @@
1
- import{memoEval as e}from"#package/domain";import{createMessageDescriptor as t}from"../../../core/index.js";import{specCodeEvalIds as r}from"../../runtime-spec/index.js";import{resolveSpecCode as a}from"../spec-code/index.js";let n=(e,r)=>{if("literal"===e.kind)return e.value;if("slot"===e.kind)return r[e.depIndex];if("msg"===e.kind)return t(e.marker);if("array"===e.kind)return e.items.map(e=>n(e,r));let a={};for(let[t,l]of e.entries)a[t]=n(l,r);return a};export const generateMemoEvalPlanRuntime=(t,l,i)=>{if(0===t.deps.length){let e=n(t.template,[]);return()=>e}let o=r(t,l),s=t.deps.map((e,t)=>{let r=o[t];return"eval"===e.kind&&void 0!==r?a(i,r,e.code):void 0});return e(e=>t.deps.map((t,r)=>"eval"===t.kind?s[r](e):Reflect.get(e,t.target)),(...e)=>n(t.template,e))};export const evaluateStaticMemoEvalPlan=(e,t,l)=>{if(e.usesSelf)throw Error("Cannot evaluate a plan that uses self as a static value. Filter self-dependent plans before evaluating constants.");let i=r(e,t),o=e.deps.map((e,t)=>{if("read"===e.kind)throw Error(`Cannot evaluate the self-dependent read "${e.target}" as a static value. Filter self-dependent plans before evaluating constants.`);return a(l,i[t],e.code)()});return n(e.template,o)};
1
+ import{createMessageDescriptor as e,memoEval as t}from"#package/domain";import{specCodeEvalIds as a}from"../../runtime-spec/index.js";import{resolveSpecCode as r}from"../spec-code/index.js";let n=(t,a)=>{if("literal"===t.kind)return t.value;if("slot"===t.kind)return a[t.depIndex];if("msg"===t.kind)return e(t.marker);if("array"===t.kind)return t.items.map(e=>n(e,a));let r={};for(let[e,l]of t.entries)r[e]=n(l,a);return r};export const generateMemoEvalPlanRuntime=(e,l,i)=>{if(0===e.deps.length){let t=n(e.template,[]);return()=>t}let s=a(e,l),o=e.deps.map((e,t)=>{let a=s[t];return"eval"===e.kind&&void 0!==a?r(i,a,e.code):void 0});return t(t=>e.deps.map((e,a)=>"eval"===e.kind?o[a](t):Reflect.get(t,e.target)),(...t)=>n(e.template,t))};export const evaluateStaticMemoEvalPlan=(e,t,l)=>{if(e.usesSelf)throw Error("Cannot evaluate a plan that uses self as a static value. Filter self-dependent plans before evaluating constants.");let i=a(e,t),s=e.deps.map((e,t)=>{if("read"===e.kind)throw Error(`Cannot evaluate the self-dependent read "${e.target}" as a static value. Filter self-dependent plans before evaluating constants.`);return r(l,i[t],e.code)()});return n(e.template,s)};
@@ -1,7 +1,6 @@
1
1
  import { Branded } from '@salsita-ai/common/utils';
2
- import type { DomainEntity, ProductPreset } from '#package/domain';
2
+ import type { DomainEntity, ProductPreset, SpecPreset } from '#package/domain';
3
3
  import type { RuntimeReferenceStore } from '../../../caching/index.js';
4
- import type { Preset } from '../../../parse-application-files/index.js';
5
4
  type AnyProductPreset = ProductPreset<DomainEntity<string>, DomainEntity<string>>;
6
5
  /** Collection of runtime presets with change tracking. */
7
6
  export type PresetRuntime = Branded<'PresetRuntime', {
@@ -10,7 +9,7 @@ export type PresetRuntime = Branded<'PresetRuntime', {
10
9
  }>;
11
10
  interface PresetRuntimeProps {
12
11
  readonly referenceScope: string;
13
- readonly presets: readonly Preset[];
12
+ readonly presets: readonly SpecPreset[];
14
13
  }
15
14
  /**
16
15
  * Builds preset runtime objects with per-item reference stability.
@@ -1,4 +1,5 @@
1
- import type { ExpressionName, Expressions, MemoEvalPlan } from '../../../parse-application-files/index.js';
1
+ import type { ExpressionName } from '#package/domain';
2
+ import type { Expressions, MemoEvalPlan } from '../../../parse-application-files/index.js';
2
3
  import type { SpecCodeMap } from '../spec-code/index.js';
3
4
  /** The self-free `constants:` plans declared on one entity or alias, or `undefined` when it has none. */
4
5
  export declare const findReflectionConstants: (expressions: Expressions, entityOrAlias: string) => ReadonlyMap<ExpressionName, MemoEvalPlan> | undefined;
@@ -1,4 +1,4 @@
1
- import type { SelfAccessor } from '../../../core/index.js';
1
+ import type { SelfAccessor } from '#package/domain';
2
2
  import type { SpecCodeId } from '../../runtime-spec/index.js';
3
3
  import type { SpecCodeMap } from './spec-code-module.js';
4
4
  /**
@@ -1 +1 @@
1
- import{Branded as e}from"@salsita-ai/common/utils";import{ParseContext as s}from"../core/index.js";import{CategorizedFiles as t}from"./categorize/index.js";import{MergedSpec as i}from"./merge/index.js";import{RawSpecFiles as r}from"./raw-spec/parse-raw-spec.js";import{RawMockTemplates as p}from"./raw-spec/raw-mock-templates.js";import{ResolvedSpecFiles as a}from"./resolve/index.js";import{ApplicationSpec as o}from"./spec/index.js";export const parseApplicationFiles=(l,n)=>{let{rawProjectFiles:m,phxDefinitions:c}=l,{evalExpressionParser:d,referenceStore:f,parsingContext:F}=n,u=F??new s,S=u.startSpan("parseApplicationFiles","build","parse-application-files.ts"),g=t(m,f,u,n);if(!g)return S(),u.toResult(void 0);let w=u.startSpan("RawSpecFiles","parseApplicationFiles","parse-raw-spec.ts"),A=r(g.spec,u);w();let R=u.startSpan("RawMockTemplates","parseApplicationFiles","raw-mock-templates.ts"),j=p(g.mockTemplates,u);if(R(),!A)return S(),u.toResult(void 0);let v=u.startSpan("ResolvedSpecFiles","parseApplicationFiles","resolved-spec-files.ts"),x=a(A,m,u);v();let k=u.startSpan("MergedSpec","parseApplicationFiles","merged-spec.ts"),M=i(x,u);if(k(),u.hasErrors)return S(),u.toResult(void 0);let T=u.startSpan("ApplicationSpec","parseApplicationFiles","application-spec.ts"),b=o({merged:M,migrationFiles:g.migrations,adminMigrationFiles:g.adminMigrations,transformerFiles:g.transformers.map(e=>e.file.name),phxDefinitions:c,evalExpressionParser:d},u);return(T(),b)?(S(),u.toResult(e({rawProjectFiles:m,categorizedFiles:g,rawMockTemplates:j,applicationSpec:b}))):(S(),u.toResult(void 0))};
1
+ import{Branded as e}from"@salsita-ai/common/utils";import{ParseContext as s}from"../core/index.js";import{DiagnosticCode as t,diagnosticMessages as r}from"../errors/index.js";import{CategorizedFiles as i}from"./categorize/index.js";import{MergedSpec as a}from"./merge/index.js";import{RawSpecFiles as p}from"./raw-spec/parse-raw-spec.js";import{RawMockTemplates as o}from"./raw-spec/raw-mock-templates.js";import{ResolvedSpecFiles as l}from"./resolve/index.js";import{ApplicationSpec as n}from"./spec/index.js";export const parseApplicationFiles=(m,c)=>{let{rawProjectFiles:d,phxDefinitions:f}=m,{evalExpressionParser:u,referenceStore:F,parsingContext:A}=c,g=A??new s,w=g.startSpan("parseApplicationFiles","build","parse-application-files.ts"),R=i(d,F,g,c);if(!R)return w(),g.toResult(void 0);let S=g.startSpan("RawSpecFiles","parseApplicationFiles","parse-raw-spec.ts"),T=p(R.spec,g);S();let j=g.startSpan("RawMockTemplates","parseApplicationFiles","raw-mock-templates.ts"),O=o(R.mockTemplates,g);if(j(),!T)return w(),g.toResult(void 0);let k=g.startSpan("ResolvedSpecFiles","parseApplicationFiles","resolved-spec-files.ts"),v=l(T,d,g);k();let x=g.startSpan("MergedSpec","parseApplicationFiles","merged-spec.ts"),H=a(v,g);if(x(),g.hasErrors)return w(),g.toResult(void 0);let E=g.startSpan("ApplicationSpec","parseApplicationFiles","application-spec.ts"),M=n({merged:H,migrationFiles:R.migrations,adminMigrationFiles:R.adminMigrations,transformerFiles:R.transformers.map(e=>e.file.name),phxDefinitions:f,evalExpressionParser:u},g);return(E(),M)?(!R.hasWebhookEntry&&(M.appMetadata.useAuthHook||M.appMetadata.useClerk)&&g.warning(t.AUTH_WITHOUT_PROJECT_WEBHOOK,r.AUTH_WITHOUT_PROJECT_WEBHOOK()),w(),g.toResult(e({rawProjectFiles:d,categorizedFiles:R,rawMockTemplates:O,applicationSpec:M}))):(w(),g.toResult(void 0))};
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
+ import { type EnhancedJsonValue } from '#package/domain';
2
3
  import { type EnhancedJsonSchemaType } from '../../core/enhanced-json-schema.js';
3
- import { type EnhancedJsonValue } from '../../core/enhanced-json-value.js';
4
4
  /**
5
5
  * Discriminator tag for a single parsed expression entry.
6
6
  *
@@ -1 +1 @@
1
- import{z as r}from"zod";import{enhancedJsonSchema as e,extendEnhancedJsonSchema as s}from"../../core/enhanced-json-schema.js";import{EVAL_MARKER_KEY as n,evalMarkerSchema as o}from"../../core/markers/eval-marker.js";import{MSG_ID_MARKER_KEY as a,MSG_MARKER_KEY as t,msgMarkerSchema as i}from"../../core/markers/msg-marker.js";export const RawExpressionKind={User:"user",Value:"value"};let m=s(o),c=s(i),d=[n,t,a],l=r=>{let e={};for(let[s,n]of Object.entries(r))d.includes(s)||(e[s]=n);return e};export const rawExpressionEntrySchema=r.union([m,c,e]).transform(r=>{if(n in r)return{kind:RawExpressionKind.Value,constant:!1,value:{[n]:r.$eval},schema:l(r)};if(t in r){let e=void 0!==r.$msgId?{[t]:r.$msg,[a]:r.$msgId}:{[t]:r.$msg};return{kind:RawExpressionKind.Value,constant:!1,value:e,schema:l(r)}}return{kind:RawExpressionKind.User,schema:r}});export const rawExpressionsSchema=r.record(r.string(),r.record(r.string(),rawExpressionEntrySchema).readonly()).readonly();
1
+ import{z as e}from"zod";import{EVAL_MARKER_KEY as r,MSG_ID_MARKER_KEY as n,MSG_MARKER_KEY as s,evalMarkerSchema as o,msgMarkerSchema as a}from"#package/domain";import{enhancedJsonSchema as i,extendEnhancedJsonSchema as t}from"../../core/enhanced-json-schema.js";export const RawExpressionKind={User:"user",Value:"value"};let c=t(o),m=t(a),d=[r,s,n],p=e=>{let r={};for(let[n,s]of Object.entries(e))d.includes(n)||(r[n]=s);return r};export const rawExpressionEntrySchema=e.union([c,m,i]).transform(e=>{if(r in e)return{kind:RawExpressionKind.Value,constant:!1,value:{[r]:e.$eval},schema:p(e)};if(s in e){let r=void 0!==e.$msgId?{[s]:e.$msg,[n]:e.$msgId}:{[s]:e.$msg};return{kind:RawExpressionKind.Value,constant:!1,value:r,schema:p(e)}}return{kind:RawExpressionKind.User,schema:e}});export const rawExpressionsSchema=e.record(e.string(),e.record(e.string(),rawExpressionEntrySchema).readonly()).readonly();
@@ -1,16 +1,10 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { SpecAliases } from '#package/domain';
2
2
  import type { ParseContext } from '../../../core/index.js';
3
3
  import type { MergedModelVersion } from '../../merge/index.js';
4
4
  import type { EntityTypes } from './entity-types.js';
5
5
  import { AliasName } from './names/alias-name.js';
6
- import type { EntityTypeName } from './names/entity-type-name.js';
7
- /**
8
- * Flattened alias map — each alias name maps to the concrete entity types it resolves to.
9
- * Nested aliases (e.g. AllLegs → [SteelLegs, LegsOak] where SteelLegs is itself an alias)
10
- * are fully resolved to leaf entity types. Includes the synthetic "AnyDomainEntity" alias
11
- * that maps to all entity types in the version.
12
- */
13
- export type Aliases = Branded<'Aliases', ReadonlyMap<AliasName, readonly EntityTypeName[]>>;
6
+ /** The flattened alias map of a model version; see {@link SpecAliases} in `domain`. */
7
+ export type Aliases = SpecAliases;
14
8
  /** Well-known alias name for root entity types — required in every model version. */
15
9
  export declare const ROOT_ENTITY_ALIAS: AliasName;
16
10
  export declare const Aliases: (merged: MergedModelVersion, entityTypes: EntityTypes, ctx: ParseContext) => Aliases | undefined;
@@ -1,18 +1,10 @@
1
- import { Branded } from '@salsita-ai/common/utils';
2
- import { type EnhancedJsonSchemaType, type JsonSchema, type ParseContext, type PhoenixDefinitions } from '../../../core/index.js';
1
+ import type { CommonType as CommonTypeData, CommonTypes as CommonTypesData } from '#package/domain';
2
+ import { type ParseContext, type PhoenixDefinitions } from '../../../core/index.js';
3
3
  import type { MergedModelVersion } from '../../merge/index.js';
4
- /** A single common type definition with both enhanced schema (for type inference) and resolved runtime schema. */
5
- export type CommonType = Branded<'CommonType', {
6
- readonly name: string;
7
- readonly schema: EnhancedJsonSchemaType;
8
- readonly runtimeSchema: JsonSchema;
9
- }>;
10
- /**
11
- * Branded map of common type name to CommonType.
12
- * Entries are in topo-sorted order (dependencies before dependents),
13
- * so iterating the map yields types in valid emission order.
14
- */
15
- export type CommonTypes = Branded<'CommonTypes', ReadonlyMap<string, CommonType>>;
4
+ /** A common type with its enhanced and runtime schemas; see {@link CommonTypeData | CommonType} in `domain`. */
5
+ export type CommonType = CommonTypeData;
6
+ /** The common types of a model version by name; see {@link CommonTypesData | CommonTypes} in `domain`. */
7
+ export type CommonTypes = CommonTypesData;
16
8
  /**
17
9
  * Validates, topo-sorts, and resolves commonType entries from the merged model version.
18
10
  *
@@ -1,37 +1,12 @@
1
- import { Branded } from '@salsita-ai/common/utils';
2
- import { type EnhancedJsonValue, type ParseContext } from '../../../core/index.js';
1
+ import type { Defaults as DefaultsData } from '#package/domain';
2
+ import { type ParseContext } from '../../../core/index.js';
3
3
  import type { MergedDefaults } from '../../merge/index.js';
4
4
  import type { ModelVersion } from './model-version.js';
5
- import type { EntityTypeName } from './names/entity-type-name.js';
6
- import { ShapePropertyName } from './names/shape-property-name.js';
5
+ export type { DefaultEntries } from '#package/domain';
7
6
  /**
8
- * A map of shape property names to their default values inside a single entity block.
9
- * Raw YAML values — markers intact — keyed by a validated {@link ShapePropertyName}.
10
- * Codegen emits these as-is via `stringifyEnhancedJsonValue`; at run time
11
- * `createRecipeFactory` makes the generated `createRecipe` factory from them.
12
- */
13
- export type DefaultEntries = Readonly<Record<ShapePropertyName, EnhancedJsonValue>>;
14
- /**
15
- * Validated defaults map — source keys confirmed to exist in `model.latest`,
16
- * property names confirmed to exist on the (effective) shape of the entity
17
- * or on every alias member's effective shape, values type-checked against the
18
- * relaxed entity shape (all properties optional). Alias-keyed defaults are
19
- * flattened here to concrete entity entries so downstream codegen only serialises
20
- * a runtime-ready per-entity map.
21
- *
22
- * A source key may state part of a shape, but the flattened entry of a concrete
23
- * entity type states every property of its shape: `createRecipeFactory` validates
24
- * each entry as a whole entity when the generated module loads. An entity type
25
- * with no entry has no defaults and is not checked.
26
- *
27
- * Values are raw `EnhancedJsonValue` so codegen can emit them via
28
- * `stringifyEnhancedJsonValue` with `$msg` markers preserved.
7
+ * The validated defaults of a domain by entity type; see {@link DefaultsData | Defaults} in `domain`.
29
8
  *
30
- * **Deprecated feature.** The whole defaults surface is retained for legacy parity.
31
- * New specs should express initial values as `$data` entries. When the merged map is
32
- * non-empty, the factory emits a `DEFAULTS_DEPRECATED` warning.
9
+ * **Deprecated feature.** New specs express initial values as `$data` entries.
33
10
  */
34
- export type Defaults = Branded<'Defaults', {
35
- readonly entries: Readonly<Record<EntityTypeName, DefaultEntries>>;
36
- }>;
11
+ export type Defaults = DefaultsData;
37
12
  export declare const Defaults: (merged: MergedDefaults, latestModel: ModelVersion, ctx: ParseContext) => Defaults | undefined;
@@ -1,13 +1,8 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { EntityTypes as EntityTypesData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../core/index.js';
3
3
  import type { MergedModelVersion } from '../../merge/index.js';
4
- import { EntityTypeName } from './names/entity-type-name.js';
5
- /**
6
- * Validated list of entity type names declared in a model version (e.g. [Table, TopCircle, Legs3D]).
7
- * Entity types are the concrete domain objects that can be instantiated in the configurator.
8
- * Each name must be unique PascalCase.
9
- */
10
- export type EntityTypes = Branded<'EntityTypes', readonly EntityTypeName[]>;
4
+ /** The entity type names a model version declares; see {@link EntityTypesData | EntityTypes} in `domain`. */
5
+ export type EntityTypes = EntityTypesData;
11
6
  /**
12
7
  * Validates and brands entity type names from a merged model version.
13
8
  * Checks PascalCase naming and rejects duplicates.
@@ -1,6 +1,6 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { ModelVersionKey as ModelVersionKeyData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../core/index.js';
3
- /** Branded string for a model version key ("latest", "v1", "v2", etc.). */
4
- export type ModelVersionKey = Branded<'ModelVersionKey', string>;
3
+ /** A model version key (`latest`, `v1`, `v2`, …); see {@link ModelVersionKeyData | ModelVersionKey} in `domain`. */
4
+ export type ModelVersionKey = ModelVersionKeyData;
5
5
  /** Validates that a version key is "latest" or "v{N}" (e.g. "v1", "v2"). */
6
6
  export declare const ModelVersionKey: (key: string, ctx: ParseContext) => ModelVersionKey | undefined;
@@ -1,10 +1,6 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { ActionName as ActionNameData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../../core/index.js';
3
- /**
4
- * Branded action name: camelCase without a prefix (e.g. "movePartBy", "swapCabinets"). An action is
5
- * a named domain operation, so its name doubles as the key of its implementation and of its
6
- * generated types.
7
- */
8
- export type ActionName = Branded<'ActionName', string>;
3
+ /** A branded action name; see {@link ActionNameData | ActionName} in `domain`. */
4
+ export type ActionName = ActionNameData;
9
5
  /** Validates that a name follows the action naming convention (camelCase, no prefix). */
10
6
  export declare const ActionName: (name: string, ctx: ParseContext) => ActionName | undefined;
@@ -1,11 +1,7 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { AliasName as AliasNameData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../../core/index.js';
3
- /**
4
- * Branded PascalCase alias name (e.g. "RootEntity", "AllLegs").
5
- * Aliases group entity types so that shapes, expressions, and rules can target
6
- * multiple entities at once. "RootEntity" is required in every model version.
7
- */
8
- export type AliasName = Branded<'AliasName', string>;
3
+ /** A branded alias name; see {@link AliasNameData | AliasName} in `domain`. */
4
+ export type AliasName = AliasNameData;
9
5
  export declare const RESERVED_ALIAS_NAMES: readonly ['AnyDomainEntity'];
10
6
  /** Validates PascalCase naming and rejects reserved names (AnyDomainEntity). */
11
7
  export declare const AliasName: (name: string, ctx: ParseContext) => AliasName | undefined;
@@ -1,11 +1,6 @@
1
+ import type { EntityOrAliasName as EntityOrAliasNameData } from '#package/domain';
1
2
  import type { ParseContext } from '../../../../core/index.js';
2
- import { AliasName } from './alias-name.js';
3
- import { EntityTypeName } from './entity-type-name.js';
4
- /**
5
- * A PascalCase name that identifies either a concrete entity type (e.g. "Table")
6
- * or an alias group (e.g. "RootEntity"). Used as shape keys since shapes
7
- * can be defined for both entity types and aliases.
8
- */
9
- export type EntityOrAliasName = EntityTypeName | AliasName;
3
+ /** The name of an entity type or an alias; see {@link EntityOrAliasNameData | EntityOrAliasName} in `domain`. */
4
+ export type EntityOrAliasName = EntityOrAliasNameData;
10
5
  /** Validates that a name is valid PascalCase for either an entity type or alias. */
11
6
  export declare const EntityOrAliasName: (name: string, ctx: ParseContext) => EntityOrAliasName | undefined;
@@ -1,11 +1,6 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { EntityTypeName as EntityTypeNameData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../../core/index.js';
3
- /**
4
- * Branded PascalCase entity type name (e.g. "Table", "TopCircle", "Legs3D").
5
- * Entity types are the concrete domain objects declared in a model version.
6
- * Each entity type can have shapes, be referenced by aliases, and be instantiated
7
- * in the configurator at runtime.
8
- */
9
- export type EntityTypeName = Branded<'EntityTypeName', string>;
3
+ /** A branded entity type name; see {@link EntityTypeNameData | EntityTypeName} in `domain`. */
4
+ export type EntityTypeName = EntityTypeNameData;
10
5
  /** Validates that a name is PascalCase for use as an entity type identifier. */
11
6
  export declare const EntityTypeName: (name: string, ctx: ParseContext) => EntityTypeName | undefined;
@@ -1,9 +1,6 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { ExpressionName as ExpressionNameData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../../core/index.js';
3
- /**
4
- * Branded expression name starting with $ followed by camelCase (e.g. "$price", "$isValid", "$availableColors").
5
- * Expressions are computed properties on entities — their names are prefixed with $ to distinguish them from shape properties.
6
- */
7
- export type ExpressionName = Branded<'ExpressionName', string>;
3
+ /** A branded expression name; see {@link ExpressionNameData | ExpressionName} in `domain`. */
4
+ export type ExpressionName = ExpressionNameData;
8
5
  /** Validates that a name follows the expression naming convention ($camelCase). */
9
6
  export declare const ExpressionName: (name: string, ctx: ParseContext) => ExpressionName | undefined;
@@ -1,9 +1,5 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { InstanceName as InstanceNameData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../../core/index.js';
3
- /**
4
- * Branded component instance name.
5
- * User-declared names must start with a letter (e.g. "default", "body", "main").
6
- * SDK-derived names may include `$` prefix and `.` separators (e.g. "$top", "Table.$top").
7
- */
8
- export type InstanceName = Branded<'InstanceName', string>;
3
+ /** A branded component instance name; see {@link InstanceNameData | InstanceName} in `domain`. */
4
+ export type InstanceName = InstanceNameData;
9
5
  export declare const InstanceName: (name: string, entityKey: string, componentName: string, ctx: ParseContext) => InstanceName | undefined;
@@ -1,5 +1,5 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { InvariantName as InvariantNameData } from '#package/domain';
2
2
  import type { ParseContext } from '../../../../core/index.js';
3
- /** A camelCase identifier for an invariant implementation declared in YAML. */
4
- export type InvariantName = Branded<'InvariantName', string>;
3
+ /** A branded invariant name; see {@link InvariantNameData | InvariantName} in `domain`. */
4
+ export type InvariantName = InvariantNameData;
5
5
  export declare const InvariantName: (name: string, ctx: ParseContext) => InvariantName | undefined;
@@ -1,15 +1,7 @@
1
- import { Branded } from '@salsita-ai/common/utils';
1
+ import type { ShapePropertyName as ShapePropertyNameData } from '#package/domain';
2
2
  import { ParseContext } from '../../../../core/index.js';
3
- /**
4
- * Branded shape property name — the key under which an entity shape (or
5
- * alias shape) declares a field, and the key under which `defaults:` attaches
6
- * initial values. Must match /^[a-z]\w*$/: start with a lowercase letter,
7
- * then word characters (letters, digits, underscore).
8
- *
9
- * Examples: `height`, `positionX`, `hoodId`. Rejected: `Height`, `$height`,
10
- * `3D`, `height-px`.
11
- */
12
- export type ShapePropertyName = Branded<'ShapePropertyName', string>;
3
+ /** A branded shape property name; see {@link ShapePropertyNameData | ShapePropertyName} in `domain`. */
4
+ export type ShapePropertyName = ShapePropertyNameData;
13
5
  /** Validates `name` as a shape property identifier. Emits `INVALID_SHAPE_PROPERTY_NAME` on failure. */
14
6
  export declare const ShapePropertyName: (name: string, ctx: ParseContext) => ShapePropertyName | undefined;
15
7
  /**