@syntrologie/runtime-sdk 2.1.0 → 2.2.0-canary.10

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 (360) hide show
  1. package/CAPABILITIES.md +50 -43
  2. package/README.md +7 -7
  3. package/dist/RuntimeProvider.d.ts +1 -1
  4. package/dist/ShadowRootContext.d.ts +19 -0
  5. package/dist/SmartCanvasApp.d.ts +7 -4
  6. package/dist/SmartCanvasElement.d.ts +7 -2
  7. package/dist/SmartCanvasPortal.d.ts +1 -1
  8. package/dist/actions/executors/core-flow.d.ts +19 -0
  9. package/dist/actions/executors/index.d.ts +4 -3
  10. package/dist/actions/executors/tour.d.ts +1 -1
  11. package/dist/actions/index.d.ts +4 -3
  12. package/dist/actions/schema.d.ts +1229 -0
  13. package/dist/actions/schema.js +67 -0
  14. package/dist/actions/schema.js.map +7 -0
  15. package/dist/api.d.ts +4 -2
  16. package/dist/apps/builtinRuntimeModules.generated.d.ts +20 -0
  17. package/dist/apps/examples/gamification-app.example.d.ts +4 -4
  18. package/dist/apps/index.d.ts +7 -7
  19. package/dist/blocks/data/index.d.ts +1 -1
  20. package/dist/blocks/index.d.ts +2 -2
  21. package/dist/blocks/interactive/index.d.ts +1 -1
  22. package/dist/blocks/notification/NotificationBlock.d.ts +1 -1
  23. package/dist/blocks/notification/index.d.ts +1 -1
  24. package/dist/bootstrap.d.ts +4 -4
  25. package/dist/chunk-AYTRRBR5.js +251 -0
  26. package/dist/chunk-AYTRRBR5.js.map +7 -0
  27. package/dist/chunk-VLWWR22N.js +9266 -0
  28. package/dist/chunk-VLWWR22N.js.map +7 -0
  29. package/dist/components/ShadowCanvasOverlay.d.ts +2 -2
  30. package/dist/components/TileCard.d.ts +1 -1
  31. package/dist/context/ContextManager.d.ts +1 -1
  32. package/dist/context/index.d.ts +3 -3
  33. package/dist/decisions/engine.d.ts +1 -1
  34. package/dist/decisions/index.d.ts +3 -3
  35. package/dist/decisions/schema.d.ts +24 -24
  36. package/dist/decisions/strategies/rules.d.ts +1 -1
  37. package/dist/decisions/strategies/score.d.ts +1 -1
  38. package/dist/editorLoader.d.ts +4 -4
  39. package/dist/events/EventAccumulator.d.ts +1 -1
  40. package/dist/events/EventBus.d.ts +1 -1
  41. package/dist/events/index.d.ts +7 -6
  42. package/dist/events/registerConfigPredicates.d.ts +19 -0
  43. package/dist/experiments/adapters/growthbook.d.ts +1 -1
  44. package/dist/experiments/index.d.ts +2 -2
  45. package/dist/experiments/registry.d.ts +1 -1
  46. package/dist/fetchers/index.d.ts +2 -2
  47. package/dist/hooks/useShadowCanvasConfig.d.ts +1 -1
  48. package/dist/hostPatcher/index.d.ts +2 -2
  49. package/dist/index.d.ts +24 -21
  50. package/dist/index.js +2349 -75
  51. package/dist/index.js.map +7 -1
  52. package/dist/metrics/index.d.ts +1 -1
  53. package/dist/notifications/index.d.ts +6 -6
  54. package/dist/overlays/runtime/index.d.ts +3 -3
  55. package/dist/overlays/runtime/overlay/root.d.ts +17 -1
  56. package/dist/overlays/runtime/overlay/tooltip.d.ts +1 -1
  57. package/dist/react.js +90 -134
  58. package/dist/react.js.map +7 -1
  59. package/dist/render/RenderContext.d.ts +2 -2
  60. package/dist/render/index.d.ts +2 -2
  61. package/dist/render/types.d.ts +2 -2
  62. package/dist/runtime.d.ts +8 -8
  63. package/dist/smart-canvas.esm.js +158 -126
  64. package/dist/smart-canvas.esm.js.map +4 -4
  65. package/dist/smart-canvas.js +18872 -16744
  66. package/dist/smart-canvas.js.map +4 -4
  67. package/dist/smart-canvas.min.js +158 -126
  68. package/dist/smart-canvas.min.js.map +4 -4
  69. package/dist/state/StateStore.d.ts +1 -1
  70. package/dist/state/helpers/cooldowns.d.ts +1 -1
  71. package/dist/state/helpers/dismissals.d.ts +1 -1
  72. package/dist/state/helpers/frequency.d.ts +1 -1
  73. package/dist/state/index.d.ts +3 -3
  74. package/dist/surfaces/index.d.ts +3 -3
  75. package/dist/surfaces/positioning.d.ts +1 -1
  76. package/dist/telemetry/adapters/posthog.d.ts +2 -2
  77. package/dist/telemetry/index.d.ts +3 -3
  78. package/dist/telemetry/registry.d.ts +1 -1
  79. package/dist/telemetry/types.d.ts +5 -0
  80. package/dist/theme/ThemeProvider.d.ts +1 -1
  81. package/dist/theme/extractHostTheme.d.ts +1 -1
  82. package/dist/theme/index.d.ts +4 -4
  83. package/dist/types-only.d.ts +1 -1
  84. package/dist/types-only.js +1 -11
  85. package/dist/types-only.js.map +7 -1
  86. package/dist/types.d.ts +1 -1
  87. package/dist/version.d.ts +1 -1
  88. package/dist/widgets/index.d.ts +1 -1
  89. package/package.json +29 -17
  90. package/schema/canvas-config.base.schema.json +351 -0
  91. package/schema/canvas-config.schema.json +3308 -444
  92. package/scripts/validate-config.mjs +54 -58
  93. package/dist/RuntimeProvider.js +0 -113
  94. package/dist/RuntimeProvider.js.map +0 -1
  95. package/dist/SmartCanvasApp.js +0 -143
  96. package/dist/SmartCanvasApp.js.map +0 -1
  97. package/dist/SmartCanvasElement.js +0 -138
  98. package/dist/SmartCanvasElement.js.map +0 -1
  99. package/dist/SmartCanvasPortal.js +0 -17
  100. package/dist/SmartCanvasPortal.js.map +0 -1
  101. package/dist/actions/ActionEngine.js +0 -272
  102. package/dist/actions/ActionEngine.js.map +0 -1
  103. package/dist/actions/executors/index.js +0 -240
  104. package/dist/actions/executors/index.js.map +0 -1
  105. package/dist/actions/executors/tour.js +0 -332
  106. package/dist/actions/executors/tour.js.map +0 -1
  107. package/dist/actions/index.js +0 -12
  108. package/dist/actions/index.js.map +0 -1
  109. package/dist/actions/types.js +0 -8
  110. package/dist/actions/types.js.map +0 -1
  111. package/dist/actions/validation.js +0 -577
  112. package/dist/actions/validation.js.map +0 -1
  113. package/dist/adaptives/adaptive-chatbot/index.js +0 -9
  114. package/dist/adaptives/adaptive-chatbot/index.js.map +0 -7
  115. package/dist/adaptives/adaptive-content/index.js +0 -22
  116. package/dist/adaptives/adaptive-content/index.js.map +0 -7
  117. package/dist/adaptives/adaptive-faq/index.js +0 -11
  118. package/dist/adaptives/adaptive-faq/index.js.map +0 -7
  119. package/dist/adaptives/adaptive-gamification/index.js +0 -2
  120. package/dist/adaptives/adaptive-gamification/index.js.map +0 -7
  121. package/dist/adaptives/adaptive-nav/index.js +0 -12
  122. package/dist/adaptives/adaptive-nav/index.js.map +0 -7
  123. package/dist/adaptives/adaptive-overlays/index.js +0 -94
  124. package/dist/adaptives/adaptive-overlays/index.js.map +0 -7
  125. package/dist/antiFlicker.js +0 -39
  126. package/dist/antiFlicker.js.map +0 -1
  127. package/dist/api.js +0 -205
  128. package/dist/api.js.map +0 -1
  129. package/dist/apps/AppContext.js +0 -91
  130. package/dist/apps/AppContext.js.map +0 -1
  131. package/dist/apps/AppLoader.js +0 -293
  132. package/dist/apps/AppLoader.js.map +0 -1
  133. package/dist/apps/AppRegistry.js +0 -317
  134. package/dist/apps/AppRegistry.js.map +0 -1
  135. package/dist/apps/examples/gamification-app.example.js +0 -329
  136. package/dist/apps/examples/gamification-app.example.js.map +0 -1
  137. package/dist/apps/index.js +0 -16
  138. package/dist/apps/index.js.map +0 -1
  139. package/dist/apps/types.js +0 -8
  140. package/dist/apps/types.js.map +0 -1
  141. package/dist/blocks/data/ComparisonBlock.js +0 -95
  142. package/dist/blocks/data/ComparisonBlock.js.map +0 -1
  143. package/dist/blocks/data/StatsBlock.js +0 -102
  144. package/dist/blocks/data/StatsBlock.js.map +0 -1
  145. package/dist/blocks/data/index.js +0 -3
  146. package/dist/blocks/data/index.js.map +0 -1
  147. package/dist/blocks/index.js +0 -93
  148. package/dist/blocks/index.js.map +0 -1
  149. package/dist/blocks/interactive/ChecklistBlock.js +0 -111
  150. package/dist/blocks/interactive/ChecklistBlock.js.map +0 -1
  151. package/dist/blocks/interactive/RatingBlock.js +0 -147
  152. package/dist/blocks/interactive/RatingBlock.js.map +0 -1
  153. package/dist/blocks/interactive/index.js +0 -3
  154. package/dist/blocks/interactive/index.js.map +0 -1
  155. package/dist/blocks/notification/NotificationBlock.js +0 -171
  156. package/dist/blocks/notification/NotificationBlock.js.map +0 -1
  157. package/dist/blocks/notification/index.js +0 -2
  158. package/dist/blocks/notification/index.js.map +0 -1
  159. package/dist/blocks/theme-tokens.js +0 -25
  160. package/dist/blocks/theme-tokens.js.map +0 -1
  161. package/dist/bootstrap.js +0 -448
  162. package/dist/bootstrap.js.map +0 -1
  163. package/dist/bundle-entry.js +0 -9
  164. package/dist/bundle-entry.js.map +0 -1
  165. package/dist/components/ShadowCanvasOverlay.js +0 -327
  166. package/dist/components/ShadowCanvasOverlay.js.map +0 -1
  167. package/dist/components/TileCard.js +0 -103
  168. package/dist/components/TileCard.js.map +0 -1
  169. package/dist/components/TileWheel.js +0 -50
  170. package/dist/components/TileWheel.js.map +0 -1
  171. package/dist/config-validator.js +0 -173
  172. package/dist/config-validator.js.map +0 -1
  173. package/dist/configFetcher.js +0 -131
  174. package/dist/configFetcher.js.map +0 -1
  175. package/dist/context/ContextManager.js +0 -269
  176. package/dist/context/ContextManager.js.map +0 -1
  177. package/dist/context/index.js +0 -7
  178. package/dist/context/index.js.map +0 -1
  179. package/dist/context/schema.js +0 -50
  180. package/dist/context/schema.js.map +0 -1
  181. package/dist/context/types.js +0 -8
  182. package/dist/context/types.js.map +0 -1
  183. package/dist/controller.js +0 -34
  184. package/dist/controller.js.map +0 -1
  185. package/dist/decisions/engine.js +0 -117
  186. package/dist/decisions/engine.js.map +0 -1
  187. package/dist/decisions/index.js +0 -10
  188. package/dist/decisions/index.js.map +0 -1
  189. package/dist/decisions/schema.js +0 -151
  190. package/dist/decisions/schema.js.map +0 -1
  191. package/dist/decisions/strategies/rules.js +0 -166
  192. package/dist/decisions/strategies/rules.js.map +0 -1
  193. package/dist/decisions/strategies/score.js +0 -29
  194. package/dist/decisions/strategies/score.js.map +0 -1
  195. package/dist/decisions/types.js +0 -2
  196. package/dist/decisions/types.js.map +0 -1
  197. package/dist/earlyPatcher.js +0 -20
  198. package/dist/earlyPatcher.js.map +0 -1
  199. package/dist/editorLoader.js +0 -254
  200. package/dist/editorLoader.js.map +0 -1
  201. package/dist/events/EventAccumulator.js +0 -101
  202. package/dist/events/EventAccumulator.js.map +0 -1
  203. package/dist/events/EventBus.js +0 -152
  204. package/dist/events/EventBus.js.map +0 -1
  205. package/dist/events/index.js +0 -11
  206. package/dist/events/index.js.map +0 -1
  207. package/dist/events/normalizers/canvas.js +0 -116
  208. package/dist/events/normalizers/canvas.js.map +0 -1
  209. package/dist/events/normalizers/posthog.js +0 -171
  210. package/dist/events/normalizers/posthog.js.map +0 -1
  211. package/dist/events/schema.js +0 -30
  212. package/dist/events/schema.js.map +0 -1
  213. package/dist/events/types.js +0 -54
  214. package/dist/events/types.js.map +0 -1
  215. package/dist/experiments/adapters/growthbook.js +0 -81
  216. package/dist/experiments/adapters/growthbook.js.map +0 -1
  217. package/dist/experiments/index.js +0 -4
  218. package/dist/experiments/index.js.map +0 -1
  219. package/dist/experiments/registry.js +0 -30
  220. package/dist/experiments/registry.js.map +0 -1
  221. package/dist/experiments/types.js +0 -2
  222. package/dist/experiments/types.js.map +0 -1
  223. package/dist/fetchers/cdnFetcher.js +0 -96
  224. package/dist/fetchers/cdnFetcher.js.map +0 -1
  225. package/dist/fetchers/experimentsFetcher.js +0 -109
  226. package/dist/fetchers/experimentsFetcher.js.map +0 -1
  227. package/dist/fetchers/index.js +0 -5
  228. package/dist/fetchers/index.js.map +0 -1
  229. package/dist/fetchers/mergeConfigs.js +0 -38
  230. package/dist/fetchers/mergeConfigs.js.map +0 -1
  231. package/dist/fetchers/registry.js +0 -58
  232. package/dist/fetchers/registry.js.map +0 -1
  233. package/dist/fetchers/types.js +0 -2
  234. package/dist/fetchers/types.js.map +0 -1
  235. package/dist/hooks/useCanvasOverlays.js +0 -128
  236. package/dist/hooks/useCanvasOverlays.js.map +0 -1
  237. package/dist/hooks/useHostPatches.js +0 -40
  238. package/dist/hooks/useHostPatches.js.map +0 -1
  239. package/dist/hooks/useShadowCanvasConfig.js +0 -63
  240. package/dist/hooks/useShadowCanvasConfig.js.map +0 -1
  241. package/dist/hostPatcher/core/patcher.js +0 -181
  242. package/dist/hostPatcher/core/patcher.js.map +0 -1
  243. package/dist/hostPatcher/core/sanitizer.js +0 -66
  244. package/dist/hostPatcher/core/sanitizer.js.map +0 -1
  245. package/dist/hostPatcher/core/types.js +0 -2
  246. package/dist/hostPatcher/core/types.js.map +0 -1
  247. package/dist/hostPatcher/index.js +0 -7
  248. package/dist/hostPatcher/index.js.map +0 -1
  249. package/dist/hostPatcher/policy/defaultPolicy.js +0 -23
  250. package/dist/hostPatcher/policy/defaultPolicy.js.map +0 -1
  251. package/dist/hostPatcher/utils/anchors.js +0 -105
  252. package/dist/hostPatcher/utils/anchors.js.map +0 -1
  253. package/dist/hostPatcher/utils/observer.js +0 -11
  254. package/dist/hostPatcher/utils/observer.js.map +0 -1
  255. package/dist/logger.js +0 -81
  256. package/dist/logger.js.map +0 -1
  257. package/dist/metrics/index.js +0 -5
  258. package/dist/metrics/index.js.map +0 -1
  259. package/dist/metrics/sessionMetrics.js +0 -178
  260. package/dist/metrics/sessionMetrics.js.map +0 -1
  261. package/dist/notifications/NotificationToastStack.js +0 -118
  262. package/dist/notifications/NotificationToastStack.js.map +0 -1
  263. package/dist/notifications/index.js +0 -6
  264. package/dist/notifications/index.js.map +0 -1
  265. package/dist/notifications/matcher.js +0 -66
  266. package/dist/notifications/matcher.js.map +0 -1
  267. package/dist/notifications/types.js +0 -13
  268. package/dist/notifications/types.js.map +0 -1
  269. package/dist/notifications/useNotifications.js +0 -104
  270. package/dist/notifications/useNotifications.js.map +0 -1
  271. package/dist/notifications/useNotifyWatcher.js +0 -62
  272. package/dist/notifications/useNotifyWatcher.js.map +0 -1
  273. package/dist/overlays/fetcher.js +0 -15
  274. package/dist/overlays/fetcher.js.map +0 -1
  275. package/dist/overlays/recipeRegistry.js +0 -32
  276. package/dist/overlays/recipeRegistry.js.map +0 -1
  277. package/dist/overlays/runtime/anchor/resolve.js +0 -87
  278. package/dist/overlays/runtime/anchor/resolve.js.map +0 -1
  279. package/dist/overlays/runtime/index.js +0 -8
  280. package/dist/overlays/runtime/index.js.map +0 -1
  281. package/dist/overlays/runtime/overlay/highlight.js +0 -160
  282. package/dist/overlays/runtime/overlay/highlight.js.map +0 -1
  283. package/dist/overlays/runtime/overlay/modal.js +0 -78
  284. package/dist/overlays/runtime/overlay/modal.js.map +0 -1
  285. package/dist/overlays/runtime/overlay/root.js +0 -297
  286. package/dist/overlays/runtime/overlay/root.js.map +0 -1
  287. package/dist/overlays/runtime/overlay/runner.js +0 -602
  288. package/dist/overlays/runtime/overlay/runner.js.map +0 -1
  289. package/dist/overlays/runtime/overlay/tooltip.js +0 -232
  290. package/dist/overlays/runtime/overlay/tooltip.js.map +0 -1
  291. package/dist/overlays/runtime/utils/dom.js +0 -12
  292. package/dist/overlays/runtime/utils/dom.js.map +0 -1
  293. package/dist/overlays/schema.js +0 -52
  294. package/dist/overlays/schema.js.map +0 -1
  295. package/dist/overlays/types.js +0 -2
  296. package/dist/overlays/types.js.map +0 -1
  297. package/dist/render/RenderContext.js +0 -69
  298. package/dist/render/RenderContext.js.map +0 -1
  299. package/dist/render/index.js +0 -3
  300. package/dist/render/index.js.map +0 -1
  301. package/dist/render/types.js +0 -2
  302. package/dist/render/types.js.map +0 -1
  303. package/dist/runtime.js +0 -237
  304. package/dist/runtime.js.map +0 -1
  305. package/dist/state/StateStore.js +0 -176
  306. package/dist/state/StateStore.js.map +0 -1
  307. package/dist/state/helpers/cooldowns.js +0 -31
  308. package/dist/state/helpers/cooldowns.js.map +0 -1
  309. package/dist/state/helpers/dismissals.js +0 -34
  310. package/dist/state/helpers/dismissals.js.map +0 -1
  311. package/dist/state/helpers/frequency.js +0 -43
  312. package/dist/state/helpers/frequency.js.map +0 -1
  313. package/dist/state/index.js +0 -7
  314. package/dist/state/index.js.map +0 -1
  315. package/dist/state/schema.js +0 -25
  316. package/dist/state/schema.js.map +0 -1
  317. package/dist/state/types.js +0 -9
  318. package/dist/state/types.js.map +0 -1
  319. package/dist/store/example.js +0 -43
  320. package/dist/store/example.js.map +0 -1
  321. package/dist/store/mini-effector.js +0 -88
  322. package/dist/store/mini-effector.js.map +0 -1
  323. package/dist/surfaces/Surfaces.js +0 -361
  324. package/dist/surfaces/Surfaces.js.map +0 -1
  325. package/dist/surfaces/index.js +0 -12
  326. package/dist/surfaces/index.js.map +0 -1
  327. package/dist/surfaces/positioning.js +0 -228
  328. package/dist/surfaces/positioning.js.map +0 -1
  329. package/dist/surfaces/types.js +0 -23
  330. package/dist/surfaces/types.js.map +0 -1
  331. package/dist/telemetry/adapters/noop.js +0 -42
  332. package/dist/telemetry/adapters/noop.js.map +0 -1
  333. package/dist/telemetry/adapters/posthog.js +0 -180
  334. package/dist/telemetry/adapters/posthog.js.map +0 -1
  335. package/dist/telemetry/index.js +0 -4
  336. package/dist/telemetry/index.js.map +0 -1
  337. package/dist/telemetry/registry.js +0 -29
  338. package/dist/telemetry/registry.js.map +0 -1
  339. package/dist/telemetry/types.js +0 -2
  340. package/dist/telemetry/types.js.map +0 -1
  341. package/dist/theme/ThemeProvider.js +0 -109
  342. package/dist/theme/ThemeProvider.js.map +0 -1
  343. package/dist/theme/defaultTheme.js +0 -190
  344. package/dist/theme/defaultTheme.js.map +0 -1
  345. package/dist/theme/extractHostTheme.js +0 -259
  346. package/dist/theme/extractHostTheme.js.map +0 -1
  347. package/dist/theme/index.js +0 -7
  348. package/dist/theme/index.js.map +0 -1
  349. package/dist/theme/types.js +0 -6
  350. package/dist/theme/types.js.map +0 -1
  351. package/dist/token.js +0 -44
  352. package/dist/token.js.map +0 -1
  353. package/dist/types.js +0 -17
  354. package/dist/types.js.map +0 -1
  355. package/dist/version.js +0 -14
  356. package/dist/version.js.map +0 -1
  357. package/dist/widgets/WidgetRegistry.js +0 -190
  358. package/dist/widgets/WidgetRegistry.js.map +0 -1
  359. package/dist/widgets/index.js +0 -7
  360. package/dist/widgets/index.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,77 +1,2351 @@
