@syntrologie/runtime-sdk 0.2.20 → 1.0.0-canary.1

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 (332) hide show
  1. package/CAPABILITIES.md +756 -284
  2. package/README.md +310 -68
  3. package/dist/RuntimeProvider.d.ts +51 -0
  4. package/dist/RuntimeProvider.js +113 -0
  5. package/dist/RuntimeProvider.js.map +1 -0
  6. package/dist/SmartCanvasApp.d.ts +16 -10
  7. package/dist/SmartCanvasApp.js +45 -49
  8. package/dist/SmartCanvasApp.js.map +1 -1
  9. package/dist/SmartCanvasElement.d.ts +5 -5
  10. package/dist/SmartCanvasElement.js +24 -14
  11. package/dist/SmartCanvasElement.js.map +1 -1
  12. package/dist/SmartCanvasPortal.d.ts +2 -2
  13. package/dist/SmartCanvasPortal.js +2 -2
  14. package/dist/actions/ActionEngine.d.ts +11 -0
  15. package/dist/actions/ActionEngine.js +274 -0
  16. package/dist/actions/ActionEngine.js.map +1 -0
  17. package/dist/actions/executors/index.d.ts +117 -0
  18. package/dist/actions/executors/index.js +242 -0
  19. package/dist/actions/executors/index.js.map +1 -0
  20. package/dist/actions/executors/tour.d.ts +18 -0
  21. package/dist/actions/executors/tour.js +332 -0
  22. package/dist/actions/executors/tour.js.map +1 -0
  23. package/dist/actions/index.d.ts +10 -0
  24. package/dist/actions/index.js +12 -0
  25. package/dist/actions/index.js.map +1 -0
  26. package/dist/actions/types.d.ts +399 -0
  27. package/dist/actions/types.js +8 -0
  28. package/dist/actions/types.js.map +1 -0
  29. package/dist/actions/validation.d.ts +14 -0
  30. package/dist/actions/validation.js +602 -0
  31. package/dist/actions/validation.js.map +1 -0
  32. package/dist/antiFlicker.js +1 -1
  33. package/dist/api.d.ts +40 -26
  34. package/dist/api.js +90 -59
  35. package/dist/api.js.map +1 -1
  36. package/dist/apps/AppContext.d.ts +31 -0
  37. package/dist/apps/AppContext.js +93 -0
  38. package/dist/apps/AppContext.js.map +1 -0
  39. package/dist/apps/AppLoader.d.ts +84 -0
  40. package/dist/apps/AppLoader.js +256 -0
  41. package/dist/apps/AppLoader.js.map +1 -0
  42. package/dist/apps/AppRegistry.d.ts +102 -0
  43. package/dist/apps/AppRegistry.js +317 -0
  44. package/dist/apps/AppRegistry.js.map +1 -0
  45. package/dist/apps/adaptive-chatbot/index.js +7 -0
  46. package/dist/apps/adaptive-chatbot/index.js.map +7 -0
  47. package/dist/apps/examples/gamification-app.example.d.ts +305 -0
  48. package/dist/apps/examples/gamification-app.example.js +329 -0
  49. package/dist/apps/examples/gamification-app.example.js.map +1 -0
  50. package/dist/apps/faq/index.js +11 -0
  51. package/dist/apps/faq/index.js.map +7 -0
  52. package/dist/apps/gamification/index.js +2 -0
  53. package/dist/apps/gamification/index.js.map +7 -0
  54. package/dist/apps/index.d.ts +15 -0
  55. package/dist/apps/index.js +17 -0
  56. package/dist/apps/index.js.map +1 -0
  57. package/dist/apps/nav/index.js +11 -0
  58. package/dist/apps/nav/index.js.map +7 -0
  59. package/dist/apps/types.d.ts +231 -0
  60. package/dist/apps/types.js +8 -0
  61. package/dist/apps/types.js.map +1 -0
  62. package/dist/blocks/data/ComparisonBlock.d.ts +1 -1
  63. package/dist/blocks/data/ComparisonBlock.js +40 -40
  64. package/dist/blocks/data/ComparisonBlock.js.map +1 -1
  65. package/dist/blocks/data/StatsBlock.d.ts +1 -1
  66. package/dist/blocks/data/StatsBlock.js +41 -41
  67. package/dist/blocks/data/StatsBlock.js.map +1 -1
  68. package/dist/blocks/data/index.d.ts +2 -2
  69. package/dist/blocks/data/index.js +2 -2
  70. package/dist/blocks/index.d.ts +5 -5
  71. package/dist/blocks/index.js +29 -29
  72. package/dist/blocks/index.js.map +1 -1
  73. package/dist/blocks/interactive/ChecklistBlock.d.ts +1 -1
  74. package/dist/blocks/interactive/ChecklistBlock.js +60 -60
  75. package/dist/blocks/interactive/ChecklistBlock.js.map +1 -1
  76. package/dist/blocks/interactive/RatingBlock.d.ts +1 -1
  77. package/dist/blocks/interactive/RatingBlock.js +75 -65
  78. package/dist/blocks/interactive/RatingBlock.js.map +1 -1
  79. package/dist/blocks/interactive/index.d.ts +2 -2
  80. package/dist/blocks/interactive/index.js +2 -2
  81. package/dist/blocks/notification/NotificationBlock.d.ts +2 -2
  82. package/dist/blocks/notification/NotificationBlock.js +67 -63
  83. package/dist/blocks/notification/NotificationBlock.js.map +1 -1
  84. package/dist/blocks/notification/index.d.ts +1 -1
  85. package/dist/blocks/notification/index.js +1 -1
  86. package/dist/bootstrap.d.ts +47 -9
  87. package/dist/bootstrap.js +237 -69
  88. package/dist/bootstrap.js.map +1 -1
  89. package/dist/components/ShadowCanvasOverlay.d.ts +6 -6
  90. package/dist/components/ShadowCanvasOverlay.js +144 -107
  91. package/dist/components/ShadowCanvasOverlay.js.map +1 -1
  92. package/dist/components/TileCard.d.ts +5 -5
  93. package/dist/components/TileCard.js +204 -154
  94. package/dist/components/TileCard.js.map +1 -1
  95. package/dist/components/TileWheel.d.ts +3 -3
  96. package/dist/components/TileWheel.js +7 -7
  97. package/dist/components/TileWheel.js.map +1 -1
  98. package/dist/config-validator.d.ts +49 -0
  99. package/dist/config-validator.js +173 -0
  100. package/dist/config-validator.js.map +1 -0
  101. package/dist/configFetcher.d.ts +2 -2
  102. package/dist/configFetcher.js +20 -8
  103. package/dist/configFetcher.js.map +1 -1
  104. package/dist/context/ContextManager.d.ts +66 -0
  105. package/dist/context/ContextManager.js +268 -0
  106. package/dist/context/ContextManager.js.map +1 -0
  107. package/dist/context/index.d.ts +7 -0
  108. package/dist/context/index.js +7 -0
  109. package/dist/context/index.js.map +1 -0
  110. package/dist/context/schema.d.ts +360 -0
  111. package/dist/context/schema.js +50 -0
  112. package/dist/context/schema.js.map +1 -0
  113. package/dist/context/types.d.ts +101 -0
  114. package/dist/context/types.js +8 -0
  115. package/dist/context/types.js.map +1 -0
  116. package/dist/decisions/engine.d.ts +43 -0
  117. package/dist/decisions/engine.js +112 -0
  118. package/dist/decisions/engine.js.map +1 -0
  119. package/dist/decisions/index.d.ts +9 -0
  120. package/dist/decisions/index.js +10 -0
  121. package/dist/decisions/index.js.map +1 -0
  122. package/dist/decisions/schema.d.ts +2166 -0
  123. package/dist/decisions/schema.js +143 -0
  124. package/dist/decisions/schema.js.map +1 -0
  125. package/dist/decisions/strategies/rules.d.ts +24 -0
  126. package/dist/decisions/strategies/rules.js +152 -0
  127. package/dist/decisions/strategies/rules.js.map +1 -0
  128. package/dist/decisions/strategies/score.d.ts +10 -0
  129. package/dist/decisions/strategies/score.js +29 -0
  130. package/dist/decisions/strategies/score.js.map +1 -0
  131. package/dist/decisions/types.d.ts +242 -0
  132. package/dist/decisions/types.js +2 -0
  133. package/dist/decisions/types.js.map +1 -0
  134. package/dist/earlyPatcher.d.ts +8 -20
  135. package/dist/earlyPatcher.js +13 -62
  136. package/dist/earlyPatcher.js.map +1 -1
  137. package/dist/editorLoader.d.ts +12 -0
  138. package/dist/editorLoader.js +132 -48
  139. package/dist/editorLoader.js.map +1 -1
  140. package/dist/events/EventBus.d.ts +59 -0
  141. package/dist/events/EventBus.js +152 -0
  142. package/dist/events/EventBus.js.map +1 -0
  143. package/dist/events/index.d.ts +9 -0
  144. package/dist/events/index.js +10 -0
  145. package/dist/events/index.js.map +1 -0
  146. package/dist/events/normalizers/canvas.d.ts +67 -0
  147. package/dist/events/normalizers/canvas.js +116 -0
  148. package/dist/events/normalizers/canvas.js.map +1 -0
  149. package/dist/events/normalizers/posthog.d.ts +53 -0
  150. package/dist/events/normalizers/posthog.js +163 -0
  151. package/dist/events/normalizers/posthog.js.map +1 -0
  152. package/dist/events/schema.d.ts +70 -0
  153. package/dist/events/schema.js +30 -0
  154. package/dist/events/schema.js.map +1 -0
  155. package/dist/events/types.d.ts +79 -0
  156. package/dist/events/types.js +49 -0
  157. package/dist/events/types.js.map +1 -0
  158. package/dist/experiments/adapters/growthbook.d.ts +4 -4
  159. package/dist/experiments/adapters/growthbook.js +5 -5
  160. package/dist/experiments/adapters/growthbook.js.map +1 -1
  161. package/dist/experiments/index.d.ts +3 -3
  162. package/dist/experiments/index.js +1 -1
  163. package/dist/experiments/registry.d.ts +2 -2
  164. package/dist/experiments/registry.js +2 -2
  165. package/dist/experiments/types.d.ts +5 -1
  166. package/dist/fetchers/cdnFetcher.d.ts +1 -1
  167. package/dist/fetchers/cdnFetcher.js +4 -8
  168. package/dist/fetchers/cdnFetcher.js.map +1 -1
  169. package/dist/fetchers/experimentsFetcher.d.ts +2 -2
  170. package/dist/fetchers/experimentsFetcher.js +7 -7
  171. package/dist/fetchers/experimentsFetcher.js.map +1 -1
  172. package/dist/fetchers/index.d.ts +3 -3
  173. package/dist/fetchers/index.js +2 -2
  174. package/dist/fetchers/index.js.map +1 -1
  175. package/dist/fetchers/registry.d.ts +1 -1
  176. package/dist/fetchers/registry.js +4 -4
  177. package/dist/fetchers/types.d.ts +1 -1
  178. package/dist/hooks/useCanvasOverlays.d.ts +8 -5
  179. package/dist/hooks/useCanvasOverlays.js +66 -17
  180. package/dist/hooks/useCanvasOverlays.js.map +1 -1
  181. package/dist/hooks/useHostPatches.d.ts +2 -2
  182. package/dist/hooks/useHostPatches.js +8 -8
  183. package/dist/hooks/useHostPatches.js.map +1 -1
  184. package/dist/hooks/useShadowCanvasConfig.d.ts +9 -9
  185. package/dist/hooks/useShadowCanvasConfig.js +24 -8
  186. package/dist/hooks/useShadowCanvasConfig.js.map +1 -1
  187. package/dist/hostPatcher/core/patcher.d.ts +1 -1
  188. package/dist/hostPatcher/core/patcher.js +18 -9
  189. package/dist/hostPatcher/core/patcher.js.map +1 -1
  190. package/dist/hostPatcher/core/sanitizer.js +24 -3
  191. package/dist/hostPatcher/core/sanitizer.js.map +1 -1
  192. package/dist/hostPatcher/policy/defaultPolicy.js +15 -5
  193. package/dist/hostPatcher/policy/defaultPolicy.js.map +1 -1
  194. package/dist/hostPatcher/utils/anchors.js +4 -6
  195. package/dist/hostPatcher/utils/anchors.js.map +1 -1
  196. package/dist/index.d.ts +34 -21
  197. package/dist/index.js +46 -19
  198. package/dist/index.js.map +1 -1
  199. package/dist/logger.d.ts +29 -0
  200. package/dist/logger.js +81 -0
  201. package/dist/logger.js.map +1 -0
  202. package/dist/metrics/index.d.ts +1 -1
  203. package/dist/metrics/index.js +1 -1
  204. package/dist/metrics/sessionMetrics.d.ts +1 -1
  205. package/dist/metrics/sessionMetrics.js +6 -6
  206. package/dist/overlays/fetcher.d.ts +2 -2
  207. package/dist/overlays/fetcher.js +4 -4
  208. package/dist/overlays/recipeRegistry.js +2 -2
  209. package/dist/overlays/recipeRegistry.js.map +1 -1
  210. package/dist/overlays/runtime/anchor/resolve.js +1 -1
  211. package/dist/overlays/runtime/anchor/resolve.js.map +1 -1
  212. package/dist/overlays/runtime/index.d.ts +7 -7
  213. package/dist/overlays/runtime/index.js +7 -7
  214. package/dist/overlays/runtime/overlay/highlight.js +39 -39
  215. package/dist/overlays/runtime/overlay/highlight.js.map +1 -1
  216. package/dist/overlays/runtime/overlay/modal.js +5 -5
  217. package/dist/overlays/runtime/overlay/modal.js.map +1 -1
  218. package/dist/overlays/runtime/overlay/root.js +1 -1
  219. package/dist/overlays/runtime/overlay/runner.js +70 -23
  220. package/dist/overlays/runtime/overlay/runner.js.map +1 -1
  221. package/dist/overlays/runtime/overlay/tooltip.d.ts +1 -1
  222. package/dist/overlays/runtime/overlay/tooltip.js +10 -10
  223. package/dist/overlays/runtime/overlay/tooltip.js.map +1 -1
  224. package/dist/overlays/runtime/utils/dom.js +4 -1
  225. package/dist/overlays/runtime/utils/dom.js.map +1 -1
  226. package/dist/overlays/schema.d.ts +98 -98
  227. package/dist/overlays/schema.js +12 -8
  228. package/dist/overlays/schema.js.map +1 -1
  229. package/dist/react.d.ts +7 -7
  230. package/dist/react.js +4 -4
  231. package/dist/react.js.map +1 -1
  232. package/dist/render/RenderContext.d.ts +2 -2
  233. package/dist/render/RenderContext.js +5 -5
  234. package/dist/render/RenderContext.js.map +1 -1
  235. package/dist/render/index.d.ts +3 -3
  236. package/dist/render/index.js +1 -1
  237. package/dist/render/types.d.ts +4 -4
  238. package/dist/runtime.d.ts +110 -0
  239. package/dist/runtime.js +206 -0
  240. package/dist/runtime.js.map +1 -0
  241. package/dist/smart-canvas.esm.js +155 -78
  242. package/dist/smart-canvas.esm.js.map +4 -4
  243. package/dist/smart-canvas.js +44390 -37343
  244. package/dist/smart-canvas.js.map +4 -4
  245. package/dist/smart-canvas.min.js +156 -78
  246. package/dist/smart-canvas.min.js.map +4 -4
  247. package/dist/state/StateStore.d.ts +41 -0
  248. package/dist/state/StateStore.js +170 -0
  249. package/dist/state/StateStore.js.map +1 -0
  250. package/dist/state/helpers/cooldowns.d.ts +7 -0
  251. package/dist/state/helpers/cooldowns.js +31 -0
  252. package/dist/state/helpers/cooldowns.js.map +1 -0
  253. package/dist/state/helpers/dismissals.d.ts +7 -0
  254. package/dist/state/helpers/dismissals.js +34 -0
  255. package/dist/state/helpers/dismissals.js.map +1 -0
  256. package/dist/state/helpers/frequency.d.ts +8 -0
  257. package/dist/state/helpers/frequency.js +43 -0
  258. package/dist/state/helpers/frequency.js.map +1 -0
  259. package/dist/state/index.d.ts +7 -0
  260. package/dist/state/index.js +7 -0
  261. package/dist/state/index.js.map +1 -0
  262. package/dist/state/schema.d.ts +49 -0
  263. package/dist/state/schema.js +25 -0
  264. package/dist/state/schema.js.map +1 -0
  265. package/dist/state/types.d.ts +137 -0
  266. package/dist/state/types.js +9 -0
  267. package/dist/state/types.js.map +1 -0
  268. package/dist/store/example.d.ts +1 -0
  269. package/dist/store/example.js +43 -0
  270. package/dist/store/example.js.map +1 -0
  271. package/dist/store/mini-effector.d.ts +46 -0
  272. package/dist/store/mini-effector.js +88 -0
  273. package/dist/store/mini-effector.js.map +1 -0
  274. package/dist/surfaces/Surfaces.d.ts +11 -0
  275. package/dist/surfaces/Surfaces.js +361 -0
  276. package/dist/surfaces/Surfaces.js.map +1 -0
  277. package/dist/surfaces/index.d.ts +9 -0
  278. package/dist/surfaces/index.js +12 -0
  279. package/dist/surfaces/index.js.map +1 -0
  280. package/dist/surfaces/positioning.d.ts +50 -0
  281. package/dist/surfaces/positioning.js +228 -0
  282. package/dist/surfaces/positioning.js.map +1 -0
  283. package/dist/surfaces/types.d.ts +167 -0
  284. package/dist/surfaces/types.js +23 -0
  285. package/dist/surfaces/types.js.map +1 -0
  286. package/dist/telemetry/adapters/noop.d.ts +12 -0
  287. package/dist/telemetry/adapters/noop.js +42 -0
  288. package/dist/telemetry/adapters/noop.js.map +1 -0
  289. package/dist/telemetry/adapters/posthog.d.ts +9 -3
  290. package/dist/telemetry/adapters/posthog.js +36 -14
  291. package/dist/telemetry/adapters/posthog.js.map +1 -1
  292. package/dist/telemetry/index.d.ts +4 -3
  293. package/dist/telemetry/index.js +3 -2
  294. package/dist/telemetry/index.js.map +1 -1
  295. package/dist/telemetry/registry.d.ts +2 -2
  296. package/dist/telemetry/registry.js +4 -2
  297. package/dist/telemetry/registry.js.map +1 -1
  298. package/dist/telemetry/types.d.ts +1 -1
  299. package/dist/theme/ThemeProvider.d.ts +2 -2
  300. package/dist/theme/ThemeProvider.js +21 -21
  301. package/dist/theme/ThemeProvider.js.map +1 -1
  302. package/dist/theme/defaultTheme.d.ts +2 -2
  303. package/dist/theme/defaultTheme.js +111 -111
  304. package/dist/theme/defaultTheme.js.map +1 -1
  305. package/dist/theme/extractHostTheme.d.ts +1 -1
  306. package/dist/theme/extractHostTheme.js +42 -44
  307. package/dist/theme/extractHostTheme.js.map +1 -1
  308. package/dist/theme/index.d.ts +5 -5
  309. package/dist/theme/index.js +3 -3
  310. package/dist/theme/index.js.map +1 -1
  311. package/dist/theme/types.d.ts +2 -2
  312. package/dist/token.d.ts +2 -0
  313. package/dist/token.js +3 -6
  314. package/dist/token.js.map +1 -1
  315. package/dist/types-only.d.ts +32 -0
  316. package/dist/types-only.js +11 -0
  317. package/dist/types-only.js.map +1 -0
  318. package/dist/types.d.ts +95 -54
  319. package/dist/types.js +15 -2
  320. package/dist/types.js.map +1 -1
  321. package/dist/version.d.ts +13 -0
  322. package/dist/version.js +14 -0
  323. package/dist/version.js.map +1 -0
  324. package/dist/widgets/WidgetRegistry.d.ts +139 -0
  325. package/dist/widgets/WidgetRegistry.js +182 -0
  326. package/dist/widgets/WidgetRegistry.js.map +1 -0
  327. package/dist/widgets/index.d.ts +7 -0
  328. package/dist/widgets/index.js +7 -0
  329. package/dist/widgets/index.js.map +1 -0
  330. package/package.json +27 -11
  331. package/schema/canvas-config.schema.json +666 -227
  332. package/schema/runtime-context.schema.json +127 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Config validation and migration for SDK versioning.
