@salsita-ai/sdk 0.50.0-develop.016963b09e → 0.50.0-develop.08837efd9c

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 (260) hide show
  1. package/dist/application-spec/core/components/component-filter.d.ts +53 -0
  2. package/dist/application-spec/core/components/component-filter.js +1 -0
  3. package/dist/application-spec/core/components/index.d.ts +2 -0
  4. package/dist/application-spec/core/components/index.js +1 -0
  5. package/dist/application-spec/core/components/sdk-code-ref.d.ts +9 -0
  6. package/dist/application-spec/core/components/sdk-code-ref.js +1 -0
  7. package/dist/application-spec/core/enhanced-json-value.d.ts +0 -68
  8. package/dist/application-spec/core/enhanced-json-value.js +1 -1
  9. package/dist/application-spec/core/index.d.ts +1 -0
  10. package/dist/application-spec/core/index.js +1 -1
  11. package/dist/application-spec/core/json-value.d.ts +1 -1
  12. package/dist/application-spec/{core → enhanced-json}/eval-to-constant.d.ts +1 -1
  13. package/dist/application-spec/enhanced-json/index.d.ts +4 -0
  14. package/dist/application-spec/enhanced-json/index.js +1 -0
  15. package/dist/application-spec/enhanced-json/is-enhanced-json-array.d.ts +2 -0
  16. package/dist/application-spec/enhanced-json/is-enhanced-json-array.js +1 -0
  17. package/dist/application-spec/enhanced-json/resolve-enhanced-json-value.d.ts +18 -0
  18. package/dist/application-spec/enhanced-json/resolve-enhanced-json-value.js +1 -0
  19. package/dist/application-spec/enhanced-json/schema-from-value.d.ts +24 -0
  20. package/dist/application-spec/enhanced-json/schema-from-value.js +1 -0
  21. package/dist/application-spec/enhanced-json/stringify-enhanced-json-value.d.ts +14 -0
  22. package/dist/application-spec/enhanced-json/stringify-enhanced-json-value.js +1 -0
  23. package/dist/application-spec/enhanced-json/validate-enhanced-json-value-caps.d.ts +12 -0
  24. package/dist/application-spec/enhanced-json/validate-enhanced-json-value-caps.js +1 -0
  25. package/dist/application-spec/enhanced-json/validate-no-legacy-code-ref.d.ts +13 -0
  26. package/dist/application-spec/enhanced-json/validate-no-legacy-code-ref.js +1 -0
  27. package/dist/application-spec/errors/diagnostic-codes.d.ts +5 -0
  28. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  29. package/dist/application-spec/errors/diagnostic-messages.d.ts +8 -0
  30. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  31. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-component-optics.js +4 -4
  32. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-defaults.js +1 -1
  33. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.js +41 -40
  34. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-phx-globals.js +3 -0
  35. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-resources.d.ts +6 -8
  36. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-resources.js +11 -11
  37. package/dist/application-spec/generate-application/code/templates/domain-spec/index.d.ts +1 -1
  38. package/dist/application-spec/generate-application/code/templates/domain-spec/index.js +1 -1
  39. package/dist/application-spec/generate-application/code/templates/domain-spec.js +12 -12
  40. package/dist/application-spec/generate-application/code/templates/globals.js +5 -4
  41. package/dist/application-spec/generate-application/code/templates/skills/phoenix-review-skill.js +8 -2
  42. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +3 -2
  43. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +2 -2
  44. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.d.ts +1 -1
  45. package/dist/application-spec/generate-application/runtime/sections/build-sdk-optic.js +1 -1
  46. package/dist/application-spec/index.d.ts +1 -0
  47. package/dist/application-spec/index.js +1 -1
  48. package/dist/application-spec/parse-application-files/categorize/module-analysis.d.ts +1 -1
  49. package/dist/application-spec/parse-application-files/categorize/module-analysis.js +1 -1
  50. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.d.ts +16 -3
  51. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.js +1 -1
  52. package/dist/application-spec/parse-application-files/raw-spec/raw-spec-file.js +1 -1
  53. package/dist/application-spec/parse-application-files/spec/components/component-entry.d.ts +1 -9
  54. package/dist/application-spec/parse-application-files/spec/components/component-entry.js +1 -1
  55. package/dist/application-spec/parse-application-files/spec/components/component-filter.d.ts +1 -54
  56. package/dist/application-spec/parse-application-files/spec/components/component-filter.js +1 -1
  57. package/dist/application-spec/parse-application-files/spec/components/index.d.ts +1 -1
  58. package/dist/application-spec/parse-application-files/spec/components/index.js +1 -1
  59. package/dist/application-spec/parse-application-files/spec/expressions/memo-eval-plan.js +1 -1
  60. package/dist/application-spec/parse-application-files/spec/expressions/user-expressions.js +1 -1
  61. package/dist/application-spec/parse-application-files/spec/model/defaults.js +1 -1
  62. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.js +1 -1
  63. package/dist/application-spec/parse-application-files/spec/sections/infra.d.ts +2 -0
  64. package/dist/application-spec/parse-application-files/spec/sections/infra.js +1 -1
  65. package/dist/client/phoenix-api.d.ts +96 -0
  66. package/dist/configurator/application-runtime/extensions/create-configurator-extensions.js +1 -1
  67. package/dist/configurator/application-runtime/extensions/selectors.d.ts +3 -1
  68. package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
  69. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +3 -1
  70. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -1
  71. package/dist/configurator/application-runtime/extensions/systems/drag-and-drop-system/drag-and-drop-system.d.ts +3 -3
  72. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.d.ts +14 -4
  73. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.js +1 -1
  74. package/dist/configurator/application-runtime/extensions/systems/graphql-system/inject-assistant-lenses.d.ts +11 -0
  75. package/dist/configurator/application-runtime/extensions/systems/graphql-system/inject-assistant-lenses.js +1 -0
  76. package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.d.ts +2 -2
  77. package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.js +1 -1
  78. package/dist/configurator/common/configurator-interface.d.ts +5 -1
  79. package/dist/configurator/common/configurator-interface.js +1 -1
  80. package/dist/configurator/common/frontend-analytics.d.ts +2 -0
  81. package/dist/configurator/common/frontend-analytics.js +1 -1
  82. package/dist/configurator/configurator-context/configurator-hooks/layout-hooks.d.ts +1 -1
  83. package/dist/configurator/scene/scene-controls/hotspot-drag-handle/HotspotDragHandle.d.ts +1 -1
  84. package/dist/configurator/scene/scene-controls/hotspot-drag-handle/HotspotDragSceneHandle.d.ts +1 -1
  85. package/dist/configurator/scene/scene-entity/dimension-indicators/DimensionIndicator.d.ts +1 -1
  86. package/dist/configurator/scene/scene-entity/dimension-indicators/DimensionIndicatorInternal.d.ts +1 -1
  87. package/dist/configurator/scene/scene-entity/drag-and-drop/shared.d.ts +2 -2
  88. package/dist/configurator/scene/scene-entity/drag-and-drop/use-drag-object.d.ts +1 -1
  89. package/dist/configurator/scene/scene-entity/materials/RemoteReplacedMaterial.js +1 -1
  90. package/dist/configurator/scene/scene-entity/objects/SceneEntityObjectTextDecal.d.ts +1 -1
  91. package/dist/configurator/ui/assistant/AssistantMarkdown.d.ts +1 -1
  92. package/dist/configurator/ui/assistant/AssistantMarkdown.js +1 -1
  93. package/dist/configurator/ui/assistant/AssistantThread.js +1 -1
  94. package/dist/configurator/ui/assistant/entity-link/AssistantEntityLink.d.ts +13 -0
  95. package/dist/configurator/ui/assistant/entity-link/AssistantEntityLink.js +1 -0
  96. package/dist/configurator/ui/assistant/entity-link/entity-link-selection.d.ts +22 -0
  97. package/dist/configurator/ui/assistant/entity-link/entity-link-selection.js +1 -0
  98. package/dist/configurator/ui/assistant/entity-link/entity-link-state.d.ts +27 -0
  99. package/dist/configurator/ui/assistant/entity-link/entity-link-state.js +1 -0
  100. package/dist/configurator/ui/assistant/entity-link/entity-link-target.d.ts +5 -0
  101. package/dist/configurator/ui/assistant/entity-link/entity-link-target.js +1 -0
  102. package/dist/configurator/ui/assistant/entity-link/index.d.ts +3 -0
  103. package/dist/configurator/ui/assistant/entity-link/index.js +1 -0
  104. package/dist/configurator/ui/configurator-layout/sidebar-keys/index.d.ts +1 -0
  105. package/dist/configurator/ui/configurator-layout/sidebar-keys/index.js +1 -0
  106. package/dist/configurator/ui/configurator-layout/sidebar-keys/sidebar-keys.d.ts +11 -0
  107. package/dist/configurator/ui/configurator-layout/sidebar-keys/sidebar-keys.js +1 -0
  108. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/DesktopSidebar.d.ts +101 -0
  109. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/DesktopSidebar.js +16 -0
  110. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/index.d.ts +1 -0
  111. package/dist/configurator/ui/configurator-layout/slots/desktop-sidebar/index.js +1 -0
  112. package/dist/configurator/ui/configurator-layout/slots/slots.d.ts +1 -0
  113. package/dist/configurator/ui/configurator-layout/slots/slots.js +1 -1
  114. package/dist/configurator/ui/configurator-layout/universal/DesktopLayout.d.ts +0 -74
  115. package/dist/configurator/ui/configurator-layout/universal/DesktopLayout.js +5 -20
  116. package/dist/configurator/ui/legacy/layout/steps/StepsNavigation.d.ts +2 -2
  117. package/dist/configurator/ui/phoenix-layout-elements/header/common/step-navigation/StepsNavigation.d.ts +2 -2
  118. package/dist/docs/dimensions/3d-scene-integration/dimension-indicators.mdx +2 -2
  119. package/dist/docs/dimensions/3d-scene-integration/editable-angle-indicator.mdx +1 -1
  120. package/dist/docs/dimensions/3d-scene-integration/editable-distance-dimension-indicator.mdx +1 -1
  121. package/dist/docs/dimensions/3d-scene-integration/list-selector-dimension-indicator.mdx +1 -1
  122. package/dist/docs/drag-and-drop/drag-handle.mdx +1 -1
  123. package/dist/docs/drag-and-drop/hotspot-handle.mdx +1 -1
  124. package/dist/docs/drag-and-drop/planes.mdx +1 -1
  125. package/dist/docs/drag-and-drop/rotatable.mdx +2 -2
  126. package/dist/docs/index.json +32 -1
  127. package/dist/docs/layouts/custom-layout.mdx +981 -0
  128. package/dist/docs/layouts/header/fixed.mdx +2 -2
  129. package/dist/docs/layouts/header/floating.mdx +2 -2
  130. package/dist/docs/layouts/sidebar/in-a-custom-layout.mdx +380 -0
  131. package/dist/docs/other-features/client-side-rendering/declarative.mdx +1 -1
  132. package/dist/docs/other-features/transformers.mdx +4 -0
  133. package/dist/docs/phoenix/configurator-interface.mdx +8 -2
  134. package/dist/docs/phoenix/project-structure.mdx +2 -1
  135. package/dist/docs/phoenix/testing.mdx +140 -0
  136. package/dist/docs/phoenix/webhook-membership.mdx +10 -9
  137. package/dist/docs/phoenix/webhooks.mdx +1 -1
  138. package/dist/domain/application/assistant/assistant-fields.d.ts +12 -0
  139. package/dist/domain/application/assistant/assistant-fields.js +1 -0
  140. package/dist/domain/application/assistant/assistant-manifest.d.ts +9 -1
  141. package/dist/domain/application/assistant/assistant-resolved-manifest.d.ts +38 -2
  142. package/dist/domain/application/assistant/assistant-resolved-manifest.js +1 -1
  143. package/dist/domain/application/assistant/build-assistant-lenses.d.ts +14 -0
  144. package/dist/domain/application/assistant/build-assistant-lenses.js +5 -0
  145. package/dist/domain/application/assistant/build-assistant-manifest.js +1 -1
  146. package/dist/domain/application/assistant/create-assistant-execution-schema.d.ts +32 -0
  147. package/dist/domain/application/assistant/create-assistant-execution-schema.js +1 -0
  148. package/dist/domain/application/assistant/generate-assistant-prompt.js +1 -1
  149. package/dist/domain/application/assistant/index.d.ts +6 -1
  150. package/dist/domain/application/assistant/index.js +1 -1
  151. package/dist/domain/application/assistant/session-setup/AssistantSetupHandler.d.ts +20 -0
  152. package/dist/domain/application/assistant/session-setup/AssistantSetupHandler.js +1 -0
  153. package/dist/domain/application/assistant/session-setup/apply-assistant-setup.d.ts +10 -0
  154. package/dist/domain/application/assistant/session-setup/apply-assistant-setup.js +1 -0
  155. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.d.ts +48 -0
  156. package/dist/domain/application/assistant/session-setup/assistant-setup-manifest.js +1 -0
  157. package/dist/domain/application/assistant/session-setup/create-session-assistant.d.ts +15 -0
  158. package/dist/domain/application/assistant/session-setup/create-session-assistant.js +1 -0
  159. package/dist/domain/application/assistant/session-setup/index.d.ts +4 -0
  160. package/dist/domain/application/assistant/session-setup/index.js +1 -0
  161. package/dist/domain/application/configurator-builder.d.ts +1 -1
  162. package/dist/domain/application/configurator-builder.js +1 -1
  163. package/dist/domain/application/index.d.ts +0 -1
  164. package/dist/domain/application/index.js +1 -1
  165. package/dist/domain/core/expression/constant-expressions.d.ts +16 -8
  166. package/dist/domain/core/invariant/violation.d.ts +50 -2
  167. package/dist/domain/core/invariant/violation.js +1 -1
  168. package/dist/domain/domain-runtime/access/selectors.d.ts +9 -0
  169. package/dist/domain/domain-runtime/access/selectors.js +1 -1
  170. package/dist/domain/domain-runtime/access/types.d.ts +2 -0
  171. package/dist/domain/domain-runtime/access/types.js +1 -1
  172. package/dist/domain/domain-runtime/domain-context/selectors.js +1 -1
  173. package/dist/domain/domain-runtime/domain-context/types.d.ts +4 -1
  174. package/dist/domain/domain-runtime/domain-runtime.d.ts +16 -0
  175. package/dist/domain/domain-runtime/errors/implementation-error-collector.d.ts +19 -0
  176. package/dist/domain/domain-runtime/errors/implementation-error-collector.js +1 -0
  177. package/dist/domain/domain-runtime/errors/implementation-error.d.ts +46 -0
  178. package/dist/domain/domain-runtime/errors/implementation-error.js +1 -0
  179. package/dist/domain/domain-runtime/errors/implementation-errors.d.ts +13 -0
  180. package/dist/domain/domain-runtime/errors/implementation-errors.js +1 -0
  181. package/dist/domain/domain-runtime/errors/index.d.ts +4 -0
  182. package/dist/domain/domain-runtime/errors/index.js +1 -0
  183. package/dist/domain/domain-runtime/errors/to-implementation-errors.d.ts +10 -0
  184. package/dist/domain/domain-runtime/errors/to-implementation-errors.js +1 -0
  185. package/dist/domain/domain-runtime/index.d.ts +1 -0
  186. package/dist/domain/domain-runtime/index.js +1 -1
  187. package/dist/domain/domain-runtime/spec/initialize.d.ts +11 -0
  188. package/dist/domain/domain-runtime/spec/initialize.js +1 -1
  189. package/dist/domain/domain-runtime/spec/module-checks/project-modules.d.ts +8 -1
  190. package/dist/domain/domain-runtime/spec/module-checks/project-modules.js +1 -1
  191. package/dist/domain/domain-runtime/spec/module-checks/resolve-action-modules.js +1 -1
  192. package/dist/domain/domain-runtime/spec/module-checks/resolve-expression-modules.js +1 -1
  193. package/dist/domain/domain-runtime/spec/module-checks/resolve-imported-transformers.js +1 -1
  194. package/dist/domain/domain-runtime/spec/module-checks/resolve-invariant-modules.js +1 -1
  195. package/dist/domain/extensions/canvas-config.d.ts +1 -1
  196. package/dist/domain/extensions/client-side-image.d.ts +2 -2
  197. package/dist/domain/extensions/client-side-image.js +1 -1
  198. package/dist/domain/extensions/common/angle-indicator-schema.d.ts +2 -2
  199. package/dist/domain/extensions/common/dimension-indicator-schema.d.ts +2 -2
  200. package/dist/domain/extensions/editable-angle-indicator.d.ts +1 -1
  201. package/dist/domain/extensions/editable-distance-dimension-indicator.d.ts +1 -1
  202. package/dist/domain/extensions/editable-offset-indicator.d.ts +1 -1
  203. package/dist/domain/extensions/editable-offset-indicator.js +1 -1
  204. package/dist/domain/extensions/horizontal-tabs.d.ts +2 -2
  205. package/dist/domain/extensions/list-selector-dimension-indicator.d.ts +1 -1
  206. package/dist/domain/extensions/navigation-steps.d.ts +2 -2
  207. package/dist/domain/extensions/offset-indicator.js +1 -1
  208. package/dist/domain/extensions/rotation-handle.d.ts +2 -2
  209. package/dist/domain/extensions/save-template-thumbnail.d.ts +2 -2
  210. package/dist/domain/extensions/save-template-thumbnail.js +1 -1
  211. package/dist/domain/mocks/create-mock-domain-runtime.d.ts +9 -0
  212. package/dist/domain/mocks/create-mock-domain-runtime.js +1 -1
  213. package/dist/domain/mocks/create-mock-domain.js +1 -1
  214. package/dist/domain/mocks/create-test-application-config.d.ts +59 -0
  215. package/dist/domain/mocks/create-test-application-config.js +1 -0
  216. package/dist/domain/mocks/index.d.ts +1 -0
  217. package/dist/domain/mocks/index.js +1 -1
  218. package/dist/domain/system-components/application-config.d.ts +2 -2
  219. package/dist/domain/system-components/collision-box-geometry.d.ts +4 -2
  220. package/dist/domain/system-components/collision-geometry.d.ts +4 -2
  221. package/dist/domain/system-components/collision-point-geometry.d.ts +4 -2
  222. package/dist/domain/system-components/common/material-override-schema.d.ts +2 -2
  223. package/dist/domain/system-components/constraint.d.ts +10 -23
  224. package/dist/domain/system-components/drag-handle.d.ts +1 -1
  225. package/dist/domain/system-components/hotspot-drag-handle.d.ts +1 -1
  226. package/dist/domain/system-components/material-swatch.js +1 -1
  227. package/dist/domain/system-components/scene-entity-material-override.d.ts +1 -1
  228. package/dist/domain/system-components/scene-entity-object-material-override.d.ts +1 -1
  229. package/dist/domain/system-components/scene-entity-object-text-decal.d.ts +1 -1
  230. package/dist/domain/system-components/scene-entity-object-transimissive-material-override.d.ts +1 -1
  231. package/dist/domain/system-components/scene-entity-transimissive-material-override.d.ts +1 -1
  232. package/dist/editor/mocks/EditorMockContext.js +1 -1
  233. package/dist/legacy/domain-cli/gen/configurator-builder.js +13 -12
  234. package/dist/legacy/domain-cli/gen/constant-expressions.js +1 -1
  235. package/dist/legacy/domain-cli/utils/cache.d.ts +1 -1
  236. package/dist/legacy/domain-cli/utils/cache.js +1 -1
  237. package/dist/legacy/domain-spec/__generated/domain-schema.d.ts +16 -5
  238. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/claude-md.d.ts +1 -1
  239. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/cursor-rules.d.ts +1 -1
  240. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.d.ts +1 -1
  241. package/dist/legacy/phoenix-cli/project-gen/generators/file-templates/agents/shared-sdk-content.js +1 -1
  242. package/dist/react-sdk/application-runtime/hooks/use-access-service.d.ts +2 -0
  243. package/dist/react-sdk/application-runtime/mocks/create-mock-application-runtime.js +1 -1
  244. package/dist/react-sdk/application-runtime/routing/access-service.d.ts +1 -0
  245. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.d.ts +17 -0
  246. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.js +1 -1
  247. package/dist/react-sdk/domain-context/index.d.ts +1 -1
  248. package/dist/react-sdk/domain-context/index.js +1 -1
  249. package/dist/react-sdk/domain-context/system-hooks/navigation-hooks.d.ts +6 -0
  250. package/dist/react-sdk/domain-context/system-hooks/navigation-hooks.js +1 -1
  251. package/dist/react-sdk/domain-controls/hooks/use-angle-dimension.d.ts +1 -1
  252. package/dist/ui-sdk/theme/types.d.ts +1 -1
  253. package/dist/webhook/builders/webhook-builder.js +1 -1
  254. package/package.json +3 -3
  255. package/schema/domain-spec.json +209 -16
  256. package/dist/domain/application/resource-builder.d.ts +0 -13
  257. package/dist/domain/application/resource-builder.js +0 -1
  258. /package/dist/application-spec/{core → enhanced-json}/eval-code-uses-self.d.ts +0 -0
  259. /package/dist/application-spec/{core → enhanced-json}/eval-code-uses-self.js +0 -0
  260. /package/dist/application-spec/{core → enhanced-json}/eval-to-constant.js +0 -0
