@syntrologie/runtime-sdk 1.0.1 → 2.0.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.
- package/CAPABILITIES.md +630 -463
- package/README.md +285 -62
- package/dist/RuntimeProvider.d.ts +51 -0
- package/dist/RuntimeProvider.js +114 -0
- package/dist/RuntimeProvider.js.map +1 -0
- package/dist/SmartCanvasApp.d.ts +9 -3
- package/dist/SmartCanvasApp.js +36 -38
- package/dist/SmartCanvasApp.js.map +1 -1
- package/dist/actions/ActionEngine.d.ts +11 -0
- package/dist/actions/ActionEngine.js +274 -0
- package/dist/actions/ActionEngine.js.map +1 -0
- package/dist/actions/executors/index.d.ts +117 -0
- package/dist/actions/executors/index.js +242 -0
- package/dist/actions/executors/index.js.map +1 -0
- package/dist/actions/executors/tour.d.ts +18 -0
- package/dist/actions/executors/tour.js +332 -0
- package/dist/actions/executors/tour.js.map +1 -0
- package/dist/actions/index.d.ts +10 -0
- package/dist/actions/index.js +12 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/types.d.ts +399 -0
- package/dist/actions/types.js +8 -0
- package/dist/actions/types.js.map +1 -0
- package/dist/actions/validation.d.ts +14 -0
- package/dist/actions/validation.js +603 -0
- package/dist/actions/validation.js.map +1 -0
- package/dist/api.d.ts +32 -18
- package/dist/api.js +56 -39
- package/dist/api.js.map +1 -1
- package/dist/apps/AppContext.d.ts +31 -0
- package/dist/apps/AppContext.js +93 -0
- package/dist/apps/AppContext.js.map +1 -0
- package/dist/apps/AppLoader.d.ts +84 -0
- package/dist/apps/AppLoader.js +256 -0
- package/dist/apps/AppLoader.js.map +1 -0
- package/dist/apps/AppRegistry.d.ts +102 -0
- package/dist/apps/AppRegistry.js +317 -0
- package/dist/apps/AppRegistry.js.map +1 -0
- package/dist/apps/examples/gamification-app.example.d.ts +305 -0
- package/dist/apps/examples/gamification-app.example.js +329 -0
- package/dist/apps/examples/gamification-app.example.js.map +1 -0
- package/dist/apps/faq/index.js +11 -0
- package/dist/apps/faq/index.js.map +7 -0
- package/dist/apps/gamification/index.js +2 -0
- package/dist/apps/gamification/index.js.map +7 -0
- package/dist/apps/index.d.ts +15 -0
- package/dist/apps/index.js +17 -0
- package/dist/apps/index.js.map +1 -0
- package/dist/apps/nav/index.js +11 -0
- package/dist/apps/nav/index.js.map +7 -0
- package/dist/apps/types.d.ts +231 -0
- package/dist/apps/types.js +8 -0
- package/dist/apps/types.js.map +1 -0
- package/dist/bootstrap.d.ts +24 -0
- package/dist/bootstrap.js +133 -33
- package/dist/bootstrap.js.map +1 -1
- package/dist/components/ShadowCanvasOverlay.js +36 -9
- package/dist/components/ShadowCanvasOverlay.js.map +1 -1
- package/dist/components/TileCard.js +37 -18
- package/dist/components/TileCard.js.map +1 -1
- package/dist/context/schema.d.ts +16 -16
- package/dist/decisions/schema.d.ts +96 -96
- package/dist/earlyPatcher.d.ts +8 -20
- package/dist/earlyPatcher.js +13 -62
- package/dist/earlyPatcher.js.map +1 -1
- package/dist/editorLoader.d.ts +2 -0
- package/dist/editorLoader.js +52 -7
- package/dist/editorLoader.js.map +1 -1
- package/dist/events/normalizers/posthog.d.ts +24 -0
- package/dist/events/normalizers/posthog.js.map +1 -1
- package/dist/events/schema.d.ts +8 -8
- package/dist/events/types.d.ts +6 -0
- package/dist/events/types.js +8 -0
- package/dist/events/types.js.map +1 -1
- package/dist/hooks/useCanvasOverlays.d.ts +4 -1
- package/dist/hooks/useCanvasOverlays.js +53 -6
- package/dist/hooks/useCanvasOverlays.js.map +1 -1
- package/dist/hooks/useShadowCanvasConfig.d.ts +3 -7
- package/dist/hooks/useShadowCanvasConfig.js +2 -3
- package/dist/hooks/useShadowCanvasConfig.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/overlays/schema.d.ts +153 -153
- package/dist/runtime.d.ts +24 -0
- package/dist/runtime.js +75 -1
- package/dist/runtime.js.map +1 -1
- package/dist/smart-canvas.esm.js +155 -78
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +41155 -35362
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +155 -78
- package/dist/smart-canvas.min.js.map +4 -4
- package/dist/store/example.d.ts +1 -0
- package/dist/store/example.js +43 -0
- package/dist/store/example.js.map +1 -0
- package/dist/store/mini-effector.d.ts +46 -0
- package/dist/store/mini-effector.js +90 -0
- package/dist/store/mini-effector.js.map +1 -0
- package/dist/surfaces/Surfaces.d.ts +11 -0
- package/dist/surfaces/Surfaces.js +361 -0
- package/dist/surfaces/Surfaces.js.map +1 -0
- package/dist/surfaces/index.d.ts +9 -0
- package/dist/surfaces/index.js +12 -0
- package/dist/surfaces/index.js.map +1 -0
- package/dist/surfaces/positioning.d.ts +50 -0
- package/dist/surfaces/positioning.js +231 -0
- package/dist/surfaces/positioning.js.map +1 -0
- package/dist/surfaces/types.d.ts +167 -0
- package/dist/surfaces/types.js +23 -0
- package/dist/surfaces/types.js.map +1 -0
- package/dist/telemetry/adapters/posthog.d.ts +6 -0
- package/dist/telemetry/adapters/posthog.js +9 -0
- package/dist/telemetry/adapters/posthog.js.map +1 -1
- package/dist/types-only.d.ts +32 -0
- package/dist/types-only.js +11 -0
- package/dist/types-only.js.map +1 -0
- package/dist/types.d.ts +26 -14
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/widgets/WidgetRegistry.d.ts +139 -0
- package/dist/widgets/WidgetRegistry.js +182 -0
- package/dist/widgets/WidgetRegistry.js.map +1 -0
- package/dist/widgets/index.d.ts +7 -0
- package/dist/widgets/index.js +7 -0
- package/dist/widgets/index.js.map +1 -0
- package/package.json +14 -7
- package/schema/canvas-config.schema.json +444 -254
package/README.md
CHANGED
|
@@ -2,19 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
## Smart Canvas SDK (React + Shadow DOM)
|
|
4
4
|
|
|
5
|
-
The SDK
|
|
5
|
+
The SDK ships a framework-agnostic `<smart-canvas>` custom element with an **open shadow root**. We render everything with React, but the canvas is encapsulated so host Tailwind configs, resets, or stacking contexts can't break the UI.
|
|
6
6
|
|
|
7
|
-
### What
|
|
7
|
+
### What's Included
|
|
8
8
|
|
|
9
9
|
- `SmartCanvasElement` – the custom element that owns the shadow DOM, overlay root, and controller.
|
|
10
10
|
- `SmartCanvasApp` – the React tree (overlay, rectangles, toggle) you portal into the shadow.
|
|
11
11
|
- `SmartCanvasPortal` – helper for React hosts to portal their tree (and context) into the element mount.
|
|
12
12
|
- `createSmartCanvas` – imperative API (`window.SmartCanvas.create`) for non-React hosts.
|
|
13
|
+
- **ActionEngine** – unified execution layer for interventions (highlight, tooltip, badge, DOM modifications)
|
|
14
|
+
- **Surfaces** – managed surface system for rendering UI into named slots
|
|
13
15
|
- GrowthBook/PostHog wrappers, hooks, rectangle components, and wheel remain available.
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
---
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { Syntro } from "@syntrologie/runtime-sdk";
|
|
23
|
+
|
|
24
|
+
const { runtime } = await Syntro.init({ token: "syn_..." });
|
|
25
|
+
|
|
26
|
+
// Change a headline
|
|
27
|
+
const handle = await runtime.actions.apply({
|
|
28
|
+
kind: "set_text",
|
|
29
|
+
anchorId: "h1.hero-title",
|
|
30
|
+
text: "Welcome to Our New Experience"
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Show a toast notification
|
|
34
|
+
const toast = runtime.surfaces.mount("toast_top", {
|
|
35
|
+
type: "html",
|
|
36
|
+
content: '<div class="toast">Changes applied!</div>'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Later: revert and cleanup
|
|
40
|
+
await handle.revert();
|
|
41
|
+
toast.unmount();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
### NPM/Yarn
|
|
18
49
|
|
|
19
50
|
```bash
|
|
20
51
|
npm install @syntrologie/smart-canvas-sdk
|
|
@@ -22,7 +53,7 @@ npm install @syntrologie/smart-canvas-sdk
|
|
|
22
53
|
yarn add @syntrologie/smart-canvas-sdk
|
|
23
54
|
```
|
|
24
55
|
|
|
25
|
-
|
|
56
|
+
### CDN
|
|
26
57
|
|
|
27
58
|
For quick setup without a build process:
|
|
28
59
|
|
|
@@ -39,18 +70,96 @@ For quick setup without a build process:
|
|
|
39
70
|
</script>
|
|
40
71
|
```
|
|
41
72
|
|
|
42
|
-
|
|
73
|
+
### Local Development
|
|
43
74
|
|
|
44
75
|
```bash
|
|
45
|
-
cd tech-core/sdks/
|
|
76
|
+
cd tech-core/sdks/runtime-sdk
|
|
46
77
|
npm run build
|
|
47
|
-
cd ../../tax_landing_page
|
|
48
|
-
npm install @syntrologie/smart-canvas-sdk@file:../tech-core/sdks/shadow-canvas
|
|
49
78
|
```
|
|
50
79
|
|
|
51
|
-
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Core Modules
|
|
83
|
+
|
|
84
|
+
### ActionEngine
|
|
85
|
+
|
|
86
|
+
The ActionEngine provides a unified API for applying reversible interventions:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// Visual actions
|
|
90
|
+
await runtime.actions.apply({ kind: "highlight", anchorId: "#cta", style: { color: "#4f46e5" } });
|
|
91
|
+
await runtime.actions.apply({ kind: "tooltip", anchorId: "#help", content: { body: "Click for help" } });
|
|
92
|
+
await runtime.actions.apply({ kind: "badge", anchorId: "#inbox", content: "3" });
|
|
93
|
+
await runtime.actions.apply({ kind: "pulse", anchorId: "#notification" });
|
|
94
|
+
|
|
95
|
+
// DOM actions
|
|
96
|
+
await runtime.actions.apply({ kind: "set_text", anchorId: "h1", text: "New headline" });
|
|
97
|
+
await runtime.actions.apply({ kind: "insert_html", anchorId: ".cta", html: "<span>NEW</span>", position: "append" });
|
|
98
|
+
await runtime.actions.apply({ kind: "add_class", anchorId: ".card", className: "highlighted" });
|
|
99
|
+
await runtime.actions.apply({ kind: "set_style", anchorId: ".hero", styles: { "background": "#1e40af" } });
|
|
100
|
+
|
|
101
|
+
// Navigation actions
|
|
102
|
+
await runtime.actions.apply({ kind: "scroll_to", anchorId: "#pricing" });
|
|
103
|
+
await runtime.actions.apply({ kind: "navigate", url: "/signup" });
|
|
104
|
+
|
|
105
|
+
// Batch with atomic rollback
|
|
106
|
+
const batch = await runtime.actions.applyBatch([
|
|
107
|
+
{ kind: "set_text", anchorId: "h1", text: "New" },
|
|
108
|
+
{ kind: "highlight", anchorId: "h1" }
|
|
109
|
+
]);
|
|
110
|
+
await batch.revertAll();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Surfaces
|
|
52
114
|
|
|
53
|
-
|
|
115
|
+
The Surfaces system manages UI rendering into named slots:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Static slots
|
|
119
|
+
runtime.surfaces.mount("toast_top", { type: "html", content: "<div>Saved!</div>" });
|
|
120
|
+
runtime.surfaces.mount("drawer_right", { type: "html", content: "<div>Settings</div>" });
|
|
121
|
+
runtime.surfaces.mount("overlay_center", { type: "html", content: "<div>Modal</div>" });
|
|
122
|
+
|
|
123
|
+
// Dynamic slots (positioned relative to anchors)
|
|
124
|
+
runtime.surfaces.mount("inline:product-card", { type: "html", content: "<span>SALE</span>" });
|
|
125
|
+
runtime.surfaces.mount("adjacent:help-icon", { type: "html", content: "<div>Help text</div>" }, {
|
|
126
|
+
position: { placement: "bottom" }
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Priority-based arbitration
|
|
130
|
+
runtime.surfaces.mount("toast_top", content, { priority: 10 }); // Higher priority wins
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Available Static Slots:**
|
|
134
|
+
| Slot | Position |
|
|
135
|
+
|------|----------|
|
|
136
|
+
| `drawer_right` | Right edge, full height |
|
|
137
|
+
| `drawer_left` | Left edge, full height |
|
|
138
|
+
| `drawer_bottom` | Bottom edge, full width |
|
|
139
|
+
| `overlay_center` | Centered modal |
|
|
140
|
+
| `overlay_corner_br` | Bottom-right corner |
|
|
141
|
+
| `overlay_corner_bl` | Bottom-left corner |
|
|
142
|
+
| `toast_top` | Top center |
|
|
143
|
+
| `toast_bottom` | Bottom center |
|
|
144
|
+
|
|
145
|
+
### Runtime
|
|
146
|
+
|
|
147
|
+
The runtime provides access to all core providers:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const { runtime } = await Syntro.init({ token: "syn_..." });
|
|
151
|
+
|
|
152
|
+
runtime.telemetry // Event tracking (PostHog)
|
|
153
|
+
runtime.context // Page/session/viewport state
|
|
154
|
+
runtime.events // Normalized event stream
|
|
155
|
+
runtime.state // Persistent storage
|
|
156
|
+
runtime.actions // ActionEngine
|
|
157
|
+
runtime.surfaces // Surfaces
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Using the Custom Element (React Host)
|
|
54
163
|
|
|
55
164
|
```tsx
|
|
56
165
|
import {
|
|
@@ -90,7 +199,9 @@ function SmartCanvasBridge() {
|
|
|
90
199
|
}
|
|
91
200
|
```
|
|
92
201
|
|
|
93
|
-
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Using the Imperative API (Plain JS Host)
|
|
94
205
|
|
|
95
206
|
When using via CDN, the SDK is available as `window.SyntrologieSDK`:
|
|
96
207
|
|
|
@@ -109,77 +220,189 @@ await window.SmartCanvas?.create({
|
|
|
109
220
|
});
|
|
110
221
|
```
|
|
111
222
|
|
|
112
|
-
|
|
223
|
+
---
|
|
113
224
|
|
|
114
|
-
|
|
115
|
-
- `--syntro-tooltip-bg`, `--syntro-tooltip-fg`, `--syntro-tooltip-radius`, `--syntro-tooltip-shadow`
|
|
116
|
-
- `--syntro-ring`, `--syntro-spotlight-backdrop` for highlights
|
|
117
|
-
- A scoped reset is injected via `adoptedStyleSheets` (fallbacks to `<style>`).
|
|
118
|
-
- Tooltips/popovers should use the Popover API or Floating UI with the exposed overlay root (`element.getOverlayRoot()`).
|
|
225
|
+
## Event System
|
|
119
226
|
|
|
120
|
-
|
|
227
|
+
The EventBus provides a unified stream of normalized events:
|
|
121
228
|
|
|
122
|
-
|
|
229
|
+
```typescript
|
|
230
|
+
// Subscribe to events
|
|
231
|
+
runtime.events.subscribe({ names: ["ui.click", "action.applied"] }, (event) => {
|
|
232
|
+
console.log(event.name, event.props);
|
|
233
|
+
});
|
|
123
234
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
235
|
+
// Standard events
|
|
236
|
+
// UI: ui.click, ui.scroll, ui.input, ui.submit
|
|
237
|
+
// Navigation: nav.page_view, nav.page_leave
|
|
238
|
+
// Canvas: canvas.opened, canvas.closed, tile.viewed, tile.action
|
|
239
|
+
// Actions: action.applied, action.reverted, action.failed
|
|
240
|
+
// Surfaces: surface.mounted, surface.unmounted
|
|
241
|
+
```
|
|
129
242
|
|
|
130
|
-
|
|
243
|
+
---
|
|
131
244
|
|
|
132
|
-
|
|
245
|
+
## State Management
|
|
133
246
|
|
|
134
|
-
|
|
247
|
+
```typescript
|
|
248
|
+
// Dismissals
|
|
249
|
+
runtime.state.dismissals.mark("promo-banner");
|
|
250
|
+
if (runtime.state.dismissals.isDismissed("promo-banner")) { ... }
|
|
135
251
|
|
|
136
|
-
|
|
137
|
-
|
|
252
|
+
// Cooldowns
|
|
253
|
+
runtime.state.cooldowns.set("upsell", 86400000); // 24h
|
|
254
|
+
if (runtime.state.cooldowns.isActive("upsell")) { ... }
|
|
138
255
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
256
|
+
// Frequency caps
|
|
257
|
+
runtime.state.frequency.increment("tooltip-shown");
|
|
258
|
+
if (runtime.state.frequency.count("tooltip-shown") >= 3) { ... }
|
|
142
259
|
```
|
|
143
260
|
|
|
144
|
-
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Decision Strategies
|
|
264
|
+
|
|
265
|
+
Control when adaptives activate:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
const result = runtime.evaluateSync({
|
|
269
|
+
type: "rules",
|
|
270
|
+
rules: [
|
|
271
|
+
{
|
|
272
|
+
conditions: [
|
|
273
|
+
{ type: "page_url", pattern: "/pricing*" },
|
|
274
|
+
{ type: "viewport", minWidth: 768 },
|
|
275
|
+
{ type: "dismissed", key: "promo", inverted: true }
|
|
276
|
+
],
|
|
277
|
+
value: true
|
|
278
|
+
}
|
|
279
|
+
],
|
|
280
|
+
default: false
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
if (result.value) {
|
|
284
|
+
// Apply adaptive
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Styling & Overlays
|
|
145
291
|
|
|
146
|
-
|
|
292
|
+
- Fonts, colors, and CSS variables are inherited from the host
|
|
293
|
+
- Tokens can be overridden via `setTokens` or standard CSS:
|
|
294
|
+
- `--syntro-tooltip-bg`, `--syntro-tooltip-fg`, `--syntro-tooltip-radius`
|
|
295
|
+
- `--syntro-ring`, `--syntro-spotlight-backdrop` for highlights
|
|
296
|
+
- A scoped reset is injected via `adoptedStyleSheets`
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Schema & Validation
|
|
301
|
+
|
|
302
|
+
- JSON schema lives at `schema/canvas-config.schema.json`
|
|
303
|
+
- Validate a config file locally:
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
cd tech-core/sdks/runtime-sdk
|
|
307
|
+
npm run validate-config -- path/to/config.json
|
|
308
|
+
```
|
|
147
309
|
|
|
148
|
-
|
|
149
|
-
- Provide a recipe URI via `overlayConfigUri` or let GrowthBook supply `smart-canvas-overlay-uri`.
|
|
150
|
-
- Overlays render in `#syntro-overlays` (fixed, pointer-events: none) and use Floating UI for tethering.
|
|
151
|
-
- The Canvas runtime dynamically imports the overlay chunk only when a recipe resolves.
|
|
152
|
-
- Exposed helpers:
|
|
153
|
-
- `createOverlayRecipeFetcher`, `resolveConfigUri`
|
|
154
|
-
- `runOverlays`, `showTooltip`, `showHighlight`
|
|
155
|
-
- `createAnchorResolver` (works for main DOM + shadow DOM)
|
|
310
|
+
---
|
|
156
311
|
|
|
157
|
-
|
|
312
|
+
## Documentation
|
|
158
313
|
|
|
159
|
-
|
|
314
|
+
- **[APPS.md](./APPS.md)** - App architecture: how to build runtime extensions with actions, schemas, and editor modules
|
|
315
|
+
- **[CAPABILITIES.md](./CAPABILITIES.md)** - Complete reference for all actions, surfaces, and config options
|
|
316
|
+
- **[RUNTIME_V2_REFERENCE.md](./RUNTIME_V2_REFERENCE.md)** - Context, Events, State, Decisions modules
|
|
160
317
|
|
|
161
|
-
|
|
162
|
-
- Data hooks: `[data-shadow-canvas-id="overlay-launcher"]`, `[data-shadow-canvas-id="rectangle-${id}"]`, etc.
|
|
163
|
-
- `SmartCanvasController` exposes `open/close` for deterministic tests.
|
|
318
|
+
---
|
|
164
319
|
|
|
165
|
-
|
|
320
|
+
## Directory Overview
|
|
166
321
|
|
|
167
322
|
```
|
|
168
|
-
tech-core/sdks/
|
|
323
|
+
tech-core/sdks/runtime-sdk
|
|
169
324
|
├─ src
|
|
170
|
-
│ ├─
|
|
171
|
-
│ ├─
|
|
172
|
-
│ ├─
|
|
173
|
-
│ ├─
|
|
174
|
-
│
|
|
175
|
-
│
|
|
325
|
+
│ ├─ actions/ # ActionEngine (interventions)
|
|
326
|
+
│ │ ├─ types.ts
|
|
327
|
+
│ │ ├─ ActionEngine.ts
|
|
328
|
+
│ │ ├─ validation.ts
|
|
329
|
+
│ │ └─ executors/ # visual, dom, navigation executors
|
|
330
|
+
│ ├─ apps/ # App system (see APPS.md)
|
|
331
|
+
│ │ ├─ AppRegistry.ts # App registration and lifecycle
|
|
332
|
+
│ │ ├─ AppLoader.ts # Dynamic app loading
|
|
333
|
+
│ │ ├─ types.ts # AppManifest, AppContext types
|
|
334
|
+
│ │ └─ built-in/ # Core apps (bundled with runtime)
|
|
335
|
+
│ ├─ surfaces/ # Surfaces (UI rendering)
|
|
336
|
+
│ │ ├─ types.ts
|
|
337
|
+
│ │ ├─ Surfaces.ts
|
|
338
|
+
│ │ └─ positioning.ts
|
|
339
|
+
│ ├─ context/ # Page/session/viewport state
|
|
340
|
+
│ ├─ events/ # EventBus
|
|
341
|
+
│ ├─ state/ # StateStore
|
|
342
|
+
│ ├─ decisions/ # DecisionStrategy evaluation
|
|
343
|
+
│ ├─ runtime.ts # SmartCanvasRuntime factory
|
|
344
|
+
│ ├─ bootstrap.ts # Syntro.init()
|
|
345
|
+
│ ├─ SmartCanvasElement.tsx
|
|
346
|
+
│ ├─ SmartCanvasApp.tsx
|
|
347
|
+
│ └─ SmartCanvasPortal.tsx
|
|
348
|
+
├─ schema/
|
|
349
|
+
│ └─ canvas-config.schema.json
|
|
350
|
+
├─ APPS.md
|
|
351
|
+
├─ CAPABILITIES.md
|
|
352
|
+
├─ RUNTIME_V2_REFERENCE.md
|
|
176
353
|
└─ README.md
|
|
177
354
|
```
|
|
178
355
|
|
|
179
|
-
|
|
356
|
+
---
|
|
180
357
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
358
|
+
## Development Commands
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
# Build TypeScript library
|
|
362
|
+
npm run build:lib
|
|
363
|
+
|
|
364
|
+
# Build CDN bundle
|
|
365
|
+
npm run build:cdn
|
|
366
|
+
|
|
367
|
+
# Full build
|
|
368
|
+
npm run build
|
|
369
|
+
|
|
370
|
+
# Validate a config file
|
|
371
|
+
npm run validate-config -- path/to/config.json
|
|
372
|
+
|
|
373
|
+
# Type check
|
|
374
|
+
npx tsc --noEmit
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Testing
|
|
380
|
+
|
|
381
|
+
- Shadow root is **open**, so Playwright/Cypress can traverse via `.shadow()`
|
|
382
|
+
- Data hooks: `[data-shadow-canvas-id="overlay-launcher"]`, `[data-shadow-canvas-id="rectangle-${id}"]`
|
|
383
|
+
- `SmartCanvasController` exposes `open/close` for deterministic tests
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Analytics Events
|
|
388
|
+
|
|
389
|
+
The telemetry client emits:
|
|
390
|
+
|
|
391
|
+
| Event | Description |
|
|
392
|
+
| --- | --- |
|
|
393
|
+
| `shadow_canvas_opened` / `shadow_canvas_closed` | Toggle button interactions |
|
|
394
|
+
| `shadow_canvas_rectangle_viewed` | A rectangle becomes visible |
|
|
395
|
+
| `shadow_canvas_action` | CTA click, chatbot send, overlay events |
|
|
396
|
+
| `action.applied` / `action.reverted` | ActionEngine events |
|
|
397
|
+
| `surface.mounted` / `surface.unmounted` | Surfaces events |
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Quick Checklist
|
|
402
|
+
|
|
403
|
+
1. Call `registerSmartCanvasElement()` once per app
|
|
404
|
+
2. Render `<smart-canvas>` (custom element)
|
|
405
|
+
3. Portal your React tree into the element's shadow via `SmartCanvasPortal`
|
|
406
|
+
4. Configure the SDK with your API credentials
|
|
407
|
+
5. Use `runtime.actions` for interventions, `runtime.surfaces` for UI
|
|
408
|
+
6. For non-React pages, call `window.SmartCanvas.create()` with configuration
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RuntimeProvider - React context for accessing the v2 Runtime.
|
|
3
|
+
*
|
|
4
|
+
* Provides access to the SmartCanvasRuntime from any component in the tree.
|
|
5
|
+
*/
|
|
6
|
+
import { ReactNode } from "react";
|
|
7
|
+
import type { SmartCanvasRuntime } from "./runtime";
|
|
8
|
+
import type { RuntimeContext } from "./context/types";
|
|
9
|
+
export interface RuntimeProviderProps {
|
|
10
|
+
/** The SmartCanvasRuntime instance */
|
|
11
|
+
runtime: SmartCanvasRuntime | null;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Provider component for the SmartCanvasRuntime.
|
|
16
|
+
*/
|
|
17
|
+
export declare function RuntimeProvider({ runtime, children }: RuntimeProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
/**
|
|
19
|
+
* Hook to access the SmartCanvasRuntime.
|
|
20
|
+
*/
|
|
21
|
+
export declare function useRuntime(): SmartCanvasRuntime | null;
|
|
22
|
+
/**
|
|
23
|
+
* Hook to access the current runtime context (reactive).
|
|
24
|
+
*/
|
|
25
|
+
export declare function useRuntimeContext(): RuntimeContext | null;
|
|
26
|
+
/**
|
|
27
|
+
* Hook to access a specific part of the runtime context.
|
|
28
|
+
*/
|
|
29
|
+
export declare function usePageContext(): import("./context").PageContext | null;
|
|
30
|
+
export declare function useSessionContext(): import("./context").SessionContext | null;
|
|
31
|
+
export declare function useViewportContext(): import("./context").ViewportContext | null;
|
|
32
|
+
/**
|
|
33
|
+
* Hook to subscribe to runtime events.
|
|
34
|
+
*/
|
|
35
|
+
export declare function useRuntimeEvents(filter: {
|
|
36
|
+
names?: string[];
|
|
37
|
+
patterns?: string[];
|
|
38
|
+
sources?: Array<"posthog" | "canvas" | "derived">;
|
|
39
|
+
} | undefined, callback: (event: import("./events/types").NormalizedEvent) => void, deps?: React.DependencyList): void;
|
|
40
|
+
/**
|
|
41
|
+
* Hook to access state helpers.
|
|
42
|
+
*/
|
|
43
|
+
export declare function useRuntimeState(): import("./state").StateStore | null;
|
|
44
|
+
/**
|
|
45
|
+
* Hook to evaluate a decision strategy.
|
|
46
|
+
*/
|
|
47
|
+
export declare function useDecision<T>(strategy: import("./decisions/types").DecisionStrategy<T> | undefined | null, defaultValue: T): {
|
|
48
|
+
value: T;
|
|
49
|
+
isFallback: boolean;
|
|
50
|
+
isLoading: boolean;
|
|
51
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* RuntimeProvider - React context for accessing the v2 Runtime.
|
|
4
|
+
*
|
|
5
|
+
* Provides access to the SmartCanvasRuntime from any component in the tree.
|
|
6
|
+
*/
|
|
7
|
+
import { createContext, useContext, useMemo, useEffect, useState } from "react";
|
|
8
|
+
const RuntimeReactContext = createContext({
|
|
9
|
+
runtime: null,
|
|
10
|
+
context: null,
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Provider component for the SmartCanvasRuntime.
|
|
14
|
+
*/
|
|
15
|
+
export function RuntimeProvider({ runtime, children }) {
|
|
16
|
+
// Subscribe to context changes and re-render when they occur
|
|
17
|
+
const [context, setContext] = useState(runtime ? runtime.context.get() : null);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!runtime)
|
|
20
|
+
return;
|
|
21
|
+
// Set initial context
|
|
22
|
+
setContext(runtime.context.get());
|
|
23
|
+
// Subscribe to changes
|
|
24
|
+
const unsubscribe = runtime.context.subscribe((ctx) => {
|
|
25
|
+
setContext(ctx);
|
|
26
|
+
});
|
|
27
|
+
return unsubscribe;
|
|
28
|
+
}, [runtime]);
|
|
29
|
+
const value = useMemo(() => ({ runtime, context }), [runtime, context]);
|
|
30
|
+
return (_jsx(RuntimeReactContext.Provider, { value: value, children: children }));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Hook to access the SmartCanvasRuntime.
|
|
34
|
+
*/
|
|
35
|
+
export function useRuntime() {
|
|
36
|
+
const { runtime } = useContext(RuntimeReactContext);
|
|
37
|
+
return runtime;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Hook to access the current runtime context (reactive).
|
|
41
|
+
*/
|
|
42
|
+
export function useRuntimeContext() {
|
|
43
|
+
const { context } = useContext(RuntimeReactContext);
|
|
44
|
+
return context;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Hook to access a specific part of the runtime context.
|
|
48
|
+
*/
|
|
49
|
+
export function usePageContext() {
|
|
50
|
+
var _a;
|
|
51
|
+
const context = useRuntimeContext();
|
|
52
|
+
return (_a = context === null || context === void 0 ? void 0 : context.page) !== null && _a !== void 0 ? _a : null;
|
|
53
|
+
}
|
|
54
|
+
export function useSessionContext() {
|
|
55
|
+
var _a;
|
|
56
|
+
const context = useRuntimeContext();
|
|
57
|
+
return (_a = context === null || context === void 0 ? void 0 : context.session) !== null && _a !== void 0 ? _a : null;
|
|
58
|
+
}
|
|
59
|
+
export function useViewportContext() {
|
|
60
|
+
var _a;
|
|
61
|
+
const context = useRuntimeContext();
|
|
62
|
+
return (_a = context === null || context === void 0 ? void 0 : context.viewport) !== null && _a !== void 0 ? _a : null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Hook to subscribe to runtime events.
|
|
66
|
+
*/
|
|
67
|
+
export function useRuntimeEvents(filter, callback, deps = []) {
|
|
68
|
+
const runtime = useRuntime();
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!runtime)
|
|
71
|
+
return;
|
|
72
|
+
const unsubscribe = filter
|
|
73
|
+
? runtime.events.subscribe(filter, callback)
|
|
74
|
+
: runtime.events.subscribe(callback);
|
|
75
|
+
return unsubscribe;
|
|
76
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
77
|
+
}, [runtime, ...deps]);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Hook to access state helpers.
|
|
81
|
+
*/
|
|
82
|
+
export function useRuntimeState() {
|
|
83
|
+
var _a;
|
|
84
|
+
const runtime = useRuntime();
|
|
85
|
+
return (_a = runtime === null || runtime === void 0 ? void 0 : runtime.state) !== null && _a !== void 0 ? _a : null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Hook to evaluate a decision strategy.
|
|
89
|
+
*/
|
|
90
|
+
export function useDecision(strategy, defaultValue) {
|
|
91
|
+
const runtime = useRuntime();
|
|
92
|
+
const [result, setResult] = useState({
|
|
93
|
+
value: defaultValue,
|
|
94
|
+
isFallback: true,
|
|
95
|
+
isLoading: true,
|
|
96
|
+
});
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!runtime || !strategy) {
|
|
99
|
+
setResult({ value: defaultValue, isFallback: true, isLoading: false });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let cancelled = false;
|
|
103
|
+
runtime.evaluate(strategy).then((res) => {
|
|
104
|
+
if (!cancelled) {
|
|
105
|
+
setResult({ value: res.value, isFallback: res.isFallback, isLoading: false });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return () => {
|
|
109
|
+
cancelled = true;
|
|
110
|
+
};
|
|
111
|
+
}, [runtime, strategy, defaultValue]);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=RuntimeProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RuntimeProvider.js","sourceRoot":"","sources":["../src/RuntimeProvider.tsx"],"names":[],"mappings":"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"}
|
package/dist/SmartCanvasApp.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ import { SmartCanvasController } from "./controller";
|
|
|
3
3
|
import type { CanvasConfigFetcher } from "./types";
|
|
4
4
|
import type { ExperimentClient } from "./experiments/types";
|
|
5
5
|
import type { TelemetryClient } from "./telemetry/types";
|
|
6
|
-
import type { OverlayRecipeFetcher } from "./overlays/fetcher";
|
|
7
6
|
import { MountableComponent } from "./api";
|
|
8
7
|
import { CanvasTheme } from "./components/ShadowCanvasOverlay";
|
|
8
|
+
import type { SmartCanvasRuntime } from "./runtime";
|
|
9
9
|
export interface SmartCanvasAppProps {
|
|
10
10
|
controller: SmartCanvasController;
|
|
11
11
|
fetcher?: CanvasConfigFetcher;
|
|
@@ -16,9 +16,15 @@ export interface SmartCanvasAppProps {
|
|
|
16
16
|
pollIntervalMs?: number;
|
|
17
17
|
experiments?: ExperimentClient;
|
|
18
18
|
telemetry?: TelemetryClient;
|
|
19
|
-
|
|
19
|
+
/** v2 Runtime instance for context, events, state, and decisions */
|
|
20
|
+
runtime?: SmartCanvasRuntime;
|
|
21
|
+
/** @deprecated Actions replace overlay recipes. Use config.actions instead. */
|
|
22
|
+
overlayFetcher?: () => Promise<unknown>;
|
|
23
|
+
/** @deprecated Actions replace overlay recipes. Use config.actions instead. */
|
|
20
24
|
overlayConfigUri?: string;
|
|
25
|
+
/** @deprecated Actions replace overlay recipes. Use config.actions instead. */
|
|
21
26
|
overlayConfigFeatureKey?: string;
|
|
27
|
+
/** @deprecated Actions replace overlay recipes. Use config.actions instead. */
|
|
22
28
|
overlayFetchCredentials?: RequestCredentials;
|
|
23
29
|
footerSlot?: ReactNode;
|
|
24
30
|
launcherLabel?: string;
|
|
@@ -26,4 +32,4 @@ export interface SmartCanvasAppProps {
|
|
|
26
32
|
customRenderers?: Record<string, MountableComponent>;
|
|
27
33
|
theme?: Partial<CanvasTheme>;
|
|
28
34
|
}
|
|
29
|
-
export declare function SmartCanvasApp({ controller, fetcher, configUri, configUriFeatureKey, configFeatureKey, fetchCredentials, pollIntervalMs, experiments, telemetry, overlayFetcher, overlayConfigUri, overlayConfigFeatureKey, overlayFetchCredentials, footerSlot, launcherLabel, canvasHost, customRenderers, theme, }: SmartCanvasAppProps): import("react/jsx-runtime").JSX.Element
|
|
35
|
+
export declare function SmartCanvasApp({ controller, fetcher, configUri, configUriFeatureKey, configFeatureKey, fetchCredentials, pollIntervalMs, experiments, telemetry, runtime, overlayFetcher, overlayConfigUri, overlayConfigFeatureKey, overlayFetchCredentials, footerSlot, launcherLabel, canvasHost, customRenderers, theme, }: SmartCanvasAppProps): import("react/jsx-runtime").JSX.Element;
|