@syntrologie/runtime-sdk 2.10.0 → 2.12.0

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 (45) hide show
  1. package/CAPABILITIES.md +176 -117
  2. package/README.md +2 -0
  3. package/dist/actions/schema.d.ts +7 -7
  4. package/dist/actions/schema.js +1 -1
  5. package/dist/actions/types.d.ts +1 -1
  6. package/dist/actions/validation-core.d.ts +24 -0
  7. package/dist/actions/validation-rules.d.ts +74 -0
  8. package/dist/actions/validation.d.ts +5 -11
  9. package/dist/bootstrap-init.d.ts +33 -0
  10. package/dist/bootstrap-runtime.d.ts +7 -0
  11. package/dist/bootstrap-types.d.ts +90 -0
  12. package/dist/bootstrap.d.ts +17 -83
  13. package/dist/{chunk-OIDBMIRB.js → chunk-J2LGX2PV.js} +1282 -488
  14. package/dist/chunk-J2LGX2PV.js.map +7 -0
  15. package/dist/{chunk-R5DNAIRI.js → chunk-L6RJMBR2.js} +2 -2
  16. package/dist/{chunk-R5DNAIRI.js.map → chunk-L6RJMBR2.js.map} +2 -2
  17. package/dist/events/EventBus.d.ts +27 -1
  18. package/dist/events/history.d.ts +9 -0
  19. package/dist/events/index.d.ts +3 -0
  20. package/dist/events/normalizers/posthog.d.ts +4 -50
  21. package/dist/events/types.d.ts +30 -23
  22. package/dist/events/validation.d.ts +7 -0
  23. package/dist/index.d.ts +0 -2
  24. package/dist/index.js +1125 -2027
  25. package/dist/index.js.map +4 -4
  26. package/dist/overlays/runtime/overlay/overlay-runner.d.ts +4 -0
  27. package/dist/overlays/runtime/overlay/overlay-state.d.ts +21 -0
  28. package/dist/overlays/types.d.ts +3 -1
  29. package/dist/react.js +4 -2
  30. package/dist/react.js.map +2 -2
  31. package/dist/smart-canvas.esm.js +92 -108
  32. package/dist/smart-canvas.esm.js.map +4 -4
  33. package/dist/smart-canvas.js +5225 -5012
  34. package/dist/smart-canvas.js.map +4 -4
  35. package/dist/smart-canvas.min.js +92 -108
  36. package/dist/smart-canvas.min.js.map +4 -4
  37. package/dist/telemetry/adapters/posthog.d.ts +30 -4
  38. package/dist/test/setup.d.ts +1 -0
  39. package/dist/token.d.ts +2 -0
  40. package/dist/version.d.ts +1 -1
  41. package/package.json +23 -28
  42. package/schema/canvas-config.schema.json +1 -1
  43. package/scripts/syntroReactPlugin.mjs +3 -0
  44. package/scripts/validate-config.mjs +42 -0
  45. package/dist/chunk-OIDBMIRB.js.map +0 -7
@@ -32,10 +32,12 @@ export interface PostHogAdapterOptions {
32
32
  */
33
33
  sessionRecording?: boolean;
34
34
  /**
35
- * Enable pageview capture.
36
- * @default true
35
+ * Pageview capture mode.
36
+ * - true: capture only on initial page load
37
+ * - 'history_change': auto-capture on SPA navigation (pushState/replaceState)
38
+ * @default "history_change"
37
39
  */
38
- capturePageview?: boolean;
40
+ capturePageview?: boolean | 'history_change';
39
41
  /**
40
42
  * Enable page leave capture.
41
43
  * @default true
@@ -71,6 +73,18 @@ export interface PostHogAdapterOptions {
71
73
  * @default false
72
74
  */
73
75
  requireExplicitConsent?: boolean;
76
+ /**
77
+ * Enable behavioral signal detection (hesitation, rage click, etc.)
78
+ * Pass `true` for defaults, or a partial DetectorConfig to customize thresholds.
79
+ * @default false
80
+ */
81
+ behavioralSignals?: boolean | Record<string, number>;
82
+ /**
83
+ * Callback for raw rrweb events from session recording.
84
+ * Called with each rrweb eventWithTime before PostHog processes it.
85
+ * Used by the event processor for behavioral signal detection.
86
+ */
87
+ onRRWebEvent?: (event: Record<string, unknown>) => void;
74
88
  }