1
- // ============================================================================
2
- // Early SynOS exposure for adaptive self-registration + shared React
3
- // ============================================================================
4
- // Adaptive bundles loaded via <script> (IIFE) check window.SynOS.appRegistry
5
- // to self-register. In the Chrome extension's dev mode, adaptives load BEFORE
6
- // Syntro.init() runs. Expose the singleton appRegistry here (module scope) so
7
- // it's available as soon as smart-canvas.min.js loads. Syntro.init() later
8
- // enriches the SynOS object with runtime/version but reuses the same registry.
9
- //
10
- // React and ReactDOM are also exposed here so that adaptive bundles built with
11
- // syntroReactPlugin can resolve their lazy shims via SynOS.React / SynOS.ReactDOM.
12
- // This makes the runtime SDK the single React owner — adaptives and the editor
13
- // SDK consume React from SynOS, never from their own bundles.
14
- import { appRegistry as _earlyAppRegistry } from './apps';
15
- import React from 'react';
16
- import * as ReactDOMClient from 'react-dom/client';
17
- import { createPortal, flushSync } from 'react-dom';
18
- export * from './version';
19
- export * from './types';
20
- export * from './config-validator';
21
- export * from './telemetry';
22
- export * from './experiments';
23
- export * from './hooks/useShadowCanvasConfig';
24
- export * from './components/TileCard';
25
- export * from './components/ShadowCanvasOverlay';
26
- export * from './components/TileWheel';
27
- export * from './controller';
28
- export * from './SmartCanvasApp';
29
- export * from './SmartCanvasElement';
30
- export * from './SmartCanvasPortal';
31
- export * from './api';
32
- export * from './configFetcher';
33
- export * from './overlays/types';
34
- export * from './overlays/schema';
35
- export * from './overlays/fetcher';
36
- // Metrics for session-based targeting
37
- export * from './metrics';
38
- // ============================================================================
39
- // v2 Runtime Modules
40
- // ============================================================================
41
- // Context - Page/session/viewport state management
42
- export * from './context';
43
- // Events - Normalized event stream
44
- export * from './events';
45
- // Notifications - Toast notification system
46
- export * from './notifications';
47
- // State - Persistent state storage with helpers
48
- export * from './state';
49
- // Decisions - Strategy-based conditional rendering
50
- export * from './decisions';
51
- // Actions - Unified execution layer for interventions
52
- export * from './actions';
53
- // Surfaces - Managed surface system for rendering UI
54
- export * from './surfaces';
55
- // Widgets - Mountable component registry
56
- export * from './widgets';
57
- // Apps - SynOS app system
58
- export * from './apps';
59
- // Unified runtime
60
- export { createSmartCanvasRuntime, RUNTIME_VERSION } from './runtime';
61
- // React context for runtime access
62
- export { RuntimeProvider, useRuntime, useRuntimeContext, usePageContext, useSessionContext, useViewportContext, useRuntimeEvents, useRuntimeState, useDecision, } from './RuntimeProvider';
63
- // ============================================================================
64
- // Single-token initialization
65
- // ============================================================================
66
- export { Syntro } from './bootstrap';
67
- export { encodeToken, decodeToken } from './token';
68
- if (typeof window !== 'undefined') {
69
- const existing = window.SynOS;
70
- window.SynOS = {
71
- ...existing,
72
- appRegistry: (existing === null || existing === void 0 ? void 0 : existing.appRegistry) || _earlyAppRegistry,
73
- React,
74
- ReactDOM: { ...ReactDOMClient, createPortal, flushSync },
1
+ import {
2
+ ANIMATION_KEYFRAMES,
3
+ AppRegistry,
4
+ CanvasEvents,
5
+ ContextManager,
6
+ DEFAULT_COOLDOWN,
7
+ DEFAULT_TTL,
8
+ EVENT_SCHEMA_VERSION,
9
+ EventBus,
10
+ ExecutorRegistry,
11
+ MAX_VISIBLE_TOASTS,
12
+ NotificationToastStack,
13
+ RUNTIME_VERSION,
14
+ RuntimeProvider,
15
+ SDK_SCHEMA_VERSION,
16
+ SDK_VERSION,
17
+ STATIC_SLOT_STYLES,
18
+ SessionMetricTracker,
19
+ ShadowCanvasOverlay,
20
+ ShadowRootProvider,
21
+ SmartCanvasApp,
22
+ SmartCanvasController,
23
+ SmartCanvasElement,
24
+ StandardEvents,
25
+ StateStore,
26
+ Syntro,
27
+ TileCard,
28
+ WidgetRegistry,
29
+ appRegistry,
30
+ applyStaticSlotStyles,
31
+ base,
32
+ border,
33
+ brand,
34
+ cleanupAppContext,
35
+ createActionEngine,
36
+ createAppContext,
37
+ createAppLoader,
38
+ createCanvasConfigFetcher,
39
+ createContextManager,
40
+ createDecisionEngine,
41
+ createEventAccumulator,
42
+ createEventBus,
43
+ createGrowthBookClient,
44
+ createNoopClient,
45
+ createPostHogClient,
46
+ createPostHogNormalizer,
47
+ createSessionMetricTracker,
48
+ createSmartCanvas,
49
+ createSmartCanvasController,
50
+ createSmartCanvasRuntime,
51
+ createStateStore,
52
+ createSurfaceContainer,
53
+ createSurfaces,
54
+ decodeToken,
55
+ encodeToken,
56
+ evaluate,
57
+ evaluateCondition,
58
+ evaluateRule,
59
+ evaluateRuleStrategy,
60
+ evaluateScoreStrategy,
61
+ evaluateSync,
62
+ executorRegistry,
63
+ getAntiFlickerSnippet,
64
+ getAppIdFromActionKind,
65
+ getAppIdFromWidgetId,
66
+ getExecutor,
67
+ getSlotAnchorId,
68
+ getSlotType,
69
+ getSlotZIndex,
70
+ hasExecutor,
71
+ interpolateTemplate,
72
+ isCoreActionKind,
73
+ matchEvent,
74
+ normalizePostHogEvent,
75
+ playEnterAnimation,
76
+ playExitAnimation,
77
+ purple,
78
+ red,
79
+ registerConfigPredicates,
80
+ registerSmartCanvasElement,
81
+ resolveConfigUri,
82
+ runtime,
83
+ runtime2,
84
+ setupAdjacentPositioning,
85
+ setupInlinePositioning,
86
+ shouldNormalizeEvent,
87
+ slateGrey,
88
+ useDecision,
89
+ useNotifications,
90
+ useNotifyWatcher,
91
+ usePageContext,
92
+ useRuntime,
93
+ useRuntimeContext,
94
+ useRuntimeEvents,
95
+ useRuntimeState,
96
+ useSessionContext,
97
+ useShadowCanvasConfig,
98
+ useShadowRoot,
99
+ useViewportContext,
100
+ validateAction,
101
+ validateActions,
102
+ widgetRegistry
103
+ } from "./chunk-VLWWR22N.js";
104
+ import {
105
+ AddClassZ,
106
+ BadgePositionZ,
107
+ BadgeZ,
108
+ CtaButtonZ,
109
+ HighlightStyleZ,
110
+ HighlightZ,
111
+ InsertHtmlZ,
112
+ InsertPositionZ,
113
+ ModalContentZ,
114
+ ModalZ,
115
+ MountWidgetZ,
116
+ NavigateZ,
117
+ ParallelZ,
118
+ PlacementZ,
119
+ PulseZ,
120
+ RemoveClassZ,
121
+ ScrollBehaviorZ,
122
+ ScrollLogicalPositionZ,
123
+ ScrollToZ,
124
+ SequenceZ,
125
+ SetAttrZ,
126
+ SetStyleZ,
127
+ SetTextZ,
128
+ TooltipContentZ,
129
+ TooltipTriggerZ,
130
+ TooltipZ,
131
+ TourStepForSchemaZ,
132
+ TourZ,
133
+ WaitZ,
134
+ WidgetConfigZ,
135
+ coreActionStepSchemas
136
+ } from "./chunk-AYTRRBR5.js";
137
+
138
+ // src/index.ts
139
+ import React4 from "react";
140
+ import { createPortal as createPortal2, flushSync } from "react-dom";
141
+ import * as ReactDOMClient from "react-dom/client";
142
+
143
+ // ../adaptives/adaptive-chatbot/dist/ChatAssistant.js
144
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
145
+ import React, { useEffect, useRef as useRef2 } from "react";
146
+ import { createRoot } from "react-dom/client";
147
+
148
+ // ../adaptives/adaptive-chatbot/dist/useChat.js
149
+ import { useCallback, useRef, useState } from "react";
150
+
151
+ // ../adaptives/adaptive-chatbot/dist/actionParser.js
152
+ var JSON_FENCE_RE = /```json\s*\n([\s\S]*?)```/g;
153
+ function parseActions(input) {
154
+ const actions = [];
155
+ let displayText = input;
156
+ const matches = [];
157
+ let match;
158
+ JSON_FENCE_RE.lastIndex = 0;
159
+ while ((match = JSON_FENCE_RE.exec(input)) !== null) {
160
+ matches.push({
161
+ fullMatch: match[0],
162
+ json: match[1],
163
+ index: match.index
164
+ });
165
+ }
166
+ for (let i = matches.length - 1; i >= 0; i--) {
167
+ const { fullMatch, json } = matches[i];
168
+ let parsed;
169
+ try {
170
+ parsed = JSON.parse(json);
171
+ } catch {
172
+ continue;
173
+ }
174
+ if (typeof parsed === "object" && parsed !== null && "kind" in parsed && typeof parsed.kind === "string") {
175
+ actions.unshift(parsed);
176
+ displayText = displayText.replace(fullMatch, "");
177
+ }
178
+ }
179
+ displayText = displayText.replace(/\n{3,}/g, "\n\n").trim();
180
+ return { displayText, actions };
181
+ }
182
+
183
+ // ../adaptives/adaptive-chatbot/dist/apiClient.js
184
+ var AuthError = class extends Error {
185
+ constructor(message) {
186
+ super(message);
187
+ this.name = "AuthError";
188
+ }
189
+ };
190
+ function getAuthHeaders() {
191
+ const cookieMatch = document.cookie.match(/stytch_session_jwt=([^;]*)/);
192
+ if (!cookieMatch || !cookieMatch[1]) {
193
+ throw new AuthError("No authentication token found");
194
+ }
195
+ const workspaceId = localStorage.getItem("syntrologie_workspace_id");
196
+ if (!workspaceId) {
197
+ throw new AuthError("No workspace ID found");
198
+ }
199
+ return {
200
+ Authorization: `Bearer ${cookieMatch[1]}`,
201
+ "X-Workspace-Id": workspaceId
202
+ };
203
+ }
204
+ async function sendMessage(url, request) {
205
+ const authHeaders = getAuthHeaders();
206
+ const response = await fetch(url, {
207
+ method: "POST",
208
+ headers: {
209
+ "Content-Type": "application/json",
210
+ ...authHeaders
211
+ },
212
+ body: JSON.stringify(request)
213
+ });
214
+ if (!response.ok) {
215
+ if (response.status === 401) {
216
+ throw new AuthError("Session expired or unauthorized");
217
+ }
218
+ throw new Error(`Chat request failed: ${response.status} ${response.statusText}`);
219
+ }
220
+ return response.json();
221
+ }
222
+
223
+ // ../adaptives/adaptive-chatbot/dist/useChat.js
224
+ var nextId = 0;
225
+ function generateId() {
226
+ return `msg-${Date.now()}-${++nextId}`;
227
+ }
228
+ function useChat(options) {
229
+ const { backendUrl, tileId, runtime: runtime7, greeting, maxHistory = 20, mlflowRunId, config } = options;
230
+ const [messages, setMessages] = useState(() => {
231
+ if (greeting) {
232
+ return [
233
+ {
234
+ id: generateId(),
235
+ role: "assistant",
236
+ text: greeting,
237
+ timestamp: Date.now()
238
+ }
239
+ ];
240
+ }
241
+ return [];
242
+ });
243
+ const [isLoading, setIsLoading] = useState(false);
244
+ const [error, setError] = useState(null);
245
+ const batchHandleRef = useRef(null);
246
+ const send = useCallback(async (text) => {
247
+ var _a;
248
+ const trimmed = text.trim();
249
+ if (!trimmed)
250
+ return;
251
+ setError(null);
252
+ const userMessage = {
253
+ id: generateId(),
254
+ role: "user",
255
+ text: trimmed,
256
+ timestamp: Date.now()
257
+ };
258
+ setMessages((prev) => [...prev, userMessage]);
259
+ setIsLoading(true);
260
+ try {
261
+ const currentMessages = [...messages, userMessage];
262
+ const historySlice = currentMessages.slice(-maxHistory).map((m) => ({
263
+ role: m.role,
264
+ content: m.text
265
+ }));
266
+ const response = await sendMessage(backendUrl, {
267
+ message: trimmed,
268
+ history: historySlice,
269
+ mlflow_run_id: mlflowRunId,
270
+ current_config: config
271
+ });
272
+ const { displayText, actions } = parseActions(response.response);
273
+ const assistantMessage = {
274
+ id: generateId(),
275
+ role: "assistant",
276
+ text: displayText,
277
+ timestamp: Date.now()
278
+ };
279
+ setMessages((prev) => [...prev, assistantMessage]);
280
+ if (actions.length > 0) {
281
+ if ((_a = batchHandleRef.current) == null ? void 0 : _a.isApplied()) {
282
+ await batchHandleRef.current.revertAll();
283
+ }
284
+ batchHandleRef.current = await runtime7.actions.applyBatch(actions);
285
+ runtime7.events.publish("chatbot.actions_applied", {
286
+ count: actions.length,
287
+ kinds: actions.map((a) => a.kind),
288
+ tileId
289
+ });
290
+ }
291
+ } catch (err) {
292
+ const message = err instanceof Error ? err.message : "An unexpected error occurred";
293
+ setError(message);
294
+ } finally {
295
+ setIsLoading(false);
296
+ }
297
+ }, [backendUrl, messages, maxHistory, mlflowRunId, config, runtime7, tileId]);
298
+ const clearMessages = useCallback(() => {
299
+ var _a;
300
+ setMessages([]);
301
+ setError(null);
302
+ if ((_a = batchHandleRef.current) == null ? void 0 : _a.isApplied()) {
303
+ batchHandleRef.current.revertAll();
304
+ batchHandleRef.current = null;
305
+ }
306
+ sessionStorage.removeItem(`syntro:chatbot:history:${tileId}`);
307
+ }, [tileId]);
308
+ return {
309
+ messages,
310
+ isLoading,
311
+ error,
312
+ sendMessage: send,
313
+ clearMessages
314
+ };
315
+ }
316
+
317
+ // ../adaptives/adaptive-chatbot/dist/ChatAssistant.js
318
+ var styles = {
319
+ container: {
320
+ display: "flex",
321
+ flexDirection: "column",
322
+ height: "100%",
323
+ fontFamily: "system-ui, -apple-system, sans-serif",
324
+ fontSize: "14px"
325
+ },
326
+ messageList: {
327
+ flex: 1,
328
+ overflowY: "auto",
329
+ padding: "12px",
330
+ display: "flex",
331
+ flexDirection: "column",
332
+ gap: "8px"
333
+ },
334
+ messageBubble: {
335
+ maxWidth: "85%",
336
+ padding: "8px 12px",
337
+ borderRadius: "12px",
338
+ lineHeight: 1.5,
339
+ wordBreak: "break-word"
340
+ },
341
+ userMessage: {
342
+ alignSelf: "flex-end",
343
+ backgroundColor: purple[4],
344
+ color: base.white,
345
+ borderBottomRightRadius: "4px"
346
+ },
347
+ assistantMessage: {
348
+ alignSelf: "flex-start",
349
+ backgroundColor: "rgba(255, 255, 255, 0.08)",
350
+ color: slateGrey[10],
351
+ borderBottomLeftRadius: "4px"
352
+ },
353
+ loadingDots: {
354
+ alignSelf: "flex-start",
355
+ padding: "8px 16px",
356
+ backgroundColor: "rgba(255, 255, 255, 0.05)",
357
+ borderRadius: "12px",
358
+ color: slateGrey[8],
359
+ fontSize: "13px"
360
+ },
361
+ errorBanner: {
362
+ padding: "8px 12px",
363
+ backgroundColor: "rgba(239, 68, 68, 0.1)",
364
+ color: red[4],
365
+ fontSize: "13px",
366
+ borderRadius: "8px",
367
+ margin: "0 12px"
368
+ },
369
+ inputForm: {
370
+ display: "flex",
371
+ gap: "8px",
372
+ padding: "12px",
373
+ borderTop: "1px solid rgba(255, 255, 255, 0.06)"
374
+ },
375
+ input: {
376
+ flex: 1,
377
+ padding: "8px 12px",
378
+ borderRadius: "8px",
379
+ border: "1px solid rgba(255, 255, 255, 0.1)",
380
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
381
+ color: slateGrey[12],
382
+ fontSize: "14px",
383
+ outline: "none",
384
+ fontFamily: "inherit"
385
+ },
386
+ sendButton: {
387
+ padding: "8px 16px",
388
+ borderRadius: "8px",
389
+ border: "none",
390
+ backgroundColor: purple[4],
391
+ color: base.white,
392
+ fontWeight: 600,
393
+ fontSize: "13px",
394
+ cursor: "pointer",
395
+ whiteSpace: "nowrap"
396
+ },
397
+ sendButtonDisabled: {
398
+ opacity: 0.5,
399
+ cursor: "not-allowed"
400
+ }
401
+ };
402
+ function MessageBubble({ message }) {
403
+ const isUser = message.role === "user";
404
+ const bubbleStyle = {
405
+ ...styles.messageBubble,
406
+ ...isUser ? styles.userMessage : styles.assistantMessage
407
+ };
408
+ return _jsx("div", { style: bubbleStyle, children: message.text });
409
+ }
410
+ function ChatAssistant({ config, runtime: runtime7, tileId }) {
411
+ const { messages, isLoading, error, sendMessage: sendMessage2, clearMessages: _clearMessages } = useChat({
412
+ backendUrl: config.backendUrl,
413
+ tileId,
414
+ runtime: runtime7,
415
+ greeting: config.greeting,
416
+ maxHistory: config.maxHistory,
417
+ mlflowRunId: config.mlflowRunId
418
+ });
419
+ const messageListRef = useRef2(null);
420
+ const inputRef = useRef2(null);
421
+ useEffect(() => {
422
+ if (messageListRef.current) {
423
+ messageListRef.current.scrollTop = messageListRef.current.scrollHeight;
424
+ }
425
+ }, []);
426
+ const handleSubmit = (e) => {
427
+ e.preventDefault();
428
+ const input = inputRef.current;
429
+ if (!input || !input.value.trim() || isLoading)
430
+ return;
431
+ const text = input.value;
432
+ input.value = "";
433
+ sendMessage2(text);
434
+ };
435
+ return _jsxs("div", { style: styles.container, "data-testid": "chat-assistant", children: [_jsxs("div", { ref: messageListRef, style: styles.messageList, children: [messages.map((msg) => _jsx(MessageBubble, { message: msg }, msg.id)), isLoading && _jsx("div", { style: styles.loadingDots, children: "Thinking..." })] }), error && _jsx("div", { style: styles.errorBanner, children: error }), _jsxs("form", { onSubmit: handleSubmit, style: styles.inputForm, children: [_jsx("input", { ref: inputRef, style: styles.input, placeholder: "Ask anything...", disabled: isLoading, "data-testid": "chat-input" }), _jsx("button", { type: "submit", disabled: isLoading, style: {
436
+ ...styles.sendButton,
437
+ ...isLoading ? styles.sendButtonDisabled : {}
438
+ }, "data-testid": "chat-send", children: "Send" })] })] });
439
+ }
440
+ var ChatAssistantMountableWidget = {
441
+ mount(container, mountConfig) {
442
+ const { config, runtime: runtime7, tileId = "chatbot-widget" } = mountConfig || {};
443
+ if (config && runtime7 && typeof createRoot === "function") {
444
+ const root = createRoot(container);
445
+ root.render(React.createElement(ChatAssistant, {
446
+ config,
447
+ runtime: runtime7,
448
+ tileId
449
+ }));
450
+ return () => {
451
+ root.unmount();
452
+ };
453
+ }
454
+ if (!config || !runtime7) {
455
+ container.innerHTML = `<div style="padding: 16px; color: ${slateGrey[8]};">Chat widget requires config and runtime.</div>`;
456
+ return () => {
457
+ container.innerHTML = "";
458
+ };
459
+ }
460
+ container.innerHTML = `
461
+ <div style="padding: 16px; font-family: system-ui; color: ${slateGrey[10]};">
462
+ <p style="margin: 0 0 8px; color: ${slateGrey[8]};">${config.greeting || "Hi! How can I help?"}</p>
463
+ <p style="margin: 0; font-size: 12px; color: ${slateGrey[7]};">Chat widget mounted. Awaiting React renderer.</p>
464
+ </div>
465
+ `;
466
+ return () => {
467
+ container.innerHTML = "";
468
+ };
469
+ }
470
+ };
471
+
472
+ // ../adaptives/adaptive-chatbot/dist/runtime.js
473
+ var runtime3 = {
474
+ id: "adaptive-chatbot",
475
+ version: "1.0.0",
476
+ name: "Chat Assistant",
477
+ description: "AI chat assistant with action execution capabilities",
478
+ /** No action executors — chatbot uses existing action kinds via applyBatch */
479
+ executors: [],
480
+ /** Widget definitions for the runtime's WidgetRegistry */
481
+ widgets: [
482
+ {
483
+ id: "adaptive-chatbot:assistant",
484
+ component: ChatAssistantMountableWidget,
485
+ metadata: {
486
+ name: "Chat Assistant",
487
+ description: "AI-powered chat assistant that can execute DOM actions",
488
+ icon: "\u{1F4AC}"
489
+ }
490
+ }
491
+ ]
492
+ };
493
+
494
+ // ../adaptives/adaptive-faq/dist/executors.js
495
+ function resolveItem(store, itemId, itemQuestion) {
496
+ if (itemId) {
497
+ const found = store.getState().items.find((i) => i.config.id === itemId);
498
+ if (found)
499
+ return found;
500
+ }
501
+ if (itemQuestion) {
502
+ const found = store.findByQuestion(itemQuestion);
503
+ if (found)
504
+ return found;
505
+ }
506
+ throw new Error("FAQ item not found");
507
+ }
508
+ async function executeScrollToFaq(action, context, store) {
509
+ var _a;
510
+ const item = resolveItem(store, action.itemId, action.itemQuestion);
511
+ const { id } = item.config;
512
+ if (action.expand !== false) {
513
+ store.expand(id);
514
+ }
515
+ const el = document.querySelector(`[data-faq-item-id="${id}"]`);
516
+ if (el) {
517
+ el.scrollIntoView({
518
+ behavior: (_a = action.behavior) != null ? _a : "smooth"
519
+ });
520
+ }
521
+ context.publishEvent("faq:scroll_to", { itemId: id });
522
+ return {
523
+ cleanup: () => {
524
+ }
525
+ };
526
+ }
527
+ async function executeToggleFaqItem(action, context, store) {
528
+ var _a;
529
+ const item = resolveItem(store, action.itemId, action.itemQuestion);
530
+ const { id } = item.config;
531
+ const desiredState = (_a = action.state) != null ? _a : "toggle";
532
+ let newState;
533
+ switch (desiredState) {
534
+ case "open":
535
+ store.expand(id);
536
+ newState = "open";
537
+ break;
538
+ case "closed":
539
+ store.collapse(id);
540
+ newState = "closed";
541
+ break;
542
+ default: {
543
+ const wasExpanded = store.getState().expandedItems.has(id);
544
+ store.toggle(id);
545
+ newState = wasExpanded ? "closed" : "open";
546
+ break;
547
+ }
548
+ }
549
+ context.publishEvent("faq:toggle", { itemId: id, newState });
550
+ return {
551
+ cleanup: () => {
552
+ }
553
+ };
554
+ }
555
+ async function executeUpdateFaq(action, context, store) {
556
+ var _a, _b, _c;
557
+ switch (action.operation) {
558
+ case "add": {
559
+ const items = (_a = action.items) != null ? _a : [];
560
+ const position = action.position === "prepend" ? "prepend" : "append";
561
+ store.addItems(items, position);
562
+ break;
563
+ }
564
+ case "remove": {
565
+ if (!action.itemId) {
566
+ throw new Error("FAQ item not found");
567
+ }
568
+ const exists = store.getState().items.some((i) => i.config.id === action.itemId);
569
+ if (!exists) {
570
+ throw new Error("FAQ item not found");
571
+ }
572
+ store.removeItem(action.itemId);
573
+ break;
574
+ }
575
+ case "reorder": {
576
+ const order = (_b = action.order) != null ? _b : [];
577
+ store.reorderItems(order);
578
+ break;
579
+ }
580
+ case "replace": {
581
+ const items = (_c = action.items) != null ? _c : [];
582
+ store.replaceItems(items);
583
+ break;
584
+ }
585
+ }
586
+ context.publishEvent("faq:update", { operation: action.operation });
587
+ return {
588
+ cleanup: () => {
589
+ }
590
+ };
591
+ }
592
+ var executorDefinitions = [
593
+ { kind: "faq:scroll_to", executor: executeScrollToFaq },
594
+ { kind: "faq:toggle_item", executor: executeToggleFaqItem },
595
+ { kind: "faq:update", executor: executeUpdateFaq }
596
+ ];
597
+
598
+ // ../adaptives/adaptive-faq/dist/FAQWidget.js
599
+ import { jsx as _jsx2, jsxs as _jsxs2 } from "react/jsx-runtime";
600
+ import React2, { useCallback as useCallback2, useEffect as useEffect2, useMemo, useReducer, useState as useState2 } from "react";
601
+ import { createRoot as createRoot2 } from "react-dom/client";
602
+ function getAnswerText(answer) {
603
+ if (typeof answer === "string")
604
+ return answer;
605
+ if (answer.type === "rich")
606
+ return answer.html;
607
+ return answer.content;
608
+ }
609
+ function renderAnswer(answer) {
610
+ if (typeof answer === "string") {
611
+ return _jsx2("p", { style: { margin: 0 }, children: answer });
612
+ }
613
+ if (answer.type === "rich") {
614
+ return _jsx2("div", { style: { margin: 0 }, dangerouslySetInnerHTML: { __html: answer.html } });
615
+ }
616
+ return _jsx2("p", { style: { margin: 0 }, children: answer.content });
617
+ }
618
+ function resolveFeedbackConfig(feedback) {
619
+ if (!feedback)
620
+ return null;
621
+ if (feedback === true) {
622
+ return { style: "thumbs" };
623
+ }
624
+ return feedback;
625
+ }
626
+ function getFeedbackPrompt(feedbackConfig) {
627
+ return feedbackConfig.prompt || "Was this helpful?";
628
+ }
629
+ var baseStyles = {
630
+ container: {
631
+ fontFamily: "system-ui, -apple-system, sans-serif",
632
+ maxWidth: "800px",
633
+ margin: "0 auto"
634
+ },
635
+ searchWrapper: {
636
+ marginBottom: "16px"
637
+ },
638
+ searchInput: {
639
+ width: "100%",
640
+ padding: "12px 16px",
641
+ borderRadius: "8px",
642
+ fontSize: "14px",
643
+ outline: "none",
644
+ transition: "border-color 0.15s ease"
645
+ },
646
+ accordion: {
647
+ display: "flex",
648
+ flexDirection: "column",
649
+ gap: "8px"
650
+ },
651
+ item: {
652
+ borderRadius: "8px",
653
+ overflow: "hidden",
654
+ transition: "box-shadow 0.15s ease"
655
+ },
656
+ question: {
657
+ width: "100%",
658
+ padding: "16px 20px",
659
+ display: "flex",
660
+ alignItems: "center",
661
+ justifyContent: "space-between",
662
+ border: "none",
663
+ cursor: "pointer",
664
+ fontSize: "15px",
665
+ fontWeight: 500,
666
+ textAlign: "left",
667
+ transition: "background-color 0.15s ease"
668
+ },
669
+ chevron: {
670
+ fontSize: "18px",
671
+ transition: "transform 0.2s ease"
672
+ },
673
+ answer: {
674
+ padding: "0 20px 16px 20px",
675
+ fontSize: "14px",
676
+ lineHeight: 1.6,
677
+ overflow: "hidden",
678
+ transition: "max-height 0.2s ease, padding 0.2s ease"
679
+ },
680
+ category: {
681
+ display: "inline-block",
682
+ fontSize: "11px",
683
+ fontWeight: 600,
684
+ textTransform: "uppercase",
685
+ letterSpacing: "0.05em",
686
+ padding: "4px 8px",
687
+ borderRadius: "4px",
688
+ marginBottom: "8px"
689
+ },
690
+ categoryHeader: {
691
+ fontSize: "13px",
692
+ fontWeight: 700,
693
+ textTransform: "uppercase",
694
+ letterSpacing: "0.05em",
695
+ padding: "12px 4px 6px 4px",
696
+ marginTop: "8px"
697
+ },
698
+ feedback: {
699
+ display: "flex",
700
+ alignItems: "center",
701
+ gap: "8px",
702
+ marginTop: "12px",
703
+ paddingTop: "10px",
704
+ borderTop: "1px solid rgba(0, 0, 0, 0.08)",
705
+ fontSize: "13px"
706
+ },
707
+ feedbackButton: {
708
+ background: "none",
709
+ border: "1px solid transparent",
710
+ cursor: "pointer",
711
+ fontSize: "16px",
712
+ padding: "4px 8px",
713
+ borderRadius: "4px",
714
+ transition: "background-color 0.15s ease, border-color 0.15s ease"
715
+ },
716
+ feedbackButtonSelected: {
717
+ borderColor: "rgba(0, 0, 0, 0.2)",
718
+ backgroundColor: "rgba(0, 0, 0, 0.04)"
719
+ },
720
+ emptyState: {
721
+ textAlign: "center",
722
+ padding: "48px 24px",
723
+ fontSize: "14px"
724
+ },
725
+ noResults: {
726
+ textAlign: "center",
727
+ padding: "32px 16px",
728
+ fontSize: "14px"
729
+ }
730
+ };
731
+ var themeStyles = {
732
+ light: {
733
+ container: {
734
+ backgroundColor: base.white,
735
+ color: slateGrey[1]
736
+ },
737
+ searchInput: {
738
+ backgroundColor: slateGrey[12],
739
+ border: `1px solid ${slateGrey[11]}`,
740
+ color: slateGrey[1]
741
+ },
742
+ item: {
743
+ backgroundColor: slateGrey[12],
744
+ border: `1px solid ${slateGrey[11]}`
745
+ },
746
+ itemExpanded: {
747
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.08)"
748
+ },
749
+ question: {
750
+ backgroundColor: "transparent",
751
+ color: slateGrey[1]
752
+ },
753
+ questionHover: {
754
+ backgroundColor: slateGrey[12]
755
+ },
756
+ answer: {
757
+ color: slateGrey[6]
758
+ },
759
+ category: {
760
+ backgroundColor: purple[8],
761
+ color: purple[2]
762
+ },
763
+ categoryHeader: {
764
+ color: slateGrey[7]
765
+ },
766
+ emptyState: {
767
+ color: slateGrey[8]
768
+ },
769
+ feedbackPrompt: {
770
+ color: slateGrey[7]
771
+ }
772
+ },
773
+ dark: {
774
+ container: {
775
+ backgroundColor: slateGrey[1],
776
+ color: slateGrey[12]
777
+ },
778
+ searchInput: {
779
+ backgroundColor: slateGrey[3],
780
+ border: `1px solid ${slateGrey[5]}`,
781
+ color: slateGrey[12]
782
+ },
783
+ item: {
784
+ backgroundColor: slateGrey[3],
785
+ border: `1px solid ${slateGrey[5]}`
786
+ },
787
+ itemExpanded: {
788
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.3)"
789
+ },
790
+ question: {
791
+ backgroundColor: "transparent",
792
+ color: slateGrey[12]
793
+ },
794
+ questionHover: {
795
+ backgroundColor: slateGrey[5]
796
+ },
797
+ answer: {
798
+ color: slateGrey[8]
799
+ },
800
+ category: {
801
+ backgroundColor: purple[0],
802
+ color: purple[6]
803
+ },
804
+ categoryHeader: {
805
+ color: slateGrey[8]
806
+ },
807
+ emptyState: {
808
+ color: slateGrey[7]
809
+ },
810
+ feedbackPrompt: {
811
+ color: slateGrey[8]
812
+ }
813
+ }
814
+ };
815
+ function FAQItem({ item, isExpanded, onToggle, theme, feedbackConfig, feedbackValue, onFeedback }) {
816
+ const [isHovered, setIsHovered] = useState2(false);
817
+ const colors = themeStyles[theme];
818
+ const { question, answer } = item.config;
819
+ const itemStyle = {
820
+ ...baseStyles.item,
821
+ ...colors.item,
822
+ ...isExpanded ? colors.itemExpanded : {}
823
+ };
824
+ const questionStyle = {
825
+ ...baseStyles.question,
826
+ ...colors.question,
827
+ ...isHovered ? colors.questionHover : {}
828
+ };
829
+ const chevronStyle = {
830
+ ...baseStyles.chevron,
831
+ transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)"
832
+ };
833
+ const answerStyle = {
834
+ ...baseStyles.answer,
835
+ ...colors.answer,
836
+ maxHeight: isExpanded ? "500px" : "0",
837
+ paddingBottom: isExpanded ? "16px" : "0"
838
+ };
839
+ const feedbackStyle = {
840
+ ...baseStyles.feedback,
841
+ ...colors.feedbackPrompt
842
+ };
843
+ return _jsxs2("div", { style: itemStyle, "data-faq-item-id": item.config.id, children: [_jsxs2("button", { type: "button", style: questionStyle, onClick: onToggle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "aria-expanded": isExpanded, children: [_jsx2("span", { children: question }), _jsx2("span", { style: chevronStyle, children: "\u25BC" })] }), _jsxs2("div", { style: answerStyle, "aria-hidden": !isExpanded, children: [renderAnswer(answer), isExpanded && feedbackConfig && _jsxs2("div", { style: feedbackStyle, children: [_jsx2("span", { children: getFeedbackPrompt(feedbackConfig) }), _jsx2("button", { type: "button", style: {
844
+ ...baseStyles.feedbackButton,
845
+ ...feedbackValue === "up" ? baseStyles.feedbackButtonSelected : {}
846
+ }, "aria-label": "Thumbs up", onClick: () => onFeedback(item.config.id, question, "up"), children: "\u{1F44D}" }), _jsx2("button", { type: "button", style: {
847
+ ...baseStyles.feedbackButton,
848
+ ...feedbackValue === "down" ? baseStyles.feedbackButtonSelected : {}
849
+ }, "aria-label": "Thumbs down", onClick: () => onFeedback(item.config.id, question, "down"), children: "\u{1F44E}" })] })] })] });
850
+ }
851
+ function FAQWidget({ config, runtime: runtime7, instanceId }) {
852
+ const [renderTick, forceUpdate] = useReducer((x) => x + 1, 0);
853
+ const [expandedIds, setExpandedIds] = useState2(/* @__PURE__ */ new Set());
854
+ const [searchQuery, setSearchQuery] = useState2("");
855
+ const [feedbackState, setFeedbackState] = useState2(/* @__PURE__ */ new Map());
856
+ const feedbackConfig = useMemo(() => resolveFeedbackConfig(config.feedback), [config.feedback]);
857
+ useEffect2(() => {
858
+ const unsubscribe = runtime7.context.subscribe(() => {
859
+ forceUpdate();
860
+ });
861
+ return unsubscribe;
862
+ }, [runtime7.context]);
863
+ useEffect2(() => {
864
+ var _a;
865
+ if (!((_a = runtime7.accumulator) == null ? void 0 : _a.subscribe))
866
+ return;
867
+ return runtime7.accumulator.subscribe(() => {
868
+ forceUpdate();
869
+ });
870
+ }, [runtime7.accumulator]);
871
+ useEffect2(() => {
872
+ var _a, _b;
873
+ if (!config.scope || !((_a = runtime7.accumulator) == null ? void 0 : _a.register))
874
+ return;
875
+ const { events: eventNames, urlContains, props: propFilters } = config.scope;
876
+ const keys = /* @__PURE__ */ new Set();
877
+ for (const action of config.actions) {
878
+ if (((_b = action.showWhen) == null ? void 0 : _b.type) === "rules") {
879
+ for (const rule of action.showWhen.rules) {
880
+ for (const cond of rule.conditions) {
881
+ if (cond.type === "event_count" && cond.key) {
882
+ keys.add(cond.key);
883
+ }
884
+ }
885
+ }
886
+ }
887
+ }
888
+ for (const key of keys) {
889
+ runtime7.accumulator.register(key, (event) => {
890
+ var _a2, _b2, _c;
891
+ if (!eventNames.includes(event.name))
892
+ return false;
893
+ if (urlContains) {
894
+ const pathname = String((_b2 = (_a2 = event.props) == null ? void 0 : _a2.pathname) != null ? _b2 : "");
895
+ if (!pathname.includes(urlContains))
896
+ return false;
897
+ }
898
+ if (propFilters) {
899
+ for (const [k, v] of Object.entries(propFilters)) {
900
+ if (((_c = event.props) == null ? void 0 : _c[k]) !== v)
901
+ return false;
902
+ }
903
+ }
904
+ return true;
905
+ });
906
+ }
907
+ }, [config.scope, config.actions, runtime7.accumulator]);
908
+ useEffect2(() => {
909
+ if (!runtime7.events.subscribe)
910
+ return;
911
+ if (runtime7.events.getRecent) {
912
+ const recentEvents = runtime7.events.getRecent({ patterns: ["^action\\.tooltip_cta_clicked$", "^action\\.modal_cta_clicked$"] }, 10);
913
+ const pendingEvent = recentEvents.filter((e) => {
914
+ var _a;
915
+ const actionId = (_a = e.props) == null ? void 0 : _a.actionId;
916
+ return typeof actionId === "string" && actionId.startsWith("faq:open:");
917
+ }).pop();
918
+ if (pendingEvent && Date.now() - pendingEvent.ts < 1e4) {
919
+ const questionId = pendingEvent.props.actionId.replace("faq:open:", "");
920
+ setExpandedIds(/* @__PURE__ */ new Set([questionId]));
921
+ requestAnimationFrame(() => {
922
+ const el = document.querySelector(`[data-faq-item-id="${questionId}"]`);
923
+ if (el)
924
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
925
+ });
926
+ }
927
+ }
928
+ const unsubscribe = runtime7.events.subscribe({ patterns: ["^action\\.tooltip_cta_clicked$", "^action\\.modal_cta_clicked$"] }, (event) => {
929
+ var _a;
930
+ const actionId = (_a = event.props) == null ? void 0 : _a.actionId;
931
+ if (typeof actionId !== "string" || !actionId.startsWith("faq:open:"))
932
+ return;
933
+ const questionId = actionId.replace("faq:open:", "");
934
+ setExpandedIds(/* @__PURE__ */ new Set([questionId]));
935
+ requestAnimationFrame(() => {
936
+ const el = document.querySelector(`[data-faq-item-id="${questionId}"]`);
937
+ if (el)
938
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
939
+ });
940
+ runtime7.events.publish("canvas.requestOpen");
941
+ });
942
+ return unsubscribe;
943
+ }, [runtime7]);
944
+ const visibleQuestions = useMemo(() => config.actions.filter((q) => {
945
+ if (!q.showWhen)
946
+ return true;
947
+ const result = runtime7.evaluateSync(q.showWhen);
948
+ return result.value;
949
+ }), [config.actions, runtime7, renderTick]);
950
+ const orderedQuestions = useMemo(() => {
951
+ if (config.ordering === "priority") {
952
+ return [...visibleQuestions].sort((a, b) => {
953
+ var _a, _b;
954
+ return ((_a = b.config.priority) != null ? _a : 0) - ((_b = a.config.priority) != null ? _b : 0);
955
+ });
956
+ }
957
+ return visibleQuestions;
958
+ }, [visibleQuestions, config.ordering]);
959
+ const filteredQuestions = useMemo(() => {
960
+ if (!config.searchable || !searchQuery.trim()) {
961
+ return orderedQuestions;
962
+ }
963
+ const query = searchQuery.toLowerCase();
964
+ return orderedQuestions.filter((q) => {
965
+ var _a;
966
+ return q.config.question.toLowerCase().includes(query) || getAnswerText(q.config.answer).toLowerCase().includes(query) || ((_a = q.config.category) == null ? void 0 : _a.toLowerCase().includes(query));
967
+ });
968
+ }, [orderedQuestions, searchQuery, config.searchable]);
969
+ const categoryGroups = useMemo(() => {
970
+ const groups = /* @__PURE__ */ new Map();
971
+ for (const q of filteredQuestions) {
972
+ const cat = q.config.category;
973
+ if (!groups.has(cat)) {
974
+ groups.set(cat, []);
975
+ }
976
+ groups.get(cat).push(q);
977
+ }
978
+ return groups;
979
+ }, [filteredQuestions]);
980
+ const hasCategories = useMemo(() => filteredQuestions.some((q) => q.config.category), [filteredQuestions]);
981
+ const resolvedTheme = useMemo(() => {
982
+ var _a;
983
+ if (config.theme !== "auto")
984
+ return config.theme;
985
+ if (typeof window !== "undefined") {
986
+ return ((_a = window.matchMedia) == null ? void 0 : _a.call(window, "(prefers-color-scheme: dark)").matches) ? "dark" : "light";
987
+ }
988
+ return "light";
989
+ }, [config.theme]);
990
+ const handleToggle = useCallback2((id) => {
991
+ setExpandedIds((prev) => {
992
+ const next = new Set(prev);
993
+ if (config.expandBehavior === "single") {
994
+ if (prev.has(id)) {
995
+ return /* @__PURE__ */ new Set();
996
+ }
997
+ return /* @__PURE__ */ new Set([id]);
998
+ }
999
+ if (prev.has(id)) {
1000
+ next.delete(id);
1001
+ } else {
1002
+ next.add(id);
1003
+ }
1004
+ return next;
1005
+ });
1006
+ runtime7.events.publish("faq:toggled", {
1007
+ instanceId,
1008
+ questionId: id,
1009
+ expanded: !expandedIds.has(id),
1010
+ timestamp: Date.now()
1011
+ });
1012
+ }, [config.expandBehavior, runtime7.events, instanceId, expandedIds]);
1013
+ const handleFeedback = useCallback2((itemId, question, value) => {
1014
+ setFeedbackState((prev) => {
1015
+ const next = new Map(prev);
1016
+ next.set(itemId, value);
1017
+ return next;
1018
+ });
1019
+ runtime7.events.publish("faq:feedback", {
1020
+ itemId,
1021
+ question,
1022
+ value
1023
+ });
1024
+ }, [runtime7.events]);
1025
+ const containerStyle = {
1026
+ ...baseStyles.container,
1027
+ ...themeStyles[resolvedTheme].container
1028
+ };
1029
+ const searchInputStyle = {
1030
+ ...baseStyles.searchInput,
1031
+ ...themeStyles[resolvedTheme].searchInput
1032
+ };
1033
+ const emptyStateStyle = {
1034
+ ...baseStyles.emptyState,
1035
+ ...themeStyles[resolvedTheme].emptyState
1036
+ };
1037
+ const categoryHeaderStyle = {
1038
+ ...baseStyles.categoryHeader,
1039
+ ...themeStyles[resolvedTheme].categoryHeader
1040
+ };
1041
+ const renderItems = (items) => items.map((q) => _jsx2(FAQItem, { item: q, isExpanded: expandedIds.has(q.config.id), onToggle: () => handleToggle(q.config.id), theme: resolvedTheme, feedbackConfig, feedbackValue: feedbackState.get(q.config.id), onFeedback: handleFeedback }, q.config.id));
1042
+ if (visibleQuestions.length === 0) {
1043
+ return _jsx2("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-faq", children: _jsx2("div", { style: emptyStateStyle, children: "No FAQ questions available." }) });
1044
+ }
1045
+ return _jsxs2("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-faq", children: [config.searchable && _jsx2("div", { style: baseStyles.searchWrapper, children: _jsx2("input", { type: "text", placeholder: "Search questions...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), style: searchInputStyle }) }), _jsx2("div", { style: baseStyles.accordion, children: hasCategories ? Array.from(categoryGroups.entries()).map(([category, items]) => _jsxs2(React2.Fragment, { children: [category && _jsx2("div", { style: categoryHeaderStyle, "data-category-header": category, children: category }), renderItems(items)] }, category != null ? category : "__ungrouped")) : renderItems(filteredQuestions) }), config.searchable && filteredQuestions.length === 0 && searchQuery && _jsxs2("div", { style: { ...baseStyles.noResults, ...themeStyles[resolvedTheme].emptyState }, children: ['No questions found matching "', searchQuery, '"'] })] });
1046
+ }
1047
+ var FAQMountableWidget = {
1048
+ mount(container, config) {
1049
+ const { runtime: runtime7, instanceId = "faq-widget", ...faqConfig } = config || {
1050
+ expandBehavior: "single",
1051
+ searchable: false,
1052
+ theme: "auto",
1053
+ actions: []
1054
+ };
1055
+ if (runtime7 && typeof createRoot2 === "function") {
1056
+ const root = createRoot2(container);
1057
+ root.render(React2.createElement(FAQWidget, {
1058
+ config: faqConfig,
1059
+ runtime: runtime7,
1060
+ instanceId
1061
+ }));
1062
+ return () => {
1063
+ root.unmount();
1064
+ };
1065
+ }
1066
+ const questions = faqConfig.actions || [];
1067
+ container.innerHTML = `
1068
+ <div style="font-family: system-ui; max-width: 800px;">
1069
+ ${questions.map((q) => `
1070
+ <div style="margin-bottom: 8px; padding: 16px; background: ${slateGrey[12]}; border-radius: 8px;">
1071
+ <strong>${q.config.question}</strong>
1072
+ <p style="margin-top: 8px; color: ${slateGrey[6]};">${getAnswerText(q.config.answer)}</p>
1073
+ </div>
1074
+ `).join("")}
1075
+ </div>
1076
+ `;
1077
+ return () => {
1078
+ container.innerHTML = "";
1079
+ };
1080
+ }
1081
+ };
1082
+
1083
+ // ../adaptives/adaptive-faq/dist/runtime.js
1084
+ var runtime4 = {
1085
+ id: "adaptive-faq",
1086
+ version: "2.0.0",
1087
+ name: "FAQ Accordion",
1088
+ description: "Collapsible Q&A accordion with actions, rich content, feedback, and personalization",
1089
+ /**
1090
+ * Action executors for programmatic FAQ interaction.
1091
+ */
1092
+ executors: executorDefinitions,
1093
+ /**
1094
+ * Widget definitions for the runtime's WidgetRegistry.
1095
+ */
1096
+ widgets: [
1097
+ {
1098
+ id: "adaptive-faq:accordion",
1099
+ component: FAQMountableWidget,
1100
+ metadata: {
1101
+ name: "FAQ Accordion",
1102
+ description: "Collapsible Q&A accordion with search, categories, and feedback",
1103
+ icon: "\u2753"
1104
+ }
1105
+ }
1106
+ ],
1107
+ /**
1108
+ * Extract notify watcher entries from tile config props.
1109
+ * The runtime evaluates these continuously (even with drawer closed)
1110
+ * and publishes faq:question_revealed when showWhen transitions false → true.
1111
+ */
1112
+ notifyWatchers(props) {
1113
+ var _a;
1114
+ const actions = (_a = props.actions) != null ? _a : [];
1115
+ return actions.filter((a) => a.notify && a.showWhen).map((a) => ({
1116
+ id: `faq:${a.config.id}`,
1117
+ strategy: a.showWhen,
1118
+ eventName: "faq:question_revealed",
1119
+ eventProps: {
1120
+ questionId: a.config.id,
1121
+ question: a.config.question,
1122
+ title: a.notify.title,
1123
+ body: a.notify.body,
1124
+ icon: a.notify.icon
1125
+ }
1126
+ }));
1127
+ }
1128
+ };
1129
+
1130
+ // ../adaptives/adaptive-gamification/dist/runtime.js
1131
+ var executeAwardBadge = async (action, context) => {
1132
+ const { badgeId } = action;
1133
+ context.publishEvent("gamification.badge_awarded", {
1134
+ badgeId,
1135
+ awardedAt: Date.now()
1136
+ });
1137
+ return {
1138
+ cleanup: () => {
1139
+ }
1140
+ };
1141
+ };
1142
+ var executeAddPoints = async (action, context) => {
1143
+ const { points, reason } = action;
1144
+ context.publishEvent("gamification.points_added", {
1145
+ points,
1146
+ reason,
1147
+ timestamp: Date.now()
1148
+ });
1149
+ return {
1150
+ cleanup: () => {
1151
+ }
1152
+ };
1153
+ };
1154
+ var badgeTriggerHandler = {
1155
+ names: ["page_view", "button_click"],
1156
+ handler: (_event, _ctx) => {
1157
+ console.log("[Gamification] Event received for badge trigger check");
1158
+ }
1159
+ };
1160
+ var executors = [
1161
+ { kind: "gamification:awardBadge", executor: executeAwardBadge },
1162
+ { kind: "gamification:addPoints", executor: executeAddPoints }
1163
+ ];
1164
+ var eventHandlers = [badgeTriggerHandler];
1165
+ var runtime5 = {
1166
+ id: "adaptive-gamification",
1167
+ version: "1.0.0",
1168
+ name: "Gamification",
1169
+ description: "Badges, rewards, points, and engagement mechanics",
1170
+ executors,
1171
+ eventHandlers
1172
+ };
1173
+
1174
+ // ../adaptives/adaptive-nav/dist/NavWidget.js
1175
+ import { jsx as _jsx3, jsxs as _jsxs3 } from "react/jsx-runtime";
1176
+ import React3, { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo2, useReducer as useReducer2, useState as useState3 } from "react";
1177
+ import { createRoot as createRoot3 } from "react-dom/client";
1178
+ function escapeHtml(str) {
1179
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1180
+ }
1181
+ var baseStyles2 = {
1182
+ container: {
1183
+ fontFamily: "system-ui, -apple-system, sans-serif",
1184
+ padding: "8px",
1185
+ maxWidth: "100%",
1186
+ overflow: "hidden"
1187
+ },
1188
+ accordion: {
1189
+ display: "flex",
1190
+ flexDirection: "column",
1191
+ gap: "4px"
1192
+ },
1193
+ item: {
1194
+ borderRadius: "8px",
1195
+ overflow: "hidden",
1196
+ transition: "box-shadow 0.2s ease"
1197
+ },
1198
+ header: {
1199
+ display: "flex",
1200
+ alignItems: "center",
1201
+ gap: "8px",
1202
+ width: "100%",
1203
+ padding: "12px 16px",
1204
+ border: "none",
1205
+ cursor: "pointer",
1206
+ fontSize: "14px",
1207
+ fontWeight: 500,
1208
+ fontFamily: "inherit",
1209
+ textAlign: "left",
1210
+ transition: "background-color 0.15s ease"
1211
+ },
1212
+ chevron: {
1213
+ fontSize: "10px",
1214
+ transition: "transform 0.2s ease",
1215
+ marginLeft: "auto",
1216
+ flexShrink: 0
1217
+ },
1218
+ icon: {
1219
+ fontSize: "16px",
1220
+ flexShrink: 0
1221
+ },
1222
+ body: {
1223
+ overflow: "hidden",
1224
+ transition: "max-height 0.25s ease, padding-bottom 0.25s ease",
1225
+ padding: "0 16px"
1226
+ },
1227
+ description: {
1228
+ fontSize: "13px",
1229
+ lineHeight: "1.5",
1230
+ margin: 0
1231
+ },
1232
+ linkButton: {
1233
+ display: "inline-flex",
1234
+ alignItems: "center",
1235
+ gap: "4px",
1236
+ marginTop: "10px",
1237
+ padding: "6px 12px",
1238
+ borderRadius: "6px",
1239
+ textDecoration: "none",
1240
+ fontSize: "13px",
1241
+ fontWeight: 500,
1242
+ cursor: "pointer",
1243
+ border: "none",
1244
+ transition: "background-color 0.15s ease"
1245
+ },
1246
+ categoryHeader: {
1247
+ fontSize: "11px",
1248
+ fontWeight: 600,
1249
+ textTransform: "uppercase",
1250
+ letterSpacing: "0.05em",
1251
+ padding: "12px 4px 4px"
1252
+ },
1253
+ emptyState: {
1254
+ fontSize: "13px",
1255
+ padding: "16px",
1256
+ textAlign: "center"
1257
+ }
1258
+ };
1259
+ var themeStyles2 = {
1260
+ light: {
1261
+ container: {
1262
+ backgroundColor: base.white,
1263
+ color: slateGrey[1]
1264
+ },
1265
+ item: {
1266
+ backgroundColor: slateGrey[12],
1267
+ border: `1px solid ${slateGrey[11]}`
1268
+ },
1269
+ itemExpanded: {
1270
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.08)"
1271
+ },
1272
+ header: {
1273
+ backgroundColor: "transparent",
1274
+ color: slateGrey[1]
1275
+ },
1276
+ headerHover: {
1277
+ backgroundColor: slateGrey[12]
1278
+ },
1279
+ body: {
1280
+ color: slateGrey[6]
1281
+ },
1282
+ linkButton: {
1283
+ backgroundColor: purple[8],
1284
+ color: purple[2]
1285
+ },
1286
+ categoryHeader: {
1287
+ color: slateGrey[7]
1288
+ },
1289
+ emptyState: {
1290
+ color: slateGrey[8]
1291
+ }
1292
+ },
1293
+ dark: {
1294
+ container: {
1295
+ backgroundColor: slateGrey[1],
1296
+ color: slateGrey[12]
1297
+ },
1298
+ item: {
1299
+ backgroundColor: slateGrey[3],
1300
+ border: `1px solid ${slateGrey[5]}`
1301
+ },
1302
+ itemExpanded: {
1303
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.3)"
1304
+ },
1305
+ header: {
1306
+ backgroundColor: "transparent",
1307
+ color: slateGrey[12]
1308
+ },
1309
+ headerHover: {
1310
+ backgroundColor: slateGrey[5]
1311
+ },
1312
+ body: {
1313
+ color: slateGrey[8]
1314
+ },
1315
+ linkButton: {
1316
+ backgroundColor: purple[0],
1317
+ color: purple[6]
1318
+ },
1319
+ categoryHeader: {
1320
+ color: slateGrey[8]
1321
+ },
1322
+ emptyState: {
1323
+ color: slateGrey[7]
1324
+ }
1325
+ }
1326
+ };
1327
+ function NavTipItem({ item, isExpanded, onToggle, onNavigate, theme }) {
1328
+ const [isHovered, setIsHovered] = useState3(false);
1329
+ const colors = themeStyles2[theme];
1330
+ const { title, description, href, icon, external } = item.config;
1331
+ const itemStyle = {
1332
+ ...baseStyles2.item,
1333
+ ...colors.item,
1334
+ ...isExpanded ? colors.itemExpanded : {}
1335
+ };
1336
+ const headerStyle = {
1337
+ ...baseStyles2.header,
1338
+ ...colors.header,
1339
+ ...isHovered ? colors.headerHover : {}
1340
+ };
1341
+ const chevronStyle = {
1342
+ ...baseStyles2.chevron,
1343
+ transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)"
1344
+ };
1345
+ const bodyStyle = {
1346
+ ...baseStyles2.body,
1347
+ ...colors.body,
1348
+ maxHeight: isExpanded ? "500px" : "0",
1349
+ paddingBottom: isExpanded ? "16px" : "0"
1350
+ };
1351
+ const handleLinkClick = (e) => {
1352
+ e.preventDefault();
1353
+ e.stopPropagation();
1354
+ if (href) {
1355
+ onNavigate(href, external != null ? external : false);
1356
+ }
1357
+ };
1358
+ return _jsxs3("div", { style: itemStyle, "data-nav-tip-id": item.config.id, children: [_jsxs3("button", { type: "button", style: headerStyle, onClick: onToggle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "aria-expanded": isExpanded, children: [icon && _jsx3("span", { style: baseStyles2.icon, children: icon }), _jsx3("span", { children: title }), _jsx3("span", { style: chevronStyle, children: "\u25BC" })] }), _jsxs3("div", { style: bodyStyle, "aria-hidden": !isExpanded, children: [_jsx3("p", { style: baseStyles2.description, children: description }), href && _jsxs3("a", { href, onClick: handleLinkClick, style: { ...baseStyles2.linkButton, ...colors.linkButton }, target: external ? "_blank" : void 0, rel: external ? "noopener noreferrer" : void 0, children: ["Go ", external ? "\u2197" : "\u2192"] })] })] });
1359
+ }
1360
+ function NavWidget({ config, runtime: runtime7, instanceId }) {
1361
+ const [renderTick, forceUpdate] = useReducer2((x) => x + 1, 0);
1362
+ const [expandedIds, setExpandedIds] = useState3(/* @__PURE__ */ new Set());
1363
+ useEffect3(() => {
1364
+ const unsubscribe = runtime7.context.subscribe(() => {
1365
+ forceUpdate();
1366
+ });
1367
+ return unsubscribe;
1368
+ }, [runtime7.context]);
1369
+ useEffect3(() => {
1370
+ var _a;
1371
+ if (!((_a = runtime7.accumulator) == null ? void 0 : _a.subscribe))
1372
+ return;
1373
+ return runtime7.accumulator.subscribe(() => {
1374
+ forceUpdate();
1375
+ });
1376
+ }, [runtime7.accumulator]);
1377
+ useEffect3(() => {
1378
+ var _a, _b;
1379
+ if (!config.scope || !((_a = runtime7.accumulator) == null ? void 0 : _a.register))
1380
+ return;
1381
+ const { events: eventNames, urlContains, props: propFilters } = config.scope;
1382
+ const keys = /* @__PURE__ */ new Set();
1383
+ for (const action of config.actions) {
1384
+ if (((_b = action.showWhen) == null ? void 0 : _b.type) === "rules") {
1385
+ for (const rule of action.showWhen.rules) {
1386
+ for (const cond of rule.conditions) {
1387
+ if (cond.type === "event_count" && cond.key) {
1388
+ keys.add(cond.key);
1389
+ }
1390
+ }
1391
+ }
1392
+ }
1393
+ }
1394
+ for (const key of keys) {
1395
+ runtime7.accumulator.register(key, (event) => {
1396
+ var _a2, _b2, _c;
1397
+ if (!eventNames.includes(event.name))
1398
+ return false;
1399
+ if (urlContains) {
1400
+ const pathname = String((_b2 = (_a2 = event.props) == null ? void 0 : _a2.pathname) != null ? _b2 : "");
1401
+ if (!pathname.includes(urlContains))
1402
+ return false;
1403
+ }
1404
+ if (propFilters) {
1405
+ for (const [k, v] of Object.entries(propFilters)) {
1406
+ if (((_c = event.props) == null ? void 0 : _c[k]) !== v)
1407
+ return false;
1408
+ }
1409
+ }
1410
+ return true;
1411
+ });
1412
+ }
1413
+ }, [config.scope, config.actions, runtime7.accumulator]);
1414
+ const visibleTips = useMemo2(() => config.actions.filter((tip) => {
1415
+ if (!tip.showWhen)
1416
+ return true;
1417
+ try {
1418
+ const result = runtime7.evaluateSync(tip.showWhen);
1419
+ return result.value;
1420
+ } catch {
1421
+ return false;
1422
+ }
1423
+ }), [config.actions, runtime7, renderTick]);
1424
+ const categoryGroups = useMemo2(() => {
1425
+ const groups = /* @__PURE__ */ new Map();
1426
+ for (const tip of visibleTips) {
1427
+ const cat = tip.config.category;
1428
+ if (!groups.has(cat)) {
1429
+ groups.set(cat, []);
1430
+ }
1431
+ groups.get(cat).push(tip);
1432
+ }
1433
+ return groups;
1434
+ }, [visibleTips]);
1435
+ const hasCategories = useMemo2(() => visibleTips.some((t) => t.config.category), [visibleTips]);
1436
+ const resolvedTheme = useMemo2(() => {
1437
+ var _a;
1438
+ if (config.theme !== "auto")
1439
+ return config.theme;
1440
+ if (typeof window !== "undefined") {
1441
+ return ((_a = window.matchMedia) == null ? void 0 : _a.call(window, "(prefers-color-scheme: dark)").matches) ? "dark" : "light";
1442
+ }
1443
+ return "light";
1444
+ }, [config.theme]);
1445
+ const handleToggle = useCallback3((id) => {
1446
+ setExpandedIds((prev) => {
1447
+ const wasExpanded = prev.has(id);
1448
+ let next;
1449
+ if (config.expandBehavior === "single") {
1450
+ for (const prevId of prev) {
1451
+ if (prevId !== id) {
1452
+ runtime7.events.publish("nav:toggled", {
1453
+ instanceId,
1454
+ tipId: prevId,
1455
+ expanded: false,
1456
+ timestamp: Date.now()
1457
+ });
1458
+ }
1459
+ }
1460
+ next = wasExpanded ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([id]);
1461
+ } else {
1462
+ next = new Set(prev);
1463
+ if (wasExpanded) {
1464
+ next.delete(id);
1465
+ } else {
1466
+ next.add(id);
1467
+ }
1468
+ }
1469
+ runtime7.events.publish("nav:toggled", {
1470
+ instanceId,
1471
+ tipId: id,
1472
+ expanded: !wasExpanded,
1473
+ timestamp: Date.now()
1474
+ });
1475
+ return next;
1476
+ });
1477
+ }, [config.expandBehavior, runtime7.events, instanceId]);
1478
+ const handleNavigate = useCallback3((href, external) => {
1479
+ const normalizedHref = href.trim().toLowerCase();
1480
+ if (normalizedHref.startsWith("javascript:") || normalizedHref.startsWith("data:")) {
1481
+ return;
1482
+ }
1483
+ runtime7.events.publish("nav:tip_clicked", {
1484
+ instanceId,
1485
+ href,
1486
+ external,
1487
+ timestamp: Date.now()
1488
+ });
1489
+ if (external) {
1490
+ window.open(href, "_blank", "noopener,noreferrer");
1491
+ } else {
1492
+ window.location.href = href;
1493
+ }
1494
+ }, [runtime7.events, instanceId]);
1495
+ const containerStyle = {
1496
+ ...baseStyles2.container,
1497
+ ...themeStyles2[resolvedTheme].container
1498
+ };
1499
+ const categoryHeaderStyle = {
1500
+ ...baseStyles2.categoryHeader,
1501
+ ...themeStyles2[resolvedTheme].categoryHeader
1502
+ };
1503
+ const emptyStateStyle = {
1504
+ ...baseStyles2.emptyState,
1505
+ ...themeStyles2[resolvedTheme].emptyState
1506
+ };
1507
+ const renderItems = (items) => items.map((tip) => _jsx3(NavTipItem, { item: tip, isExpanded: expandedIds.has(tip.config.id), onToggle: () => handleToggle(tip.config.id), onNavigate: handleNavigate, theme: resolvedTheme }, tip.config.id));
1508
+ if (visibleTips.length === 0) {
1509
+ return _jsx3("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-nav", children: _jsx3("div", { style: emptyStateStyle, children: "No navigation tips available." }) });
1510
+ }
1511
+ return _jsx3("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-nav", children: _jsx3("div", { style: baseStyles2.accordion, children: hasCategories ? Array.from(categoryGroups.entries()).map(([category, items]) => _jsxs3(React3.Fragment, { children: [category && _jsx3("div", { style: categoryHeaderStyle, "data-category-header": category, children: category }), renderItems(items)] }, category != null ? category : "__ungrouped")) : renderItems(visibleTips) }) });
1512
+ }
1513
+ var NavMountableWidget = {
1514
+ mount(container, config) {
1515
+ const { runtime: runtime7, instanceId = "nav-widget", ...navConfig } = config || {
1516
+ expandBehavior: "single",
1517
+ theme: "auto",
1518
+ actions: []
1519
+ };
1520
+ if (runtime7 && typeof createRoot3 === "function") {
1521
+ const root = createRoot3(container);
1522
+ root.render(React3.createElement(NavWidget, {
1523
+ config: navConfig,
1524
+ runtime: runtime7,
1525
+ instanceId
1526
+ }));
1527
+ return () => {
1528
+ root.unmount();
1529
+ };
1530
+ }
1531
+ const tips = navConfig.actions || [];
1532
+ container.innerHTML = `
1533
+ <div style="font-family: system-ui; max-width: 100%;">
1534
+ ${tips.map((tip) => `
1535
+ <div style="margin-bottom: 4px; padding: 12px 16px; background: ${slateGrey[12]}; border-radius: 8px;">
1536
+ ${tip.config.icon ? `<span>${escapeHtml(tip.config.icon)}</span> ` : ""}<strong>${escapeHtml(tip.config.title)}</strong>
1537
+ <p style="margin-top: 8px; color: ${slateGrey[6]}; font-size: 13px;">${escapeHtml(tip.config.description)}</p>
1538
+ ${tip.config.href ? `<a href="${escapeHtml(tip.config.href)}" style="color: ${purple[2]}; font-size: 13px;">Go &rarr;</a>` : ""}
1539
+ </div>
1540
+ `).join("")}
1541
+ </div>
1542
+ `;
1543
+ return () => {
1544
+ container.innerHTML = "";
75
1545
  };
1546
+ }
1547
+ };
1548
+
1549
+ // ../adaptives/adaptive-nav/dist/runtime.js
1550
+ var executeScrollTo = async (action, context) => {
1551
+ var _a, _b, _c, _d;
1552
+ const anchorEl = context.resolveAnchor(action.anchorId);
1553
+ if (!anchorEl) {
1554
+ throw new Error(`Anchor not found: ${action.anchorId}`);
1555
+ }
1556
+ anchorEl.scrollIntoView({
1557
+ behavior: (_a = action.behavior) != null ? _a : "smooth",
1558
+ block: (_b = action.block) != null ? _b : "center",
1559
+ inline: (_c = action.inline) != null ? _c : "nearest"
1560
+ });
1561
+ context.publishEvent("action.applied", {
1562
+ id: context.generateId(),
1563
+ kind: "navigation:scrollTo",
1564
+ anchorId: action.anchorId,
1565
+ behavior: (_d = action.behavior) != null ? _d : "smooth"
1566
+ });
1567
+ return {
1568
+ cleanup: () => {
1569
+ }
1570
+ };
1571
+ };
1572
+ var executeNavigate = async (action, context) => {
1573
+ var _a;
1574
+ const url = action.url.trim();
1575
+ if (url.toLowerCase().startsWith("javascript:")) {
1576
+ throw new Error("javascript: URLs are not allowed");
1577
+ }
1578
+ const target = (_a = action.target) != null ? _a : "_self";
1579
+ context.publishEvent("action.applied", {
1580
+ id: context.generateId(),
1581
+ kind: "navigation:navigate",
1582
+ url: action.url,
1583
+ target
1584
+ });
1585
+ if (target === "_blank") {
1586
+ window.open(url, "_blank", "noopener,noreferrer");
1587
+ } else {
1588
+ window.location.href = url;
1589
+ }
1590
+ return {
1591
+ cleanup: () => {
1592
+ }
1593
+ };
1594
+ };
1595
+ var executors2 = [
1596
+ { kind: "navigation:scrollTo", executor: executeScrollTo },
1597
+ { kind: "navigation:navigate", executor: executeNavigate }
1598
+ ];
1599
+ var runtime6 = {
1600
+ id: "adaptive-nav",
1601
+ version: "2.0.0",
1602
+ name: "Navigation Tips",
1603
+ description: "Navigation actions and accordion-based tips with per-item conditional visibility",
1604
+ /**
1605
+ * Navigation action executors (scrollTo, navigate).
1606
+ */
1607
+ executors: executors2,
1608
+ /**
1609
+ * Widget definitions for the runtime's WidgetRegistry.
1610
+ */
1611
+ widgets: [
1612
+ {
1613
+ id: "adaptive-nav:tips",
1614
+ component: NavMountableWidget,
1615
+ metadata: {
1616
+ name: "Navigation Tips",
1617
+ description: "Accordion of contextual navigation tips with per-item visibility",
1618
+ icon: "\u{1F9ED}"
1619
+ }
1620
+ }
1621
+ ],
1622
+ /**
1623
+ * Extract notify watcher entries from tile config props.
1624
+ * The runtime evaluates these continuously (even with drawer closed)
1625
+ * and publishes nav:tip_revealed when showWhen transitions false → true.
1626
+ */
1627
+ notifyWatchers(props) {
1628
+ var _a;
1629
+ const actions = (_a = props.actions) != null ? _a : [];
1630
+ return actions.filter((a) => a.notify && a.showWhen).map((a) => ({
1631
+ id: `nav:${a.config.id}`,
1632
+ strategy: a.showWhen,
1633
+ eventName: "nav:tip_revealed",
1634
+ eventProps: {
1635
+ tipId: a.config.id,
1636
+ title: a.notify.title,
1637
+ body: a.notify.body,
1638
+ icon: a.notify.icon
1639
+ }
1640
+ }));
1641
+ }
1642
+ };
1643
+
1644
+ // src/apps/builtinRuntimeModules.generated.ts
1645
+ var allRuntimes = [runtime3, runtime, runtime4, runtime5, runtime6, runtime2];
1646
+ var builtinAdaptiveManifests = allRuntimes.map((r) => ({
1647
+ id: r.id,
1648
+ version: r.version,
1649
+ name: r.name,
1650
+ description: r.description,
1651
+ runtime: {
1652
+ actions: (r.executors || []).map(({ kind, executor }) => ({ kind, executor })),
1653
+ widgets: r.widgets,
1654
+ notifyWatchers: r.notifyWatchers,
1655
+ events: r.eventHandlers
1656
+ },
1657
+ editor: void 0,
1658
+ metadata: { isBuiltIn: true }
1659
+ }));
1660
+ function registerBuiltinRuntimeModules(registry) {
1661
+ let count = 0;
1662
+ for (const manifest of builtinAdaptiveManifests) {
1663
+ if (!registry.has(manifest.id)) {
1664
+ registry.register(manifest);
1665
+ count++;
1666
+ }
1667
+ }
1668
+ console.log("[Syntro Runtime] Registered", count, "built-in runtime modules");
1669
+ }
1670
+
1671
+ // src/components/TileWheel.tsx
1672
+ import { useEffect as useEffect4, useMemo as useMemo3, useState as useState4 } from "react";
1673
+ import { jsx, jsxs } from "react/jsx-runtime";
1674
+ function TileWheel({ tiles, intervalMs = 7e3, telemetry }) {
1675
+ const [index, setIndex] = useState4(0);
1676
+ const ordered = useMemo3(
1677
+ () => [...tiles].sort((a, b) => {
1678
+ var _a, _b;
1679
+ return ((_a = a.priority) != null ? _a : 0) - ((_b = b.priority) != null ? _b : 0);
1680
+ }),
1681
+ [tiles]
1682
+ );
1683
+ useEffect4(() => {
1684
+ telemetry == null ? void 0 : telemetry.trackCanvasOpened("wheel");
1685
+ }, [telemetry]);
1686
+ useEffect4(() => {
1687
+ if (ordered.length <= 1) return;
1688
+ const id = setInterval(() => {
1689
+ setIndex((prev) => (prev + 1) % ordered.length);
1690
+ }, intervalMs);
1691
+ return () => clearInterval(id);
1692
+ }, [ordered, intervalMs]);
1693
+ useEffect4(() => {
1694
+ const current = ordered[index];
1695
+ if (current) {
1696
+ telemetry == null ? void 0 : telemetry.trackRectangleViewed(current.id, "wheel");
1697
+ }
1698
+ }, [index, ordered, telemetry]);
1699
+ if (!ordered.length) return null;
1700
+ return /* @__PURE__ */ jsxs(
1701
+ "div",
1702
+ {
1703
+ style: {
1704
+ position: "relative",
1705
+ overflow: "hidden",
1706
+ borderRadius: "1.5rem",
1707
+ border: `1px solid ${border.primary}`,
1708
+ background: slateGrey[1],
1709
+ padding: "1.5rem",
1710
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
1711
+ },
1712
+ "data-shadow-canvas-id": "wheel",
1713
+ children: [
1714
+ /* @__PURE__ */ jsx(
1715
+ "div",
1716
+ {
1717
+ style: {
1718
+ display: "flex",
1719
+ transition: "transform 700ms ease-out",
1720
+ transform: `translateX(-${index * 100}%)`,
1721
+ width: `${ordered.length * 100}%`
1722
+ },
1723
+ children: ordered.map((tile) => /* @__PURE__ */ jsx("div", { style: { width: "100%", flexShrink: 0, padding: "0 1rem" }, children: /* @__PURE__ */ jsx(TileCard, { config: tile, surface: "wheel", telemetry }) }, tile.id))
1724
+ }
1725
+ ),
1726
+ /* @__PURE__ */ jsx("div", { style: { marginTop: "1rem", display: "flex", justifyContent: "center", gap: "0.5rem" }, children: ordered.map((tile, idx) => /* @__PURE__ */ jsx(
1727
+ "button",
1728
+ {
1729
+ type: "button",
1730
+ style: {
1731
+ height: "0.5rem",
1732
+ width: "1.5rem",
1733
+ borderRadius: "9999px",
1734
+ background: idx === index ? brand[3] : slateGrey[6],
1735
+ border: "none",
1736
+ cursor: "pointer",
1737
+ padding: 0
1738
+ },
1739
+ onClick: () => setIndex(idx)
1740
+ },
1741
+ tile.id
1742
+ )) })
1743
+ ]
1744
+ }
1745
+ );
1746
+ }
1747
+
1748
+ // src/config-validator.ts
1749
+ function parseVersion(version) {
1750
+ const parts = version.split(".");
1751
+ return {
1752
+ major: parseInt(parts[0] || "0", 10),
1753
+ minor: parseInt(parts[1] || "0", 10)
1754
+ };
1755
+ }
1756
+ function validateConfig(config) {
1757
+ const warnings = [];
1758
+ const errors = [];
1759
+ if (!config || typeof config !== "object") {
1760
+ return {
1761
+ valid: false,
1762
+ errors: ["Config must be an object"],
1763
+ warnings
1764
+ };
1765
+ }
1766
+ const typedConfig = config;
1767
+ if (!typedConfig.tiles) {
1768
+ errors.push("Config missing required field: tiles");
1769
+ }
1770
+ if (!typedConfig.actions) {
1771
+ errors.push("Config missing required field: actions");
1772
+ }
1773
+ if (!typedConfig.fetchedAt) {
1774
+ errors.push("Config missing required field: fetchedAt");
1775
+ }
1776
+ if (errors.length > 0) {
1777
+ return { valid: false, errors, warnings };
1778
+ }
1779
+ const configVersion = typedConfig.schemaVersion || "1.0";
1780
+ const configVer = parseVersion(configVersion);
1781
+ const sdkVer = parseVersion(SDK_SCHEMA_VERSION);
1782
+ if (configVer.major > sdkVer.major) {
1783
+ warnings.push(
1784
+ `Config schema v${configVersion} is newer than SDK v${SDK_SCHEMA_VERSION}. Some features may not work. Update SDK to latest version.`
1785
+ );
1786
+ }
1787
+ if (configVer.major < sdkVer.major || !typedConfig.schemaVersion) {
1788
+ warnings.push(
1789
+ `Config schema v${configVersion} is older than SDK v${SDK_SCHEMA_VERSION}. Migrating config to current version.`
1790
+ );
1791
+ return {
1792
+ valid: true,
1793
+ warnings,
1794
+ errors,
1795
+ migratedConfig: migrateConfig(typedConfig, configVersion)
1796
+ };
1797
+ }
1798
+ return {
1799
+ valid: true,
1800
+ warnings,
1801
+ errors
1802
+ };
1803
+ }
1804
+ function migrateConfig(config, fromVersion) {
1805
+ let migrated = { ...config };
1806
+ const fromVer = parseVersion(fromVersion);
1807
+ if (fromVer.major === 1) {
1808
+ migrated = migrateV1ToV2(migrated);
1809
+ }
1810
+ migrated.schemaVersion = SDK_SCHEMA_VERSION;
1811
+ return migrated;
1812
+ }
1813
+ function migrateV1ToV2(config) {
1814
+ const migrated = {
1815
+ schemaVersion: "2.0",
1816
+ tiles: [],
1817
+ actions: config.actions || [],
1818
+ fetchedAt: config.fetchedAt || (/* @__PURE__ */ new Date()).toISOString()
1819
+ };
1820
+ if (config.tiles && Array.isArray(config.tiles)) {
1821
+ migrated.tiles = config.tiles.map((tile) => {
1822
+ const migratedTile = { ...tile };
1823
+ if (tile.experiment && !tile.activation) {
1824
+ const exp = tile.experiment;
1825
+ if (exp.featureKey) {
1826
+ migratedTile.activation = {
1827
+ strategy: {
1828
+ type: "external",
1829
+ provider: "growthbook",
1830
+ featureKey: exp.featureKey,
1831
+ fallback: false
1832
+ }
1833
+ };
1834
+ }
1835
+ delete migratedTile.experiment;
1836
+ }
1837
+ return migratedTile;
1838
+ });
1839
+ }
1840
+ if (config.configVersion) migrated.configVersion = config.configVersion;
1841
+ if (config.canvasTitle) migrated.canvasTitle = config.canvasTitle;
1842
+ if (config.theme) migrated.theme = config.theme;
1843
+ if (config.launcher) migrated.launcher = config.launcher;
1844
+ if (config.routes) migrated.routes = config.routes;
1845
+ return migrated;
1846
+ }
1847
+ function needsMigration(config) {
1848
+ if (!config || typeof config !== "object") {
1849
+ return false;
1850
+ }
1851
+ const typedConfig = config;
1852
+ const configVersion = typedConfig.schemaVersion || "1.0";
1853
+ const configVer = parseVersion(configVersion);
1854
+ const sdkVer = parseVersion(SDK_SCHEMA_VERSION);
1855
+ return configVer.major < sdkVer.major || !typedConfig.schemaVersion;
1856
+ }
1857
+
1858
+ // src/overlays/schema.ts
1859
+ import { z } from "zod";
1860
+ var SelectorZ = z.union([
1861
+ z.object({ type: z.literal("data"), key: z.string(), value: z.string().optional() }),
1862
+ z.object({ type: z.literal("css"), value: z.string() }),
1863
+ z.object({ type: z.literal("aria"), role: z.string().optional(), label: z.string().optional() }),
1864
+ z.object({ type: z.literal("shadow-css"), value: z.string() }),
1865
+ z.object({ type: z.literal("ref"), el: z.any() })
1866
+ // runtime-only
1867
+ ]);
1868
+ var TooltipStepZ = z.object({
1869
+ kind: z.literal("tooltip"),
1870
+ id: z.string(),
1871
+ anchor: SelectorZ,
1872
+ content: z.object({ title: z.string().optional(), body: z.string() }),
1873
+ placement: z.enum(["top", "bottom", "left", "right", "auto"]).optional(),
1874
+ offsetPx: z.number().optional(),
1875
+ blocking: z.boolean().optional(),
1876
+ trigger: z.enum(["immediate", "hover", "click"]).optional(),
1877
+ dismiss: z.object({
1878
+ onEsc: z.boolean().optional(),
1879
+ closeButton: z.boolean().optional(),
1880
+ timeoutMs: z.number().optional()
1881
+ }).optional()
1882
+ });
1883
+ var HighlightStepZ = z.object({
1884
+ kind: z.literal("highlight"),
1885
+ id: z.string(),
1886
+ anchor: SelectorZ,
1887
+ copy: z.string().optional(),
1888
+ ring: z.object({ paddingPx: z.number().optional(), radiusPx: z.number().optional() }).optional(),
1889
+ scrim: z.object({ opacity: z.number().optional() }).optional(),
1890
+ ringColor: z.string().optional(),
1891
+ blocking: z.boolean().optional(),
1892
+ dismiss: z.object({
1893
+ onClickOutside: z.boolean().optional(),
1894
+ onEsc: z.boolean().optional(),
1895
+ timeoutMs: z.number().optional()
1896
+ }).optional()
1897
+ });
1898
+ var CanvasRecipeZ = z.object({
1899
+ id: z.string(),
1900
+ version: z.number(),
1901
+ routes: z.array(z.string()).optional(),
1902
+ steps: z.array(z.union([TooltipStepZ, HighlightStepZ]))
1903
+ });
1904
+ function validateRecipe(json) {
1905
+ return CanvasRecipeZ.parse(json);
1906
+ }
1907
+
1908
+ // src/overlays/fetcher.ts
1909
+ var createOverlayRecipeFetcher = ({
1910
+ configUri,
1911
+ experiments,
1912
+ featureKey = "smart-canvas-overlay-uri",
1913
+ credentials = "include"
1914
+ } = {}) => async () => {
1915
+ const uri = resolveConfigUri({ configUri, experiments, featureKey });
1916
+ if (!uri) {
1917
+ throw new Error("SmartCanvas overlays: recipe URI missing (env + feature unset).");
1918
+ }
1919
+ const response = await fetch(uri, { credentials });
1920
+ if (!response.ok) {
1921
+ throw new Error(`SmartCanvas overlays: failed to fetch recipe (${response.status})`);
1922
+ }
1923
+ const json = await response.json();
1924
+ return CanvasRecipeZ.parse(json);
1925
+ };
1926
+
1927
+ // src/SmartCanvasPortal.tsx
1928
+ import { useLayoutEffect, useState as useState5 } from "react";
1929
+ import { createPortal } from "react-dom";
1930
+ function SmartCanvasPortal({ element, children }) {
1931
+ const [mountNode, setMountNode] = useState5(null);
1932
+ useLayoutEffect(() => {
1933
+ if (!element) {
1934
+ setMountNode(null);
1935
+ return;
1936
+ }
1937
+ setMountNode(element.getMountNode());
1938
+ return () => setMountNode(null);
1939
+ }, [element]);
1940
+ if (!mountNode) return null;
1941
+ return createPortal(children, mountNode);
1942
+ }
1943
+
1944
+ // src/context/schema.ts
1945
+ import { z as z2 } from "zod";
1946
+ var PageContextZ = z2.object({
1947
+ url: z2.string(),
1948
+ routeId: z2.string().optional(),
1949
+ title: z2.string().optional(),
1950
+ locale: z2.string().optional()
1951
+ });
1952
+ var PageHistoryEntryZ = z2.object({
1953
+ url: z2.string(),
1954
+ ts: z2.number()
1955
+ });
1956
+ var SessionContextZ = z2.object({
1957
+ sessionId: z2.string(),
1958
+ startTs: z2.number(),
1959
+ pageHistory: z2.array(PageHistoryEntryZ).optional()
1960
+ });
1961
+ var ViewportContextZ = z2.object({
1962
+ width: z2.number(),
1963
+ height: z2.number()
1964
+ });
1965
+ var BoundingBoxZ = z2.object({
1966
+ x: z2.number(),
1967
+ y: z2.number(),
1968
+ w: z2.number(),
1969
+ h: z2.number()
1970
+ });
1971
+ var AnchorStateZ = z2.object({
1972
+ anchorId: z2.string(),
1973
+ present: z2.boolean(),
1974
+ visible: z2.boolean().optional(),
1975
+ boundingBox: BoundingBoxZ.optional()
1976
+ });
1977
+ var AugmentationZ = z2.record(
1978
+ z2.string(),
1979
+ z2.union([z2.number(), z2.string(), z2.boolean(), z2.undefined()])
1980
+ );
1981
+ var RuntimeContextZ = z2.object({
1982
+ page: PageContextZ,
1983
+ session: SessionContextZ,
1984
+ viewport: ViewportContextZ,
1985
+ anchors: z2.array(AnchorStateZ).optional(),
1986
+ augmented: AugmentationZ.optional()
1987
+ });
1988
+ function validateRuntimeContext(data) {
1989
+ return RuntimeContextZ.safeParse(data);
1990
+ }
1991
+
1992
+ // src/decisions/schema.ts
1993
+ import { z as z3 } from "zod";
1994
+ var PageUrlConditionZ = z3.object({
1995
+ type: z3.literal("page_url"),
1996
+ url: z3.string()
1997
+ });
1998
+ var RouteConditionZ = z3.object({
1999
+ type: z3.literal("route"),
2000
+ routeId: z3.string()
2001
+ });
2002
+ var AnchorVisibleConditionZ = z3.object({
2003
+ type: z3.literal("anchor_visible"),
2004
+ anchorId: z3.string(),
2005
+ state: z3.enum(["visible", "present", "absent"])
2006
+ });
2007
+ var EventOccurredConditionZ = z3.object({
2008
+ type: z3.literal("event_occurred"),
2009
+ eventName: z3.string(),
2010
+ withinMs: z3.number().optional()
2011
+ });
2012
+ var StateEqualsConditionZ = z3.object({
2013
+ type: z3.literal("state_equals"),
2014
+ key: z3.string(),
2015
+ value: z3.unknown()
2016
+ });
2017
+ var ViewportConditionZ = z3.object({
2018
+ type: z3.literal("viewport"),
2019
+ minWidth: z3.number().optional(),
2020
+ maxWidth: z3.number().optional(),
2021
+ minHeight: z3.number().optional(),
2022
+ maxHeight: z3.number().optional()
2023
+ });
2024
+ var SessionMetricConditionZ = z3.object({
2025
+ type: z3.literal("session_metric"),
2026
+ key: z3.string(),
2027
+ operator: z3.enum(["gte", "lte", "eq", "gt", "lt"]),
2028
+ threshold: z3.number()
2029
+ });
2030
+ var DismissedConditionZ = z3.object({
2031
+ type: z3.literal("dismissed"),
2032
+ key: z3.string(),
2033
+ inverted: z3.boolean().optional()
2034
+ });
2035
+ var CooldownActiveConditionZ = z3.object({
2036
+ type: z3.literal("cooldown_active"),
2037
+ key: z3.string(),
2038
+ inverted: z3.boolean().optional()
2039
+ });
2040
+ var FrequencyLimitConditionZ = z3.object({
2041
+ type: z3.literal("frequency_limit"),
2042
+ key: z3.string(),
2043
+ limit: z3.number(),
2044
+ inverted: z3.boolean().optional()
2045
+ });
2046
+ var EventCountConditionZ = z3.object({
2047
+ type: z3.literal("event_count"),
2048
+ key: z3.string(),
2049
+ operator: z3.enum(["gte", "lte", "eq", "gt", "lt"]),
2050
+ count: z3.number().int().min(0),
2051
+ withinMs: z3.number().positive().optional()
2052
+ });
2053
+ var ConditionZ = z3.discriminatedUnion("type", [
2054
+ PageUrlConditionZ,
2055
+ RouteConditionZ,
2056
+ AnchorVisibleConditionZ,
2057
+ EventOccurredConditionZ,
2058
+ StateEqualsConditionZ,
2059
+ ViewportConditionZ,
2060
+ SessionMetricConditionZ,
2061
+ DismissedConditionZ,
2062
+ CooldownActiveConditionZ,
2063
+ FrequencyLimitConditionZ,
2064
+ EventCountConditionZ
2065
+ ]);
2066
+ var RuleZ = z3.object({
2067
+ conditions: z3.array(ConditionZ),
2068
+ value: z3.unknown()
2069
+ });
2070
+ var RuleStrategyZ = z3.object({
2071
+ type: z3.literal("rules"),
2072
+ rules: z3.array(RuleZ),
2073
+ default: z3.unknown()
2074
+ });
2075
+ var ScoreStrategyZ = z3.object({
2076
+ type: z3.literal("score"),
2077
+ field: z3.string(),
2078
+ threshold: z3.number(),
2079
+ above: z3.unknown(),
2080
+ below: z3.unknown()
2081
+ });
2082
+ var ModelStrategyZ = z3.object({
2083
+ type: z3.literal("model"),
2084
+ modelId: z3.string(),
2085
+ inputs: z3.array(z3.string()),
2086
+ outputMapping: z3.record(z3.string(), z3.unknown()),
2087
+ default: z3.unknown()
2088
+ });
2089
+ var ExternalStrategyZ = z3.object({
2090
+ type: z3.literal("external"),
2091
+ endpoint: z3.string(),
2092
+ method: z3.enum(["GET", "POST"]).optional(),
2093
+ default: z3.unknown(),
2094
+ timeoutMs: z3.number().optional()
2095
+ });
2096
+ var DecisionStrategyZ = z3.discriminatedUnion("type", [
2097
+ RuleStrategyZ,
2098
+ ScoreStrategyZ,
2099
+ ModelStrategyZ,
2100
+ ExternalStrategyZ
2101
+ ]);
2102
+ var RouteFilterZ = z3.object({
2103
+ include: z3.array(z3.string()).optional(),
2104
+ exclude: z3.array(z3.string()).optional()
2105
+ });
2106
+ var ActivationConfigZ = z3.object({
2107
+ routes: RouteFilterZ.optional(),
2108
+ strategy: DecisionStrategyZ.optional()
2109
+ });
2110
+ function validateCondition(data) {
2111
+ return ConditionZ.safeParse(data);
2112
+ }
2113
+ function validateStrategy(data) {
2114
+ return DecisionStrategyZ.safeParse(data);
2115
+ }
2116
+ function validateActivationConfig(data) {
2117
+ return ActivationConfigZ.safeParse(data);
2118
+ }
2119
+
2120
+ // src/events/schema.ts
2121
+ import { z as z4 } from "zod";
2122
+ var EventSourceZ = z4.enum(["posthog", "canvas", "derived"]);
2123
+ var NormalizedEventZ = z4.object({
2124
+ ts: z4.number(),
2125
+ name: z4.string(),
2126
+ source: EventSourceZ,
2127
+ props: z4.record(z4.string(), z4.unknown()).optional(),
2128
+ schemaVersion: z4.string()
2129
+ });
2130
+ var EventFilterZ = z4.object({
2131
+ names: z4.array(z4.string()).optional(),
2132
+ patterns: z4.array(z4.string()).optional(),
2133
+ sources: z4.array(EventSourceZ).optional()
2134
+ });
2135
+ function validateNormalizedEvent(data) {
2136
+ return NormalizedEventZ.safeParse(data);
2137
+ }
2138
+ function validateEventFilter(data) {
2139
+ return EventFilterZ.safeParse(data);
2140
+ }
2141
+
2142
+ // src/state/schema.ts
2143
+ import { z as z5 } from "zod";
2144
+ var StoredValueZ = z5.object({
2145
+ value: z5.unknown(),
2146
+ expiresAt: z5.number().optional()
2147
+ });
2148
+ var FrequencyEntryZ = z5.object({
2149
+ count: z5.number(),
2150
+ resetAt: z5.number().optional()
2151
+ });
2152
+ function validateStoredValue(data) {
2153
+ return StoredValueZ.safeParse(data);
2154
+ }
2155
+ function validateFrequencyEntry(data) {
2156
+ return FrequencyEntryZ.safeParse(data);
2157
+ }
2158
+
2159
+ // src/index.ts
2160
+ if (typeof window !== "undefined") {
2161
+ const existing = window.SynOS;
2162
+ const registry = (existing == null ? void 0 : existing.appRegistry) || appRegistry;
2163
+ window.SynOS = {
2164
+ ...existing,
2165
+ appRegistry: registry,
2166
+ React: React4,
2167
+ ReactDOM: { ...ReactDOMClient, createPortal: createPortal2, flushSync }
2168
+ };
2169
+ registerBuiltinRuntimeModules(registry);
76
2170
  }