@@ -145,7 +145,7 @@ interface HorizontalTab {
145
145
  /**
146
146
  * List of navigation states when the tab is active. First one will be used for activation.
147
147
  */
148
- readonly navigationStates: string[]
148
+ readonly navigationStates: readonly string[]
149
149
  }
150
150
  ```
151
151
 
@@ -158,7 +158,7 @@ type HorizontalTabsComponentState = {
158
158
  /**
159
159
  * List of tabs in the horizontal tabs.
160
160
  */
161
- readonly tabs: HorizontalTab[]
161
+ readonly tabs: readonly HorizontalTab[]
162
162
  }
163
163
  ```
164
164
 
@@ -110,11 +110,11 @@ The configuration uses these component types:
110
110
  ```typescript
111
111
  export interface NavigationStep {
112
112
  readonly label: Localizable
113
- readonly navigationStates: string[]
113
+ readonly navigationStates: readonly string[]
114
114
  }
115
115
 
116
116
  export type NavigationStepsComponentState = {
117
- readonly steps: NavigationStep[]
117
+ readonly steps: readonly NavigationStep[]
118
118
  }
119
119
  ```
120
120
 
@@ -0,0 +1,380 @@
1
+ # Sidebar in a Custom Layout
2
+
3
+ - [Use case](#use-case)
4
+ - [Guide](#guide)
5
+ - [Example](#example)
6
+ - [Known gaps](#known-gaps)
7
+ - [Test cases](#test-cases)
8
+ - [Complete Implementation](#complete-implementation)
9
+
10
+ ## Use case
11
+
12
+ A project wants the configurator arranged differently, for example with the sidebar on the left, but the sidebar itself is right as it is: the spec's tabs, property pages and sidebar footer, with their spacing, scrolling and empty states. The project writes its own layout, a `ConfiguratorLayout` element, and places the built-in sidebar in it as one piece, `LayoutSlots.DesktopSidebar`. The spec keeps describing what the sidebar shows; the layout only decides where it goes.
13
+
14
+ Build the sidebar's controls yourself instead when they have to look like the brand's own, as [Custom Layout](?path=/docs/layouts-custom-layout--docs) does; [Configurator Interface → Loaded Configuration UI](?path=/docs/phoenix-configurator-interface--docs#loaded-configuration-ui) lists what a project layout can use. Stay with the built-in layout when its arrangement fits: [Sidebar - General](?path=/docs/layouts-sidebar-general--docs) describes what the spec configures in the sidebar.
15
+
16
+ ## Guide
17
+
18
+ The layout registers itself under the name `ConfiguratorLayout` and mounts the scene, the safe area and the sidebar:
19
+
20
+ ```tsx
21
+ // src/elements/ConfiguratorLayout.tsx
22
+ import { LayoutSlots, useSceneSafeArea } from '@salsita-ai/sdk/configurator'
23
+
24
+ import { phx } from '../../.phoenix/phx.js'
25
+
26
+ const GUTTER = 24
27
+ const SIDEBAR_WIDTH = 380
28
+
29
+ const ConfiguratorLayout = () => {
30
+ const { containerRef, safeAreaRef } = useSceneSafeArea()
31
+ const isFullscreen = phx.frontend.useIsFullscreenActive()
32
+
33
+ return (
34
+ <div ref={containerRef} style={{ position: 'absolute', inset: 0 }}>
35
+ <LayoutSlots.Services />
36
+ <LayoutSlots.SharedCanvas />
37
+
38
+ {!isFullscreen && (
39
+ <aside
40
+ style={{
41
+ position: 'absolute',
42
+ insetBlock: GUTTER,
43
+ insetInlineStart: GUTTER,
44
+ inlineSize: SIDEBAR_WIDTH,
45
+ }}
46
+ >
47
+ <LayoutSlots.DesktopSidebar side="start" />
48
+ </aside>
49
+ )}
50
+
51
+ <div
52
+ ref={safeAreaRef}
53
+ style={{
54
+ position: 'absolute',
55
+ insetBlock: 0,
56
+ insetInlineStart: isFullscreen ? 0 : SIDEBAR_WIDTH + 2 * GUTTER,
57
+ insetInlineEnd: 0,
58
+ pointerEvents: 'none',
59
+ }}
60
+ >
61
+ <div style={{ position: 'absolute', insetBlockEnd: GUTTER, insetInlineStart: GUTTER, pointerEvents: 'auto' }}>
62
+ <LayoutSlots.DesktopToolbar />
63
+ </div>
64
+ </div>
65
+ </div>
66
+ )
67
+ }
68
+
69
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
70
+ ```
71
+
72
+ - **Size the container.** Without `width`, `LayoutSlots.DesktopSidebar` fills the width and height of its container. The layout positions the container above the canvas and gives it a size, here a fixed width and the full height less a gutter. The sidebar's content scrolls inside that height and its footer stays at the bottom.
73
+ - **Say which side it is on.** The sidebar's tabs sit outside it. With `side="start"` they sit on its right, toward the scene; the default, `side="end"`, puts them on its left, as in the built-in layout.
74
+ - **Frame the scene beside it.** `useSceneSafeArea()` measures the free region right of the sidebar, so the camera frames the table there.
75
+ - **Decide what fullscreen does.** In fullscreen the sidebar stays in place, transparent and inert. This layout removes it while `phx.frontend.useIsFullscreenActive()` is set and lets the safe area start at the left edge, so the table is framed in the whole canvas. The toolbar's fullscreen button sets the flag.
76
+ - **Read mode.** The same element renders a configuration shared for viewing. The sidebar handles read mode itself: it applies the spec's `$filter.modes`, so the tabs, which the spec limits to owners, are gone and the footer shows the price only. The banner that offers **Edit configuration** to a viewer is the layout's to mount: the built-in layout shows `LayoutSlots.DesktopReadonlyBanner` in read mode outside fullscreen, and it renders only when the spec sets `shareCloneToEdit` and the viewer's role may create configurations. This spec does not set it, so this layout mounts no banner.
77
+
78
+ `LayoutSlots.DesktopSidebar` takes two optional props:
79
+
80
+ | Prop | Type | Default | Meaning |
81
+ | ------- | -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
+ | `width` | CSS width | none | Fixed inline size; the sidebar then takes its content's height unless its container stretches it. Without it the sidebar fills its container's width and height. |
83
+ | `side` | `'start'` \| `'end'` | `'end'` | The side of the layout the sidebar is on; its tabs sit on the other side of it. |
84
+
85
+ Its look follows the theme component `PhxDesktopSidebar`, as in the built-in layout, see [Theming](?path=/docs/phoenix-theming--docs).
86
+
87
+ ## Example
88
+
89
+ The spec is a table with one property, its edge finish, on a **Design** tab and a short text on a **Details** tab, and a price. Nothing in the YAML refers to the layout.
90
+
91
+ ## Known gaps
92
+
93
+ - The finalize button is disabled unless the spec configures `finalizeButton` or `finalizePage`, as in the built-in layout. A `finalizePage` is not shown by a project layout unless the layout renders it.
94
+ - `LayoutSlots.DesktopSidebar` is the desktop sidebar. At phone width a project layout needs its own arrangement, for example the `Mobile*` members of `LayoutSlots` in a drawer.
95
+ - The tabs overlap the scene beside the sidebar; the safe area in this example does not leave room for them.
96
+ - `miniSidebar` does not shrink the sidebar: the built-in layout does that, and here the sidebar fills its container. A layout that honours it reads `LayoutSlots.useSidebarContent().hasMiniSidebar` and gives the container no fixed height, anchored at the bottom for example, so the sidebar takes its content's height.
97
+
98
+ ## Test cases
99
+
100
+ - The sidebar sits on the left with its tabs on its right; the table is framed in the space right of the sidebar.
101
+ - **Design** shows the edge finishes; choosing one changes the table. **Details** shows the text.
102
+ - The footer shows the price and the finalize button.
103
+ - Fullscreen removes the sidebar and frames the table in the whole canvas; leaving it brings the sidebar back.
104
+ - With the **Read User** mock template the tabs are gone and the footer shows the price only.
105
+
106
+ ## Complete Implementation
107
+
108
+ {/* AUTO-GENERATED SECTION: This section is automatically updated by 'phoenix story build' */}
109
+
110
+ <details>
111
+ <summary>Click to view the complete implementation files</summary>
112
+
113
+ ### ./spec/domain.yaml
114
+
115
+ ```yaml
116
+ model:
117
+ latest:
118
+ entityTypes:
119
+ - Table
120
+ aliases:
121
+ RootEntity:
122
+ - Table
123
+ commonTypes:
124
+ EdgeFinish:
125
+ enum:
126
+ - None
127
+ - Facet
128
+ - Round
129
+ - TreeTrunk
130
+ shapes:
131
+ Table:
132
+ edgeFinish:
133
+ $ref: '#/model/latest/commonTypes/EdgeFinish'
134
+
135
+ presets:
136
+ - rootEntityType: 'Table'
137
+ initialDomainEntities:
138
+ - id: 'Table-1'
139
+ type: 'Table'
140
+ edgeFinish: 'None'
141
+
142
+ navigationStates:
143
+ - design
144
+ - details
145
+
146
+ invariants:
147
+ Table:
148
+ trunkDisabled:
149
+ types:
150
+ - 'trunkDisabled'
151
+
152
+ components:
153
+ Table:
154
+ propertyPage:
155
+ design:
156
+ $filter:
157
+ navigationStates:
158
+ - design
159
+ children:
160
+ - kind: propertyContainerGroup
161
+ props:
162
+ spacing: large
163
+ children:
164
+ - kind: propertyContainerItem
165
+ props:
166
+ title: Edge Finish
167
+ description: Select the edge finish for the table.
168
+ children:
169
+ - kind: attributeCardSelector
170
+ props:
171
+ instanceName: edgeFinish
172
+ details:
173
+ $filter:
174
+ navigationStates:
175
+ - details
176
+ children:
177
+ - kind: propertyContainerItem
178
+ props:
179
+ title: Dimensions
180
+ description: 1600 × 800 mm, 750 mm high. Solid oak top on powder-coated steel legs.
181
+ sidebarTabs:
182
+ main:
183
+ $filter:
184
+ modes:
185
+ - owner
186
+ tabs:
187
+ - label: Design
188
+ navigationStates:
189
+ - design
190
+ - label: Details
191
+ navigationStates:
192
+ - details
193
+ price:
194
+ main:
195
+ price: 1200
196
+ fitRootPerspectiveCamera:
197
+ main:
198
+ priority: 1
199
+ fov: 35
200
+ near: 100
201
+ far: 10000
202
+ minDistance: 1000
203
+ maxDistance: 9000
204
+ distance: 5000
205
+ azimuthAngle: 1.5
206
+ polarAngle: 1.1
207
+ fitMeshChanges: true
208
+ animateOnLoad: true
209
+ sceneEntityRemoteObject:
210
+ top:
211
+ fileUrl: '/models/tables.gltf'
212
+ objectName: RECHTHOEK_RECTANGLE
213
+ dimensionUnit: m
214
+ leg:
215
+ fileUrl: '/models/tables.gltf'
216
+ objectName: AXL_LEG
217
+ dimensionUnit: m
218
+ sceneEntityObjectProperties:
219
+ top:
220
+ offsetY: 820
221
+ morphTargetInfluences:
222
+ Facet:
223
+ value:
224
+ $read: $edgeFinishFacet
225
+ scaleOne: 1
226
+ scaleZero: 0
227
+ Bol:
228
+ value:
229
+ $read: $edgeFinishRound
230
+ scaleOne: 1
231
+ scaleZero: 0
232
+ Boomstamrand:
233
+ value:
234
+ $read: $edgeFinishTreeTrunk
235
+ scaleOne: 1
236
+ scaleZero: 0
237
+ leg:
238
+ morphTargetInfluences:
239
+ Length:
240
+ value: 1000
241
+ scaleOne: 3000
242
+ scaleZero: 1400
243
+ Width:
244
+ value: 700
245
+ scaleOne: 1300
246
+ scaleZero: 600
247
+ Height:
248
+ value: 780
249
+ scaleOne: 780
250
+ scaleZero: 740
251
+ attributeSelection:
252
+ edgeFinish:
253
+ value:
254
+ $bind: edgeFinish
255
+ options:
256
+ $read: $edgeFinishOptions
257
+ ```
258
+
259
+ ### ./src/elements/ConfiguratorLayout.tsx
260
+
261
+ ```tsx
262
+ import { LayoutSlots, useSceneSafeArea } from '@salsita-ai/sdk/configurator'
263
+
264
+ import { phx } from '../../.phoenix/phx.js'
265
+
266
+ const GUTTER = 24
267
+ const SIDEBAR_WIDTH = 380
268
+
269
+ const ConfiguratorLayout = () => {
270
+ const { containerRef, safeAreaRef } = useSceneSafeArea()
271
+ const isFullscreen = phx.frontend.useIsFullscreenActive()
272
+
273
+ return (
274
+ <div ref={containerRef} style={{ position: 'absolute', inset: 0 }}>
275
+ <LayoutSlots.Services />
276
+ <LayoutSlots.SharedCanvas />
277
+
278
+ {!isFullscreen && (
279
+ <aside
280
+ style={{
281
+ position: 'absolute',
282
+ insetBlock: GUTTER,
283
+ insetInlineStart: GUTTER,
284
+ inlineSize: SIDEBAR_WIDTH,
285
+ }}
286
+ >
287
+ <LayoutSlots.DesktopSidebar side="start" />
288
+ </aside>
289
+ )}
290
+
291
+ <div
292
+ ref={safeAreaRef}
293
+ style={{
294
+ position: 'absolute',
295
+ insetBlock: 0,
296
+ insetInlineStart: isFullscreen ? 0 : SIDEBAR_WIDTH + 2 * GUTTER,
297
+ insetInlineEnd: 0,
298
+ pointerEvents: 'none',
299
+ }}
300
+ >
301
+ <div style={{ position: 'absolute', insetBlockEnd: GUTTER, insetInlineStart: GUTTER, pointerEvents: 'auto' }}>
302
+ <LayoutSlots.DesktopToolbar />
303
+ </div>
304
+ </div>
305
+ </div>
306
+ )
307
+ }
308
+
309
+ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout', ConfiguratorLayout)
310
+ ```
311
+
312
+ ### ./src/expressions/expressions.ts
313
+
314
+ ```ts
315
+ import { phx } from '../../.phoenix/phx.js'
316
+
317
+ export default phx.domain.implementCustomExpressions({
318
+ Table: {
319
+ $edgeFinishFacet: s => {
320
+ return s.edgeFinish === 'Facet' ? 1 : 0
321
+ },
322
+ $edgeFinishRound: s => {
323
+ return s.edgeFinish === 'Round' ? 1 : 0
324
+ },
325
+ $edgeFinishTreeTrunk: s => {
326
+ return s.edgeFinish === 'TreeTrunk' ? 1 : 0
327
+ },
328
+ $edgeFinishOptions: () => {
329
+ return [
330
+ {
331
+ label: 'None',
332
+ img: '/images/edge-none.png',
333
+ value: phx.domain.model.EdgeFinish.None,
334
+ },
335
+ {
336
+ label: 'Facet',
337
+ img: '/images/edge-facet.png',
338
+ value: phx.domain.model.EdgeFinish.Facet,
339
+ },
340
+ {
341
+ label: 'Round',
342
+ img: '/images/edge-round.png',
343
+ value: phx.domain.model.EdgeFinish.Round,
344
+ },
345
+ {
346
+ label: 'TreeTrunk',
347
+ img: '/images/edge-tree-trunk.png',
348
+ value: phx.domain.model.EdgeFinish.TreeTrunk,
349
+ },
350
+ ]
351
+ },
352
+ },
353
+ })
354
+ ```
355
+
356
+ ### ./src/invariants/invariants.ts
357
+
358
+ ```ts
359
+ import { phx } from '../../.phoenix/phx.js'
360
+
361
+ export default phx.domain.implementCustomInvariants({
362
+ Table: {
363
+ trunkDisabled: s => {
364
+ if (s.edgeFinish === 'TreeTrunk') {
365
+ return [
366
+ {
367
+ type: 'trunkDisabled',
368
+ severity: 'fatal',
369
+ message: 'TreeTrunk finish is disabled because stuff!',
370
+ },
371
+ ]
372
+ }
373
+
374
+ return []
375
+ },
376
+ },
377
+ })
378
+ ```
379
+
380
+ </details>
@@ -229,7 +229,7 @@ export type ClientSideImageComponentState = {
229
229
  /** Output format: PNG (with transparency) or JPEG */
230
230
  readonly fileFormat: 'PNG' | 'JPEG'
231
231
  /** Optional background color (hex string) */
232
- readonly backgroundColor?: string
232
+ readonly backgroundColor?: HexColor
233
233
 
234
234
  /** Tool state the image is rendered in (pins component filters keyed on tool state) */
235
235
  readonly toolState: string
@@ -433,6 +433,10 @@ The following sample application has all the above described transformers active
433
433
  - When the view changes to `Y`, the navigation state is changed to `C`.
434
434
  - When any entity is deselected in view `Z`, the view is changed to `X`.
435
435
 
436
+ The example's own tests under `__tests__/` check these cases with `createMockDomainContext` on the config
437
+ `createTestApplicationConfig` builds from the generated application; [Testing](?path=/docs/phoenix-testing--docs)
438
+ shows how a project's test sets that up.
439
+
436
440
  ## Complete Implementation
437
441
 
438
442
  {/* AUTO-GENERATED SECTION: This section is automatically updated by 'phoenix story build' */}
@@ -161,6 +161,10 @@ const toolState = phx.frontend.useActiveToolState()
161
161
  const navigate = phx.frontend.useNavigate()
162
162
  const pushNavigate = phx.frontend.usePushNavigate()
163
163
  const popNavigate = phx.frontend.usePopNavigate()
164
+
165
+ // Fullscreen: a flag in the configurator's state that the layout honours; it does not put the browser into fullscreen
166
+ const isFullscreen = phx.frontend.useIsFullscreenActive()
167
+ const setFullscreen = phx.frontend.useSetFullscreen() // setFullscreen(true) or setFullscreen(false)
164
168
  ```
165
169
 
166
170
  ### Controls
@@ -386,7 +390,7 @@ const PresetOverlay = phx.frontend.createPresetDeviceNotSupported(SmallScreenNot
386
390
 
387
391
  ### Loaded Configuration UI
388
392
 
389
- A layout element registered under the name `ConfiguratorLayout` replaces the whole UI of a loaded configuration, in owner and in read mode, whatever `layout` the spec sets. Without it, Phoenix renders the layout the spec selects.
393
+ A layout element registered under the name `ConfiguratorLayout` replaces the whole UI of a loaded configuration, in owner and in read mode, whatever `layout` the spec sets. Without it, Phoenix renders the layout the spec selects. [Custom Layout](?path=/docs/layouts-custom-layout--docs) is a worked example: a fully custom product page with its panel on the left, built from the scene, the safe-area hook and state hooks.
390
394
 
391
395
  ```typescript
392
396
  // src/elements/ConfiguratorLayout.tsx
@@ -417,7 +421,9 @@ export default phx.frontend.createCustomPhoenixLayoutElement('ConfiguratorLayout
417
421
  - `useSceneSafeArea()`, called without arguments, tells the camera which part of the canvas the UI leaves free. Attach `containerRef` to the element that covers the whole canvas and `safeAreaRef` to the region the scene should stay visible in: the hook measures the gap between the two and the camera frames the scene inside the safe area. Without it the scene is framed in the whole canvas. The safe-area element lies over the canvas, so it sets `pointerEvents: 'none'` to leave orbiting and clicking to the scene. A `canvasPadding` component in the spec scales the measured gaps, see [Canvas Padding](?path=/docs/layouts-canvas-padding--docs).
418
422
  - The layout has to mount `LayoutSlots.SharedCanvas`, or the project sets `appLoader: legacy`. Otherwise the app loader stays on screen.
419
423
  - The layout composes the rest from what `@salsita-ai/sdk/configurator` exports: `LayoutSlots.Services` and the other members of `LayoutSlots`.
420
- - Nothing of the built-in layouts is rendered for it. The finalize page is `Legacy.CommonFinalizePage`, the dialog is `LayoutDialog`, and the preview start screen is `DesktopPreview` or `MobilePreview`, which the layout shows while `usePreview().isPreview` is set. Both previews frame the scene themselves, so the layout renders the component that calls `useSceneSafeArea()` only while `isPreview` is not set; it then measures when it mounts after the preview. The assistant panel is not available to a project layout.
424
+ - `LayoutSlots.DesktopSidebar` is the built-in desktop sidebar as one piece: the spec's tabs, back button, property pages and sidebar footer with their spacing, scrolling and empty states, and the assistant panel. Use it when the spec's property pages are what the customer should see and only their place changes, for example a sidebar on the left; build the controls yourself when they have to look like the brand's own. Without `width` it fills its container, so the layout positions and sizes that container; `miniSidebar` does not shrink it, so a layout that honours it reads `LayoutSlots.useSidebarContent().hasMiniSidebar` and lets the container take the sidebar's height. Its tabs sit outside it on the left; `side="start"` puts them on its right, for a sidebar on the left. In fullscreen it stays in place, transparent and inert, so a layout that wants the space back removes it while `phx.frontend.useIsFullscreenActive()` is set. See [Sidebar in a Custom Layout](?path=/docs/layouts-sidebar-in-a-custom-layout--docs).
425
+ - Nothing of the built-in layouts is rendered for it. `Legacy.CommonFinalizePage` shows the page of the `finalizePage` component in a dialog while one of its finalize navigation states is active, so a layout that shows a finalize button mounts it; without it the button changes the navigation state and nothing appears. It is marked deprecated and is the only exported piece that does this. `LayoutDialog` renders only what the project registers with `createLayoutDialog` and is not part of the finalize flow. The preview start screen is `DesktopPreview` or `MobilePreview`, which the layout shows while `usePreview().isPreview` is set. Both previews frame the scene themselves, so the layout renders the component that calls `useSceneSafeArea()` only while `isPreview` is not set; it then measures when it mounts after the preview. The assistant panel is available to a project layout only inside `LayoutSlots.DesktopSidebar`.
426
+ - The layout reads the state it has to react to from hooks. Read mode: `phx.frontend.useAccessService().accessInfo.viewMode`. Fullscreen: `phx.frontend.useIsFullscreenActive()` reads it and `phx.frontend.useSetFullscreen()` sets it; the layout decides what to hide. Preview: `usePreview()` from `@salsita-ai/sdk/configurator`.
421
427
  - Any project layout element named `ConfiguratorLayout` takes over the page.
422
428
 
423
429
  ## TransformerBuilder
@@ -53,7 +53,8 @@ Every file in `components/`, `elements/`, `expressions/`, `actions/`, `invariant
53
53
  (and their `admin/` counterparts) is imported by its location, so its default export must be what that folder's `phx`
54
54
  factory returns, or an array of those. A file that exports anything else, such as a plain React component in
55
55
  `elements/`, stops the application at start with an `Invalid default export in <file>` error that names the expected
56
- shape. Keep plain components and helpers in a `_*` folder.
56
+ shape. When several files in `handlers/`, `elements/`, `transformers/`, `components/`, `admin/elements/` and
57
+ `admin/components/` are wrong, the error lists all of them, one numbered line per file. Keep plain components and helpers in a `_*` folder.
57
58
 
58
59
  ### Admin Folders (src/admin/)
59
60
 
@@ -0,0 +1,140 @@
1
+ # Testing
2
+
3
+ - [Your application in a test](#your-application-in-a-test)
4
+ - [Run the domain on a preset](#run-the-domain-on-a-preset)
5
+ - [Test a transformer](#test-a-transformer)
6
+ - [Mock a domain context](#mock-a-domain-context)
7
+ - [Options](#options)
8
+
9
+ A project's tests check its own logic, such as an expression on a preset, a transformer that completes an
10
+ edit, a Blender projection or a migration, against the application the project ships. They run with
11
+ Vitest in Node, without a browser or a server.
12
+
13
+ ## Your application in a test
14
+
15
+ `createTestApplicationConfig` from `@salsita-ai/sdk/domain` is the way a test builds the project's
16
+ application. It takes the generated application the test imports and returns its application config,
17
+ typed with the project's entities, states and data, with no type argument at the call:
18
+
19
+ ```ts
20
+ import { createTestApplicationConfig } from '@salsita-ai/sdk/domain'
21
+
22
+ import { configuratorBuilder } from '../../.phoenix/domain.js'
23
+
24
+ const config = createTestApplicationConfig(configuratorBuilder)
25
+
26
+ config.domain.presets // the presets of spec/presets
27
+ config.initialPublishedData // the published data the application starts with
28
+ ```
29
+
30
+ `configuratorBuilder` from `.phoenix/domain.js` is the domain of the configurator: the model, expressions,
31
+ invariants, actions, migrations, presets and the components declared in YAML. `configuratorConfig` from
32
+ `.phoenix/configurator-config.js` is the whole configurator as the browser runs it, with every component,
33
+ handler, element and transformer; it reads the frontend environment when it is imported, so a test that
34
+ uses it stubs `phx.frontendEnv` first.
35
+
36
+ A test passes the generated export to the helper and does not call the export's methods: they are how the
37
+ SDK assembles an application, not an interface for tests, while the helper's call does not depend on that
38
+ assembly.
39
+
40
+ ## Run the domain on a preset
41
+
42
+ The config goes into `createDomainRuntime`, which runs the same systems as the configurator:
43
+
44
+ ```ts
45
+ import { vi } from 'vitest'
46
+
47
+ import { NoopAnalyticsSystem, createDomainRuntime, createTestApplicationConfig } from '@salsita-ai/sdk/domain'
48
+
49
+ import { configuratorBuilder, createI18n } from '../../.phoenix/domain.js'
50
+
51
+ const logger = {
52
+ info: vi.fn(),
53
+ error: vi.fn(),
54
+ warn: vi.fn(),
55
+ debug: vi.fn(),
56
+ verbose: vi.fn(),
57
+ appendToGlobalContext: vi.fn(),
58
+ }
59
+ const config = createTestApplicationConfig(configuratorBuilder)
60
+ const runtime = createDomainRuntime({
61
+ config,
62
+ services: { analyticsService: new NoopAnalyticsSystem(), i18n: createI18n(), logger },
63
+ })
64
+
65
+ runtime.actions.domainContext.configurator.setExecutionMode('finalize')
66
+ runtime.actions.domainData.setDomainData({
67
+ publishedData: config.initialPublishedData,
68
+ backendData: undefined,
69
+ frontendData: {},
70
+ })
71
+ runtime.actions.sessionContext.setSessionContext({ role: 'anonymous', data: {} })
72
+
73
+ const preset = config.domain.presets[0]!
74
+ runtime.actions.loadedData.completeConfiguratorLoad({
75
+ initialRevisionId: 'test',
76
+ initialEntities: preset.initialDomainEntities,
77
+ modelVersion: config.domain.domainFactory.modelVersion,
78
+ rootEntityType: preset.rootEntityType,
79
+ schemaIdentity: runtime.selectors.spec.getConfiguratorFactory(),
80
+ })
81
+ runtime.selectors.domainContext.configurator.getDomainContext().initialize()
82
+ ```
83
+
84
+ ## Test a transformer
85
+
86
+ The domain of `configuratorBuilder` has no code-attached components and no transformers. A test adds the
87
+ ones it needs, the way the configurator and the webhooks add them:
88
+
89
+ ```ts
90
+ // Files that read `phx.domain` at module scope are imported after `.phoenix/domain.js`.
91
+ const { customComponentOptics } = await import('../../.phoenix/configurator-domain-code.js')
92
+ const { default: addCookingTop } = await import('../transformers/add-cooking-top.js')
93
+
94
+ const config = createTestApplicationConfig(configuratorBuilder, {
95
+ componentModules: customComponentOptics,
96
+ transformers: {
97
+ importedTransformers: [{ origin: 'src/transformers/add-cooking-top.ts', exports: addCookingTop }],
98
+ specTransformers: [{ name: 'addCookingTop', priority: 30 }],
99
+ },
100
+ })
101
+ ```
102
+
103
+ `specTransformers` are the entries of the `transformers` section of `spec/application.yaml` that the test
104
+ runs, with the priorities the spec gives them.
105
+
106
+ ## Mock a domain context
107
+
108
+ `createMockState`, `createMockDomain` and `createMockDomainContext` take the same config and check the
109
+ mock data against the project's types:
110
+
111
+ ```ts
112
+ import { createMockDomainContext, createTestApplicationConfig } from '@salsita-ai/sdk/domain'
113
+
114
+ const config = createTestApplicationConfig(configuratorBuilder)
115
+ const preset = config.domain.presets[0]!
116
+ const { domainContext, destroy } = createMockDomainContext(config, {
117
+ entities: preset.initialDomainEntities,
118
+ rootEntityType: preset.rootEntityType,
119
+ publishedData: config.initialPublishedData,
120
+ frontendData: {},
121
+ sessionData: {},
122
+ backendData: undefined,
123
+ mode: 'owner',
124
+ role: 'anonymous',
125
+ transformers: [],
126
+ })
127
+ ```
128
+
129
+ ## Options
130
+
131
+ | Option | What it does |
132
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------ |
133
+ | `componentModules` | Component files added after the components the application already has, each `{ origin, exports }` |
134
+ | `transformers` | Replaces the application's transformers: files (`importedTransformers`) and spec entries (`specTransformers`) |
135
+ | `tag` | The tag of the custom element the application mounts as; without it the application's own (`salsita-configurator`) |
136
+
137
+ ## See Also
138
+
139
+ - [Best Practices](?path=/docs/phoenix-best-practices--docs) - Where custom code lives
140
+ - [Transformers](?path=/docs/other-features-transformers--docs) - Writing transformers
@@ -4,21 +4,22 @@ Build component controls with React and browser SDKs without pulling them into t
4
4
 
5
5
  ## Choose Where Each File Runs
6
6
 
7
- | User file | Frontend | Webhook |
8
- | ------------------------------------------------- | -------- | ------- |
9
- | Component or admin component without a directive | Yes | No |
10
- | Component or admin component with `'use webhook'` | Yes | Yes |
11
- | Ordinary handler | Yes | No |
12
- | Published-data or validator handler | Yes | Yes |
13
- | Any other handler with `'use webhook'` | Yes | Yes |
14
- | File under `src/webhooks/` | No | Yes |
7
+ | User file | Frontend | Webhook |
8
+ | ---------------------------------------------------- | -------- | ------- |
9
+ | Component or admin component without a directive | Yes | No |
10
+ | Component or admin component with `'use webhook'` | Yes | Yes |
11
+ | Ordinary handler | Yes | No |
12
+ | Published-data, validator or assistant setup handler | Yes | Yes |
13
+ | Any other handler with `'use webhook'` | Yes | Yes |
14
+ | File under `src/webhooks/` | No | Yes |
15
15
 
16
- Published-data and validator handlers are detected when they register one of these APIs:
16
+ Published-data, validator and assistant setup handlers are detected when they register one of these APIs:
17
17
 
18
18
  - `createMapPublishedRevisionDataHandler`
19
19
  - `createMapPublishedChunkedDataHandler`
20
20
  - `createDataRowValidatorHandler`
21
21
  - `createSheetValidatorHandler`
22
+ - `phx.domain.createAssistantSetupHandler`
22
23
 
23
24
  ## Pin a Server-Safe Component
24
25
 
@@ -148,7 +148,7 @@ resources:
148
148
  s3Key: clientImage
149
149
  ```
150
150
 
151
- These resources are automatically made available as typed properties in task handlers via the `resources` parameter.
151
+ These resources are automatically made available as typed properties in task handlers via the `resources` parameter. Two static resources with the same name are an error: `phoenix check` and `phoenix build` report the second entry (`DUPLICATE_RESOURCE_NAME`).
152
152
 
153
153
  #### Task Payload
154
154