75
89
  interface CanvasAnalyticsPayload extends Properties {
76
90
  rectangleId?: string;
@@ -84,13 +98,25 @@ export declare class PostHogAdapter implements TelemetryClient {
84
98
  private client?;
85
99
  private featureFlagsCallback?;
86
100
  private captureCallback?;
87
- private consentUnsub?;
101
+ private rrwebCallback?;
88
102
  constructor(options?: PostHogAdapterOptions);
89
103
  /**
90
104
  * Initialize the PostHog client. Called immediately (no consent gate)
91
105
  * or deferred (when consent gate grants).
92
106
  */
93
107
  private initPostHog;
108
+ /**
109
+ * Set up rrweb event interception on PostHog's session recording.
110
+ *
111
+ * PostHog lazy-loads the rrweb recorder. The SessionRecording wrapper has
112
+ * an `onRRwebEmit` method, but rrweb delivers events directly to the
113
+ * lazy-loaded recorder instance's `onRRwebEmit`, bypassing the wrapper.
114
+ * We must find and patch the recorder instance, not the wrapper.
115
+ *
116
+ * The recorder instance is stored on a minified property of SessionRecording.
117
+ * We detect it by looking for an object with both `onRRwebEmit` and `start` methods.
118
+ */
119
+ private setupRRWebIntercept;
94
120
  /**
95
121
  * Get all feature flags from PostHog.
96
122
  * Used to extract segment membership flags (in_segment_*).
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom/vitest';
package/dist/token.d.ts CHANGED
@@ -20,6 +20,8 @@ export interface SyntroTokenPayload {
20
20
  f?: string;
21
21
  /** Fetcher-specific options (e.g., configId for cdn fetcher) */
22
22
  o?: Record<string, string>;
23
+ /** Geo worker URL (e.g., "https://dev-geo.syntrologie.com" for dev) */
24
+ g?: string;
23
25
  /** Debug mode - enables console logging (default: false) */
24
26
  d?: boolean;
25
27
  }
package/dist/version.d.ts CHANGED
@@ -10,4 +10,4 @@
10
10
  *
11
11
  * @since 2.0.0
12
12
  */
13
- export declare const SDK_VERSION = "2.10.0";
13
+ export declare const SDK_VERSION = "2.12.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntrologie/runtime-sdk",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "Syntrologie Runtime SDK for web experimentation and analytics",
5
5
  "license": "Proprietary",
6
6
  "private": false,
@@ -61,21 +61,16 @@
61
61
  "validate-config": "node ./scripts/validate-config.mjs",
62
62
  "typecheck": "tsc --noEmit -p tsconfig.build.json",
63
63
  "test": "vitest run",
64
- "prepublishOnly": "npm run clean && npm run build"
64
+ "strip-internal-deps": "node ./scripts/strip-internal-deps.mjs",
65
+ "prepublishOnly": "npm run clean && npm run build && npm run strip-internal-deps"
65
66
  },
66
67
  "dependencies": {
67
- "@floating-ui/dom": "^1.7.5",
68
+ "@floating-ui/dom": "1.7.5",
68
69
  "@growthbook/growthbook": "~1.6.2",
69
- "@growthbook/growthbook-react": "^1.6.4",
70
- "@syntrologie/adapt-chatbot": "2.10.0",
71
- "@syntrologie/adapt-content": "2.10.0",
72
- "@syntrologie/adapt-faq": "2.10.0",
73
- "@syntrologie/adapt-gamification": "2.10.0",
74
- "@syntrologie/adapt-nav": "2.10.0",
75
- "@syntrologie/adapt-overlays": "2.10.0",
76
- "lucide-react": "^0.576.0",
77
- "posthog-js": "~1.302.2",
78
- "zod": "^3.25.76"
70
+ "@growthbook/growthbook-react": "1.6.4",
71
+ "lucide-react": "0.576.0",
72
+ "posthog-js": "1.341.0",
73
+ "zod": "3.25.76"
79
74
  },
80
75
  "peerDependencies": {
81
76
  "react": ">=18.0.0",
@@ -86,21 +81,21 @@
86
81
  "@semantic-release/github": "~12.0.3",
87
82
  "@semantic-release/npm": "~13.1.3",
88
83
  "@syntro/design-system": "*",
89
- "@testing-library/dom": "^10.4.1",
90
- "@testing-library/jest-dom": "^6.9.1",
91
- "@testing-library/react": "^16.3.2",
92
- "@types/node": "^22.19.7",
93
- "@types/react": "^19.2.0",
94
- "@types/react-dom": "^19.2.0",
95
- "ajv": "^8.18.0",
96
- "ajv-formats": "^3.0.1",
97
- "esbuild": "^0.27.2",
98
- "jsdom": "^26.1.0",
99
- "react": "^19.2.0",
100
- "react-dom": "^19.2.0",
84
+ "@testing-library/dom": "10.4.1",
85
+ "@testing-library/jest-dom": "6.9.1",
86
+ "@testing-library/react": "16.3.2",
87
+ "@types/node": "22.19.7",
88
+ "@types/react": "19.2.14",
89
+ "@types/react-dom": "19.2.3",
90
+ "ajv": "8.18.0",
91
+ "ajv-formats": "3.0.1",
92
+ "esbuild": "0.27.2",
93
+ "jsdom": "26.1.0",
94
+ "react": "19.2.1",
95
+ "react-dom": "19.2.1",
101
96
  "semantic-release": "~25.0.3",
102
- "typescript": "^5.9.3",
103
- "vitest": "^4.0.18",
104
- "zod-to-json-schema": "^3.25.1"
97
+ "typescript": "5.9.3",
98
+ "vitest": "4.0.18",
99
+ "zod-to-json-schema": "3.25.1"
105
100
  }
