@syntrologie/runtime-sdk 2.2.0-canary.8 → 2.2.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/README.md +2 -1
  2. package/dist/actions/types.d.ts +7 -0
  3. package/dist/antiFlicker.d.ts +2 -0
  4. package/dist/apps/builtinRuntimeModules.generated.d.ts +20 -0
  5. package/dist/{chunk-MEBUEMEZ.js → chunk-V4MDQX67.js} +2868 -1417
  6. package/dist/chunk-V4MDQX67.js.map +7 -0
  7. package/dist/configFetcher.d.ts +3 -1
  8. package/dist/context/ContextManager.d.ts +4 -0
  9. package/dist/diagnostics/service-worker-check.d.ts +23 -0
  10. package/dist/editorLoader.d.ts +8 -2
  11. package/dist/index.d.ts +3 -0
  12. package/dist/index.js +1563 -12
  13. package/dist/index.js.map +4 -4
  14. package/dist/integrations/gtm-bridge.d.ts +36 -0
  15. package/dist/navigation/NavigationMonitor.d.ts +45 -0
  16. package/dist/overlays/runtime/utils/AnchorWatcher.d.ts +22 -0
  17. package/dist/overlays/types.d.ts +2 -0
  18. package/dist/react.js +1 -1
  19. package/dist/runtime.d.ts +3 -0
  20. package/dist/smart-canvas.esm.js +62 -36
  21. package/dist/smart-canvas.esm.js.map +4 -4
  22. package/dist/smart-canvas.js +15828 -23049
  23. package/dist/smart-canvas.js.map +4 -4
  24. package/dist/smart-canvas.min.js +62 -36
  25. package/dist/smart-canvas.min.js.map +4 -4
  26. package/dist/telemetry/adapters/posthog.d.ts +19 -0
  27. package/dist/telemetry/consent.d.ts +62 -0
  28. package/dist/version.d.ts +1 -1
  29. package/dist/widgets/WidgetRegistry.d.ts +10 -0
  30. package/package.json +13 -4
  31. package/schema/canvas-config.schema.json +124 -22
  32. package/scripts/syntroReactPlugin.mjs +113 -0
  33. package/dist/adaptives/adaptive-chatbot/index.js +0 -9
  34. package/dist/adaptives/adaptive-chatbot/index.js.map +0 -7
  35. package/dist/adaptives/adaptive-content/index.js +0 -22
  36. package/dist/adaptives/adaptive-content/index.js.map +0 -7
  37. package/dist/adaptives/adaptive-faq/index.js +0 -28
  38. package/dist/adaptives/adaptive-faq/index.js.map +0 -7
  39. package/dist/adaptives/adaptive-gamification/index.js +0 -2
  40. package/dist/adaptives/adaptive-gamification/index.js.map +0 -7
  41. package/dist/adaptives/adaptive-nav/index.js +0 -27
  42. package/dist/adaptives/adaptive-nav/index.js.map +0 -7
  43. package/dist/adaptives/adaptive-overlays/index.js +0 -94
  44. package/dist/adaptives/adaptive-overlays/index.js.map +0 -7
  45. package/dist/chunk-MEBUEMEZ.js.map +0 -7
@@ -5,6 +5,7 @@
5
5
  * and use the TelemetryClient interface.
6
6
  */
7
7
  import type { PostHog, Properties } from 'posthog-js';
8
+ import type { ConsentGate } from '../consent';
8
9
  import type { CanvasSurface, TelemetryClient } from '../types';
9
10
  export interface PostHogAdapterOptions {
10
11
  /**
@@ -58,6 +59,18 @@ export interface PostHogAdapterOptions {
58
59
  * Used to feed events into the EventBus for runtime decisions.
59
60
  */
60
61
  onCapture?: (eventName: string, properties?: Record<string, unknown>) => void;
62
+ /**
63
+ * Consent gate for GDPR compliance.
64
+ * When provided with requireExplicitConsent, PostHog initialization is
65
+ * deferred until consent is granted.
66
+ */
67
+ consent?: ConsentGate;
68
+ /**
69
+ * Require explicit consent before initializing PostHog.
70
+ * When true, PostHog will not init until consent.grant() is called.
71
+ * @default false
72
+ */
73
+ requireExplicitConsent?: boolean;
61
74
  }