77
- //# sourceMappingURL=index.js.map
2171
+ export {
2172
+ ANIMATION_KEYFRAMES,
2173
+ ActivationConfigZ,
2174
+ AddClassZ,
2175
+ AnchorStateZ,
2176
+ AnchorVisibleConditionZ,
2177
+ AppRegistry,
2178
+ AugmentationZ,
2179
+ BadgePositionZ,
2180
+ BadgeZ,
2181
+ BoundingBoxZ,
2182
+ CanvasEvents,
2183
+ CanvasRecipeZ,
2184
+ ConditionZ,
2185
+ ContextManager,
2186
+ CooldownActiveConditionZ,
2187
+ CtaButtonZ,
2188
+ DEFAULT_COOLDOWN,
2189
+ DEFAULT_TTL,
2190
+ DecisionStrategyZ,
2191
+ DismissedConditionZ,
2192
+ EVENT_SCHEMA_VERSION,
2193
+ EventBus,
2194
+ EventCountConditionZ,
2195
+ EventFilterZ,
2196
+ EventOccurredConditionZ,
2197
+ EventSourceZ,
2198
+ ExecutorRegistry,
2199
+ ExternalStrategyZ,
2200
+ FrequencyEntryZ,
2201
+ FrequencyLimitConditionZ,
2202
+ HighlightStepZ,
2203
+ HighlightStyleZ,
2204
+ HighlightZ,
2205
+ InsertHtmlZ,
2206
+ InsertPositionZ,
2207
+ MAX_VISIBLE_TOASTS,
2208
+ ModalContentZ,
2209
+ ModalZ,
2210
+ ModelStrategyZ,
2211
+ MountWidgetZ,
2212
+ NavigateZ,
2213
+ NormalizedEventZ,
2214
+ NotificationToastStack,
2215
+ PageContextZ,
2216
+ PageHistoryEntryZ,
2217
+ PageUrlConditionZ,
2218
+ ParallelZ,
2219
+ PlacementZ,
2220
+ PulseZ,
2221
+ RUNTIME_VERSION,
2222
+ RemoveClassZ,
2223
+ RouteConditionZ,
2224
+ RouteFilterZ,
2225
+ RuleStrategyZ,
2226
+ RuleZ,
2227
+ RuntimeContextZ,
2228
+ RuntimeProvider,
2229
+ SDK_SCHEMA_VERSION,
2230
+ SDK_VERSION,
2231
+ STATIC_SLOT_STYLES,
2232
+ ScoreStrategyZ,
2233
+ ScrollBehaviorZ,
2234
+ ScrollLogicalPositionZ,
2235
+ ScrollToZ,
2236
+ SelectorZ,
2237
+ SequenceZ,
2238
+ SessionContextZ,
2239
+ SessionMetricConditionZ,
2240
+ SessionMetricTracker,
2241
+ SetAttrZ,
2242
+ SetStyleZ,
2243
+ SetTextZ,
2244
+ ShadowCanvasOverlay,
2245
+ ShadowRootProvider,
2246
+ SmartCanvasApp,
2247
+ SmartCanvasController,
2248
+ SmartCanvasElement,
2249
+ SmartCanvasPortal,
2250
+ StandardEvents,
2251
+ StateEqualsConditionZ,
2252
+ StateStore,
2253
+ StoredValueZ,
2254
+ Syntro,
2255
+ TileCard,
2256
+ TileWheel,
2257
+ TooltipContentZ,
2258
+ TooltipStepZ,
2259
+ TooltipTriggerZ,
2260
+ TooltipZ,
2261
+ TourStepForSchemaZ,
2262
+ TourZ,
2263
+ ViewportConditionZ,
2264
+ ViewportContextZ,
2265
+ WaitZ,
2266
+ WidgetConfigZ,
2267
+ WidgetRegistry,
2268
+ appRegistry,
2269
+ applyStaticSlotStyles,
2270
+ cleanupAppContext,
2271
+ runtime as contentRuntime,
2272
+ coreActionStepSchemas,
2273
+ createActionEngine,
2274
+ createAppContext,
2275
+ createAppLoader,
2276
+ createCanvasConfigFetcher,
2277
+ createContextManager,
2278
+ createDecisionEngine,
2279
+ createEventAccumulator,
2280
+ createEventBus,
2281
+ createGrowthBookClient,
2282
+ createNoopClient,
2283
+ createOverlayRecipeFetcher,
2284
+ createPostHogClient,
2285
+ createPostHogNormalizer,
2286
+ createSessionMetricTracker,
2287
+ createSmartCanvas,
2288
+ createSmartCanvasController,
2289
+ createSmartCanvasRuntime,
2290
+ createStateStore,
2291
+ createSurfaceContainer,
2292
+ createSurfaces,
2293
+ decodeToken,
2294
+ encodeToken,
2295
+ evaluate,
2296
+ evaluateCondition,
2297
+ evaluateRule,
2298
+ evaluateRuleStrategy,
2299
+ evaluateScoreStrategy,
2300
+ evaluateSync,
2301
+ executorRegistry,
2302
+ getAntiFlickerSnippet,
2303
+ getAppIdFromActionKind,
2304
+ getAppIdFromWidgetId,
2305
+ getExecutor,
2306
+ getSlotAnchorId,
2307
+ getSlotType,
2308
+ getSlotZIndex,
2309
+ hasExecutor,
2310
+ interpolateTemplate,
2311
+ isCoreActionKind,
2312
+ matchEvent,
2313
+ needsMigration,
2314
+ normalizePostHogEvent,
2315
+ runtime2 as overlaysRuntime,
2316
+ parseVersion,
2317
+ playEnterAnimation,
2318
+ playExitAnimation,
2319
+ registerConfigPredicates,
2320
+ registerSmartCanvasElement,
2321
+ resolveConfigUri,
2322
+ setupAdjacentPositioning,
2323
+ setupInlinePositioning,
2324
+ shouldNormalizeEvent,
2325
+ useDecision,
2326
+ useNotifications,
2327
+ useNotifyWatcher,
2328
+ usePageContext,
2329
+ useRuntime,
2330
+ useRuntimeContext,
2331
+ useRuntimeEvents,
2332
+ useRuntimeState,
2333
+ useSessionContext,
2334
+ useShadowCanvasConfig,
2335
+ useShadowRoot,
2336
+ useViewportContext,
2337
+ validateAction,
2338
+ validateActions,
2339
+ validateActivationConfig,
2340
+ validateCondition,
2341
+ validateConfig,
2342
+ validateEventFilter,
2343
+ validateFrequencyEntry,
2344
+ validateNormalizedEvent,
2345
+ validateRecipe,
2346
+ validateRuntimeContext,
2347
+ validateStoredValue,
2348
+ validateStrategy,
2349
+ widgetRegistry
2350
+ };
2351
+ //# sourceMappingURL=index.js.map