106
101
  }
@@ -9337,7 +9337,7 @@
9337
9337
  "properties": {
9338
9338
  "kind": {
9339
9339
  "type": "string",
9340
- "const": "core:tour"
9340
+ "const": "overlays:tour"
9341
9341
  },
9342
9342
  "tourId": {
9343
9343
  "type": "string"
@@ -71,6 +71,9 @@ export const syntroReactPlugin = {
71
71
  export function useReducer() { return _R().useReducer.apply(null, arguments); }
72
72
  export function useLayoutEffect() { return _R().useLayoutEffect.apply(null, arguments); }
73
73
  export function useId() { return _R().useId.apply(null, arguments); }
74
+ export function useSyncExternalStore() { return _R().useSyncExternalStore.apply(null, arguments); }
75
+ export function useDebugValue() { return _R().useDebugValue.apply(null, arguments); }
76
+ export function useInsertionEffect() { return _R().useInsertionEffect.apply(null, arguments); }
74
77
 
75
78
  // Creation APIs — lazy function wrappers
76
79
  export function createElement() { return _R().createElement.apply(null, arguments); }
@@ -119,6 +119,29 @@ if (semanticErrors.length > 0) {
119
119
  process.exit(1);
120
120
  }
121
121
 
122
+ // --- Semantic check: tiles with notifications must have actions ---
123
+ // Notifications reference content (FAQ items, nav tips) that lives in
124
+ // tile.props.actions. Without actions, notifications have nothing to show.
125
+ for (const tile of config.tiles ?? []) {
126
+ const notifications = tile.notifications ?? [];
127
+ if (notifications.length === 0) continue;
128
+
129
+ const actions = tile.props?.actions ?? [];
130
+ if (actions.length === 0) {
131
+ semanticErrors.push(
132
+ `Tile "${tile.id}": has ${notifications.length} notification(s) but no actions.\n` +
133
+ ` Notifications reference tile content (FAQ items, nav tips) defined in tile.props.actions.\n` +
134
+ ` Add actions to the tile, or remove the notifications.`
135
+ );
136
+ }
137
+ }
138
+
139
+ if (semanticErrors.length > 0) {
140
+ console.error(`\n\u274C ${semanticErrors.length} semantic error(s):`);
141
+ for (const e of semanticErrors) console.error(` - ${e}`);
142
+ process.exit(1);
143
+ }
144
+
122
145
  // --- Semantic check: anchorId.route must include at least one concrete route ---
123
146
  // Wildcards allowed by canvas-config.schema.json anchorId.route;
124
147
  // update here if the schema adds new glob patterns.
@@ -241,6 +264,25 @@ for (const { path, url } of pageUrlHits) {
241
264
  }
242
265
  }
243
266
 
267
+ // Hidden insertHtml without a triggerWhen is dead HTML — the SDK has no way to show it.
268
+ // The LLM sometimes generates `display:none` elements expecting a trigger type (e.g.,
269
+ // exit-intent) that doesn't exist in the SDK. Without triggerWhen, the element is
270
+ // injected hidden and stays hidden forever.
271
+ for (const [i, action] of (config.actions ?? []).entries()) {
272
+ if (action.kind !== 'content:insertHtml') continue;
273
+ if (action.triggerWhen) continue;
274
+ const html = action.html ?? '';
275
+ if (!/display\s*:\s*none/i.test(html)) continue;
276
+
277
+ const label = action.label ? ` (label: "${action.label}")` : '';
278
+ warnings.push(
279
+ `actions[${i}]${label}: content:insertHtml injects hidden HTML (display:none) with no triggerWhen.\n` +
280
+ ` This element will be inserted into the DOM but never shown — the SDK has no mechanism to reveal it.\n` +
281
+ ` Either add a triggerWhen with a valid condition (e.g., event_count, session_metric) to control visibility,\n` +
282
+ ` or remove display:none to show it immediately.`
283
+ );
284
+ }
285
+
244
286
  if (warnings.length > 0) {
245
287
  console.warn(`\n\u26A0\uFE0F ${warnings.length} design warning(s):`);
246
288
  for (const w of warnings) console.warn(` - ${w}`);