62
75
  interface CanvasAnalyticsPayload extends Properties {
63
76
  rectangleId?: string;
@@ -71,7 +84,13 @@ export declare class PostHogAdapter implements TelemetryClient {
71
84
  private client?;
72
85
  private featureFlagsCallback?;
73
86
  private captureCallback?;
87
+ private consentUnsub?;
74
88
  constructor(options?: PostHogAdapterOptions);
89
+ /**
90
+ * Initialize the PostHog client. Called immediately (no consent gate)
91
+ * or deferred (when consent gate grants).
92
+ */
93
+ private initPostHog;
75
94
  /**
76
95
  * Get all feature flags from PostHog.
77
96
  * Used to extract segment membership flags (in_segment_*).
@@ -0,0 +1,62 @@
1
+ /**
2
+ * ConsentGate - GDPR-compliant consent management for telemetry.
3
+ *
4
+ * Gates PostHog (and any future telemetry provider) initialization on
5
+ * user consent status. Supports:
6
+ * - Explicit consent requirement (opt-in model)
7
+ * - GTM Consent Mode v2 integration (reads analytics_storage from dataLayer)
8
+ * - Programmatic grant/deny API for host page consent banners
9
+ *
10
+ * The ConsentGate lives in the runtime (not the PostHog adapter) because
11
+ * consent is provider-agnostic — if we switch from PostHog to Segment or
12
+ * another provider, consent logic should not change.
13
+ */
14
+ export type ConsentStatus = 'granted' | 'denied' | 'pending';
15
+ export interface ConsentConfig {
16
+ /** Initial consent status. Default: 'pending' */
17
+ initialStatus?: ConsentStatus;
18
+ /** If true, telemetry is blocked until grant() is called. Default: false */
19
+ requireExplicitConsent?: boolean;
20
+ /** Read consent state from GTM's window.dataLayer consent events. Default: false */
21
+ readFromGtmConsentMode?: boolean;
22
+ /** Called whenever consent status changes. */
23
+ onConsentChange?: (status: ConsentStatus) => void;
24
+ }
25
+ type ConsentListener = (status: ConsentStatus) => void;
26
+ export declare class ConsentGate {
27
+ private status;
28
+ private listeners;
29
+ private configCallback?;
30
+ private gtmEnabled;
31
+ private destroyed;
32
+ constructor(config?: ConsentConfig);
33
+ /**
34
+ * Grant consent — enables telemetry collection.
35
+ */
36
+ grant(): void;
37
+ /**
38
+ * Deny consent — disables telemetry collection.
39
+ */
40
+ deny(): void;
41
+ /**
42
+ * Get the current consent status.
43
+ */
44
+ getStatus(): ConsentStatus;
45
+ /**
46
+ * Subscribe to consent status changes.
47
+ * Returns an unsubscribe function.
48
+ */
49
+ subscribe(listener: ConsentListener): () => void;
50
+ /**
51
+ * Poll GTM's dataLayer for consent state.
52
+ * Scans for the most recent consent update event with analytics_storage.
53
+ */
54
+ pollGtmConsent(): void;
55
+ /**
56
+ * Clean up listeners and stop responding to changes.
57
+ */
58
+ destroy(): void;
59
+ private setStatus;
60
+ private notify;
61
+ }
62
+ export {};
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.2.0-canary.8";
13
+ export declare const SDK_VERSION = "2.2.0";
@@ -68,11 +68,16 @@ export interface MountedWidgetHandle {
68
68
  * Allows apps to register custom widgets that can be rendered via
69
69
  * mountWidget actions or directly through the Surfaces system.
70
70
  */
71
+ export type WidgetRegistryListener = (event: {
72
+ type: 'registered' | 'unregistered';
73
+ widgetId: string;
74
+ }) => void;
71
75
  export declare class WidgetRegistry {
72
76
  private widgets;
73
77
  private mountedWidgets;
74
78
  private mountIdCounter;
75
79
  private runtimeRef?;
80
+ private listeners;
76
81
  /**
77
82
  * Bind a runtime reference so it can be injected into widget mount() calls.
78
83
  * Uses `unknown` to avoid circular imports (WidgetRegistry ← runtime.ts).
@@ -133,6 +138,11 @@ export declare class WidgetRegistry {
133
138
  * Get all widgets from a specific source.
134
139
  */
135
140
  getBySource(source: string): WidgetRegistration[];
141
+ /**
142
+ * Subscribe to widget registration changes.
143
+ */
144
+ subscribe(callback: WidgetRegistryListener): () => void;
145
+ private notify;
136
146
  /**
137
147
  * Clean up all mounted widgets.
138
148
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntrologie/runtime-sdk",
3
- "version": "2.2.0-canary.8",
3
+ "version": "2.2.0",
4
4
  "description": "Syntrologie Runtime SDK for web experimentation and analytics",
5
5
  "license": "Proprietary",
6
6
  "private": false,
@@ -35,12 +35,16 @@
35
35
  "./cdn": {
36
36
  "import": "./dist/smart-canvas.esm.js",
37
37
  "require": "./dist/smart-canvas.js"
38
+ },
39
+ "./build-plugin": {
40
+ "import": "./scripts/syntroReactPlugin.mjs"
38
41
  }
39
42
  },
40
43
  "files": [
41
44
  "dist",
42
45
  "schema",
43
46
  "scripts/validate-config.mjs",
47
+ "scripts/syntroReactPlugin.mjs",
44
48
  "CAPABILITIES.md"
45
49
  ],
46
50
  "scripts": {
@@ -48,7 +52,8 @@
48
52
  "aggregate-capabilities": "node ./scripts/aggregate-capabilities.mjs",
49
53
  "generate-schema": "node ./scripts/generate-unified-schema.mjs",
50
54
  "generate-schema:check": "node ./scripts/generate-unified-schema.mjs --check",
51
- "build": "npm run aggregate-capabilities && npm run build:types && npm run build:lib && npm run generate-schema && npm run build:cdn",
55
+ "generate:builtin-modules": "node ./scripts/generate-builtin-runtime-modules.mjs",
56
+ "build": "npm run aggregate-capabilities && npm run generate:builtin-modules && npm run build:types && npm run build:lib && npm run generate-schema && npm run build:cdn",
52
57
  "build:types": "tsc --project tsconfig.build.json",
53
58
  "build:lib": "node ./scripts/build-lib.mjs",
54
59
  "build:cdn": "node ./scripts/build-cdn.js",
@@ -62,8 +67,12 @@
62
67
  "@floating-ui/dom": "^1.7.5",
63
68
  "@growthbook/growthbook": "~1.6.2",
64
69
  "@growthbook/growthbook-react": "^1.6.4",
65
- "@syntrologie/adapt-content": "2.2.0-canary.8",
66
- "@syntrologie/adapt-overlays": "2.2.0-canary.8",
70
+ "@syntrologie/adapt-chatbot": "2.2.0",
71
+ "@syntrologie/adapt-content": "2.2.0",
72
+ "@syntrologie/adapt-faq": "2.2.0",
73
+ "@syntrologie/adapt-gamification": "2.2.0",
74
+ "@syntrologie/adapt-nav": "2.2.0",
75
+ "@syntrologie/adapt-overlays": "2.2.0",
67
76
  "posthog-js": "~1.302.2",
68
77
  "zod": "^3.25.76"
69
78
  },
@@ -1711,6 +1711,28 @@
1711
1711
  "type": "null"
1712
1712
  }
1713
1713
  ]
1714
+ },
1715
+ "notify": {
1716
+ "anyOf": [
1717
+ {
1718
+ "type": "object",
1719
+ "properties": {
1720
+ "title": {
1721
+ "type": "string"
1722
+ },
1723
+ "body": {
1724
+ "type": "string"
1725
+ },
1726
+ "icon": {
1727
+ "type": "string"
1728
+ }
1729
+ },
1730
+ "additionalProperties": false
1731
+ },
1732
+ {
1733
+ "type": "null"
1734
+ }
1735
+ ]
1714
1736
  }
1715
1737
  },
1716
1738
  "required": [
@@ -2067,6 +2089,28 @@
2067
2089
  "type": "null"
2068
2090
  }
2069
2091
  ]
2092
+ },
2093
+ "notify": {
2094
+ "anyOf": [
2095
+ {
2096
+ "type": "object",
2097
+ "properties": {
2098
+ "title": {
2099
+ "type": "string"
2100
+ },
2101
+ "body": {
2102
+ "type": "string"
2103
+ },
2104
+ "icon": {
2105
+ "type": "string"
2106
+ }
2107
+ },
2108
+ "additionalProperties": false
2109
+ },
2110
+ {
2111
+ "type": "null"
2112
+ }
2113
+ ]
2070
2114
  }
2071
2115
  },
2072
2116
  "required": [
@@ -2329,19 +2373,26 @@
2329
2373
  ]
2330
2374
  },
2331
2375
  "notify": {
2332
- "type": "object",
2333
- "properties": {
2334
- "title": {
2335
- "type": "string"
2336
- },
2337
- "body": {
2338
- "type": "string"
2376
+ "anyOf": [
2377
+ {
2378
+ "type": "object",
2379
+ "properties": {
2380
+ "title": {
2381
+ "type": "string"
2382
+ },
2383
+ "body": {
2384
+ "type": "string"
2385
+ },
2386
+ "icon": {
2387
+ "type": "string"
2388
+ }
2389
+ },
2390
+ "additionalProperties": false
2339
2391
  },
2340
- "icon": {
2341
- "type": "string"
2392
+ {
2393
+ "type": "null"
2342
2394
  }
2343
- },
2344
- "additionalProperties": false
2395
+ ]
2345
2396
  },
2346
2397
  "rationale": {
2347
2398
  "type": "object",
@@ -2692,6 +2743,28 @@
2692
2743
  "type": "null"
2693
2744
  }
2694
2745
  ]
2746
+ },
2747
+ "notify": {
2748
+ "anyOf": [
2749
+ {
2750
+ "type": "object",
2751
+ "properties": {
2752
+ "title": {
2753
+ "type": "string"
2754
+ },
2755
+ "body": {
2756
+ "type": "string"
2757
+ },
2758
+ "icon": {
2759
+ "type": "string"
2760
+ }
2761
+ },
2762
+ "additionalProperties": false
2763
+ },
2764
+ {
2765
+ "type": "null"
2766
+ }
2767
+ ]
2695
2768
  }
2696
2769
  },
2697
2770
  "required": [
@@ -3169,6 +3242,28 @@
3169
3242
  "type": "null"
3170
3243
  }
3171
3244
  ]
3245
+ },
3246
+ "notify": {
3247
+ "anyOf": [
3248
+ {
3249
+ "type": "object",
3250
+ "properties": {
3251
+ "title": {
3252
+ "type": "string"
3253
+ },
3254
+ "body": {
3255
+ "type": "string"
3256
+ },
3257
+ "icon": {
3258
+ "type": "string"
3259
+ }
3260
+ },
3261
+ "additionalProperties": false
3262
+ },
3263
+ {
3264
+ "type": "null"
3265
+ }
3266
+ ]
3172
3267
  }
3173
3268
  },
3174
3269
  "required": [
@@ -3431,19 +3526,26 @@
3431
3526
  ]
3432
3527
  },
3433
3528
  "notify": {
3434
- "type": "object",
3435
- "properties": {
3436
- "title": {
3437
- "type": "string"
3438
- },
3439
- "body": {
3440
- "type": "string"
3529
+ "anyOf": [
3530
+ {
3531
+ "type": "object",
3532
+ "properties": {
3533
+ "title": {
3534
+ "type": "string"
3535
+ },
3536
+ "body": {
3537
+ "type": "string"
3538
+ },
3539
+ "icon": {
3540
+ "type": "string"
3541
+ }
3542
+ },
3543
+ "additionalProperties": false
3441
3544
  },
3442
- "icon": {
3443
- "type": "string"
3545
+ {
3546
+ "type": "null"
3444
3547
  }
3445
- },
3446
- "additionalProperties": false
3548
+ ]
3447
3549
  },
3448
3550
  "rationale": {
3449
3551
  "type": "object",
@@ -0,0 +1,113 @@
1
+ /**
2
+ * syntroReactPlugin — esbuild plugin for shared React via SynOS
3
+ *
4
+ * Replaces `import { useState } from 'react'` (and react-dom, jsx-runtime)
5
+ * with lazy wrappers that resolve to SynOS.React / SynOS.ReactDOM at call
6
+ * time. This means:
7
+ * - Adaptive modules load and self-register without React being available
8
+ * - React resolves when components actually render
9
+ * - The runtime SDK sets SynOS.React at module scope before any render
10
+ *
11
+ * Used by: build-cdn.js, build-adaptives-only.js, editor-sdk/build.js
12
+ */
13
+ export const syntroReactPlugin = {
14
+ name: 'syntro-react',
15
+ setup(build) {
16
+ build.onResolve({ filter: /^react(-dom)?(\/.*)?$/ }, (args) => ({
17
+ path: args.path,
18
+ namespace: 'syntro-react',
19
+ }));
20
+
21
+ build.onLoad({ filter: /.*/, namespace: 'syntro-react' }, (args) => {
22
+ if (args.path === 'react/jsx-runtime' || args.path === 'react/jsx-dev-runtime') {
23
+ return {
24
+ contents: `
25
+ function _R() {
26
+ return (typeof SynOS !== 'undefined' && SynOS.React) || {};
27
+ }
28
+ function _jsx(type, props, key) {
29
+ var R = _R();
30
+ var p = props || {};
31
+ var c = p.children;
32
+ delete p.children;
33
+ if (key !== undefined) p.key = key;
34
+ return Array.isArray(c)
35
+ ? R.createElement.apply(null, [type, p].concat(c))
36
+ : c !== undefined
37
+ ? R.createElement(type, p, c)
38
+ : R.createElement(type, p);
39
+ }
40
+ export var jsx = _jsx;
41
+ export var jsxs = _jsx;
42
+ export var Fragment = _R().Fragment;
43
+ `,
44
+ loader: 'js',
45
+ };
46
+ }
47
+ if (args.path === 'react') {
48
+ // Hooks and creation APIs are lazy function wrappers — they resolve
49
+ // SynOS.React at call time (during render), not at module load.
50
+ //
51
+ // Component types (Fragment, Suspense, etc.) are resolved at module
52
+ // evaluation via _R(). This is fine because the runtime SDK always
53
+ // loads before adaptive modules evaluate, so SynOS.React is set.
54
+ // ES module named exports can't be truly lazy (no getter support).
55
+ return {
56
+ contents: `
57
+ function _R() {
58
+ return (typeof SynOS !== 'undefined' && SynOS.React) || {};
59
+ }
60
+
61
+ // Default export — lazy proxy for React.* access
62
+ export default new Proxy({}, { get: function(_, k) { return _R()[k]; } });
63
+
64
+ // Hooks — lazy function wrappers (resolve at call time)
65
+ export function useState() { return _R().useState.apply(null, arguments); }
66
+ export function useEffect() { return _R().useEffect.apply(null, arguments); }
67
+ export function useMemo() { return _R().useMemo.apply(null, arguments); }
68
+ export function useCallback() { return _R().useCallback.apply(null, arguments); }
69
+ export function useRef() { return _R().useRef.apply(null, arguments); }
70
+ export function useContext() { return _R().useContext.apply(null, arguments); }
71
+ export function useReducer() { return _R().useReducer.apply(null, arguments); }
72
+ export function useLayoutEffect() { return _R().useLayoutEffect.apply(null, arguments); }
73
+ export function useId() { return _R().useId.apply(null, arguments); }
74
+
75
+ // Creation APIs — lazy function wrappers
76
+ export function createElement() { return _R().createElement.apply(null, arguments); }
77
+ export function createContext() { return _R().createContext.apply(null, arguments); }
78
+ export function forwardRef() { return _R().forwardRef.apply(null, arguments); }
79
+ export function memo() { return _R().memo.apply(null, arguments); }
80
+ export function lazy() { return _R().lazy.apply(null, arguments); }
81
+ export function isValidElement() { return _R().isValidElement.apply(null, arguments); }
82
+ export function cloneElement() { return _R().cloneElement.apply(null, arguments); }
83
+
84
+ // Component types — resolved at module eval (runtime loads first)
85
+ var _r = _R();
86
+ export var Fragment = _r.Fragment;
87
+ export var Suspense = _r.Suspense;
88
+ export var Children = _r.Children;
89
+ export var Component = _r.Component;
90
+ export var PureComponent = _r.PureComponent;
91
+ `,
92
+ loader: 'js',
93
+ };
94
+ }
95
+ if (args.path === 'react-dom' || args.path.startsWith('react-dom/')) {
96
+ return {
97
+ contents: `
98
+ function _RD() {
99
+ return (typeof SynOS !== 'undefined' && SynOS.ReactDOM) || {};
100
+ }
101
+ export default new Proxy({}, { get: function(_, k) { return _RD()[k]; } });
102
+ export function createRoot() { return _RD().createRoot.apply(null, arguments); }
103
+ export function hydrateRoot() { return _RD().hydrateRoot.apply(null, arguments); }
104
+ export function createPortal() { return _RD().createPortal.apply(null, arguments); }
105
+ export function flushSync() { return _RD().flushSync.apply(null, arguments); }
106
+ `,
107
+ loader: 'js',
108
+ };
109
+ }
110
+ return { contents: 'export default {};', loader: 'js' };
111
+ });
112
+ },
113
+ };
@@ -1,9 +0,0 @@
1
- function m(...t){return t.filter(Boolean).join(" ")}function re(){return typeof SynOS<"u"&&SynOS.React||{}}function oe(t,n,r){var s=re(),a=n||{},i=a.children;return delete a.children,r!==void 0&&(a.key=r),Array.isArray(i)?s.createElement.apply(null,[t,a].concat(i)):i!==void 0?s.createElement(t,a,i):s.createElement(t,a)}var o=oe,l=oe,ne=re().Fragment;function T(){return typeof SynOS<"u"&&SynOS.React||{}}var se=new Proxy({},{get:function(t,n){return T()[n]}});function y(){return T().useState.apply(null,arguments)}function v(){return T().useEffect.apply(null,arguments)}function k(){return T().useCallback.apply(null,arguments)}function g(){return T().useRef.apply(null,arguments)}var A=T(),Ye=A.Fragment,Ve=A.Suspense,Ze=A.Children,Je=A.Component,Xe=A.PureComponent;function ke(){return typeof SynOS<"u"&&SynOS.ReactDOM||{}}var Qe=new Proxy({},{get:function(t,n){return ke()[n]}});var f={id:"id",class:"class",tag:"tag",attribute:"attribute",nthchild:"nthchild",nthoftype:"nthoftype"};var Re="CssSelectorGenerator";function z(t="unknown problem",...n){console.warn(`${Re}: ${t}`,...n)}var ut={selectors:[f.id,f.class,f.tag,f.attribute],includeTag:!1,whitelist:[],blacklist:[],combineWithinSelector:!0,combineBetweenSelectors:!0,root:null,maxCombinations:Number.POSITIVE_INFINITY,maxCandidates:Number.POSITIVE_INFINITY,useScope:!1};function ae(t){return t instanceof RegExp}function $e(t){return t.replace(/[|\\{}()[\]^$+?.]/g,"\\$&").replace(/\*/g,".+")}function q(t){let n=t.map(r=>{if(ae(r))return s=>r.test(s);if(typeof r=="function")return s=>{let a=r(s);return typeof a!="boolean"?(z("pattern matcher function invalid","Provided pattern matching function does not return boolean. It's result will be ignored.",r),!1):a};if(typeof r=="string"){let s=new RegExp("^"+$e(r)+"$");return a=>s.test(a)}return z("pattern matcher invalid","Pattern matching only accepts strings, regular expressions and/or functions. This item is invalid and will be ignored.",r),()=>!1});return r=>n.some(s=>s(r))}var Te=new RegExp(["^$","\\s"].join("|")),Ie=new RegExp(["^$"].join("|")),ie=[f.nthoftype,f.tag,f.id,f.class,f.attribute,f.nthchild];var Et=q(["class","id","ng-*"]);var yr="3a".toUpperCase();function V({children:t}){return o("div",{className:"se-flex-1 se-overflow-auto se-p-6",children:t})}function Z({onSave:t,onPublish:n}){return l("div",{className:"se-py-3 se-px-4 se-border-t se-border-border-primary se-flex se-gap-2",children:[o("button",{onClick:t,className:"se-flex-1 se-h-10 se-px-4 se-py-2 se-rounded-md se-bg-btn-neutral se-text-btn-neutral-text se-border se-border-btn-neutral-border hover:se-text-btn-neutral-text-hover se-text-sm se-font-medium se-cursor-pointer se-inline-flex se-items-center se-justify-center focus-visible:se-shadow-focus-primary focus-visible:se-outline-none",children:"Save Draft"}),o("button",{onClick:n,className:"se-flex-1 se-h-10 se-px-4 se-py-2 se-rounded-md se-border-none se-bg-btn-primary se-text-btn-primary-text hover:se-bg-btn-primary-hover se-text-sm se-font-medium se-cursor-pointer se-inline-flex se-items-center se-justify-center focus-visible:se-shadow-focus-primary focus-visible:se-outline-none",children:"Publish"})]})}function J({title:t,subtitle:n}){return l("div",{className:"se-px-4 se-pt-3 se-pb-2",children:[o("h2",{className:"se-m-0 se-text-base se-font-semibold se-text-text-primary",children:t}),n&&o("p",{className:"se-mt-0.5 se-mb-0 se-text-xs se-text-text-secondary",children:n})]})}function P({label:t,className:n,...r}){return l("div",{children:[t&&o("label",{className:"se-text-sm se-font-medium se-text-input-field-text-label se-mb-1 se-block",children:t}),o("input",{...r,className:m("se-w-full se-py-2 se-px-3 se-rounded-lg se-border se-border-input-field-border se-bg-slate-grey-3 se-text-text-primary se-text-sm se-font-[inherit] se-mb-2 se-box-border","placeholder:se-text-input-field-text-placeholder","focus:se-border-input-field-border-selected focus:se-outline-none focus:se-shadow-focus-primary","disabled:se-bg-input-field-bg-disabled disabled:se-cursor-not-allowed disabled:se-opacity-50",n)})]})}function X({children:t}){return o("div",{className:"se-flex se-flex-col se-h-full se-font-sans",children:t})}function K({label:t,className:n,value:r,...s}){let a=g(null);return v(()=>{let i=a.current;i&&(i.style.height="auto",i.style.height=`${i.scrollHeight}px`)},[r]),l("div",{children:[t&&o("label",{className:"se-text-sm se-font-medium se-text-input-field-text-label se-mb-1 se-block",children:t}),o("textarea",{ref:a,value:r,...s,className:m("se-w-full se-py-2 se-px-3 se-rounded-lg se-border se-border-input-field-border se-bg-slate-grey-3 se-text-text-primary se-text-sm se-font-[inherit] se-mb-2 se-resize-y se-min-h-[60px] se-max-h-[50vh] se-overflow-y-auto se-box-border","placeholder:se-text-input-field-text-placeholder","focus:se-border-input-field-border-selected focus:se-outline-none focus:se-shadow-focus-primary","disabled:se-bg-input-field-bg-disabled disabled:se-cursor-not-allowed disabled:se-opacity-50",n)})]})}function Be({config:t,onChange:n,editor:r}){let s=t,a=g(!1);v(()=>{!a.current&&(r.initialEditKey!=null||r.initialCreate)&&(a.current=!0,r.clearInitialState?.())},[r]);let i=(d,S)=>{n({...t,[d]:S}),r.setDirty(!0)};return l(X,{children:[o(J,{title:"Chat Assistant",subtitle:"Configure AI chat assistant",onBack:()=>r.navigateHome()}),l(V,{children:[l("div",{className:"se-mb-6",children:[o("div",{className:"se-text-xs se-font-semibold se-text-slate-grey-8 se-uppercase se-tracking-wide se-mb-3",children:"API Configuration"}),o(P,{label:"Backend URL",type:"text",value:s.backendUrl||"",onChange:d=>i("backendUrl",d.target.value),placeholder:"/api/chat/message"}),o(P,{label:"MLflow Run ID (optional)",type:"text",value:s.mlflowRunId||"",onChange:d=>i("mlflowRunId",d.target.value),placeholder:"e.g., abc123"})]}),l("div",{className:"se-mb-6",children:[o("div",{className:"se-text-xs se-font-semibold se-text-slate-grey-8 se-uppercase se-tracking-wide se-mb-3",children:"Chat Settings"}),o(K,{label:"Greeting Message",value:s.greeting||"",onChange:d=>i("greeting",d.target.value),placeholder:"Hi! How can I help?"}),o(P,{label:"Max History (messages sent to backend)",type:"number",value:s.maxHistory||20,onChange:d=>i("maxHistory",parseInt(d.target.value,10)),min:1,max:100})]})]}),o(Z,{onSave:()=>r.save(),onPublish:()=>r.publish()})]})}var ue={title:"Chat Assistant",icon:"\u{1F4AC}",description:"AI chat assistant with action execution"},de=Be;var b={white:"#ffffff",black:"#000000"},x={0:"#2c0b0a",1:"#5b1715",2:"#89221f",3:"#b72e2a",4:"#d44844",5:"#dd6d69",6:"#e5918f",7:"#eeb6b4",8:"#f6dada",9:"#faebea"},e={0:"#07080a",1:"#0f1318",2:"#0e1114",3:"#1c222a",4:"#2b333f",5:"#394454",6:"#475569",7:"#677384",8:"#87919f",9:"#a8afba",10:"#cbd0d7",11:"#e8eaee",12:"#f6f7f9"},c={0:"#07230a",1:"#0e4514",2:"#16681e",3:"#1d8a28",4:"#24ad32",5:"#4fbd5a",6:"#7acd82",7:"#a5deab",8:"#d0eed3",9:"#e5f6e7"},C={0:"#301f09",1:"#5f3e12",2:"#8f5e1b",3:"#be7d24",4:"#ee9c2d",5:"#f1b057",6:"#f5c481",7:"#f8d7ab",8:"#fcebd5",9:"#fdf5ea"},u={0:"#330707",1:"#660f0e",2:"#991616",3:"#cc1e1d",4:"#ff2524",5:"#ff5150",6:"#ff7c7c",7:"#ffa8a7",8:"#ffd3d3",9:"#ffe9e9"},M={0:"#051533",1:"#0a2a66",2:"#0f3f98",3:"#1454cb",4:"#1969fe",5:"#4787fe",6:"#75a5fe",7:"#a3c3ff",8:"#d1e1ff",9:"#e8f0ff"},j={0:"#662500",1:"#993d00",2:"#cc5800",3:"#ff7700",4:"#fea85d",5:"#fec58f",6:"#ffd6ae",7:"#fee6cd",8:"#fff1e1",9:"#fff8f0"},w={0:"#151229",1:"#2a2452",2:"#40357c",3:"#5547a5",4:"#6a59ce",5:"#887ad8",6:"#a69be2",7:"#c3bdeb",8:"#e1def5",9:"#f0eefa"},O={0:"#37091f",1:"#69123c",2:"#9b1c58",3:"#cd2575",4:"#ff2e92",5:"#ff58a8",6:"#ff82be",7:"#ffabd3",8:"#ffd5e9",9:"#ffeaf4"};var Vn={primary:e[10],secondary:e[9],tertiary:e[8]},Zn={primary:e[2],secondary:e[0]},Jn={primary:e[4],secondary:e[3]},Xn={primary:{text:b.white,icon:b.white,border:x[3],backgroundDefault:x[3],backgroundHover:x[2]},neutral:{text:e[10],textHover:b.white,icon:e[10],iconHover:b.white,border:e[4],background:e[2]},link:{text:b.white,icon:b.white,hover:x[5]},error:{text:u[5],hover:u[6]},success:{text:c[5],hover:c[6]}},Kn={slateGrey:{content:e[10],pillOutline:e[10],borderPrimary:e[5],borderSecondary:e[5],background:e[3]},brand:{content:x[9],pillOutline:x[9],borderPrimary:x[6],borderSecondary:x[6],background:x[0]},red:{content:u[8],pillOutline:u[4],borderPrimary:u[2],borderSecondary:u[2],background:u[0]},yellow:{content:C[8],pillOutline:C[4],borderPrimary:C[2],borderSecondary:C[2],background:C[0]},green:{content:c[8],pillOutline:c[4],borderPrimary:c[2],borderSecondary:c[2],background:c[0]},purple:{content:w[8],pillOutline:w[4],borderPrimary:w[2],borderSecondary:w[2],background:w[0]},blue:{content:M[8],pillOutline:M[4],borderPrimary:M[2],borderSecondary:M[2],background:M[0]},orange:{content:j[8],pillOutline:j[4],borderPrimary:j[2],borderSecondary:j[2],background:j[0]},pink:{content:O[8],pillOutline:O[4],borderPrimary:O[2],borderSecondary:O[2],background:O[0]}},Qn={green:{content:c[8],border:c[2],background:c[0]},yellow:{content:C[8],border:C[2],background:C[0]},red:{content:u[8],border:u[2],background:u[0]}},es={green:{content:c[1],background:c[9]},yellow:{content:C[1],background:C[9]},red:{content:u[1],background:u[9]}},ts={content:e[10],border:e[4],background:"#1c2124"},rs={backgroundDefault:e[2],backgroundHover:e[1],selected:e[3]},os={background:e[2],icon:e[10],borderDefault:e[4],borderSelected:x[3],textLabel:e[9],textPlaceholder:e[8],textHint:e[8]},ns={backgroundDefault:e[2],backgroundDisabled:e[0],textLabel:e[9],textPlaceholder:e[8],textHint:e[8],textError:u[5],iconDefault:e[9],iconPlaceholder:e[10],iconError:u[5],borderDefault:e[4],borderSelected:x[3],borderError:u[5]},ss={handleDefault:b.white,handleDisabled:e[10],off:{backgroundDefault:e[4],backgroundHover:e[5],backgroundDisabled:e[4]},on:{backgroundDefault:c[3],backgroundHover:c[2],backgroundDisabled:e[4]}},as={off:{backgroundDefault:"#00000000",backgroundHover:e[5],backgroundDisabled:e[2],border:e[6]},on:{backgroundDefault:c[0],backgroundHover:c[1],backgroundDisabled:e[2],border:c[3]}},is={content:e[10],background:e[4]},ls={background:e[4],active:c[3]},cs={background:e[1],content:e[9],border:e[4]},us={backgroundDefault:e[1],backgroundHover:e[3],backgroundActive:e[4],border:e[4],contentPrimary:e[10],contentSecondary:e[9],contentTertiary:e[8]},ds={background:e[1],content:e[9],border:e[4]},ps={activeBackground:e[3],activeContent:x[5],inactiveContent:e[9],border:e[4]},fs={header:{textDefault:e[9],textHover:e[8],backgroundDefault:e[1]},border:e[4],cell:{textPrimary:e[10],textSecondary:e[9],backgroundDefault:e[2],backgroundHover:e[1]}},ms={textPrimaryDefault:e[10],textPrimaryHover:e[10],textSecondaryDefault:e[8],textSecondaryHover:e[9],iconPrimary:e[10],iconSecondary:e[8]},xs={background:c[1],active:c[5]},gs={textDefault:e[10],textSelected:b.white,textDisabled:e[7],backgroundDefault:e[2],backgroundMiddle:e[3],backgroundSelected:x[3],border:e[4]},bs=e[9];function pe(){return typeof SynOS<"u"&&SynOS.ReactDOM||{}}var Ns=new Proxy({},{get:function(t,n){return pe()[n]}});function Q(){return pe().createRoot.apply(null,arguments)}var fe=/```json\s*\n([\s\S]*?)```/g;function me(t){let n=[],r=t,s=[],a;for(fe.lastIndex=0;(a=fe.exec(t))!==null;)s.push({fullMatch:a[0],json:a[1],index:a.index});for(let i=s.length-1;i>=0;i--){let{fullMatch:d,json:S}=s[i],p;try{p=JSON.parse(S)}catch{continue}typeof p=="object"&&p!==null&&"kind"in p&&typeof p.kind=="string"&&(n.unshift(p),r=r.replace(d,""))}return r=r.replace(/\n{3,}/g,`
2
-
3
- `).trim(),{displayText:r,actions:n}}var D=class extends Error{constructor(n){super(n),this.name="AuthError"}};function ze(){let t=document.cookie.match(/stytch_session_jwt=([^;]*)/);if(!t||!t[1])throw new D("No authentication token found");let n=localStorage.getItem("syntrologie_workspace_id");if(!n)throw new D("No workspace ID found");return{Authorization:`Bearer ${t[1]}`,"X-Workspace-Id":n}}async function xe(t,n){let r=ze(),s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...r},body:JSON.stringify(n)});if(!s.ok)throw s.status===401?new D("Session expired or unauthorized"):new Error(`Chat request failed: ${s.status} ${s.statusText}`);return s.json()}var Fe=0;function ee(){return`msg-${Date.now()}-${++Fe}`}function ge(t){let{backendUrl:n,tileId:r,runtime:s,greeting:a,maxHistory:i=20,mlflowRunId:d,config:S}=t,[p,R]=y(()=>a?[{id:ee(),role:"assistant",text:a,timestamp:Date.now()}]:[]),[W,E]=y(!1),[N,I]=y(null),$=g(null),ye=k(async Ce=>{let G=Ce.trim();if(!G)return;I(null);let te={id:ee(),role:"user",text:G,timestamp:Date.now()};R(L=>[...L,te]),E(!0);try{let U=[...p,te].slice(-i).map(_=>({role:_.role,content:_.text})),we=await xe(n,{message:G,history:U,mlflow_run_id:d,current_config:S}),{displayText:Se,actions:B}=me(we.response),Ee={id:ee(),role:"assistant",text:Se,timestamp:Date.now()};R(_=>[..._,Ee]),B.length>0&&($.current?.isApplied()&&await $.current.revertAll(),$.current=await s.actions.applyBatch(B),s.events.publish("chatbot.actions_applied",{count:B.length,kinds:B.map(_=>_.kind),tileId:r}))}catch(L){let U=L instanceof Error?L.message:"An unexpected error occurred";I(U)}finally{E(!1)}},[n,p,i,d,S,s,r]),ve=k(()=>{R([]),I(null),$.current?.isApplied()&&($.current.revertAll(),$.current=null),sessionStorage.removeItem(`syntro:chatbot:history:${r}`)},[r]);return{messages:p,isLoading:W,error:N,sendMessage:ye,clearMessages:ve}}var h={container:{display:"flex",flexDirection:"column",height:"100%",fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"14px"},messageList:{flex:1,overflowY:"auto",padding:"12px",display:"flex",flexDirection:"column",gap:"8px"},messageBubble:{maxWidth:"85%",padding:"8px 12px",borderRadius:"12px",lineHeight:1.5,wordBreak:"break-word"},userMessage:{alignSelf:"flex-end",backgroundColor:w[4],color:b.white,borderBottomRightRadius:"4px"},assistantMessage:{alignSelf:"flex-start",backgroundColor:"rgba(255, 255, 255, 0.08)",color:e[10],borderBottomLeftRadius:"4px"},loadingDots:{alignSelf:"flex-start",padding:"8px 16px",backgroundColor:"rgba(255, 255, 255, 0.05)",borderRadius:"12px",color:e[8],fontSize:"13px"},errorBanner:{padding:"8px 12px",backgroundColor:"rgba(239, 68, 68, 0.1)",color:u[4],fontSize:"13px",borderRadius:"8px",margin:"0 12px"},inputForm:{display:"flex",gap:"8px",padding:"12px",borderTop:"1px solid rgba(255, 255, 255, 0.06)"},input:{flex:1,padding:"8px 12px",borderRadius:"8px",border:"1px solid rgba(255, 255, 255, 0.1)",backgroundColor:"rgba(0, 0, 0, 0.2)",color:e[12],fontSize:"14px",outline:"none",fontFamily:"inherit"},sendButton:{padding:"8px 16px",borderRadius:"8px",border:"none",backgroundColor:w[4],color:b.white,fontWeight:600,fontSize:"13px",cursor:"pointer",whiteSpace:"nowrap"},sendButtonDisabled:{opacity:.5,cursor:"not-allowed"}};function We({message:t}){let n=t.role==="user",r={...h.messageBubble,...n?h.userMessage:h.assistantMessage};return o("div",{style:r,children:t.text})}function Ge({config:t,runtime:n,tileId:r}){let{messages:s,isLoading:a,error:i,sendMessage:d,clearMessages:S}=ge({backendUrl:t.backendUrl,tileId:r,runtime:n,greeting:t.greeting,maxHistory:t.maxHistory,mlflowRunId:t.mlflowRunId}),p=g(null),R=g(null);v(()=>{p.current&&(p.current.scrollTop=p.current.scrollHeight)},[]);let W=E=>{E.preventDefault();let N=R.current;if(!N||!N.value.trim()||a)return;let I=N.value;N.value="",d(I)};return l("div",{style:h.container,"data-testid":"chat-assistant",children:[l("div",{ref:p,style:h.messageList,children:[s.map(E=>o(We,{message:E},E.id)),a&&o("div",{style:h.loadingDots,children:"Thinking..."})]}),i&&o("div",{style:h.errorBanner,children:i}),l("form",{onSubmit:W,style:h.inputForm,children:[o("input",{ref:R,style:h.input,placeholder:"Ask anything...",disabled:a,"data-testid":"chat-input"}),o("button",{type:"submit",disabled:a,style:{...h.sendButton,...a?h.sendButtonDisabled:{}},"data-testid":"chat-send",children:"Send"})]})]})}var be={mount(t,n){let{config:r,runtime:s,tileId:a="chatbot-widget"}=n||{};if(r&&s&&typeof Q=="function"){let i=Q(t);return i.render(se.createElement(Ge,{config:r,runtime:s,tileId:a})),()=>{i.unmount()}}return!r||!s?(t.innerHTML=`<div style="padding: 16px; color: ${e[8]};">Chat widget requires config and runtime.</div>`,()=>{t.innerHTML=""}):(t.innerHTML=`
4
- <div style="padding: 16px; font-family: system-ui; color: ${e[10]};">
5
- <p style="margin: 0 0 8px; color: ${e[8]};">${r.greeting||"Hi! How can I help?"}</p>
6
- <p style="margin: 0; font-size: 12px; color: ${e[7]};">Chat widget mounted. Awaiting React renderer.</p>
7
- </div>
8
- `,()=>{t.innerHTML=""})}};var H={id:"adaptive-chatbot",version:"1.0.0",name:"Chat Assistant",description:"AI chat assistant with action execution capabilities",executors:[],widgets:[{id:"adaptive-chatbot:assistant",component:be,metadata:{name:"Chat Assistant",description:"AI-powered chat assistant that can execute DOM actions",icon:"\u{1F4AC}"}}]};var he={id:"adaptive-chatbot",version:H.version,name:H.name,description:H.description,runtime:{actions:[],widgets:H.widgets},editor:{component:de,panel:ue},metadata:{isBuiltIn:!1}};if(typeof window<"u"){let t=window.SynOS?.appRegistry;t&&typeof t.register=="function"&&t.register(he)}var Us=he;export{Us as default,he as manifest};
9
- //# sourceMappingURL=index.js.map