@syntrologie/runtime-sdk 2.4.0-canary.24 → 2.4.0-canary.26
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/dist/actions/schema.js +2 -2
- package/dist/{chunk-LD22WJ44.js → chunk-E26VPJAS.js} +138 -59
- package/dist/chunk-E26VPJAS.js.map +7 -0
- package/dist/{chunk-NM5Y27GX.js → chunk-R5DNAIRI.js} +2 -2
- package/dist/{chunk-WILWIL6L.js → chunk-XDYJ64IN.js} +18 -4
- package/dist/chunk-XDYJ64IN.js.map +7 -0
- package/dist/config/schema.d.ts +3127 -6
- package/dist/config/schema.js +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +2 -2
- package/dist/react.js +3 -3
- package/dist/smart-canvas.esm.js +35 -35
- package/dist/smart-canvas.esm.js.map +3 -3
- package/dist/smart-canvas.js +135 -48
- package/dist/smart-canvas.js.map +2 -2
- package/dist/smart-canvas.min.js +35 -35
- package/dist/smart-canvas.min.js.map +3 -3
- package/dist/version.d.ts +1 -1
- package/package.json +7 -7
- package/schema/canvas-config.schema.json +331 -5
- package/scripts/validate-config.mjs +102 -0
- package/dist/chunk-LD22WJ44.js.map +0 -7
- package/dist/chunk-WILWIL6L.js.map +0 -7
- /package/dist/{chunk-NM5Y27GX.js.map → chunk-R5DNAIRI.js.map} +0 -0
package/dist/version.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syntrologie/runtime-sdk",
|
|
3
|
-
"version": "2.4.0-canary.
|
|
3
|
+
"version": "2.4.0-canary.26",
|
|
4
4
|
"description": "Syntrologie Runtime SDK for web experimentation and analytics",
|
|
5
5
|
"license": "Proprietary",
|
|
6
6
|
"private": false,
|
|
@@ -67,12 +67,12 @@
|
|
|
67
67
|
"@floating-ui/dom": "^1.7.5",
|
|
68
68
|
"@growthbook/growthbook": "~1.6.2",
|
|
69
69
|
"@growthbook/growthbook-react": "^1.6.4",
|
|
70
|
-
"@syntrologie/adapt-chatbot": "2.4.0-canary.
|
|
71
|
-
"@syntrologie/adapt-content": "2.4.0-canary.
|
|
72
|
-
"@syntrologie/adapt-faq": "2.4.0-canary.
|
|
73
|
-
"@syntrologie/adapt-gamification": "2.4.0-canary.
|
|
74
|
-
"@syntrologie/adapt-nav": "2.4.0-canary.
|
|
75
|
-
"@syntrologie/adapt-overlays": "2.4.0-canary.
|
|
70
|
+
"@syntrologie/adapt-chatbot": "2.4.0-canary.26",
|
|
71
|
+
"@syntrologie/adapt-content": "2.4.0-canary.26",
|
|
72
|
+
"@syntrologie/adapt-faq": "2.4.0-canary.26",
|
|
73
|
+
"@syntrologie/adapt-gamification": "2.4.0-canary.26",
|
|
74
|
+
"@syntrologie/adapt-nav": "2.4.0-canary.26",
|
|
75
|
+
"@syntrologie/adapt-overlays": "2.4.0-canary.26",
|
|
76
76
|
"lucide-react": "^0.576.0",
|
|
77
77
|
"posthog-js": "~1.302.2",
|
|
78
78
|
"zod": "^3.25.76"
|
|
@@ -45,11 +45,328 @@
|
|
|
45
45
|
"$ref": "#/$defs/launcherConfig",
|
|
46
46
|
"description": "Launcher button configuration"
|
|
47
47
|
},
|
|
48
|
-
"
|
|
49
|
-
"type": "
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
48
|
+
"meta": {
|
|
49
|
+
"type": "object",
|
|
50
|
+
"properties": {
|
|
51
|
+
"verificationSteps": {
|
|
52
|
+
"type": "array",
|
|
53
|
+
"items": {
|
|
54
|
+
"anyOf": [
|
|
55
|
+
{
|
|
56
|
+
"type": "string"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"type": "object",
|
|
60
|
+
"properties": {
|
|
61
|
+
"text": {
|
|
62
|
+
"type": "string"
|
|
63
|
+
},
|
|
64
|
+
"check": {
|
|
65
|
+
"anyOf": [
|
|
66
|
+
{
|
|
67
|
+
"type": "object",
|
|
68
|
+
"properties": {
|
|
69
|
+
"type": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"const": "page_url"
|
|
72
|
+
},
|
|
73
|
+
"url": {
|
|
74
|
+
"type": "string"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"required": [
|
|
78
|
+
"type",
|
|
79
|
+
"url"
|
|
80
|
+
],
|
|
81
|
+
"additionalProperties": false
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "object",
|
|
85
|
+
"properties": {
|
|
86
|
+
"type": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"const": "route"
|
|
89
|
+
},
|
|
90
|
+
"routeId": {
|
|
91
|
+
"type": "string"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"required": [
|
|
95
|
+
"type",
|
|
96
|
+
"routeId"
|
|
97
|
+
],
|
|
98
|
+
"additionalProperties": false
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"type": "object",
|
|
102
|
+
"properties": {
|
|
103
|
+
"type": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"const": "anchor_visible"
|
|
106
|
+
},
|
|
107
|
+
"anchorId": {
|
|
108
|
+
"type": "string"
|
|
109
|
+
},
|
|
110
|
+
"state": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"enum": [
|
|
113
|
+
"visible",
|
|
114
|
+
"present",
|
|
115
|
+
"absent"
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"required": [
|
|
120
|
+
"type",
|
|
121
|
+
"anchorId",
|
|
122
|
+
"state"
|
|
123
|
+
],
|
|
124
|
+
"additionalProperties": false
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"type": "object",
|
|
128
|
+
"properties": {
|
|
129
|
+
"type": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"const": "event_occurred"
|
|
132
|
+
},
|
|
133
|
+
"eventName": {
|
|
134
|
+
"type": "string"
|
|
135
|
+
},
|
|
136
|
+
"withinMs": {
|
|
137
|
+
"type": "number"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"required": [
|
|
141
|
+
"type",
|
|
142
|
+
"eventName"
|
|
143
|
+
],
|
|
144
|
+
"additionalProperties": false
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"type": "object",
|
|
148
|
+
"properties": {
|
|
149
|
+
"type": {
|
|
150
|
+
"type": "string",
|
|
151
|
+
"const": "state_equals"
|
|
152
|
+
},
|
|
153
|
+
"key": {
|
|
154
|
+
"type": "string"
|
|
155
|
+
},
|
|
156
|
+
"value": {}
|
|
157
|
+
},
|
|
158
|
+
"required": [
|
|
159
|
+
"type",
|
|
160
|
+
"key"
|
|
161
|
+
],
|
|
162
|
+
"additionalProperties": false
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"type": "object",
|
|
166
|
+
"properties": {
|
|
167
|
+
"type": {
|
|
168
|
+
"type": "string",
|
|
169
|
+
"const": "viewport"
|
|
170
|
+
},
|
|
171
|
+
"minWidth": {
|
|
172
|
+
"type": "number"
|
|
173
|
+
},
|
|
174
|
+
"maxWidth": {
|
|
175
|
+
"type": "number"
|
|
176
|
+
},
|
|
177
|
+
"minHeight": {
|
|
178
|
+
"type": "number"
|
|
179
|
+
},
|
|
180
|
+
"maxHeight": {
|
|
181
|
+
"type": "number"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"required": [
|
|
185
|
+
"type"
|
|
186
|
+
],
|
|
187
|
+
"additionalProperties": false
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"type": "object",
|
|
191
|
+
"properties": {
|
|
192
|
+
"type": {
|
|
193
|
+
"type": "string",
|
|
194
|
+
"const": "session_metric"
|
|
195
|
+
},
|
|
196
|
+
"key": {
|
|
197
|
+
"type": "string"
|
|
198
|
+
},
|
|
199
|
+
"operator": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"enum": [
|
|
202
|
+
"gte",
|
|
203
|
+
"lte",
|
|
204
|
+
"eq",
|
|
205
|
+
"gt",
|
|
206
|
+
"lt"
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
"threshold": {
|
|
210
|
+
"type": "number"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"required": [
|
|
214
|
+
"type",
|
|
215
|
+
"key",
|
|
216
|
+
"operator",
|
|
217
|
+
"threshold"
|
|
218
|
+
],
|
|
219
|
+
"additionalProperties": false
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"type": "object",
|
|
223
|
+
"properties": {
|
|
224
|
+
"type": {
|
|
225
|
+
"type": "string",
|
|
226
|
+
"const": "dismissed"
|
|
227
|
+
},
|
|
228
|
+
"key": {
|
|
229
|
+
"type": "string"
|
|
230
|
+
},
|
|
231
|
+
"inverted": {
|
|
232
|
+
"type": "boolean"
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
"required": [
|
|
236
|
+
"type",
|
|
237
|
+
"key"
|
|
238
|
+
],
|
|
239
|
+
"additionalProperties": false
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"type": "object",
|
|
243
|
+
"properties": {
|
|
244
|
+
"type": {
|
|
245
|
+
"type": "string",
|
|
246
|
+
"const": "cooldown_active"
|
|
247
|
+
},
|
|
248
|
+
"key": {
|
|
249
|
+
"type": "string"
|
|
250
|
+
},
|
|
251
|
+
"inverted": {
|
|
252
|
+
"type": "boolean"
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
"required": [
|
|
256
|
+
"type",
|
|
257
|
+
"key"
|
|
258
|
+
],
|
|
259
|
+
"additionalProperties": false
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"type": "object",
|
|
263
|
+
"properties": {
|
|
264
|
+
"type": {
|
|
265
|
+
"type": "string",
|
|
266
|
+
"const": "frequency_limit"
|
|
267
|
+
},
|
|
268
|
+
"key": {
|
|
269
|
+
"type": "string"
|
|
270
|
+
},
|
|
271
|
+
"limit": {
|
|
272
|
+
"type": "number"
|
|
273
|
+
},
|
|
274
|
+
"inverted": {
|
|
275
|
+
"type": "boolean"
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
"required": [
|
|
279
|
+
"type",
|
|
280
|
+
"key",
|
|
281
|
+
"limit"
|
|
282
|
+
],
|
|
283
|
+
"additionalProperties": false
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"type": "object",
|
|
287
|
+
"properties": {
|
|
288
|
+
"type": {
|
|
289
|
+
"type": "string",
|
|
290
|
+
"const": "event_count"
|
|
291
|
+
},
|
|
292
|
+
"key": {
|
|
293
|
+
"type": "string"
|
|
294
|
+
},
|
|
295
|
+
"operator": {
|
|
296
|
+
"type": "string",
|
|
297
|
+
"enum": [
|
|
298
|
+
"gte",
|
|
299
|
+
"lte",
|
|
300
|
+
"eq",
|
|
301
|
+
"gt",
|
|
302
|
+
"lt"
|
|
303
|
+
]
|
|
304
|
+
},
|
|
305
|
+
"count": {
|
|
306
|
+
"type": "integer",
|
|
307
|
+
"minimum": 0
|
|
308
|
+
},
|
|
309
|
+
"withinMs": {
|
|
310
|
+
"type": "number",
|
|
311
|
+
"exclusiveMinimum": 0
|
|
312
|
+
},
|
|
313
|
+
"counter": {
|
|
314
|
+
"type": "object",
|
|
315
|
+
"properties": {
|
|
316
|
+
"events": {
|
|
317
|
+
"type": "array",
|
|
318
|
+
"items": {
|
|
319
|
+
"type": "string"
|
|
320
|
+
},
|
|
321
|
+
"minItems": 1
|
|
322
|
+
},
|
|
323
|
+
"match": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"additionalProperties": {
|
|
326
|
+
"type": "object",
|
|
327
|
+
"properties": {
|
|
328
|
+
"equals": {
|
|
329
|
+
"type": [
|
|
330
|
+
"string",
|
|
331
|
+
"number",
|
|
332
|
+
"boolean"
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
"contains": {
|
|
336
|
+
"type": "string"
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
"additionalProperties": false
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
"required": [
|
|
344
|
+
"events"
|
|
345
|
+
],
|
|
346
|
+
"additionalProperties": false
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
"required": [
|
|
350
|
+
"type",
|
|
351
|
+
"key",
|
|
352
|
+
"operator",
|
|
353
|
+
"count"
|
|
354
|
+
],
|
|
355
|
+
"additionalProperties": false
|
|
356
|
+
}
|
|
357
|
+
]
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
"required": [
|
|
361
|
+
"text"
|
|
362
|
+
],
|
|
363
|
+
"additionalProperties": false
|
|
364
|
+
}
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
"additionalProperties": true
|
|
53
370
|
}
|
|
54
371
|
},
|
|
55
372
|
"additionalProperties": false,
|
|
@@ -271,6 +588,15 @@
|
|
|
271
588
|
},
|
|
272
589
|
"width": {
|
|
273
590
|
"type": "string"
|
|
591
|
+
},
|
|
592
|
+
"transitionDuration": {
|
|
593
|
+
"type": "string"
|
|
594
|
+
},
|
|
595
|
+
"transitionEasing": {
|
|
596
|
+
"type": "string"
|
|
597
|
+
},
|
|
598
|
+
"transitionFade": {
|
|
599
|
+
"type": "string"
|
|
274
600
|
}
|
|
275
601
|
},
|
|
276
602
|
"additionalProperties": false
|
|
@@ -159,3 +159,105 @@ if (routeErrors.length > 0) {
|
|
|
159
159
|
for (const e of routeErrors) console.error(` - ${e}`);
|
|
160
160
|
process.exit(1);
|
|
161
161
|
}
|
|
162
|
+
|
|
163
|
+
// --- Semantic warnings (non-blocking, design-quality hints) ---
|
|
164
|
+
const warnings = [];
|
|
165
|
+
|
|
166
|
+
// Tile-level route restrictions should be rare. They hide the entire tile
|
|
167
|
+
// (and all its actions) on non-matching pages. The preferred pattern is:
|
|
168
|
+
// - Tile: routes ["/**"] (or omitted) + onlyIfPopulated: true
|
|
169
|
+
// - Actions: triggerWhen with route conditions to self-target specific pages
|
|
170
|
+
// This way the tile is always available and actions decide when to appear.
|
|
171
|
+
for (const tile of config.tiles ?? []) {
|
|
172
|
+
const routes = tile.activation?.routes;
|
|
173
|
+
if (!routes) continue;
|
|
174
|
+
|
|
175
|
+
const includePatterns = routes.include ?? [];
|
|
176
|
+
const hasCatchAll = includePatterns.some((r) => WILDCARD_PATTERNS.includes(r) || r === '/**');
|
|
177
|
+
if (hasCatchAll) continue;
|
|
178
|
+
|
|
179
|
+
const routeList = includePatterns.join('", "');
|
|
180
|
+
const actions = tile.props?.actions ?? [];
|
|
181
|
+
const actionsWithoutTrigger = actions.filter((a) => !a.triggerWhen).length;
|
|
182
|
+
|
|
183
|
+
let detail = '';
|
|
184
|
+
if (actionsWithoutTrigger > 0) {
|
|
185
|
+
detail =
|
|
186
|
+
`\n ${actionsWithoutTrigger} of ${actions.length} action(s) have no triggerWhen — ` +
|
|
187
|
+
`they'll never appear outside ["${routeList}"].`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
warnings.push(
|
|
191
|
+
`Tile "${tile.id}": activation.routes restricts to ["${routeList}"].${detail}\n` +
|
|
192
|
+
` Prefer: set routes to ["/**"], add onlyIfPopulated: true, and use ` +
|
|
193
|
+
`triggerWhen with a "route" condition on each action to target specific pages.`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Celebrate actions without triggerWhen fire on every page load — almost always a mistake.
|
|
198
|
+
// The effect (confetti, etc.) should be scoped to a specific page or user action.
|
|
199
|
+
for (const [i, action] of (config.actions ?? []).entries()) {
|
|
200
|
+
if (action.kind !== 'overlays:celebrate') continue;
|
|
201
|
+
if (action.triggerWhen) continue;
|
|
202
|
+
|
|
203
|
+
const label = action.label ? ` (label: "${action.label}")` : '';
|
|
204
|
+
warnings.push(
|
|
205
|
+
`actions[${i}]${label}: overlays:celebrate has no triggerWhen.\n` +
|
|
206
|
+
` This fires the "${action.effect ?? 'confetti'}" effect on EVERY page load.\n` +
|
|
207
|
+
` Add a triggerWhen with a page_url condition to scope it, e.g.:\n` +
|
|
208
|
+
` "triggerWhen": {"type":"rules","rules":[{"conditions":[{"type":"page_url","url":"**/target-page"}],"value":true}],"default":false}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// page_url conditions should use ** prefix to match any host, not absolute paths.
|
|
213
|
+
// "/dashboard/state" won't match "http://localhost:8088/dashboard/state" because
|
|
214
|
+
// page_url evaluates against the full URL. Use "**/dashboard/state" instead.
|
|
215
|
+
function collectPageUrlConditions(obj, path, results) {
|
|
216
|
+
if (!obj || typeof obj !== 'object') return;
|
|
217
|
+
if (Array.isArray(obj)) {
|
|
218
|
+
for (const [i, item] of obj.entries()) {
|
|
219
|
+
collectPageUrlConditions(item, `${path}[${i}]`, results);
|
|
220
|
+
}
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (obj.type === 'page_url' && typeof obj.url === 'string') {
|
|
224
|
+
results.push({ path, url: obj.url });
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
228
|
+
collectPageUrlConditions(val, `${path}.${key}`, results);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const pageUrlHits = [];
|
|
233
|
+
collectPageUrlConditions(config, 'config', pageUrlHits);
|
|
234
|
+
for (const { path, url } of pageUrlHits) {
|
|
235
|
+
if (url.startsWith('/')) {
|
|
236
|
+
warnings.push(
|
|
237
|
+
`${path}: page_url "${url}" uses an absolute path.\n` +
|
|
238
|
+
` page_url matches against the full URL (e.g., "http://localhost:8088${url}"),\n` +
|
|
239
|
+
` so "${url}" will never match. Use "**${url}" instead.`
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (warnings.length > 0) {
|
|
245
|
+
console.warn(`\n\u26A0\uFE0F ${warnings.length} design warning(s):`);
|
|
246
|
+
for (const w of warnings) console.warn(` - ${w}`);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// --- Display meta info (non-blocking, informational) ---
|
|
250
|
+
const meta = config.meta;
|
|
251
|
+
if (meta) {
|
|
252
|
+
if (meta.name) console.log(`\n\uD83D\uDCCB ${meta.name}`);
|
|
253
|
+
if (meta.description) console.log(` ${meta.description}`);
|
|
254
|
+
if (meta.trigger) console.log(` Trigger: ${meta.trigger}`);
|
|
255
|
+
if (meta.verificationSteps?.length > 0) {
|
|
256
|
+
console.log(`\n\uD83E\uDDEA Verification steps:`);
|
|
257
|
+
for (const [i, step] of meta.verificationSteps.entries()) {
|
|
258
|
+
const text = typeof step === 'string' ? step : step.text;
|
|
259
|
+
const check = typeof step === 'object' && step.check ? ` [auto: ${step.check.type}]` : '';
|
|
260
|
+
console.log(` ${i + 1}. ${text}${check}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|