3
+ *
4
+ * This module handles:
5
+ * - Validating configs against the current SDK schema version
6
+ * - Migrating old config formats to current version
7
+ * - Providing warnings for version mismatches
8
+ */
9
+ import type { CanvasConfigResponse } from './types';
10
+ /**
11
+ * Result of config validation.
12
+ */
13
+ export interface ConfigValidationResult {
14
+ /** Whether the config is valid and can be used */
15
+ valid: boolean;
16
+ /** Warning messages (non-fatal issues) */
17
+ warnings: string[];
18
+ /** Error messages (fatal issues that prevent usage) */
19
+ errors: string[];
20
+ /** Migrated config if old version was detected */
21
+ migratedConfig?: CanvasConfigResponse;
22
+ }
23
+ /**
24
+ * Parse a schema version string into major and minor numbers.
25
+ */
26
+ export declare function parseVersion(version: string): {
27
+ major: number;
28
+ minor: number;
29
+ };
30
+ /**
31
+ * Validate and normalize a config, handling version mismatches.
32
+ *
33
+ * This function:
34
+ * 1. Checks if config is valid object
35
+ * 2. Compares config schema version with SDK version
36
+ * 3. Migrates old configs to current version
37
+ * 4. Returns validation result with warnings/errors
38
+ *
39
+ * @param config - Raw config from backend or fetcher
40
+ * @returns Validation result with any migrations applied
41
+ */
42
+ export declare function validateConfig(config: unknown): ConfigValidationResult;
43
+ /**
44
+ * Check if a config needs migration.
45
+ *
46
+ * @param config - Config to check
47
+ * @returns True if migration is needed
48
+ */
49
+ export declare function needsMigration(config: unknown): boolean;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Config validation and migration for SDK versioning.
3
+ *
4
+ * This module handles:
5
+ * - Validating configs against the current SDK schema version
6
+ * - Migrating old config formats to current version
7
+ * - Providing warnings for version mismatches
8
+ */
9
+ import { SDK_SCHEMA_VERSION } from './types';
10
+ /**
11
+ * Parse a schema version string into major and minor numbers.
12
+ */
13
+ export function parseVersion(version) {
14
+ const parts = version.split('.');
15
+ return {
16
+ major: parseInt(parts[0] || '0', 10),
17
+ minor: parseInt(parts[1] || '0', 10),
18
+ };
19
+ }
20
+ /**
21
+ * Validate and normalize a config, handling version mismatches.
22
+ *
23
+ * This function:
24
+ * 1. Checks if config is valid object
25
+ * 2. Compares config schema version with SDK version
26
+ * 3. Migrates old configs to current version
27
+ * 4. Returns validation result with warnings/errors
28
+ *
29
+ * @param config - Raw config from backend or fetcher
30
+ * @returns Validation result with any migrations applied
31
+ */
32
+ export function validateConfig(config) {
33
+ const warnings = [];
34
+ const errors = [];
35
+ // Type check
36
+ if (!config || typeof config !== 'object') {
37
+ return {
38
+ valid: false,
39
+ errors: ['Config must be an object'],
40
+ warnings,
41
+ };
42
+ }
43
+ const typedConfig = config;
44
+ // Check required fields
45
+ if (!typedConfig.tiles) {
46
+ errors.push('Config missing required field: tiles');
47
+ }
48
+ if (!typedConfig.actions) {
49
+ errors.push('Config missing required field: actions');
50
+ }
51
+ if (!typedConfig.fetchedAt) {
52
+ errors.push('Config missing required field: fetchedAt');
53
+ }
54
+ if (errors.length > 0) {
55
+ return { valid: false, errors, warnings };
56
+ }
57
+ // Check schema version
58
+ const configVersion = typedConfig.schemaVersion || '1.0';
59
+ const configVer = parseVersion(configVersion);
60
+ const sdkVer = parseVersion(SDK_SCHEMA_VERSION);
61
+ // Future schema version (newer backend)
62
+ if (configVer.major > sdkVer.major) {
63
+ warnings.push(`Config schema v${configVersion} is newer than SDK v${SDK_SCHEMA_VERSION}. ` +
64
+ `Some features may not work. Update SDK to latest version.`);
65
+ }
66
+ // Old schema version (older backend or missing version)
67
+ if (configVer.major < sdkVer.major || !typedConfig.schemaVersion) {
68
+ warnings.push(`Config schema v${configVersion} is older than SDK v${SDK_SCHEMA_VERSION}. ` +
69
+ `Migrating config to current version.`);
70
+ return {
71
+ valid: true,
72
+ warnings,
73
+ errors,
74
+ migratedConfig: migrateConfig(typedConfig, configVersion),
75
+ };
76
+ }
77
+ // Compatible version (same major version)
78
+ return {
79
+ valid: true,
80
+ warnings,
81
+ errors,
82
+ };
83
+ }
84
+ /**
85
+ * Migrate old config format to current SDK version.
86
+ *
87
+ * This function applies all necessary transformations to bring
88
+ * an old config up to the current schema version.
89
+ *
90
+ * @param config - Config to migrate
91
+ * @param fromVersion - Version to migrate from
92
+ * @returns Migrated config at current SDK version
93
+ */
94
+ function migrateConfig(config, fromVersion) {
95
+ let migrated = { ...config };
96
+ const fromVer = parseVersion(fromVersion);
97
+ // v1.x -> v2.x migration
98
+ if (fromVer.major === 1) {
99
+ migrated = migrateV1ToV2(migrated);
100
+ }
101
+ // Update schema version to current
102
+ migrated.schemaVersion = SDK_SCHEMA_VERSION;
103
+ return migrated;
104
+ }
105
+ /**
106
+ * Migrate v1.x config to v2.0 format.
107
+ *
108
+ * Changes in v2.0:
109
+ * - Introduced ActivationConfig to replace experiment field
110
+ * - Unified ActionStep format
111
+ * - Added schemaVersion field
112
+ */
113
+ function migrateV1ToV2(config) {
114
+ const migrated = {
115
+ schemaVersion: '2.0',
116
+ tiles: [],
117
+ actions: config.actions || [],
118
+ fetchedAt: config.fetchedAt || new Date().toISOString(),
119
+ };
120
+ // Migrate tiles
121
+ if (config.tiles && Array.isArray(config.tiles)) {
122
+ migrated.tiles = config.tiles.map((tile) => {
123
+ const migratedTile = { ...tile };
124
+ // Migrate deprecated experiment field to activation
125
+ if (tile.experiment && !tile.activation) {
126
+ const exp = tile.experiment;
127
+ // Convert old experiment format to new activation format
128
+ if (exp.featureKey) {
129
+ migratedTile.activation = {
130
+ strategy: {
131
+ type: 'external',
132
+ provider: 'growthbook',
133
+ featureKey: exp.featureKey,
134
+ fallback: false,
135
+ },
136
+ };
137
+ }
138
+ // Remove deprecated field
139
+ delete migratedTile.experiment;
140
+ }
141
+ return migratedTile;
142
+ });
143
+ }
144
+ // Copy optional fields
145
+ if (config.configVersion)
146
+ migrated.configVersion = config.configVersion;
147
+ if (config.canvasTitle)
148
+ migrated.canvasTitle = config.canvasTitle;
149
+ if (config.theme)
150
+ migrated.theme = config.theme;
151
+ if (config.launcher)
152
+ migrated.launcher = config.launcher;
153
+ if (config.routes)
154
+ migrated.routes = config.routes;
155
+ return migrated;
156
+ }
157
+ /**
158
+ * Check if a config needs migration.
159
+ *
160
+ * @param config - Config to check
161
+ * @returns True if migration is needed
162
+ */
163
+ export function needsMigration(config) {
164
+ if (!config || typeof config !== 'object') {
165
+ return false;
166
+ }
167
+ const typedConfig = config;
168
+ const configVersion = typedConfig.schemaVersion || '1.0';
169
+ const configVer = parseVersion(configVersion);
170
+ const sdkVer = parseVersion(SDK_SCHEMA_VERSION);
171
+ return configVer.major < sdkVer.major || !typedConfig.schemaVersion;
172
+ }
173
+ //# sourceMappingURL=config-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-validator.js","sourceRoot":"","sources":["../src/config-validator.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import type { CanvasConfigFetcher } from "./types";
2
- import type { ExperimentClient } from "./experiments/types";
1
+ import type { CanvasConfigFetcher } from './types';
2
+ import type { ExperimentClient } from './experiments/types';
3
3
  export interface CanvasFetcherOptions {
4
4
  configUri?: string;
5
5
  experiments?: ExperimentClient;
@@ -1,3 +1,6 @@
1
+ import { SDK_SCHEMA_VERSION } from './types';
2
+ import { SDK_VERSION } from './version';
3
+ import { debug } from './logger';
1
4
  /**
2
5
  * Allowed hosts for fetching config.
3
6
  * Only config from these hosts will be fetched.
@@ -6,7 +9,7 @@ const ALLOWED_CONFIG_HOSTS = [
6
9
  'api.syntrologie.com',
7
10
  'cdn.syntrologie.com',
8
11
  'localhost',
9
- '127.0.0.1'
12
+ '127.0.0.1',
10
13
  ];
11
14
  /**
12
15
  * Validates that a config URI is from an allowed host.
@@ -22,7 +25,7 @@ function validateConfigUri(uri) {
22
25
  return false;
23
26
  }
24
27
  // Check against allowlist
25
- const isAllowed = ALLOWED_CONFIG_HOSTS.some(host => parsed.hostname === host);
28
+ const isAllowed = ALLOWED_CONFIG_HOSTS.some((host) => parsed.hostname === host);
26
29
  if (!isAllowed) {
27
30
  console.warn('[SmartCanvas] Config URI host not in allowlist:', parsed.hostname);
28
31
  return false;
@@ -48,7 +51,7 @@ function isSameOrigin(uri) {
48
51
  return false;
49
52
  }
50
53
  }
51
- export const resolveConfigUri = ({ configUri, experiments, featureKey = "smart-canvas-config-uri", }) => {
54
+ export const resolveConfigUri = ({ configUri, experiments, featureKey = 'smart-canvas-config-uri', }) => {
52
55
  var _a;
53
56
  if (configUri)
54
57
  return configUri;
@@ -57,21 +60,22 @@ export const resolveConfigUri = ({ configUri, experiments, featureKey = "smart-c
57
60
  return fromFeature;
58
61
  return undefined;
59
62
  };
60
- export const createCanvasConfigFetcher = ({ configUri, experiments, featureKey, credentials, configFeatureKey = "smart-canvas-config", }) => {
63
+ export const createCanvasConfigFetcher = ({ configUri, experiments, featureKey, credentials, configFeatureKey = 'smart-canvas-config', }) => {
61
64
  return async () => {
62
65
  var _a;
63
66
  // First check if we have a direct config object from experiment platform
64
67
  if (experiments && configFeatureKey) {
65
68
  const directConfig = (_a = experiments.getFeatureValue) === null || _a === void 0 ? void 0 : _a.call(experiments, configFeatureKey, null);
66
69
  if (directConfig && typeof directConfig === 'object') {
67
- // Return the config directly - no fetch needed
70
+ debug('SmartCanvas Config', 'Resolved config directly from feature flag', directConfig);
68
71
  return directConfig;
69
72
  }
70
73
  }
71
74
  // Fall back to URI-based fetching
72
75
  const uri = resolveConfigUri({ configUri, experiments, featureKey });
73
76
  if (!uri) {
74
- throw new Error("SmartCanvas: config URI missing (env + feature flag unset).");
77
+ debug('SmartCanvas Config', 'No config available returning empty config');
78
+ return { tiles: [], overlays: [] };
75
79
  }
76
80
  // Security: Validate URI against allowlist
77
81
  if (!validateConfigUri(uri)) {
@@ -80,11 +84,19 @@ export const createCanvasConfigFetcher = ({ configUri, experiments, featureKey,
80
84
  // Security: Only send credentials to same-origin requests
81
85
  // This prevents leaking cookies to third-party servers
82
86
  const effectiveCredentials = credentials !== null && credentials !== void 0 ? credentials : (isSameOrigin(uri) ? 'include' : 'omit');
83
- const response = await fetch(uri, { credentials: effectiveCredentials });
87
+ const response = await fetch(uri, {
88
+ credentials: effectiveCredentials,
89
+ headers: {
90
+ 'X-SDK-Version': SDK_VERSION,
91
+ 'X-SDK-Schema-Version': SDK_SCHEMA_VERSION,
92
+ },
93
+ });
84
94
  if (!response.ok) {
85
95
  throw new Error(`SmartCanvas: failed to fetch config (${response.status})`);
86
96
  }
87
- return await response.json();
97
+ const config = await response.json();
98
+ debug('SmartCanvas Config', 'Fetched config from URI', config);
99
+ return config;
88
100
  };
89
101
  };
90
102
  //# sourceMappingURL=configFetcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"configFetcher.js","sourceRoot":"","sources":["../src/configFetcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"configFetcher.js","sourceRoot":"","sources":["../src/configFetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * ContextManager - Manages runtime context and notifies subscribers of changes.
3
+ *
4
+ * The ContextManager is responsible for:
5
+ * - Collecting context from various sources (page, session, viewport)
6
+ * - Notifying subscribers when context changes
7
+ * - Providing the current context snapshot
8
+ */
9
+ import type { RuntimeContext, AnchorState, ContextChangeCallback, Unsubscribe, PageHistoryEntry } from './types';
10
+ import type { TelemetryClient } from '../telemetry/types';
11
+ import type { RoutesConfig } from '../types';
12
+ export interface ContextManagerOptions {
13
+ /** Telemetry client for session ID */
14
+ telemetry?: TelemetryClient;
15
+ /** Routes config for route matching */
16
+ routes?: RoutesConfig;
17
+ /** Initial page history (optional) */
18
+ initialPageHistory?: PageHistoryEntry[];
19
+ }
20
+ /**
21
+ * ContextManager class for managing runtime context.
22
+ */
23
+ export declare class ContextManager {
24
+ private context;
25
+ private previousContext;
26
+ private listeners;
27
+ private telemetry?;
28
+ private routes?;
29
+ private cleanupFns;
30
+ constructor(options?: ContextManagerOptions);
31
+ /**
32
+ * Get the current runtime context.
33
+ */
34
+ get(): RuntimeContext;
35
+ /**
36
+ * Subscribe to context changes.
37
+ * Returns an unsubscribe function.
38
+ */
39
+ subscribe(callback: ContextChangeCallback): Unsubscribe;
40
+ /**
41
+ * Update the routes config (e.g., when config is fetched).
42
+ */
43
+ setRoutes(routes: RoutesConfig): void;
44
+ /**
45
+ * Update anchor states.
46
+ */
47
+ setAnchors(anchors: AnchorState[]): void;
48
+ /**
49
+ * Manually update the session ID (e.g., when telemetry initializes).
50
+ */
51
+ setSessionId(sessionId: string): void;
52
+ /**
53
+ * Clean up event listeners and subscriptions.
54
+ */
55
+ destroy(): void;
56
+ private setupBrowserListeners;
57
+ private updateViewport;
58
+ private updatePage;
59
+ private addPageToHistory;
60
+ private updateContext;
61
+ private notifyListeners;
62
+ }
63
+ /**
64
+ * Create a ContextManager instance.
65
+ */
66
+ export declare function createContextManager(options?: ContextManagerOptions): ContextManager;
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Creates a default RuntimeContext.
3
+ */
4
+ function createDefaultContext() {
5
+ const now = Date.now();
6
+ return {
7
+ page: {
8
+ url: typeof window !== 'undefined' ? window.location.href : '',
9
+ title: typeof document !== 'undefined' ? document.title : undefined,
10
+ },
11
+ session: {
12
+ sessionId: '',
13
+ startTs: now,
14
+ pageHistory: [],
15
+ },
16
+ viewport: {
17
+ width: typeof window !== 'undefined' ? window.innerWidth : 0,
18
+ height: typeof window !== 'undefined' ? window.innerHeight : 0,
19
+ },
20
+ };
21
+ }
22
+ /**
23
+ * Match a URL against route patterns from RoutesConfig.
24
+ * Returns the matched pattern or undefined.
25
+ */
26
+ function matchRoute(url, routes) {
27
+ if (!routes)
28
+ return undefined;
29
+ // Extract pathname from URL
30
+ let pathname;
31
+ try {
32
+ pathname = new URL(url).pathname;
33
+ }
34
+ catch {
35
+ pathname = url;
36
+ }
37
+ // Check exclude patterns first
38
+ if (routes.exclude) {
39
+ for (const pattern of routes.exclude) {
40
+ if (matchPattern(pathname, pattern)) {
41
+ return undefined; // Excluded route
42
+ }
43
+ }
44
+ }
45
+ // Check include patterns
46
+ if (routes.include) {
47
+ for (const pattern of routes.include) {
48
+ if (matchPattern(pathname, pattern)) {
49
+ return pattern;
50
+ }
51
+ }
52
+ return undefined; // No match in include list
53
+ }
54
+ return pathname; // No include list, return pathname as route
55
+ }
56
+ /**
57
+ * Simple pattern matching for routes.
58
+ * Supports:
59
+ * - Exact matches: "/products"
60
+ * - Wildcard segments: "/products/*"
61
+ * - Parameter segments: "/products/:id"
62
+ */
63
+ function matchPattern(pathname, pattern) {
64
+ // Normalize paths
65
+ const normalizedPath = pathname.replace(/\/$/, '') || '/';
66
+ const normalizedPattern = pattern.replace(/\/$/, '') || '/';
67
+ // Exact match
68
+ if (normalizedPath === normalizedPattern)
69
+ return true;
70
+ // Convert pattern to regex
71
+ const regexPattern = normalizedPattern
72
+ .replace(/:[^/]+/g, '[^/]+') // :param -> [^/]+
73
+ .replace(/\*/g, '.*'); // * -> .*
74
+ const regex = new RegExp(`^${regexPattern}$`);
75
+ return regex.test(normalizedPath);
76
+ }
77
+ /**
78
+ * ContextManager class for managing runtime context.
79
+ */
80
+ export class ContextManager {
81
+ constructor(options = {}) {
82
+ var _a;
83
+ this.listeners = new Set();
84
+ // Event listener cleanup functions
85
+ this.cleanupFns = [];
86
+ this.telemetry = options.telemetry;
87
+ this.routes = options.routes;
88
+ // Initialize context
89
+ this.context = createDefaultContext();
90
+ this.previousContext = { ...this.context };
91
+ // Set initial session ID from telemetry
92
+ if ((_a = options.telemetry) === null || _a === void 0 ? void 0 : _a.getSessionId) {
93
+ const sessionId = options.telemetry.getSessionId();
94
+ if (sessionId) {
95
+ this.context.session.sessionId = sessionId;
96
+ }
97
+ }
98
+ // Set initial page history
99
+ if (options.initialPageHistory) {
100
+ this.context.session.pageHistory = options.initialPageHistory;
101
+ }
102
+ // Set initial route ID
103
+ this.context.page.routeId = matchRoute(this.context.page.url, this.routes);
104
+ // Add current page to history
105
+ this.addPageToHistory(this.context.page.url);
106
+ // Setup browser event listeners
107
+ if (typeof window !== 'undefined') {
108
+ this.setupBrowserListeners();
109
+ }
110
+ }
111
+ /**
112
+ * Get the current runtime context.
113
+ */
114
+ get() {
115
+ return { ...this.context };
116
+ }
117
+ /**
118
+ * Subscribe to context changes.
119
+ * Returns an unsubscribe function.
120
+ */
121
+ subscribe(callback) {
122
+ this.listeners.add(callback);
123
+ return () => {
124
+ this.listeners.delete(callback);
125
+ };
126
+ }
127
+ /**
128
+ * Update the routes config (e.g., when config is fetched).
129
+ */
130
+ setRoutes(routes) {
131
+ this.routes = routes;
132
+ // Re-evaluate current route
133
+ const newRouteId = matchRoute(this.context.page.url, this.routes);
134
+ if (newRouteId !== this.context.page.routeId) {
135
+ this.updateContext({ page: { ...this.context.page, routeId: newRouteId } });
136
+ }
137
+ }
138
+ /**
139
+ * Update anchor states.
140
+ */
141
+ setAnchors(anchors) {
142
+ this.updateContext({ anchors });
143
+ }
144
+ /**
145
+ * Manually update the session ID (e.g., when telemetry initializes).
146
+ */
147
+ setSessionId(sessionId) {
148
+ if (sessionId !== this.context.session.sessionId) {
149
+ this.updateContext({
150
+ session: { ...this.context.session, sessionId },
151
+ });
152
+ }
153
+ }
154
+ /**
155
+ * Clean up event listeners and subscriptions.
156
+ */
157
+ destroy() {
158
+ for (const cleanup of this.cleanupFns) {
159
+ cleanup();
160
+ }
161
+ this.cleanupFns = [];
162
+ this.listeners.clear();
163
+ }
164
+ // ==================== Private Methods ====================
165
+ setupBrowserListeners() {
166
+ // Viewport resize listener (debounced)
167
+ let resizeTimeout;
168
+ const handleResize = () => {
169
+ clearTimeout(resizeTimeout);
170
+ resizeTimeout = setTimeout(() => {
171
+ this.updateViewport();
172
+ }, 100);
173
+ };
174
+ window.addEventListener('resize', handleResize);
175
+ this.cleanupFns.push(() => window.removeEventListener('resize', handleResize));
176
+ // Navigation listener (popstate for back/forward)
177
+ const handlePopState = () => {
178
+ this.updatePage();
179
+ };
180
+ window.addEventListener('popstate', handlePopState);
181
+ this.cleanupFns.push(() => window.removeEventListener('popstate', handlePopState));
182
+ // History pushState/replaceState interception
183
+ const originalPushState = history.pushState.bind(history);
184
+ const originalReplaceState = history.replaceState.bind(history);
185
+ history.pushState = (...args) => {
186
+ originalPushState(...args);
187
+ this.updatePage();
188
+ };
189
+ history.replaceState = (...args) => {
190
+ originalReplaceState(...args);
191
+ this.updatePage();
192
+ };
193
+ this.cleanupFns.push(() => {
194
+ history.pushState = originalPushState;
195
+ history.replaceState = originalReplaceState;
196
+ });
197
+ }
198
+ updateViewport() {
199
+ const newViewport = {
200
+ width: window.innerWidth,
201
+ height: window.innerHeight,
202
+ };
203
+ if (newViewport.width !== this.context.viewport.width ||
204
+ newViewport.height !== this.context.viewport.height) {
205
+ this.updateContext({ viewport: newViewport });
206
+ }
207
+ }
208
+ updatePage() {
209
+ const url = window.location.href;
210
+ const title = document.title;
211
+ const routeId = matchRoute(url, this.routes);
212
+ const newPage = {
213
+ url,
214
+ title,
215
+ routeId,
216
+ };
217
+ // Only update if something changed
218
+ if (newPage.url !== this.context.page.url ||
219
+ newPage.title !== this.context.page.title ||
220
+ newPage.routeId !== this.context.page.routeId) {
221
+ // Add to page history if URL changed
222
+ if (newPage.url !== this.context.page.url) {
223
+ this.addPageToHistory(newPage.url);
224
+ }
225
+ this.updateContext({ page: newPage });
226
+ }
227
+ }
228
+ addPageToHistory(url) {
229
+ const entry = {
230
+ url,
231
+ ts: Date.now(),
232
+ };
233
+ const pageHistory = [...(this.context.session.pageHistory || []), entry];
234
+ // Keep last 50 pages in history
235
+ if (pageHistory.length > 50) {
236
+ pageHistory.shift();
237
+ }
238
+ this.context.session.pageHistory = pageHistory;
239
+ }
240
+ updateContext(partial) {
241
+ // Save previous context
242
+ this.previousContext = { ...this.context };
243
+ // Merge updates
244
+ this.context = {
245
+ ...this.context,
246
+ ...partial,
247
+ };
248
+ // Notify listeners
249
+ this.notifyListeners();
250
+ }
251
+ notifyListeners() {
252
+ for (const callback of this.listeners) {
253
+ try {
254
+ callback(this.context, this.previousContext);
255
+ }
256
+ catch (err) {
257
+ console.error('[ContextManager] Listener error:', err);
258
+ }
259
+ }
260
+ }
261
+ }
262
+ /**
263
+ * Create a ContextManager instance.
264
+ */
265
+ export function createContextManager(options = {}) {
266
+ return new ContextManager(options);
267
+ }
268
+ //# sourceMappingURL=ContextManager.js.map