@salsita-ai/sdk 0.50.0-develop.514d19d58c → 0.50.0-develop.5a0bcdee42

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 (283) hide show
  1. package/README.md +19 -11
  2. package/dist/application-spec/errors/diagnostic-codes.d.ts +6 -0
  3. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  4. package/dist/application-spec/errors/diagnostic-messages.d.ts +6 -0
  5. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  6. package/dist/application-spec/generate-application/code/domain-runtime-files.js +1 -1
  7. package/dist/application-spec/generate-application/code/project-scaffolding.js +2 -2
  8. package/dist/application-spec/generate-application/code/templates/application-types.js +6 -6
  9. package/dist/application-spec/generate-application/code/templates/configurator-domain-code.d.ts +1 -0
  10. package/dist/application-spec/generate-application/code/templates/configurator-domain-code.js +11 -8
  11. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.d.ts +3 -1
  12. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.js +70 -66
  13. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-phx-globals.js +3 -0
  14. package/dist/application-spec/generate-application/code/templates/domain-spec.js +5 -5
  15. package/dist/application-spec/generate-application/code/templates/domain.js +2 -2
  16. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.d.ts +11 -0
  17. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.js +8 -0
  18. package/dist/application-spec/generate-application/code/templates/global-definition/index.d.ts +1 -0
  19. package/dist/application-spec/generate-application/code/templates/global-definition/index.js +1 -1
  20. package/dist/application-spec/generate-application/code/templates/globals.js +1 -0
  21. package/dist/application-spec/generate-application/code/templates/index.d.ts +1 -0
  22. package/dist/application-spec/generate-application/code/templates/index.js +1 -1
  23. package/dist/application-spec/generate-application/code/templates/skills/agents-md.js +1 -1
  24. package/dist/application-spec/generate-application/code/templates/skills/phoenix-cli-skill.js +1 -1
  25. package/dist/application-spec/generate-application/code/templates/skills/phoenix-create-configurator-skill.js +43 -13
  26. package/dist/application-spec/generate-application/code/templates/skills/phoenix-feedback-skill.js +39 -16
  27. package/dist/application-spec/generate-application/code/templates/skills/phoenix-review-skill.js +5 -3
  28. package/dist/application-spec/generate-application/code/templates/skills/phoenix-skill.js +1 -1
  29. package/dist/application-spec/generate-application/code/templates/skills/phoenix-variants-skill.d.ts +1 -0
  30. package/dist/application-spec/generate-application/code/templates/skills/phoenix-variants-skill.js +6 -0
  31. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +31 -3
  32. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +19 -4
  33. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.d.ts +2 -0
  34. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.js +1 -1
  35. package/dist/application-spec/generate-application/runtime/sections/actions-runtime.d.ts +14 -0
  36. package/dist/application-spec/generate-application/runtime/sections/actions-runtime.js +1 -0
  37. package/dist/application-spec/generate-application/runtime/sections/index.d.ts +1 -0
  38. package/dist/application-spec/generate-application/runtime/sections/index.js +1 -1
  39. package/dist/application-spec/parse-application-files/categorize/categorize-files.d.ts +3 -1
  40. package/dist/application-spec/parse-application-files/categorize/categorize-files.js +1 -1
  41. package/dist/application-spec/parse-application-files/merge/index.d.ts +1 -0
  42. package/dist/application-spec/parse-application-files/merge/index.js +1 -1
  43. package/dist/application-spec/parse-application-files/merge/merged-actions.d.ts +11 -0
  44. package/dist/application-spec/parse-application-files/merge/merged-actions.js +1 -0
  45. package/dist/application-spec/parse-application-files/merge/merged-spec.d.ts +2 -0
  46. package/dist/application-spec/parse-application-files/merge/merged-spec.js +1 -1
  47. package/dist/application-spec/parse-application-files/raw-spec/index.d.ts +1 -0
  48. package/dist/application-spec/parse-application-files/raw-spec/index.js +1 -1
  49. package/dist/application-spec/parse-application-files/raw-spec/raw-actions.d.ts +18 -0
  50. package/dist/application-spec/parse-application-files/raw-spec/raw-actions.js +1 -0
  51. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.d.ts +14 -2
  52. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.js +1 -1
  53. package/dist/application-spec/parse-application-files/raw-spec/raw-spec-file.d.ts +2 -0
  54. package/dist/application-spec/parse-application-files/raw-spec/raw-spec-file.js +1 -1
  55. package/dist/application-spec/parse-application-files/resolve/resolve-import-modules.js +1 -1
  56. package/dist/application-spec/parse-application-files/spec/application/application-spec.js +1 -1
  57. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/configurator-spec.d.ts +4 -2
  58. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/configurator-spec.js +1 -1
  59. package/dist/application-spec/parse-application-files/spec/common/index.d.ts +1 -0
  60. package/dist/application-spec/parse-application-files/spec/common/index.js +1 -1
  61. package/dist/application-spec/parse-application-files/spec/common/schema-ref-resolver.d.ts +23 -0
  62. package/dist/application-spec/parse-application-files/spec/common/schema-ref-resolver.js +1 -0
  63. package/dist/application-spec/parse-application-files/spec/model/names/action-name.d.ts +10 -0
  64. package/dist/application-spec/parse-application-files/spec/model/names/action-name.js +1 -0
  65. package/dist/application-spec/parse-application-files/spec/model/names/index.d.ts +1 -0
  66. package/dist/application-spec/parse-application-files/spec/model/names/index.js +1 -1
  67. package/dist/application-spec/parse-application-files/spec/sections/actions.d.ts +35 -0
  68. package/dist/application-spec/parse-application-files/spec/sections/actions.js +1 -0
  69. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-field-type.d.ts +3 -14
  70. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-field-type.js +1 -1
  71. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.d.ts +12 -3
  72. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.js +1 -1
  73. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant.d.ts +5 -3
  74. package/dist/application-spec/parse-application-files/spec/sections/index.d.ts +1 -0
  75. package/dist/application-spec/parse-application-files/spec/sections/index.js +1 -1
  76. package/dist/configurator/application-runtime/extensions/configurator-extension-systems.d.ts +2 -1
  77. package/dist/configurator/application-runtime/extensions/configurator-extension-systems.js +1 -1
  78. package/dist/configurator/application-runtime/extensions/selectors.d.ts +2 -1
  79. package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
  80. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +168 -0
  81. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -0
  82. package/dist/configurator/{assistant → application-runtime/extensions/systems/assistant-system}/browser-details.d.ts +1 -1
  83. package/dist/configurator/application-runtime/extensions/systems/assistant-system/browser-details.js +1 -0
  84. package/dist/configurator/application-runtime/extensions/systems/assistant-system/change-recorder.d.ts +85 -0
  85. package/dist/configurator/application-runtime/extensions/systems/assistant-system/change-recorder.js +1 -0
  86. package/dist/configurator/{assistant → application-runtime/extensions/systems/assistant-system}/graphql-tools.d.ts +20 -16
  87. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.js +1 -0
  88. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.d.ts +4 -0
  89. package/dist/configurator/application-runtime/extensions/systems/graphql-system/entity-meta.js +1 -1
  90. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.d.ts +16 -1
  91. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.js +1 -1
  92. package/dist/configurator/application-runtime/extensions/systems/graphql-system/side-effects.d.ts +9 -0
  93. package/dist/configurator/application-runtime/extensions/systems/graphql-system/side-effects.js +1 -0
  94. package/dist/configurator/application-runtime/extensions/systems/index.d.ts +1 -0
  95. package/dist/configurator/application-runtime/extensions/systems/index.js +1 -1
  96. package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.d.ts +2 -0
  97. package/dist/configurator/application-runtime/extensions/systems/layout-system/layout-system.js +1 -1
  98. package/dist/configurator/common/frontend-analytics.d.ts +21 -21
  99. package/dist/configurator/index.d.ts +0 -1
  100. package/dist/configurator/index.js +1 -1
  101. package/dist/configurator/pages/LoadedConfiguratorDetailPage.js +1 -1
  102. package/dist/configurator/scene/scene-analytics/scene-analytics.d.ts +2 -2
  103. package/dist/configurator/ui/assistant/AssistantChips.d.ts +11 -0
  104. package/dist/configurator/ui/assistant/AssistantChips.js +1 -0
  105. package/dist/configurator/ui/assistant/AssistantComposer.d.ts +6 -0
  106. package/dist/configurator/ui/assistant/AssistantComposer.js +1 -0
  107. package/dist/configurator/ui/assistant/AssistantMarkdown.d.ts +7 -0
  108. package/dist/configurator/ui/assistant/AssistantMarkdown.js +1 -0
  109. package/dist/configurator/ui/assistant/AssistantPanel.d.ts +11 -0
  110. package/dist/configurator/ui/assistant/AssistantPanel.js +1 -0
  111. package/dist/configurator/ui/assistant/AssistantThread.d.ts +6 -0
  112. package/dist/configurator/ui/assistant/AssistantThread.js +1 -0
  113. package/dist/configurator/ui/assistant/assistant-failure.d.ts +18 -0
  114. package/dist/configurator/ui/assistant/assistant-failure.js +1 -0
  115. package/dist/configurator/ui/assistant/index.d.ts +2 -0
  116. package/dist/configurator/ui/assistant/index.js +1 -0
  117. package/dist/configurator/ui/assistant/streamed-markdown.d.ts +6 -0
  118. package/dist/configurator/ui/assistant/streamed-markdown.js +2 -0
  119. package/dist/configurator/ui/assistant/theme.d.ts +2 -0
  120. package/dist/configurator/ui/assistant/theme.js +1 -0
  121. package/dist/configurator/ui/assistant/thread-items.d.ts +37 -0
  122. package/dist/configurator/ui/assistant/thread-items.js +1 -0
  123. package/dist/configurator/ui/assistant/tool-chip.d.ts +37 -0
  124. package/dist/configurator/ui/assistant/tool-chip.js +1 -0
  125. package/dist/configurator/ui/assistant/use-follow-stream.d.ts +17 -0
  126. package/dist/configurator/ui/assistant/use-follow-stream.js +1 -0
  127. package/dist/configurator/ui/assistant/use-is-assistant-panel-open.d.ts +5 -0
  128. package/dist/configurator/ui/assistant/use-is-assistant-panel-open.js +1 -0
  129. package/dist/configurator/ui/configurator-layout/universal/DesktopLayout.js +5 -5
  130. package/dist/configurator/ui/configurator-layout/universal/MobileLayout.d.ts +2 -0
  131. package/dist/configurator/ui/configurator-layout/universal/MobileLayout.js +4 -4
  132. package/dist/configurator/ui/legacy/mobile-controls/MobileControls.d.ts +1 -1
  133. package/dist/configurator/ui/phoenix-layout-elements/AssistantToolbarButton.d.ts +10 -0
  134. package/dist/configurator/ui/phoenix-layout-elements/AssistantToolbarButton.js +1 -0
  135. package/dist/configurator/ui/phoenix-layout-elements/index.d.ts +1 -0
  136. package/dist/configurator/ui/phoenix-layout-elements/index.js +1 -1
  137. package/dist/docs/index.json +12 -2
  138. package/dist/docs/layouts/toolbar.mdx +6 -0
  139. package/dist/docs/other-features/domain-actions.mdx +418 -0
  140. package/dist/docs/other-features/side-effects.mdx +26 -0
  141. package/dist/docs/phoenix/admin.mdx +2 -2
  142. package/dist/docs/phoenix/best-practices.mdx +1 -0
  143. package/dist/docs/phoenix/finalization.mdx +1 -1
  144. package/dist/docs/phoenix/integration/headless-mode-external.mdx +5 -5
  145. package/dist/docs/phoenix/integration/widget-mode-external.mdx +5 -5
  146. package/dist/docs/phoenix/phoenix-cli.mdx +139 -20
  147. package/dist/docs/phoenix/project-structure.mdx +7 -3
  148. package/dist/docs/phoenix/sdk-builder-workflow.mdx +5 -4
  149. package/dist/domain/actions/action-factory.d.ts +10 -0
  150. package/dist/domain/actions/action-factory.js +1 -0
  151. package/dist/domain/actions/prepare-action-implementations.d.ts +15 -0
  152. package/dist/domain/actions/prepare-action-implementations.js +5 -0
  153. package/dist/domain/application/application-config.d.ts +3 -1
  154. package/dist/domain/application/assistant-mutations.d.ts +15 -14
  155. package/dist/domain/application/assistant-mutations.js +1 -1
  156. package/dist/domain/components/updates.d.ts +16 -0
  157. package/dist/domain/core/action.d.ts +67 -0
  158. package/dist/domain/core/action.js +1 -0
  159. package/dist/domain/core/domain-factory.d.ts +4 -0
  160. package/dist/domain/core/index.d.ts +1 -0
  161. package/dist/domain/domain-builder.d.ts +7 -0
  162. package/dist/domain/domain-builder.js +1 -1
  163. package/dist/domain/domain-context/action-system/action-system.d.ts +40 -0
  164. package/dist/domain/domain-context/action-system/action-system.js +1 -0
  165. package/dist/domain/domain-context/domain-context-systems.d.ts +5 -2
  166. package/dist/domain/domain-context/index.d.ts +2 -1
  167. package/dist/domain/domain-context/index.js +1 -1
  168. package/dist/domain/domain-context/store-system/store-system.js +1 -1
  169. package/dist/domain/domain-runtime/domain-context/domain-context.js +1 -1
  170. package/dist/domain/domain-runtime/domain-context/selectors.d.ts +4 -0
  171. package/dist/domain/domain-runtime/domain-context/selectors.js +1 -1
  172. package/dist/domain/domain-runtime/domain-runtime.d.ts +12 -0
  173. package/dist/domain/domain-runtime/spec/initialize.js +1 -1
  174. package/dist/domain/domain-runtime/spec/types.d.ts +15 -1
  175. package/dist/domain/index.d.ts +2 -0
  176. package/dist/domain/index.js +1 -1
  177. package/dist/domain/mocks/create-mock-domain-runtime.d.ts +6 -0
  178. package/dist/domain/system-components/phoenix-layout-elements/assistant-toolbar-button.d.ts +44 -0
  179. package/dist/domain/system-components/phoenix-layout-elements/assistant-toolbar-button.js +1 -0
  180. package/dist/domain/system-components/phoenix-layout-elements/index.d.ts +1 -0
  181. package/dist/domain/system-components/phoenix-layout-elements/index.js +1 -1
  182. package/dist/domain/system-components/phoenix-layout-elements/phoenix-layout-element.d.ts +2 -1
  183. package/dist/domain/system-components/phoenix-layout-elements/phoenix-layout-element.js +1 -1
  184. package/dist/editor/Editor.js +1 -1
  185. package/dist/editor/domain-editors/DomainSpecContext.js +1 -1
  186. package/dist/editor/domain-editors/apply-spec-update.js +1 -1
  187. package/dist/editor/domain-editors/use-implementation-files.d.ts +7 -3
  188. package/dist/editor/domain-editors/use-implementation-files.js +1 -1
  189. package/dist/editor/graphql/GraphQLPanel.js +1 -1
  190. package/dist/editor/variants/VariantAnswerFooter.d.ts +17 -0
  191. package/dist/editor/variants/VariantAnswerFooter.js +1 -0
  192. package/dist/editor/variants/VariantPreviewHandler.d.ts +6 -0
  193. package/dist/editor/variants/VariantPreviewHandler.js +1 -0
  194. package/dist/editor/variants/variant-preview-styles.d.ts +49 -0
  195. package/dist/editor/variants/variant-preview-styles.js +1 -0
  196. package/dist/i18n/locales/cs/messages.js +1 -1
  197. package/dist/i18n/locales/da/messages.js +1 -1
  198. package/dist/i18n/locales/de/messages.js +1 -1
  199. package/dist/i18n/locales/de-AT/messages.js +1 -1
  200. package/dist/i18n/locales/en/messages.js +1 -1
  201. package/dist/i18n/locales/en-AU/messages.js +1 -1
  202. package/dist/i18n/locales/en-GB/messages.js +1 -1
  203. package/dist/i18n/locales/es/messages.js +1 -1
  204. package/dist/i18n/locales/fr/messages.js +1 -1
  205. package/dist/i18n/locales/hu/messages.js +1 -1
  206. package/dist/i18n/locales/it/messages.js +1 -1
  207. package/dist/i18n/locales/nl/messages.js +1 -1
  208. package/dist/i18n/locales/pl/messages.js +1 -1
  209. package/dist/i18n/locales/pt/messages.js +1 -1
  210. package/dist/i18n/locales/ro/messages.js +1 -1
  211. package/dist/i18n/locales/sk/messages.js +1 -1
  212. package/dist/i18n/locales/tr/messages.js +1 -1
  213. package/dist/legacy/domain-spec/__generated/domain-schema.d.ts +6 -0
  214. package/dist/phoenix/application-spec/application-spec-builder.js +1 -1
  215. package/dist/phoenix/application-spec/generate-assistant-prompt.d.ts +4 -3
  216. package/dist/phoenix/application-spec/generate-assistant-prompt.js +1 -1
  217. package/dist/phoenix/cli.js +1 -1
  218. package/dist/phoenix/commands/build.d.ts +5 -0
  219. package/dist/phoenix/commands/build.js +1 -1
  220. package/dist/phoenix/commands/deploy.js +2 -2
  221. package/dist/phoenix/commands/dev.js +5 -5
  222. package/dist/phoenix/commands/feedback.d.ts +2 -1
  223. package/dist/phoenix/commands/feedback.js +1 -1
  224. package/dist/phoenix/commands/index.d.ts +1 -0
  225. package/dist/phoenix/commands/index.js +1 -1
  226. package/dist/phoenix/commands/login.d.ts +24 -6
  227. package/dist/phoenix/commands/login.js +2 -2
  228. package/dist/phoenix/commands/story-dev.js +2 -2
  229. package/dist/phoenix/commands/variants.d.ts +35 -0
  230. package/dist/phoenix/commands/variants.js +1 -0
  231. package/dist/phoenix/editor-server/commands-router.d.ts +68 -1
  232. package/dist/phoenix/editor-server/commands-router.js +1 -1
  233. package/dist/phoenix/editor-server/editor-router.d.ts +65 -0
  234. package/dist/phoenix/editor-server/editor-server.d.ts +3 -3
  235. package/dist/phoenix/editor-server/editor-server.js +1 -1
  236. package/dist/phoenix/editor-server/protocol.d.ts +1 -0
  237. package/dist/phoenix/editor-server/spec-router.js +1 -1
  238. package/dist/phoenix/editor-server/trpc.d.ts +3 -0
  239. package/dist/phoenix/services/application-spec-project-watcher.d.ts +13 -2
  240. package/dist/phoenix/services/application-spec-project-watcher.js +3 -3
  241. package/dist/phoenix/services/index.d.ts +5 -0
  242. package/dist/phoenix/services/index.js +1 -1
  243. package/dist/phoenix/services/phoenix-application.d.ts +21 -0
  244. package/dist/phoenix/services/phoenix-application.js +1 -0
  245. package/dist/phoenix/services/phoenix-store.d.ts +48 -0
  246. package/dist/phoenix/services/phoenix-store.js +1 -0
  247. package/dist/phoenix/services/phx-banner-plugin.d.ts +32 -0
  248. package/dist/phoenix/services/phx-banner-plugin.js +1 -0
  249. package/dist/phoenix/services/phx-licenses-plugin.d.ts +55 -0
  250. package/dist/phoenix/services/phx-licenses-plugin.js +8 -0
  251. package/dist/phoenix/services/phx-variant-previews-plugin.d.ts +9 -0
  252. package/dist/phoenix/services/phx-variant-previews-plugin.js +1 -0
  253. package/dist/phoenix/services/variant-file-session.d.ts +36 -0
  254. package/dist/phoenix/services/variant-file-session.js +1 -0
  255. package/dist/phoenix/services/variant-preview-service.d.ts +80 -0
  256. package/dist/phoenix/services/variant-preview-service.js +1 -0
  257. package/dist/phoenix/services/vite-config.d.ts +2 -0
  258. package/dist/phoenix/services/vite-config.js +1 -1
  259. package/dist/phoenix/utils/index.d.ts +1 -0
  260. package/dist/phoenix/utils/index.js +1 -1
  261. package/dist/phoenix/utils/read-git-commit.d.ts +14 -0
  262. package/dist/phoenix/utils/read-git-commit.js +1 -0
  263. package/dist/react-sdk/application-runtime/common-services/analytics/analytics-service.d.ts +2 -2
  264. package/dist/react-sdk/application-runtime/common-services/analytics/domain-controls-analytics.d.ts +21 -21
  265. package/dist/react-sdk/application-runtime/hooks/data/use-published-data.d.ts +1 -1
  266. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.d.ts +12 -0
  267. package/dist/react-sdk/domain-context/common-hooks/use-domain-context.d.ts +3 -0
  268. package/dist/ui-sdk/common/use-viewport-size.d.ts +4 -1
  269. package/dist/ui-sdk/common/use-viewport-size.js +1 -1
  270. package/dist/ui-sdk/components/mobile-controls/index.d.ts +1 -1
  271. package/dist/ui-sdk/theme/types.d.ts +4 -0
  272. package/package.json +5 -8
  273. package/schema/domain-spec.json +24 -0
  274. package/dist/configurator/assistant/browser-details.js +0 -1
  275. package/dist/configurator/assistant/graphql-tools.js +0 -1
  276. package/dist/configurator/assistant/index.d.ts +0 -1
  277. package/dist/configurator/assistant/index.js +0 -1
  278. package/dist/configurator/assistant/use-assistant-chat.d.ts +0 -20
  279. package/dist/configurator/assistant/use-assistant-chat.js +0 -1
  280. package/dist/extras/assistant/AssistantChat.d.ts +0 -6
  281. package/dist/extras/assistant/AssistantChat.js +0 -1
  282. package/dist/extras/assistant/index.d.ts +0 -1
  283. package/dist/extras/assistant/index.js +0 -1
@@ -0,0 +1,36 @@
1
+ import type { Logger } from '../utils/index.js';
2
+ /** A baseline-relative edit collected by an option script; null removes the file. */
3
+ export interface VariantFileEdit {
4
+ readonly fileName: string;
5
+ readonly content: string | null;
6
+ }
7
+ /** Owns the baseline, file transactions and recovery for one live comparison. */
8
+ export declare class VariantFileSession {
9
+ private readonly props;
10
+ private readonly queue;
11
+ private readonly applied;
12
+ private readonly baseline;
13
+ private readonly contract;
14
+ private settled;
15
+ private constructor();
16
+ static create(props: {
17
+ readonly projectRoot: string;
18
+ readonly logger: Logger;
19
+ readonly onFilesChanged: (files: readonly VariantFileEdit[]) => void;
20
+ }): Promise<VariantFileSession>;
21
+ /**
22
+ * Restores the baseline a comparison left behind when its dev session ended without closing it. A file
23
+ * edited since then is left as it is, so the edit survives and the next dev session can still start.
24
+ */
25
+ static recover(projectRoot: string, logger: Logger): Promise<void>;
26
+ private static resolveFile;
27
+ getFiles(): readonly VariantFileEdit[];
28
+ apply(edits: readonly VariantFileEdit[]): Promise<void>;
29
+ finish(keep: boolean): Promise<void>;
30
+ /**
31
+ * Moves the files from what is applied now to `target`. A file edited outside the comparison is never
32
+ * overwritten: a switch is refused, so the builder sees why, while the end of the comparison keeps that
33
+ * file as it is and restores the others, so the comparison can always be closed.
34
+ */
35
+ private writeTarget;
36
+ }
@@ -0,0 +1 @@
1
+ import{mkdir as e,readFile as t,realpath as i,rename as a,rm as r,writeFile as s}from"node:fs/promises";import{dirname as o,join as n,relative as l,resolve as p,sep as c}from"node:path";import h from"promise-queue";import{z as d}from"zod";import{RawProjectFiles as f,RuntimeReferenceStore as m,TextFile as w,buildPhoenixDefinitions as u,isTextFile as g,parseApplicationFiles as v}from"#package/application-spec";import{getAllPhxDefinitions as y}from"#package/domain";import{readApplicationFiles as b}from"../application-spec/application-spec-file-reader.js";import{generateAssistantPrompt as S}from"../application-spec/generate-assistant-prompt.js";import{swcEvalExpressionParser as F,swcModuleAnalyzer as N}from"../application-spec/swc-module-analyzer.js";let j=".phoenix/variant-recovery.json",k=d.array(d.object({fileName:d.string(),original:d.string().nullable(),applied:d.string().nullable(),previous:d.string().nullable().optional()})),E=e=>!e.includes("\\")&&!e.split("/").some(e=>".."===e||"."===e||""===e)&&(/^spec\/(?!admin\/).+\.yaml$/.test(e)||/^src\/(?:components|transformers|handlers|elements|_[^/]+)\/.+\.tsx?$/.test(e)),M=e=>`Left ${e} as it is: it was edited outside the variant comparison, so restoring the baseline would overwrite that edit. Review the file and remove what the option added to it`,$=async e=>{try{return await t(e,"utf8")}catch(e){if(e instanceof Error&&"code"in e&&"ENOENT"===e.code)return null;throw e}},C=async(t,i)=>{if(null===i)return void await r(t,{force:!0});await e(o(t),{recursive:!0});let n=`${t}.variant-${crypto.randomUUID()}`;try{await s(n,i),await a(n,t)}finally{await r(n,{force:!0})}},R=(e,t)=>{let i=v({rawProjectFiles:e,phxDefinitions:u(y())},{analyzer:N,evalExpressionParser:F,referenceStore:new m,logger:t});if(!i.ok)throw Error(`Cannot apply variant: ${i.errors.map(e=>`[${e.code}] ${e.message}`).join("\n")}`);let{configurator:a,admin:r,appMetadata:s,infra:o,dataSpec:n}=i.value.applicationSpec,l=i.value.categorizedFiles,p=new Set([...l.webhooks,...l.expressions,...l.actions,...l.invariants,...l.migrations,...l.adminMigrations,...l.adminExpressions,...l.adminInvariants,...l.handlers.filter(e=>"pinned"===e.webhookMembership||"named-handler"===e.webhookMembership),...l.components.filter(e=>"pinned"===e.webhookMembership),...l.adminComponents.filter(e=>"pinned"===e.webhookMembership)].flatMap(e=>[e.file.name,...e.deps]));return JSON.stringify({webhookFiles:e.files.filter(g).filter(e=>p.has(e.name)).sort((e,t)=>e.name.localeCompare(t.name)),appMetadata:s,infra:o,dataSpec:n,model:a.latestModel,schema:a.configurationSchema,dataSchemas:a.dataSchemas,adminModel:r.latestModel,adminSchema:r.configurationSchema,assistant:a.assistant?.sdl,assistantSettings:a.assistantServerSettings,assistantPrompt:a.assistant?S(a.assistant):null},(e,t)=>t instanceof Map?[...t.entries()]:t)};export class VariantFileSession{props;queue=new h(1,1/0);applied=new Map;baseline=new Map;contract;settled=!1;constructor(e){for(let t of(this.props=e,e.rawFiles.files))g(t)&&E(t.name)&&this.baseline.set(t.name,t.content);this.contract=R(e.rawFiles,e.logger)}static async create(e){await VariantFileSession.recover(e.projectRoot,e.logger);let t=await b({projectRoot:e.projectRoot,envs:{}});return new VariantFileSession({...e,rawFiles:t})}static async recover(e,t){let i=await $(n(e,j));if(null!==i){for(let a of k.parse(JSON.parse(i))){let i=await VariantFileSession.resolveFile(e,a.fileName),r=await $(i);if(r!==a.applied&&r!==a.original&&r!==a.previous){t.warn(M(a.fileName));continue}await C(i,a.original)}await r(n(e,j),{force:!0})}}static async resolveFile(e,t){if(!E(t))throw Error(`Cannot override ${t}: variants support frontend spec and TypeScript files only. Keep server code, dependencies, environment files and assets unchanged`);let a=await i(e),r=p(a,t),s=r;for(;;)try{let e=await i(s),r=l(a,e);if(".."===r||r.startsWith(`..${c}`))throw Error(`Cannot override ${t}: its symbolic link leaves the project`);if(e!==s)throw Error(`Cannot override ${t}: it uses a symbolic link. Variant edits require regular files so restoration preserves the original file`);break}catch(e){if(!(e instanceof Error&&"code"in e&&"ENOENT"===e.code))throw e;s=o(s)}return r}getFiles(){return[...this.baseline].map(([e,t])=>({fileName:e,content:t}))}apply(e){return this.queue.add(async()=>{if(this.settled)throw Error("This variant comparison has already ended");let t=new Map;for(let i of e){if(await VariantFileSession.resolveFile(this.props.projectRoot,i.fileName),t.has(i.fileName))throw Error(`Cannot apply variant: ${i.fileName} is specified twice`);t.set(i.fileName,i.content)}if(t.size>0){let e=this.props.rawFiles.files.filter(e=>!t.has(e.name));for(let[i,a]of t)null!==a&&e.push(w(i,a));if(R(f(e),this.props.logger)!==this.contract)throw Error("Cannot apply variant: it changes the model, schemas, data or deployment settings. Variants must need no server preparation")}await this.writeTarget(t,"refuse")})}finish(e){return this.queue.add(async()=>{this.settled||(e||await this.writeTarget(new Map,"keep"),await r(n(this.props.projectRoot,j),{force:!0}),this.settled=!0)})}async writeTarget(t,i){let a=new Set([...this.applied.keys(),...t.keys()]);if(0===a.size)return;let r=new Map;for(let e of a){let t=await VariantFileSession.resolveFile(this.props.projectRoot,e),a=this.applied.has(e)?this.applied.get(e):this.baseline.get(e)??null;if(await $(t)===a){r.set(e,t);continue}if("refuse"===i)throw Error(`Cannot switch variant: ${e} was edited outside the preview, and switching would overwrite that edit. Choose the option that is shown, or close the comparison with \`phoenix variants --close\`, which keeps the edit`);this.props.logger.warn(M(e))}let s=[...r.keys()].map(e=>({fileName:e,original:this.baseline.get(e)??null,previous:this.applied.has(e)?this.applied.get(e)??null:this.baseline.get(e)??null,applied:t.has(e)?t.get(e)??null:this.baseline.get(e)??null}));await e(n(this.props.projectRoot,".phoenix"),{recursive:!0}),await C(n(this.props.projectRoot,j),JSON.stringify(s));let o=new Map(this.applied);try{for(let e of s){let t=r.get(e.fileName);void 0!==t&&await C(t,e.applied)}}catch(e){for(let[e,t]of r)await C(t,o.has(e)?o.get(e)??null:this.baseline.get(e)??null);throw await C(n(this.props.projectRoot,j),JSON.stringify([...o].map(([e,t])=>({fileName:e,original:this.baseline.get(e)??null,applied:t})))),e}for(let[e,i]of(this.applied.clear(),t))this.applied.set(e,i);this.props.onFilesChanged(s.map(e=>({fileName:e.fileName,content:e.applied})))}}
@@ -0,0 +1,80 @@
1
+ import { Observable } from 'rxjs';
2
+ import type { Logger } from '../utils/index.js';
3
+ import type { ApplicationSpecProjectWatcher } from './application-spec-project-watcher.js';
4
+ import type { PhoenixStore, VariantPreviewOption, VariantPreviewRequest, VariantPreviewResult } from './phoenix-store.js';
5
+ import { type VariantFileEdit } from './variant-file-session.js';
6
+ /** What a command asks the editor to show, and how long it waits for the answer. */
7
+ export interface VariantPreviewInput {
8
+ readonly title: string;
9
+ readonly description: string;
10
+ readonly variants: readonly VariantPreviewOption[];
11
+ readonly timeoutMs: number;
12
+ }
13
+ /** How a wait for the builder's answer ended. `waiting` leaves the comparison open. */
14
+ export type VariantPreviewOutcome = ({
15
+ readonly status: 'settled';
16
+ } & VariantPreviewResult) | {
17
+ readonly status: 'closed';
18
+ } | {
19
+ readonly status: 'waiting';
20
+ };
21
+ /** The files of one option, as the editor collected them from its script. */
22
+ export interface VariantFilesInput {
23
+ readonly requestId: string;
24
+ readonly choice: string | null;
25
+ readonly files: readonly VariantFileEdit[];
26
+ }
27
+ export interface VariantPreviewServiceProps {
28
+ readonly projectRoot: string;
29
+ }
30
+ export interface VariantPreviewServiceContext {
31
+ readonly store: PhoenixStore;
32
+ readonly logger: Logger;
33
+ readonly projectWatcher: Pick<ApplicationSpecProjectWatcher, 'suspend' | 'resume' | 'applyVariantFiles'>;
34
+ }
35
+ /**
36
+ * Owns the variant comparison of a dev session: which one is open, the file session that rewrites and
37
+ * restores the source files for it, and the answer. Its state lives in the store; every operation that
38
+ * changes it runs one at a time.
39
+ */
40
+ export declare class VariantPreviewService {
41
+ private readonly props;
42
+ private readonly context;
43
+ private readonly queue;
44
+ private readonly result$;
45
+ private readonly closed$;
46
+ private session;
47
+ private editors;
48
+ /**
49
+ * The comparison an editor has to show, or `null`. A subscriber counts as a connected editor, and gets
50
+ * the open comparison at once, so a reloaded browser tab shows it again.
51
+ */
52
+ readonly request$: Observable<VariantPreviewRequest | null>;
53
+ constructor(props: VariantPreviewServiceProps, context: VariantPreviewServiceContext);
54
+ /** True while option edits may be in the source files, so nothing else should write or deploy them. */
55
+ get isOpen(): boolean;
56
+ /**
57
+ * Opens the comparison in the editor and waits for the builder's answer. A wait that times out leaves
58
+ * it open, and a later call with the same options attaches to it again.
59
+ */
60
+ open(input: VariantPreviewInput): Promise<VariantPreviewOutcome>;
61
+ getBaseline(requestId: string): {
62
+ readonly files: readonly VariantFileEdit[];
63
+ readonly choice: string | null;
64
+ };
65
+ applyFiles(input: VariantFilesInput): Promise<void>;
66
+ submit(result: VariantPreviewResult): Promise<void>;
67
+ /** Closes whichever comparison is open without an answer, for a command that gives up on it. */
68
+ close(): Promise<{
69
+ readonly closed: boolean;
70
+ }>;
71
+ claim(requestId: string): void;
72
+ /** Restores the baseline when the dev session ends with a comparison still open. */
73
+ dispose(): Promise<void>;
74
+ private get state();
75
+ private setState;
76
+ /** Takes a comparison off the screen without an answer and ends the wait of the command that opened it. */
77
+ private forget;
78
+ private startSession;
79
+ private endSession;
80
+ }
@@ -0,0 +1 @@
1
+ import e from"promise-queue";import{Observable as t,Subject as s,distinctUntilChanged as i,filter as r,firstValueFrom as o,map as n,merge as a,of as h,timeout as l}from"rxjs";import{VariantFileSession as c}from"./variant-file-session.js";export class VariantPreviewService{props;context;queue=new e(1,1/0);result$=new s;closed$=new s;session=null;editors=0;request$=new t(e=>{this.editors+=1;let t=this.context.store.variantPreview$.pipe(n(e=>e.open),i()).subscribe(e);return()=>{this.editors-=1,t.unsubscribe()}});constructor(e,t){this.props=e,this.context=t}get isOpen(){return null!==this.session}async open(e){return(await this.queue.add(async()=>{let t=t=>JSON.stringify(t.variants)===JSON.stringify(e.variants),{open:s,unclaimed:i}=this.state;if(i&&t(i.request))return{outcome:Promise.resolve({status:"settled",...i.result})};if(0===this.editors)throw Error("No editor connected. Open the configurator in a browser");let c=s&&t(s)?s:{requestId:crypto.randomUUID(),title:e.title,description:e.description,variants:e.variants};if(c!==s)try{await this.endSession(!1),await this.startSession()}catch(e){throw this.forget(s),e}let u=o(a(this.result$.pipe(r(e=>e.requestId===c.requestId),n(e=>({status:"settled",...e}))),this.closed$.pipe(r(e=>e===c.requestId),n(()=>({status:"closed"})))).pipe(l({first:e.timeoutMs,with:()=>h({status:"waiting"})})));return c!==s&&(this.setState({open:c,activeChoice:null,unclaimed:null}),s&&this.closed$.next(s.requestId)),{outcome:u}})).outcome}getBaseline(e){if(this.state.open?.requestId!==e||!this.session)throw Error("This variant preview is no longer open");return{files:this.session.getFiles(),choice:this.state.activeChoice}}applyFiles(e){return this.queue.add(async()=>{let{open:t}=this.state;if(t?.requestId!==e.requestId||!this.session)throw Error("This variant preview is no longer open");let s=t.variants.find(t=>t.id===e.choice);if(null!==e.choice&&!s)throw Error("This option does not belong to the open variant preview");if(null===e.choice&&e.files.length>0)throw Error("The baseline cannot contain variant edits");if(s?.kind==="page"&&e.files.length>0)throw Error("HTML previews cannot override project files");await this.session.apply(e.files),this.setState({activeChoice:e.choice})})}submit(e){return this.queue.add(async()=>{let{open:t,activeChoice:s}=this.state;if(t?.requestId!==e.requestId)throw Error("This preview is no longer open. The agent closed it or replaced it with another one");if(!this.session||s!==e.choice||null!==e.choice&&!t.variants.some(t=>t.id===e.choice))throw Error("Apply this option before choosing it");await this.endSession(!0),this.setState({open:null,activeChoice:null,unclaimed:{request:t,result:e}}),this.result$.next(e)})}close(){return this.queue.add(async()=>{let{open:e}=this.state;try{await this.endSession(!1)}finally{this.forget(e)}return{closed:null!==e}})}claim(e){this.state.unclaimed?.result.requestId===e&&this.setState({unclaimed:null})}dispose(){return this.queue.add(()=>this.endSession(!1))}get state(){return this.context.store.variantPreview$.value}setState(e){this.context.store.variantPreview$.next({...this.state,...e})}forget(e){this.setState({open:null,activeChoice:null,unclaimed:null}),e&&this.closed$.next(e.requestId)}async startSession(){let{projectWatcher:e,logger:t}=this.context;e.suspend();try{this.session=await c.create({projectRoot:this.props.projectRoot,logger:t,onFilesChanged:t=>e.applyVariantFiles(t)})}catch(t){throw e.resume(),t}}async endSession(e){if(this.session)try{await this.session.finish(e)}finally{this.session=null,this.context.projectWatcher.resume()}}}
@@ -17,4 +17,6 @@ export declare const getViteDevConfig: (options?: {
17
17
  export declare const getViteBuildConfigs: (options: {
18
18
  enableEditor?: boolean;
19
19
  templateFiles: readonly string[];
20
+ sdkVersion: string;
21
+ banner: string | undefined;
20
22
  }) => Promise<InlineConfig[]>;
@@ -1 +1 @@
1
- import{lingui as e}from"@lingui/vite-plugin";import i from"@vitejs/plugin-react";import{mkdir as t,readFile as n,writeFile as r}from"fs/promises";import o from"lodash-es/camelCase.js";import{createRequire as a}from"node:module";import{dirname as s,resolve as m}from"path";import{createLogger as l}from"vite";import d from"vite-plugin-css-injected-by-js";import{isUsingLocalSdk as f}from"../utils/package-info.js";import{loadFrontendConfigModule as c}from"./frontend-config.js";import{phxCspNoncePlugin as p}from"./phx-csp-nonce-plugin.js";import{phxGlobalIsolationPlugin as g}from"./phx-global-isolation-plugin.js";let u=null;export const setViteLogSink=(e,i={})=>{u={sink:e,echo:i.echo??!1}};let h=["react","react-dom","three","@react-three/fiber","@react-three/drei","@react-three/postprocessing","its-fine","@emotion/react","@emotion/styled","@mui/material","@mui/system","@tanstack/react-query","rxjs"],S=e=>{let i=e.DEPLOYMENT_ID;if("string"!=typeof i)throw Error("DEPLOYMENT_ID is required in runtime config");return i};export const getViteDevConfig=async t=>{var n,r;let o,d,p=f(),y=c(),O=y.readRuntimeConfig(),b=y.frontendBuildConfig,D=Object.fromEntries((t?.templateFiles??[]).map(e=>[e,`.phoenix/${e}`]));return{...u&&{customLogger:(n=u.sink,r=u.echo,o=l(),{get hasWarned(){return o.hasWarned},info:(e,i)=>{n("info",e),r&&o.info(e,i)},warn:(e,i)=>{n("warn",e),r&&o.warn(e,i)},warnOnce:(e,i)=>{n("warn",e),r&&o.warnOnce(e,i)},error:(e,i)=>{n("error",e),r&&o.error(e,i)},clearScreen:e=>{r&&o.clearScreen(e)},hasErrorLogged:e=>o.hasErrorLogged(e)}),...u.echo?{}:{clearScreen:!1}},mode:"development",optimizeDeps:{exclude:["@swc/wasm-web"],...p&&{entries:["index.html","admin.html",...t?.templateFiles??[]],force:!0}},...p&&{resolve:{alias:(d=a(m(process.cwd(),"package.json")),h.flatMap(e=>{try{let i=s(d.resolve(`${e}/package.json`));return[{find:RegExp(`^${e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(/|$)`),replacement:`${i}$1`}]}catch{return[]}}))}},plugins:[i({babel:{plugins:["macros"]}}),e(),{name:"vite:runtime-config",apply:(e,i)=>"build"===i.command||"development"===i.mode,config:e=>{let i=y.readRuntimeConfig(),t=y.frontendBuildConfig;return{...e,define:{...e.define,"phx.frontendEnv":JSON.stringify(i),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(t.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(t.gltfDecoder)}}}},g({getDeploymentId:()=>S(y.readRuntimeConfig())})],define:{"process.env":{},"import.meta.env.DEV":!0,"import.meta.env.PROD":!1,"phx.frontendEnv":JSON.stringify(O),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(b.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(b.gltfDecoder)},build:{rollupOptions:{input:{index:".phoenix/index.html",admin:".phoenix/admin.html",...D}}},root:m(process.cwd(),"./.phoenix"),server:{watch:{ignored:["./**/*.{ts,tsx}","./.swc/**","../spec/**","../src/**"]}}}};export const getViteBuildConfigs=async a=>{let l=c(),f=l.readRuntimeConfig(),u=l.frontendBuildConfig,h=[{name:"salsita-configurator",entryFile:"./configurator.ts",mainScriptPath:"./configurator.ts",htmlFiles:["./index.html",...{templateFiles:a.templateFiles}.templateFiles],main:!0,format:"iife"},{name:"salsita-admin",entryFile:"./admin.ts",mainScriptPath:"./admin.ts",htmlFiles:["./admin.html"],main:!1,format:"iife"},{name:"salsita-embedded-admin",entryFile:"./embedded-admin.ts",mainScriptPath:"./embedded-admin.ts",htmlFiles:[],main:!1,format:"es"},{name:"salsita-embedded-configurator",entryFile:"./embedded-configurator.ts",mainScriptPath:"./embedded-configurator.ts",htmlFiles:[],main:!1,format:"es"}].map(c=>({plugins:[i({babel:{plugins:["macros"]}}),e(),d({useStrictCSP:!0}),p(),g({getDeploymentId:()=>S(l.readRuntimeConfig())}),{name:"vite:lib-index",writeBundle:async()=>{if(!c.htmlFiles.length)return;let e="iife"===c.format?`${c.name}.iife.js`:`${c.name}.js`;for(let i of c.htmlFiles){if(c.main&&a.enableEditor&&"./index.html"===i)continue;let o=m("./.phoenix",i),l=m("./.phoenix/dist/frontend",i);await t(s(l),{recursive:!0});let d=(await n(o,"utf-8")).replace(c.mainScriptPath,e);await r(l,d,"utf-8")}}}],build:{outDir:"./dist/frontend",chunkSizeWarningLimit:4e3,lib:{entry:c.entryFile,name:o(c.name),formats:[c.format],fileName:()=>"iife"===c.format?`${c.name}.iife.js`:`${c.name}.js`},rollupOptions:{external:[],output:{assetFileNames:`${c.name}.[ext]`}},minify:!0,emptyOutDir:!1},root:m(process.cwd(),"./.phoenix"),define:{"process.env":{},"process.env.NODE_ENV":JSON.stringify("production"),"phx.frontendEnv":JSON.stringify(f),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(u.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(u.gltfDecoder)}}));return a.enableEditor?[...h,{plugins:[i({babel:{plugins:["macros"]}}),e(),d({useStrictCSP:!0}),p()],build:{outDir:"./dist/frontend",chunkSizeWarningLimit:4e3,rollupOptions:{external:[]},minify:!0,emptyOutDir:!1},root:m(process.cwd(),"./.phoenix"),define:{"process.env":{},"process.env.NODE_ENV":JSON.stringify("production"),"phx.frontendEnv":JSON.stringify(f),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(u.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(u.gltfDecoder)}}]:h};
1
+ import{lingui as e}from"@lingui/vite-plugin";import i from"@vitejs/plugin-react";import{mkdir as t,readFile as n,writeFile as r}from"fs/promises";import o from"lodash-es/camelCase.js";import{createRequire as a}from"node:module";import{dirname as s,resolve as m}from"path";import{createLogger as l}from"vite";import p from"vite-plugin-css-injected-by-js";import{isUsingLocalSdk as d}from"../utils/package-info.js";import{loadFrontendConfigModule as f}from"./frontend-config.js";import{phxBannerPlugin as c}from"./phx-banner-plugin.js";import{phxCspNoncePlugin as g}from"./phx-csp-nonce-plugin.js";import{phxGlobalIsolationPlugin as u}from"./phx-global-isolation-plugin.js";import{phxLicensesPlugin as h}from"./phx-licenses-plugin.js";import{phxVariantPreviewsPlugin as S}from"./phx-variant-previews-plugin.js";let b=null;export const setViteLogSink=(e,i={})=>{b={sink:e,echo:i.echo??!1}};let y=["react","react-dom","three","@react-three/fiber","@react-three/drei","@react-three/postprocessing","its-fine","@emotion/react","@emotion/styled","@mui/material","@mui/system","@tanstack/react-query","rxjs"],O=e=>{let i=e.DEPLOYMENT_ID;if("string"!=typeof i)throw Error("DEPLOYMENT_ID is required in runtime config");return i};export const getViteDevConfig=async t=>{var n,r;let o,p,c=d(),g=f(),h=g.readRuntimeConfig(),x=g.frontendBuildConfig,D=Object.fromEntries((t?.templateFiles??[]).map(e=>[e,`.phoenix/${e}`]));return{...b&&{customLogger:(n=b.sink,r=b.echo,o=l(),{get hasWarned(){return o.hasWarned},info:(e,i)=>{n("info",e),r&&o.info(e,i)},warn:(e,i)=>{n("warn",e),r&&o.warn(e,i)},warnOnce:(e,i)=>{n("warn",e),r&&o.warnOnce(e,i)},error:(e,i)=>{n("error",e),r&&o.error(e,i)},clearScreen:e=>{r&&o.clearScreen(e)},hasErrorLogged:e=>o.hasErrorLogged(e)}),...b.echo?{}:{clearScreen:!1}},mode:"development",optimizeDeps:{exclude:["@swc/wasm-web"],...c&&{entries:["index.html","admin.html",...t?.templateFiles??[]],force:!0}},...c&&{resolve:{alias:(p=a(m(process.cwd(),"package.json")),y.flatMap(e=>{try{let i=s(p.resolve(`${e}/package.json`));return[{find:RegExp(`^${e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}(/|$)`),replacement:`${i}$1`}]}catch{return[]}}))}},plugins:[i({babel:{plugins:["macros"]}}),e(),{name:"vite:runtime-config",apply:(e,i)=>"build"===i.command||"development"===i.mode,config:e=>{let i=g.readRuntimeConfig(),t=g.frontendBuildConfig;return{...e,define:{...e.define,"phx.frontendEnv":JSON.stringify(i),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(t.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(t.gltfDecoder)}}}},u({getDeploymentId:()=>O(g.readRuntimeConfig())}),S()],define:{"process.env":{},"import.meta.env.DEV":!0,"import.meta.env.PROD":!1,"phx.frontendEnv":JSON.stringify(h),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(x.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(x.gltfDecoder)},build:{rollupOptions:{input:{index:".phoenix/index.html",admin:".phoenix/admin.html",...D}}},root:m(process.cwd(),"./.phoenix"),server:{watch:{ignored:["./**/*.{ts,tsx}","./.swc/**","../spec/**","../src/**"]}}}};export const getViteBuildConfigs=async a=>{let l=f(),d=l.readRuntimeConfig(),S=l.frontendBuildConfig,b=h(),y=c({sdkVersion:a.sdkVersion,banner:a.banner}),x=[{name:"salsita-configurator",entryFile:"./configurator.ts",mainScriptPath:"./configurator.ts",htmlFiles:["./index.html",...{templateFiles:a.templateFiles}.templateFiles],main:!0,format:"iife"},{name:"salsita-admin",entryFile:"./admin.ts",mainScriptPath:"./admin.ts",htmlFiles:["./admin.html"],main:!1,format:"iife"},{name:"salsita-embedded-admin",entryFile:"./embedded-admin.ts",mainScriptPath:"./embedded-admin.ts",htmlFiles:[],main:!1,format:"es"},{name:"salsita-embedded-configurator",entryFile:"./embedded-configurator.ts",mainScriptPath:"./embedded-configurator.ts",htmlFiles:[],main:!1,format:"es"}].map(f=>({plugins:[i({babel:{plugins:["macros"]}}),e(),p({useStrictCSP:!0}),g(),u({getDeploymentId:()=>O(l.readRuntimeConfig())}),{name:"vite:lib-index",writeBundle:async()=>{if(!f.htmlFiles.length)return;let e="iife"===f.format?`${f.name}.iife.js`:`${f.name}.js`;for(let i of f.htmlFiles){if(f.main&&a.enableEditor&&"./index.html"===i)continue;let o=m("./.phoenix",i),l=m("./.phoenix/dist/frontend",i);await t(s(l),{recursive:!0});let p=(await n(o,"utf-8")).replace(f.mainScriptPath,e);await r(l,p,"utf-8")}}},b,y],build:{outDir:"./dist/frontend",chunkSizeWarningLimit:4e3,lib:{entry:f.entryFile,name:o(f.name),formats:[f.format],fileName:()=>"iife"===f.format?`${f.name}.iife.js`:`${f.name}.js`},rollupOptions:{external:[],output:{assetFileNames:`${f.name}.[ext]`}},minify:!0,emptyOutDir:!1},root:m(process.cwd(),"./.phoenix"),define:{"process.env":{},"process.env.NODE_ENV":JSON.stringify("production"),"phx.frontendEnv":JSON.stringify(d),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(S.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(S.gltfDecoder)}}));return a.enableEditor?[...x,{plugins:[i({babel:{plugins:["macros"]}}),e(),p({useStrictCSP:!0}),g(),b,y],build:{outDir:"./dist/frontend",chunkSizeWarningLimit:4e3,rollupOptions:{external:[]},minify:!0,emptyOutDir:!1},root:m(process.cwd(),"./.phoenix"),define:{"process.env":{},"process.env.NODE_ENV":JSON.stringify("production"),"phx.frontendEnv":JSON.stringify(d),"globalThis.PHX_SCHEMA_VALIDATOR":JSON.stringify(S.jsonSchemaValidator),"globalThis.PHX_GLTF_DECODER":JSON.stringify(S.gltfDecoder)}}]:x};
@@ -7,5 +7,6 @@ export { FileLogger } from './file-logger.js';
7
7
  export { type Logger, type CreateLoggerOptions, createLogger } from './logger.js';
8
8
  export { addWorkspaceOverrides, ensureWorkspaceInstallSettings, getLocalOverrides, getSdkPackages, getWorkspaceDir, hasLocalOverrides, readPackageJson, removeWorkspaceOverrides, } from './package-info.js';
9
9
  export { toPascalCase } from './pascal-case.js';
10
+ export { readGitCommit } from './read-git-commit.js';
10
11
  export { type RunCommandProps, runCommand } from './run-command.js';
11
12
  export { type FileUploadInfo, type UploadLinksData, uploadFilesWithPresignedUrls, readUploadLinks, } from './upload-utils.js';
@@ -1 +1 @@
1
- export{askQuestion}from"./ask-question.js";export{checkBundleSizeBudgets}from"./check-bundle-size-budgets.js";export{formatEnvContent,formatEnvLine}from"./env-file.js";export{parseChangelog,getLatestVersion,getVersion,paginateVersions,getVersionNumbers}from"./changelog-parser.js";export{createDirectoryFromYaml,exists,scanFolderForFiles,syncChangedFiles,syncExistingFolders,validateFolders,writeFileIfNotExists,writeFilesIfNotExists,writeRawFiles}from"./file-system.js";export{FileLogger}from"./file-logger.js";export{createLogger}from"./logger.js";export{addWorkspaceOverrides,ensureWorkspaceInstallSettings,getLocalOverrides,getSdkPackages,getWorkspaceDir,hasLocalOverrides,readPackageJson,removeWorkspaceOverrides}from"./package-info.js";export{toPascalCase}from"./pascal-case.js";export{runCommand}from"./run-command.js";export{uploadFilesWithPresignedUrls,readUploadLinks}from"./upload-utils.js";
1
+ export{askQuestion}from"./ask-question.js";export{checkBundleSizeBudgets}from"./check-bundle-size-budgets.js";export{formatEnvContent,formatEnvLine}from"./env-file.js";export{parseChangelog,getLatestVersion,getVersion,paginateVersions,getVersionNumbers}from"./changelog-parser.js";export{createDirectoryFromYaml,exists,scanFolderForFiles,syncChangedFiles,syncExistingFolders,validateFolders,writeFileIfNotExists,writeFilesIfNotExists,writeRawFiles}from"./file-system.js";export{FileLogger}from"./file-logger.js";export{createLogger}from"./logger.js";export{addWorkspaceOverrides,ensureWorkspaceInstallSettings,getLocalOverrides,getSdkPackages,getWorkspaceDir,hasLocalOverrides,readPackageJson,removeWorkspaceOverrides}from"./package-info.js";export{toPascalCase}from"./pascal-case.js";export{readGitCommit}from"./read-git-commit.js";export{runCommand}from"./run-command.js";export{uploadFilesWithPresignedUrls,readUploadLinks}from"./upload-utils.js";
@@ -0,0 +1,14 @@
1
+ export interface ReadGitCommitProps {
2
+ readonly directory: string;
3
+ /**
4
+ * A file of the project, relative to `directory`, that its repository tracks. git looks for a repository in every
5
+ * parent folder, so sources unpacked inside an unrelated checkout would otherwise report that checkout's commit.
6
+ */
7
+ readonly trackedFile: string;
8
+ }
9
+ /**
10
+ * Full SHA of the commit checked out in the project's own repository. Undefined when git cannot read one: no
11
+ * checkout, git missing or refusing the repository, no commit yet, or the project is not tracked by the repository
12
+ * around it. That is normal for a build from uploaded sources.
13
+ */
14
+ export declare const readGitCommit: (props: ReadGitCommitProps) => Promise<string | undefined>;
@@ -0,0 +1 @@
1
+ import{execFile as t}from"node:child_process";import{promisify as e}from"node:util";let r=e(t),i=/^[0-9a-f]{40,64}$/;export const readGitCommit=async t=>{let e={cwd:t.directory,timeout:5e3,windowsHide:!0};try{await r("git",["ls-files","--error-unmatch","--",t.trackedFile],e);let{stdout:o}=await r("git",["rev-parse","HEAD"],e),a=o.trim();return i.test(a)?a:void 0}catch{return}};
@@ -11,8 +11,8 @@ export declare class AnalyticsService {
11
11
  constructor(_debug: boolean);
12
12
  push: (event: AnalyticsEvent) => void;
13
13
  }
14
- declare const Initialized: (userId: string, configuratorName: string) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").InitEvent;
15
- declare const ConfigurationLoaded: (configurationId: string, revisionId: string, mode: 'read' | 'owner') => import("../../../../domain/domain-context/analytics-system/analytics-contracts").DataLoadedEvent;
14
+ declare const Initialized: (userId: string, configuratorName: string) => import("#package/domain").InitEvent;
15
+ declare const ConfigurationLoaded: (configurationId: string, revisionId: string, mode: 'read' | 'owner') => import("#package/domain").DataLoadedEvent;
16
16
  export declare const CommonAnalyticsFactory: {
17
17
  Initialized: typeof Initialized;
18
18
  ConfigurationLoaded: typeof ConfigurationLoaded;
@@ -1,26 +1,26 @@
1
1
  import type { MultilingualString } from '@salsita-ai/common/utils';
2
2
  import { type DomainEntity, type DomainEntityId, type EntityId, type EntityRecipe } from '#package/domain';
3
- declare const EntityChildrenListActionButtonClicked: (id: string) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
4
- declare const EntityChildrenListItemClicked: (id: string) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
5
- declare const AngleDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
6
- declare const AngleDimensionSliderDragged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
7
- declare const GenericDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
8
- declare const GenericDimensionSliderDragged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
9
- declare const DistanceDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
10
- declare const DistanceDimensionSliderDragged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
11
- declare const SizeDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
12
- declare const OffsetDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
13
- declare const AttributeSelected: (selectorType: string) => (instanceName: string, id: EntityId, value: string | number | boolean) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
14
- declare const DimensionSelected: (selectorType: string) => (instanceName: string, id: EntityId, value: number) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
15
- declare const SwatchSelected: (instanceName: string, id: EntityId, value: string) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
16
- declare const ColorPickerChanged: (instanceName: string, id: EntityId, value: string) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
17
- declare const TextValueChanged: (instanceName: string, id: EntityId, value: string) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
18
- declare const MultilingualTextValueChanged: (instanceName: string, id: EntityId, value: MultilingualString) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
19
- declare const RecipesSelected: (recipes: ReadonlyArray<DomainEntity<string>>) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
20
- declare const RecipeReplacementSelected: (oldId: DomainEntityId<string>, recipes: ReadonlyArray<DomainEntity<string>>) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
21
- declare const ChildEntitySelected: (selectorType: string) => (id: EntityId, recipes: ReadonlyArray<EntityRecipe<DomainEntity<string>>>) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
22
- declare const EntityChildrenListDeleteButtonClicked: (id: EntityId) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
23
- declare const EntityDeleteButtonClicked: (id: EntityId) => import("../../../../domain/domain-context/analytics-system/analytics-contracts").UserActionEvent;
3
+ declare const EntityChildrenListActionButtonClicked: (id: string) => import("#package/domain").UserActionEvent;
4
+ declare const EntityChildrenListItemClicked: (id: string) => import("#package/domain").UserActionEvent;
5
+ declare const AngleDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
6
+ declare const AngleDimensionSliderDragged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
7
+ declare const GenericDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
8
+ declare const GenericDimensionSliderDragged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
9
+ declare const DistanceDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
10
+ declare const DistanceDimensionSliderDragged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
11
+ declare const SizeDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
12
+ declare const OffsetDimensionInputChanged: (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
13
+ declare const AttributeSelected: (selectorType: string) => (instanceName: string, id: EntityId, value: string | number | boolean) => import("#package/domain").UserActionEvent;
14
+ declare const DimensionSelected: (selectorType: string) => (instanceName: string, id: EntityId, value: number) => import("#package/domain").UserActionEvent;
15
+ declare const SwatchSelected: (instanceName: string, id: EntityId, value: string) => import("#package/domain").UserActionEvent;
16
+ declare const ColorPickerChanged: (instanceName: string, id: EntityId, value: string) => import("#package/domain").UserActionEvent;
17
+ declare const TextValueChanged: (instanceName: string, id: EntityId, value: string) => import("#package/domain").UserActionEvent;
18
+ declare const MultilingualTextValueChanged: (instanceName: string, id: EntityId, value: MultilingualString) => import("#package/domain").UserActionEvent;
19
+ declare const RecipesSelected: (recipes: ReadonlyArray<DomainEntity<string>>) => import("#package/domain").UserActionEvent;
20
+ declare const RecipeReplacementSelected: (oldId: DomainEntityId<string>, recipes: ReadonlyArray<DomainEntity<string>>) => import("#package/domain").UserActionEvent;
21
+ declare const ChildEntitySelected: (selectorType: string) => (id: EntityId, recipes: ReadonlyArray<EntityRecipe<DomainEntity<string>>>) => import("#package/domain").UserActionEvent;
22
+ declare const EntityChildrenListDeleteButtonClicked: (id: EntityId) => import("#package/domain").UserActionEvent;
23
+ declare const EntityDeleteButtonClicked: (id: EntityId) => import("#package/domain").UserActionEvent;
24
24
  export declare const DomainControlsAnalytics: {
25
25
  ColorPickerChanged: typeof ColorPickerChanged;
26
26
  EntityChildrenListActionButtonClicked: typeof EntityChildrenListActionButtonClicked;
@@ -9,6 +9,6 @@ interface PublishedDataValueProviderProps extends PublishedDataValue {
9
9
  }
10
10
  export declare const PublishedDataValueProvider: (props: PublishedDataValueProviderProps) => import("react/jsx-runtime").JSX.Element;
11
11
  export declare const useProvidedPublishedData: () => PublishedDataValue;
12
- export declare const usePublishedData: () => Record<string, unknown> & import("../../../../domain/admin-domain/__generated/application-types").PublishedData;
12
+ export declare const usePublishedData: () => PublishedDataValue['publishedData'];
13
13
  export type UsePublishedData<PUBLISHED_DATA extends CommonAdminPublishedData> = () => PUBLISHED_DATA;
14
14
  export {};
@@ -404,6 +404,8 @@ export declare function createApplicationRuntimeSlices<State extends Application
404
404
  getActiveConfigurationId: () => string;
405
405
  getFactory: () => import("#package/domain").AnyDomainFactory;
406
406
  getDomainExpressions: () => import("#package/domain").AnyExpressions;
407
+ getActionDefinitions: () => Readonly<Record<string, import("#package/domain").ActionDefinition>>;
408
+ getActionImplementations: () => Readonly<Record<string, import("#package/domain").AnyActionImplementation>>;
407
409
  getModelVersion: () => number;
408
410
  getAliasMap: () => import("#package/domain").AnyAliasMap;
409
411
  getAllowedRootEntityTypes: () => import("#package/domain").AnyAllowedRootEntityTypes;
@@ -444,6 +446,7 @@ export declare function createApplicationRuntimeSlices<State extends Application
444
446
  getNavigationSystem: () => import("../../../domain/domain-context/navigation-system/navigation-system.js").AnyNavigationSystem;
445
447
  getUndoSystem: () => import("../../../domain/domain-context/undo-system.js").AnyUndoSystem;
446
448
  getRecipeCookerSystem: () => import("#package/domain").AnyRecipeCookerSystem;
449
+ getActionSystem: () => import("#package/domain").AnyActionSystem;
447
450
  getBlenderProjections: () => import("#package/domain").AnyBlenderProjections;
448
451
  getExpressionContext: () => import("#package/domain").AnyExpressionContext;
449
452
  getDomainSystems: () => import("#package/domain").AnyDomainContextSystems;
@@ -510,6 +513,8 @@ export declare function createApplicationRuntimeSlices<State extends Application
510
513
  getActiveConfigurationId: () => string;
511
514
  getFactory: () => import("#package/domain").AnyDomainFactory;
512
515
  getDomainExpressions: () => import("#package/domain").AnyExpressions;
516
+ getActionDefinitions: () => Readonly<Record<string, import("#package/domain").ActionDefinition>>;
517
+ getActionImplementations: () => Readonly<Record<string, import("#package/domain").AnyActionImplementation>>;
513
518
  getModelVersion: () => number;
514
519
  getAliasMap: () => import("#package/domain").AnyAliasMap;
515
520
  getAllowedRootEntityTypes: () => import("#package/domain").AnyAllowedRootEntityTypes;
@@ -550,6 +555,7 @@ export declare function createApplicationRuntimeSlices<State extends Application
550
555
  getNavigationSystem: () => import("../../../domain/domain-context/navigation-system/navigation-system.js").AnyNavigationSystem;
551
556
  getUndoSystem: () => import("../../../domain/domain-context/undo-system.js").AnyUndoSystem;
552
557
  getRecipeCookerSystem: () => import("#package/domain").AnyRecipeCookerSystem;
558
+ getActionSystem: () => import("#package/domain").AnyActionSystem;
553
559
  getBlenderProjections: () => import("#package/domain").AnyBlenderProjections;
554
560
  getExpressionContext: () => import("#package/domain").AnyExpressionContext;
555
561
  getDomainSystems: () => import("#package/domain").AnyDomainContextSystems;
@@ -1058,6 +1064,8 @@ declare const createApplicationRuntimeImpl: <EXTENSIONS extends readonly AnyAppl
1058
1064
  getActiveConfigurationId: () => string;
1059
1065
  getFactory: () => import("#package/domain").AnyDomainFactory;
1060
1066
  getDomainExpressions: () => import("#package/domain").AnyExpressions;
1067
+ getActionDefinitions: () => Readonly<Record<string, import("#package/domain").ActionDefinition>>;
1068
+ getActionImplementations: () => Readonly<Record<string, import("#package/domain").AnyActionImplementation>>;
1061
1069
  getModelVersion: () => number;
1062
1070
  getAliasMap: () => import("#package/domain").AnyAliasMap;
1063
1071
  getAllowedRootEntityTypes: () => import("#package/domain").AnyAllowedRootEntityTypes;
@@ -1098,6 +1106,7 @@ declare const createApplicationRuntimeImpl: <EXTENSIONS extends readonly AnyAppl
1098
1106
  getNavigationSystem: () => import("../../../domain/domain-context/navigation-system/navigation-system.js").AnyNavigationSystem;
1099
1107
  getUndoSystem: () => import("../../../domain/domain-context/undo-system.js").AnyUndoSystem;
1100
1108
  getRecipeCookerSystem: () => import("#package/domain").AnyRecipeCookerSystem;
1109
+ getActionSystem: () => import("#package/domain").AnyActionSystem;
1101
1110
  getBlenderProjections: () => import("#package/domain").AnyBlenderProjections;
1102
1111
  getExpressionContext: () => import("#package/domain").AnyExpressionContext;
1103
1112
  getDomainSystems: () => import("#package/domain").AnyDomainContextSystems;
@@ -1164,6 +1173,8 @@ declare const createApplicationRuntimeImpl: <EXTENSIONS extends readonly AnyAppl
1164
1173
  getActiveConfigurationId: () => string;
1165
1174
  getFactory: () => import("#package/domain").AnyDomainFactory;
1166
1175
  getDomainExpressions: () => import("#package/domain").AnyExpressions;
1176
+ getActionDefinitions: () => Readonly<Record<string, import("#package/domain").ActionDefinition>>;
1177
+ getActionImplementations: () => Readonly<Record<string, import("#package/domain").AnyActionImplementation>>;
1167
1178
  getModelVersion: () => number;
1168
1179
  getAliasMap: () => import("#package/domain").AnyAliasMap;
1169
1180
  getAllowedRootEntityTypes: () => import("#package/domain").AnyAllowedRootEntityTypes;
@@ -1204,6 +1215,7 @@ declare const createApplicationRuntimeImpl: <EXTENSIONS extends readonly AnyAppl
1204
1215
  getNavigationSystem: () => import("../../../domain/domain-context/navigation-system/navigation-system.js").AnyNavigationSystem;
1205
1216
  getUndoSystem: () => import("../../../domain/domain-context/undo-system.js").AnyUndoSystem;
1206
1217
  getRecipeCookerSystem: () => import("#package/domain").AnyRecipeCookerSystem;
1218
+ getActionSystem: () => import("#package/domain").AnyActionSystem;
1207
1219
  getBlenderProjections: () => import("#package/domain").AnyBlenderProjections;
1208
1220
  getExpressionContext: () => import("#package/domain").AnyExpressionContext;
1209
1221
  getDomainSystems: () => import("#package/domain").AnyDomainContextSystems;
@@ -60,6 +60,8 @@ export declare const useDomainContextSelectors: () => {
60
60
  getActiveConfigurationId: () => string;
61
61
  getFactory: () => import("#package/domain").AnyDomainFactory;
62
62
  getDomainExpressions: () => import("#package/domain").AnyExpressions;
63
+ getActionDefinitions: () => Readonly<Record<string, import("#package/domain").ActionDefinition>>;
64
+ getActionImplementations: () => Readonly<Record<string, import("#package/domain").AnyActionImplementation>>;
63
65
  getModelVersion: () => number;
64
66
  getAliasMap: () => import("#package/domain").AnyAliasMap;
65
67
  getAllowedRootEntityTypes: () => import("#package/domain").AnyAllowedRootEntityTypes;
@@ -100,6 +102,7 @@ export declare const useDomainContextSelectors: () => {
100
102
  getNavigationSystem: () => import("../../../domain/domain-context/navigation-system/navigation-system.js").AnyNavigationSystem;
101
103
  getUndoSystem: () => import("../../../domain/domain-context/undo-system.js").AnyUndoSystem;
102
104
  getRecipeCookerSystem: () => import("#package/domain").AnyRecipeCookerSystem;
105
+ getActionSystem: () => import("#package/domain").AnyActionSystem;
103
106
  getBlenderProjections: () => import("#package/domain").AnyBlenderProjections;
104
107
  getExpressionContext: () => import("#package/domain").AnyExpressionContext;
105
108
  getDomainSystems: () => import("#package/domain").AnyDomainContextSystems;
@@ -13,8 +13,11 @@ export declare const getViewportSize: () => Size;
13
13
  * Returns the viewport size. This can also be used as a dependency in a
14
14
  * useEffect to trigger an update when the browser resizes.
15
15
  *
16
+ * @param subscriptionActive if `false`, the viewport is neither measured nor followed, and the size
17
+ * returned is the last one measured, if any (useful for optimization)
18
+ *
16
19
  * @see https://martijnhols.nl/gists/how-to-get-document-height-ios-safari-osk
17
20
  * @todo: investigate if this can use `viewport$`
18
21
  */
19
- export declare const useViewportSize: () => Size | undefined;
22
+ export declare const useViewportSize: (subscriptionActive?: boolean) => Size | undefined;
20
23
  export {};
@@ -1 +1 @@
1
- import{useCallback as e,useEffect as i,useLayoutEffect as t,useState as n}from"react";let o="u">typeof window?t:()=>{};export const getViewportSize=()=>window.visualViewport?[window.visualViewport.width,window.visualViewport.height]:[window.innerWidth,window.innerHeight];export const useViewportSize=()=>{let[t,r]=n(),w=e(()=>{let e=getViewportSize();r(i=>i&&i[0]===e[0]&&i[1]===e[1]?i:e)},[]);return o(w,[w]),i(()=>{let e=()=>{w(),setTimeout(w,1e3)};return window.addEventListener("resize",e),window.addEventListener("orientationchange",e),window.visualViewport?.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),window.removeEventListener("orientationchange",e),window.visualViewport?.removeEventListener("resize",e)}},[w]),t};
1
+ import{useCallback as e,useEffect as i,useLayoutEffect as t,useState as n}from"react";let r="u">typeof window?t:()=>{};export const getViewportSize=()=>window.visualViewport?[window.visualViewport.width,window.visualViewport.height]:[window.innerWidth,window.innerHeight];export const useViewportSize=(t=!0)=>{let[o,w]=n(),d=e(()=>{let e=getViewportSize();w(i=>i&&i[0]===e[0]&&i[1]===e[1]?i:e)},[]);return r(()=>{t&&d()},[t,d]),i(()=>{if(!t)return;let e=()=>{d(),setTimeout(d,1e3)};return window.addEventListener("resize",e),window.addEventListener("orientationchange",e),window.visualViewport?.addEventListener("resize",e),()=>{window.removeEventListener("resize",e),window.removeEventListener("orientationchange",e),window.visualViewport?.removeEventListener("resize",e)}},[t,d]),o};
@@ -1 +1 @@
1
- export { MobileControls, type MobileControlsLayoutProps, type MobileControlsThemeableProps } from './MobileControls.js';
1
+ export { MobileControls, type MobileControlsLayoutProps, type MobileControlsThemeableProps, type ViewOnlyModeProps, } from './MobileControls.js';
@@ -44,6 +44,7 @@ declare module '@mui/material/styles' {
44
44
  PhxChat: 'root';
45
45
  PhxChatFooter: 'root' | 'formLayout' | 'input';
46
46
  PhxChatMessage: 'base' | 'assistant' | 'user' | 'widget' | 'error' | 'helper';
47
+ PhxAssistantPanel: 'root' | 'header' | 'title' | 'closeButton' | 'thread' | 'greeting' | 'messages' | 'userMessage' | 'assistantMessage' | 'chips' | 'activity' | 'activityIcon' | 'chip' | 'status' | 'notice' | 'newReplyButton' | 'composer' | 'inputFrame' | 'input' | 'sendButton' | 'stopButton' | 'hint';
47
48
  PhxTopNavigation: 'root' | 'stepper' | 'step';
48
49
  PhxListSelector: 'root';
49
50
  PhxListSelectorItem: 'root' | 'radio' | 'title' | 'description' | 'formControlLabel';
@@ -109,6 +110,9 @@ declare module '@mui/material/styles' {
109
110
  PhxChatMessage?: {
110
111
  styleOverrides?: ComponentsOverrides<Theme>['PhxChatMessage'];
111
112
  };
113
+ PhxAssistantPanel?: {
114
+ styleOverrides?: ComponentsOverrides<Theme>['PhxAssistantPanel'];
115
+ };
112
116
  PhxPreviewLayout?: {
113
117
  styleOverrides?: ComponentsOverrides<Theme>['PhxPreviewLayout'];
114
118
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salsita-ai/sdk",
3
- "version": "0.50.0-develop.514d19d58c",
3
+ "version": "0.50.0-develop.5a0bcdee42",
4
4
  "description": "TypeScript SDK and CLI for building, running, and deploying Phoenix configurator applications.",
5
5
  "keywords": [
6
6
  "salsita",
@@ -149,10 +149,6 @@
149
149
  "import": "./dist/extras/ai-preview/index.js",
150
150
  "types": "./dist/extras/ai-preview/index.d.ts"
151
151
  },
152
- "./extras/assistant": {
153
- "import": "./dist/extras/assistant/index.js",
154
- "types": "./dist/extras/assistant/index.d.ts"
155
- },
156
152
  "./common/utils": {
157
153
  "import": "./dist/common/utils.js",
158
154
  "types": "./dist/common/utils.d.ts"
@@ -225,7 +221,7 @@
225
221
  "@swc/core": "1.15.40",
226
222
  "@swc/wasm-web": "1.15.40",
227
223
  "@tanstack/ai": "0.64.0",
228
- "@tanstack/ai-react": "0.29.4",
224
+ "@tanstack/ai-client": "0.36.1",
229
225
  "@trpc/client": "11.17.0",
230
226
  "@trpc/react-query": "11.17.0",
231
227
  "@trpc/server": "11.17.0",
@@ -275,6 +271,7 @@
275
271
  "react-json-tree": "0.20.0",
276
272
  "react-markdown": "9.0.1",
277
273
  "remark": "15.0.1",
274
+ "remark-gfm": "4.0.0",
278
275
  "rxjs": "7.8.2",
279
276
  "semver": "7.6.3",
280
277
  "spark-md5": "3.0.2",
@@ -295,8 +292,8 @@
295
292
  "yaml": "2.9.0",
296
293
  "yargs": "17.7.2",
297
294
  "zod": "3.25.76",
298
- "@salsita-ai/common": "0.50.0-develop.514d19d58c",
299
- "@salsita-ai/contracts": "0.50.0-develop.514d19d58c"
295
+ "@salsita-ai/common": "0.50.0-develop.5a0bcdee42",
296
+ "@salsita-ai/contracts": "0.50.0-develop.5a0bcdee42"
300
297
  },
301
298
  "devDependencies": {
302
299
  "@clerk/clerk-react": "5.61.8",
@@ -18586,6 +18586,30 @@
18586
18586
  "required": ["kind"],
18587
18587
  "additionalProperties": false
18588
18588
  },
18589
+ {
18590
+ "type": "object",
18591
+ "properties": {
18592
+ "kind": {
18593
+ "type": "string",
18594
+ "enum": ["assistantToolbarButton"]
18595
+ },
18596
+ "props": {
18597
+ "type": "object",
18598
+ "properties": {
18599
+ "showTitle": {
18600
+ "type": "boolean"
18601
+ },
18602
+ "icon": {
18603
+ "type": "string"
18604
+ }
18605
+ },
18606
+ "required": [],
18607
+ "additionalProperties": false
18608
+ }
18609
+ },
18610
+ "required": ["kind"],
18611
+ "additionalProperties": false
18612
+ },
18589
18613
  {
18590
18614
  "type": "object",
18591
18615
  "properties": {
@@ -1 +0,0 @@
1
- import{browserDetailsTool as e}from"@salsita-ai/contracts/assistant";let t=e=>{let t=[];for(let i=0;i<e.length;i+=64)t.push(e.slice(i,i+64));return t};export const browserDetailsClientTool=e.client(()=>{let e=(()=>{let e=[`User agent: ${navigator.userAgent}`,`Viewport: ${window.innerWidth} x ${window.innerHeight} px`,`Screen: ${window.screen.width} x ${window.screen.height} px`,`Device pixel ratio: ${window.devicePixelRatio}`,`Language: ${navigator.language}`,`Time zone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`].flatMap(t),i=document.createElement("canvas");i.width=720,i.height=48+26*e.length;let n=i.getContext("2d");if(!n)throw Error("The browser details capture failed because the canvas has no 2D context. Retry in another browser.");return n.fillStyle="#ffffff",n.fillRect(0,0,i.width,i.height),n.fillStyle="#111111",n.font="16px monospace",n.textBaseline="top",e.forEach((e,t)=>n.fillText(e,24,24+26*t)),i.toDataURL("image/png")})();return[{type:"image",source:{type:"data",value:e.slice(e.indexOf(",")+1),mimeType:"image/png"}}]});
@@ -1 +0,0 @@
1
- import{AssistantGraphQLToolInput as e,applyTool as t,queryTool as o}from"@salsita-ai/contracts/assistant";let a=e=>({results:[],committed:!1,message:e}),s=e=>JSON.parse(JSON.stringify(e)),i=t=>{let o=e.safeParse(t);if(!o.success){let e=o.error.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join("; ");return{ok:!1,refusal:a(`Nothing was run, because the tool input is not a list of operations (${e}). Send { "operations": [{ "query": "<one GraphQL operation>" }] } with at least one item.`)}}return{ok:!0,operations:o.data.operations.map(({query:e,variables:t,operationName:o})=>({document:e,variables:t??void 0,operationName:o??void 0}))}};export const queryClientTool=o.client(async(e,{context:t})=>{let o=i(e);return o.ok?t.storeSystem.isInitialized?s({results:(await t.graphQLSystem.prepare(t.storeSystem.stateSlices.committed.value.state,o.operations)).map(({result:e})=>e),committed:!1}):a("Nothing was run, because the configuration is not loaded yet, so there is no state to query. Call the tool again once the configurator has finished loading."):o.refusal});export const applyClientTool=t.client(async(e,{context:t})=>{if("owner"!==t.getActiveMode())return a("Nothing was run, because changes cannot be applied in this session: the user may view this configuration but not change it. The query tool still works here, including mutations, to show what a change would do without keeping it.");let o=i(e);return o.ok?s(await t.graphQLSystem.execute(o.operations)):o.refusal});
@@ -1 +0,0 @@
1
- export { useAssistantChat, type AssistantChatState } from './use-assistant-chat.js';
@@ -1 +0,0 @@
1
- export{useAssistantChat}from"./use-assistant-chat.js";
@@ -1,20 +0,0 @@
1
- import { type UIMessage } from '@tanstack/ai-react';
2
- /** Experimental assistant chat state and actions of the current configuration. */
3
- export interface AssistantChatState {
4
- /** The thread as painted: hydrated from the server, then streamed. */
5
- readonly messages: ReadonlyArray<UIMessage>;
6
- /** True while a reply streams or a browser tool runs. */
7
- readonly isLoading: boolean;
8
- readonly error: Error | undefined;
9
- /** Sends a user message stamped with its send time. */
10
- readonly send: (content: string) => Promise<void>;
11
- /** Stops the current reply in the browser and on the server. */
12
- readonly stop: () => Promise<void>;
13
- }
14
- /**
15
- * Experimental: the conversational assistant of the current configuration. The server owns the
16
- * thread — the chat hydrates from it on mount and rejoins a reply still streaming — so the hook
17
- * keeps nothing in browser storage. Each message carries its send time for the model. The model's
18
- * `query` and `apply` calls run here, in the browser, against the configurator this hook is rendered in.
19
- */
20
- export declare const useAssistantChat: () => AssistantChatState;
@@ -1 +0,0 @@
1
- import{fetchServerSentEvents as t,useChat as e}from"@tanstack/ai-react";import{useCallback as a,useMemo as r}from"react";import{useAuthorizedClient as s,useConfigurationId as n,useDomain as o}from"#package/react-sdk";import{useConfigurator as i}from"../application-runtime/index.js";import{browserDetailsClientTool as c}from"./browser-details.js";import{applyClientTool as p,queryClientTool as l}from"./graphql-tools.js";let m=[c,l,p];export const useAssistantChat=()=>{let c=n(),p=s(),l=r(()=>p.getAssistantChatConnection(c),[p,c]),d=r(()=>{let e=async()=>({headers:await l.headers()}),a=t(l.url,e),r=t(`${l.url}/runs`,e);return{...a,joinRun:r.joinRun}},[l]),{graphQLSystem:u}=i(),{storeSystem:h,domainContextSelectors:f}=o(),{getActiveMode:w}=f,{messages:g,isLoading:j,error:y,sendMessage:C,stop:S,runId:$}=e({threadId:`assistant:${c}`,connection:d,persistence:!0,history:{pageSize:50},tools:m,context:r(()=>({graphQLSystem:u,storeSystem:h,getActiveMode:w}),[u,h,w])});return{messages:g,isLoading:j,error:y,send:a(async t=>{let e={sentAt:new Date().toISOString()};await C({content:t,metadata:e})},[C]),stop:a(async()=>{S(),null!=$&&await fetch(`${l.url}/runs/${encodeURIComponent($)}/cancel`,{method:"POST",headers:await l.headers()})},[l,$,S])}};
@@ -1,6 +0,0 @@
1
- /**
2
- * Experimental, unstyled assistant chat for the current configuration: streamed replies, reasoning
3
- * summaries, tool calls with their payloads, a pending indicator and a stop button. It renders
4
- * nothing, and contacts no server, when the application spec has no `assistant` section.
5
- */
6
- export declare const AssistantChat: () => import("react/jsx-runtime").JSX.Element | null;
@@ -1 +0,0 @@
1
- import{jsx as e,jsxs as t}from"react/jsx-runtime";import{Alert as r,Box as a,Button as i,LinearProgress as n,Stack as o,TextField as l,Typography as s}from"@mui/material";import{useState as c}from"react";import{useAssistantChat as p}from"#package/configurator";import{useSpecAssistant as m}from"#package/react-sdk";let d=({part:t})=>{switch(t.type){case"text":return e(s,{sx:{whiteSpace:"pre-wrap"},children:t.content});case"thinking":return e(s,{variant:"body2",color:"text.secondary",sx:{fontStyle:"italic",whiteSpace:"pre-wrap"},children:t.content});case"tool-call":return e(s,{variant:"caption",component:"pre",sx:{m:0,whiteSpace:"pre-wrap"},children:`${t.name}(${JSON.stringify(t.input??t.arguments)}) \xb7 ${t.state}`});case"tool-result":{let r=(e=>{if("string"!=typeof e){for(let t of e)if("image"===t.type&&"data"===t.source.type)return`data:${t.source.mimeType};base64,${t.source.value}`}})(t.content);return r?e(a,{component:"img",src:r,alt:"Tool result",sx:{maxWidth:"100%",border:1}}):e(s,{variant:"caption",children:`Tool result \xb7 ${t.state}`})}default:return null}},u=()=>{let{messages:m,send:u,stop:h,isLoading:f,error:x}=p(),[g,v]=c("");return t(o,{spacing:1.5,sx:{p:2},children:[m.map(r=>t(a,{component:"div",sx:{alignSelf:"user"===r.role?"flex-end":"flex-start",maxWidth:"85%"},children:[e(s,{variant:"overline",children:r.role}),r.parts.map((t,r)=>e(d,{part:t},r))]},r.id)),f&&e(n,{"aria-label":"Assistant is responding"}),x&&e(r,{severity:"warning",children:x.message}),e("form",{onSubmit:e=>{e.preventDefault();let t=g.trim();t&&(v(""),u(t))},children:t(o,{direction:"row",spacing:1,children:[e(l,{size:"small",fullWidth:!0,placeholder:"Ask the assistant…",value:g,onChange:e=>v(e.target.value)}),f?e(i,{onClick:()=>void h(),children:"Stop"}):e(i,{type:"submit",variant:"contained",disabled:!g.trim(),children:"Send"})]})})]})};export const AssistantChat=()=>m()?e(u,{}):null;
@@ -1 +0,0 @@
1
- export { AssistantChat } from './AssistantChat.js';
@@ -1 +0,0 @@
1
- export{AssistantChat}from"./AssistantChat.js";