@syntrologie/adapt-content 0.0.0-semantically-released
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/editor.d.ts +22 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +18 -0
- package/dist/runtime.d.ts +83 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +265 -0
- package/dist/sanitizer.d.ts +8 -0
- package/dist/sanitizer.d.ts.map +1 -0
- package/dist/sanitizer.js +75 -0
- package/dist/schema.d.ts +140 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +56 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/package.json +50 -0
package/dist/editor.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive Content - Editor Module
|
|
3
|
+
*
|
|
4
|
+
* Editor panel for configuring content modifications.
|
|
5
|
+
*/
|
|
6
|
+
import type { EditorPanelProps } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Content editor panel component.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ContentEditor({ config: _config, onChange: _onChange, editor: _editor, }: EditorPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Editor module configuration.
|
|
13
|
+
*/
|
|
14
|
+
export declare const editor: {
|
|
15
|
+
panel: {
|
|
16
|
+
title: string;
|
|
17
|
+
icon: string;
|
|
18
|
+
description: string;
|
|
19
|
+
};
|
|
20
|
+
component: typeof ContentEditor;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,SAAS,EACnB,MAAM,EAAE,OAAO,GAChB,EAAE,gBAAgB,2CAOlB;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;;;;;;;CAOlB,CAAC"}
|
package/dist/editor.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Content editor panel component.
|
|
4
|
+
*/
|
|
5
|
+
export function ContentEditor({ config: _config, onChange: _onChange, editor: _editor, }) {
|
|
6
|
+
return (_jsxs("div", { className: "syntro-content-editor", children: [_jsx("p", { children: "Content editor coming soon..." }), _jsx("p", { children: "Configure text replacements, attribute changes, and style modifications." })] }));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Editor module configuration.
|
|
10
|
+
*/
|
|
11
|
+
export const editor = {
|
|
12
|
+
panel: {
|
|
13
|
+
title: 'Content',
|
|
14
|
+
icon: '📝',
|
|
15
|
+
description: 'Text and attribute modifications',
|
|
16
|
+
},
|
|
17
|
+
component: ContentEditor,
|
|
18
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive Content - Runtime Module
|
|
3
|
+
*
|
|
4
|
+
* DOM manipulation actions: insertHtml, setText, setAttr, addClass, removeClass, setStyle.
|
|
5
|
+
* These follow the hostPatcher snapshot pattern for safe reversibility.
|
|
6
|
+
*/
|
|
7
|
+
import type { InsertHtmlAction, SetTextAction, SetAttrAction, AddClassAction, RemoveClassAction, SetStyleAction, ActionExecutor } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* Execute an insertHtml action
|
|
10
|
+
*/
|
|
11
|
+
export declare const executeInsertHtml: ActionExecutor<InsertHtmlAction>;
|
|
12
|
+
/**
|
|
13
|
+
* Execute a setText action
|
|
14
|
+
*/
|
|
15
|
+
export declare const executeSetText: ActionExecutor<SetTextAction>;
|
|
16
|
+
/**
|
|
17
|
+
* Execute a setAttr action
|
|
18
|
+
*/
|
|
19
|
+
export declare const executeSetAttr: ActionExecutor<SetAttrAction>;
|
|
20
|
+
/**
|
|
21
|
+
* Execute an addClass action
|
|
22
|
+
*/
|
|
23
|
+
export declare const executeAddClass: ActionExecutor<AddClassAction>;
|
|
24
|
+
/**
|
|
25
|
+
* Execute a removeClass action
|
|
26
|
+
*/
|
|
27
|
+
export declare const executeRemoveClass: ActionExecutor<RemoveClassAction>;
|
|
28
|
+
/**
|
|
29
|
+
* Execute a setStyle action
|
|
30
|
+
*/
|
|
31
|
+
export declare const executeSetStyle: ActionExecutor<SetStyleAction>;
|
|
32
|
+
/**
|
|
33
|
+
* All executors provided by this app.
|
|
34
|
+
* These are registered with the runtime's ExecutorRegistry.
|
|
35
|
+
*/
|
|
36
|
+
export declare const executors: readonly [{
|
|
37
|
+
readonly kind: "content:insertHtml";
|
|
38
|
+
readonly executor: ActionExecutor<InsertHtmlAction>;
|
|
39
|
+
}, {
|
|
40
|
+
readonly kind: "content:setText";
|
|
41
|
+
readonly executor: ActionExecutor<SetTextAction>;
|
|
42
|
+
}, {
|
|
43
|
+
readonly kind: "content:setAttr";
|
|
44
|
+
readonly executor: ActionExecutor<SetAttrAction>;
|
|
45
|
+
}, {
|
|
46
|
+
readonly kind: "content:addClass";
|
|
47
|
+
readonly executor: ActionExecutor<AddClassAction>;
|
|
48
|
+
}, {
|
|
49
|
+
readonly kind: "content:removeClass";
|
|
50
|
+
readonly executor: ActionExecutor<RemoveClassAction>;
|
|
51
|
+
}, {
|
|
52
|
+
readonly kind: "content:setStyle";
|
|
53
|
+
readonly executor: ActionExecutor<SetStyleAction>;
|
|
54
|
+
}];
|
|
55
|
+
/**
|
|
56
|
+
* App runtime manifest.
|
|
57
|
+
*/
|
|
58
|
+
export declare const runtime: {
|
|
59
|
+
id: string;
|
|
60
|
+
version: string;
|
|
61
|
+
name: string;
|
|
62
|
+
description: string;
|
|
63
|
+
executors: readonly [{
|
|
64
|
+
readonly kind: "content:insertHtml";
|
|
65
|
+
readonly executor: ActionExecutor<InsertHtmlAction>;
|
|
66
|
+
}, {
|
|
67
|
+
readonly kind: "content:setText";
|
|
68
|
+
readonly executor: ActionExecutor<SetTextAction>;
|
|
69
|
+
}, {
|
|
70
|
+
readonly kind: "content:setAttr";
|
|
71
|
+
readonly executor: ActionExecutor<SetAttrAction>;
|
|
72
|
+
}, {
|
|
73
|
+
readonly kind: "content:addClass";
|
|
74
|
+
readonly executor: ActionExecutor<AddClassAction>;
|
|
75
|
+
}, {
|
|
76
|
+
readonly kind: "content:removeClass";
|
|
77
|
+
readonly executor: ActionExecutor<RemoveClassAction>;
|
|
78
|
+
}, {
|
|
79
|
+
readonly kind: "content:setStyle";
|
|
80
|
+
readonly executor: ActionExecutor<SetStyleAction>;
|
|
81
|
+
}];
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,cAAc,EAEd,cAAc,EACf,MAAM,SAAS,CAAC;AAOjB;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAAc,CAAC,gBAAgB,CAmE9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,aAAa,CA+BxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,aAAa,CA2CxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,cAAc,CA8B1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,cAAc,CAAC,iBAAiB,CA8BhE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,cAAc,CA+C1D,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;EAOZ,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;CAMnB,CAAC"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive Content - Runtime Module
|
|
3
|
+
*
|
|
4
|
+
* DOM manipulation actions: insertHtml, setText, setAttr, addClass, removeClass, setStyle.
|
|
5
|
+
* These follow the hostPatcher snapshot pattern for safe reversibility.
|
|
6
|
+
*/
|
|
7
|
+
import { sanitizeHtml } from './sanitizer';
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Executors
|
|
10
|
+
// ============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Execute an insertHtml action
|
|
13
|
+
*/
|
|
14
|
+
export const executeInsertHtml = async (action, context) => {
|
|
15
|
+
const anchorEl = context.resolveAnchor(action.anchorId);
|
|
16
|
+
if (!anchorEl) {
|
|
17
|
+
throw new Error(`Anchor not found: ${action.anchorId}`);
|
|
18
|
+
}
|
|
19
|
+
// Sanitize HTML content using context utility
|
|
20
|
+
const sanitizedHtml = sanitizeHtml(action.html);
|
|
21
|
+
// Create container for inserted content
|
|
22
|
+
const container = document.createElement('div');
|
|
23
|
+
container.setAttribute('data-syntro-action-id', context.generateId());
|
|
24
|
+
container.innerHTML = sanitizedHtml;
|
|
25
|
+
// Keep track of original state for replace position
|
|
26
|
+
let originalContent = null;
|
|
27
|
+
switch (action.position) {
|
|
28
|
+
case 'before':
|
|
29
|
+
anchorEl.insertAdjacentElement('beforebegin', container);
|
|
30
|
+
break;
|
|
31
|
+
case 'after':
|
|
32
|
+
anchorEl.insertAdjacentElement('afterend', container);
|
|
33
|
+
break;
|
|
34
|
+
case 'prepend':
|
|
35
|
+
anchorEl.insertBefore(container, anchorEl.firstChild);
|
|
36
|
+
break;
|
|
37
|
+
case 'append':
|
|
38
|
+
anchorEl.appendChild(container);
|
|
39
|
+
break;
|
|
40
|
+
case 'replace':
|
|
41
|
+
originalContent = anchorEl.innerHTML;
|
|
42
|
+
anchorEl.replaceWith(container);
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
context.publishEvent('action.applied', {
|
|
46
|
+
id: context.generateId(),
|
|
47
|
+
kind: 'content:insertHtml',
|
|
48
|
+
anchorId: action.anchorId,
|
|
49
|
+
position: action.position,
|
|
50
|
+
});
|
|
51
|
+
return {
|
|
52
|
+
cleanup: () => {
|
|
53
|
+
if (action.position === 'replace' && originalContent !== null) {
|
|
54
|
+
// Restore original element
|
|
55
|
+
const restoredEl = document.createElement(anchorEl.tagName);
|
|
56
|
+
restoredEl.innerHTML = originalContent;
|
|
57
|
+
// Copy attributes
|
|
58
|
+
Array.from(anchorEl.attributes).forEach((attr) => {
|
|
59
|
+
restoredEl.setAttribute(attr.name, attr.value);
|
|
60
|
+
});
|
|
61
|
+
container.replaceWith(restoredEl);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
container.remove();
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
updateFn: (changes) => {
|
|
68
|
+
if ('html' in changes && typeof changes.html === 'string') {
|
|
69
|
+
container.innerHTML = sanitizeHtml(changes.html);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Execute a setText action
|
|
76
|
+
*/
|
|
77
|
+
export const executeSetText = async (action, context) => {
|
|
78
|
+
const anchorEl = context.resolveAnchor(action.anchorId);
|
|
79
|
+
if (!anchorEl) {
|
|
80
|
+
throw new Error(`Anchor not found: ${action.anchorId}`);
|
|
81
|
+
}
|
|
82
|
+
// Snapshot original text
|
|
83
|
+
const originalText = anchorEl.textContent ?? '';
|
|
84
|
+
// Set new text
|
|
85
|
+
anchorEl.textContent = action.text;
|
|
86
|
+
context.publishEvent('action.applied', {
|
|
87
|
+
id: context.generateId(),
|
|
88
|
+
kind: 'content:setText',
|
|
89
|
+
anchorId: action.anchorId,
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
cleanup: () => {
|
|
93
|
+
anchorEl.textContent = originalText;
|
|
94
|
+
},
|
|
95
|
+
updateFn: (changes) => {
|
|
96
|
+
if ('text' in changes && typeof changes.text === 'string') {
|
|
97
|
+
anchorEl.textContent = changes.text;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Execute a setAttr action
|
|
104
|
+
*/
|
|
105
|
+
export const executeSetAttr = async (action, context) => {
|
|
106
|
+
const anchorEl = context.resolveAnchor(action.anchorId);
|
|
107
|
+
if (!anchorEl) {
|
|
108
|
+
throw new Error(`Anchor not found: ${action.anchorId}`);
|
|
109
|
+
}
|
|
110
|
+
// Block dangerous attributes
|
|
111
|
+
const dangerousAttrs = ['onclick', 'onerror', 'onload', 'onmouseover', 'onfocus', 'onblur'];
|
|
112
|
+
if (dangerousAttrs.includes(action.attr.toLowerCase()) || action.attr.startsWith('on')) {
|
|
113
|
+
throw new Error(`Dangerous attribute not allowed: ${action.attr}`);
|
|
114
|
+
}
|
|
115
|
+
// Snapshot original attribute value
|
|
116
|
+
const originalValue = anchorEl.getAttribute(action.attr);
|
|
117
|
+
const hadAttribute = anchorEl.hasAttribute(action.attr);
|
|
118
|
+
// Set new attribute
|
|
119
|
+
anchorEl.setAttribute(action.attr, action.value);
|
|
120
|
+
context.publishEvent('action.applied', {
|
|
121
|
+
id: context.generateId(),
|
|
122
|
+
kind: 'content:setAttr',
|
|
123
|
+
anchorId: action.anchorId,
|
|
124
|
+
attr: action.attr,
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
cleanup: () => {
|
|
128
|
+
if (hadAttribute && originalValue !== null) {
|
|
129
|
+
anchorEl.setAttribute(action.attr, originalValue);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
anchorEl.removeAttribute(action.attr);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
updateFn: (changes) => {
|
|
136
|
+
if ('value' in changes && typeof changes.value === 'string') {
|
|
137
|
+
anchorEl.setAttribute(action.attr, changes.value);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Execute an addClass action
|
|
144
|
+
*/
|
|
145
|
+
export const executeAddClass = async (action, context) => {
|
|
146
|
+
const anchorEl = context.resolveAnchor(action.anchorId);
|
|
147
|
+
if (!anchorEl) {
|
|
148
|
+
throw new Error(`Anchor not found: ${action.anchorId}`);
|
|
149
|
+
}
|
|
150
|
+
// Check if class was already present
|
|
151
|
+
const hadClass = anchorEl.classList.contains(action.className);
|
|
152
|
+
// Add class
|
|
153
|
+
anchorEl.classList.add(action.className);
|
|
154
|
+
context.publishEvent('action.applied', {
|
|
155
|
+
id: context.generateId(),
|
|
156
|
+
kind: 'content:addClass',
|
|
157
|
+
anchorId: action.anchorId,
|
|
158
|
+
className: action.className,
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
cleanup: () => {
|
|
162
|
+
// Only remove if we added it
|
|
163
|
+
if (!hadClass) {
|
|
164
|
+
anchorEl.classList.remove(action.className);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* Execute a removeClass action
|
|
171
|
+
*/
|
|
172
|
+
export const executeRemoveClass = async (action, context) => {
|
|
173
|
+
const anchorEl = context.resolveAnchor(action.anchorId);
|
|
174
|
+
if (!anchorEl) {
|
|
175
|
+
throw new Error(`Anchor not found: ${action.anchorId}`);
|
|
176
|
+
}
|
|
177
|
+
// Check if class was present
|
|
178
|
+
const hadClass = anchorEl.classList.contains(action.className);
|
|
179
|
+
// Remove class
|
|
180
|
+
anchorEl.classList.remove(action.className);
|
|
181
|
+
context.publishEvent('action.applied', {
|
|
182
|
+
id: context.generateId(),
|
|
183
|
+
kind: 'content:removeClass',
|
|
184
|
+
anchorId: action.anchorId,
|
|
185
|
+
className: action.className,
|
|
186
|
+
});
|
|
187
|
+
return {
|
|
188
|
+
cleanup: () => {
|
|
189
|
+
// Only re-add if we removed it
|
|
190
|
+
if (hadClass) {
|
|
191
|
+
anchorEl.classList.add(action.className);
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Execute a setStyle action
|
|
198
|
+
*/
|
|
199
|
+
export const executeSetStyle = async (action, context) => {
|
|
200
|
+
const anchorEl = context.resolveAnchor(action.anchorId);
|
|
201
|
+
if (!anchorEl) {
|
|
202
|
+
throw new Error(`Anchor not found: ${action.anchorId}`);
|
|
203
|
+
}
|
|
204
|
+
// Snapshot original styles
|
|
205
|
+
const originalStyles = new Map();
|
|
206
|
+
for (const prop of Object.keys(action.styles)) {
|
|
207
|
+
const current = anchorEl.style.getPropertyValue(prop);
|
|
208
|
+
originalStyles.set(prop, current);
|
|
209
|
+
}
|
|
210
|
+
// Apply new styles
|
|
211
|
+
for (const [prop, value] of Object.entries(action.styles)) {
|
|
212
|
+
anchorEl.style.setProperty(prop, value);
|
|
213
|
+
}
|
|
214
|
+
context.publishEvent('action.applied', {
|
|
215
|
+
id: context.generateId(),
|
|
216
|
+
kind: 'content:setStyle',
|
|
217
|
+
anchorId: action.anchorId,
|
|
218
|
+
styles: Object.keys(action.styles),
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
cleanup: () => {
|
|
222
|
+
// Restore original styles
|
|
223
|
+
for (const [prop, originalValue] of originalStyles) {
|
|
224
|
+
if (originalValue) {
|
|
225
|
+
anchorEl.style.setProperty(prop, originalValue);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
anchorEl.style.removeProperty(prop);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
updateFn: (changes) => {
|
|
233
|
+
if ('styles' in changes && typeof changes.styles === 'object' && changes.styles) {
|
|
234
|
+
for (const [prop, value] of Object.entries(changes.styles)) {
|
|
235
|
+
anchorEl.style.setProperty(prop, value);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
// ============================================================================
|
|
242
|
+
// Executor Definitions for Registration
|
|
243
|
+
// ============================================================================
|
|
244
|
+
/**
|
|
245
|
+
* All executors provided by this app.
|
|
246
|
+
* These are registered with the runtime's ExecutorRegistry.
|
|
247
|
+
*/
|
|
248
|
+
export const executors = [
|
|
249
|
+
{ kind: 'content:insertHtml', executor: executeInsertHtml },
|
|
250
|
+
{ kind: 'content:setText', executor: executeSetText },
|
|
251
|
+
{ kind: 'content:setAttr', executor: executeSetAttr },
|
|
252
|
+
{ kind: 'content:addClass', executor: executeAddClass },
|
|
253
|
+
{ kind: 'content:removeClass', executor: executeRemoveClass },
|
|
254
|
+
{ kind: 'content:setStyle', executor: executeSetStyle },
|
|
255
|
+
];
|
|
256
|
+
/**
|
|
257
|
+
* App runtime manifest.
|
|
258
|
+
*/
|
|
259
|
+
export const runtime = {
|
|
260
|
+
id: 'adaptive-content',
|
|
261
|
+
version: '1.0.0',
|
|
262
|
+
name: 'Content',
|
|
263
|
+
description: 'DOM manipulation for text, attributes, and styles',
|
|
264
|
+
executors,
|
|
265
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../src/sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqDjD"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML Sanitizer
|
|
3
|
+
*
|
|
4
|
+
* Sanitizes HTML to prevent XSS attacks.
|
|
5
|
+
* Uses native Sanitizer API when available, falls back to whitelist approach.
|
|
6
|
+
*/
|
|
7
|
+
const ALLOWED_TAGS = new Set([
|
|
8
|
+
'b',
|
|
9
|
+
'strong',
|
|
10
|
+
'i',
|
|
11
|
+
'em',
|
|
12
|
+
'u',
|
|
13
|
+
'span',
|
|
14
|
+
'div',
|
|
15
|
+
'p',
|
|
16
|
+
'br',
|
|
17
|
+
'ul',
|
|
18
|
+
'ol',
|
|
19
|
+
'li',
|
|
20
|
+
'code',
|
|
21
|
+
'pre',
|
|
22
|
+
'small',
|
|
23
|
+
'sup',
|
|
24
|
+
'sub',
|
|
25
|
+
'a',
|
|
26
|
+
'button',
|
|
27
|
+
]);
|
|
28
|
+
export function sanitizeHtml(html) {
|
|
29
|
+
// Try native Sanitizer API first
|
|
30
|
+
const hasNative = typeof window.Sanitizer === 'function';
|
|
31
|
+
if (hasNative) {
|
|
32
|
+
try {
|
|
33
|
+
const s = new window.Sanitizer({});
|
|
34
|
+
const frag = s.sanitizeToFragment(html);
|
|
35
|
+
const div = document.createElement('div');
|
|
36
|
+
div.append(frag);
|
|
37
|
+
return div.innerHTML;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Fall through to manual sanitizer
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Conservative fallback sanitizer
|
|
44
|
+
const tpl = document.createElement('template');
|
|
45
|
+
tpl.innerHTML = html;
|
|
46
|
+
const root = tpl.content;
|
|
47
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null);
|
|
48
|
+
const toRemove = [];
|
|
49
|
+
while (walker.nextNode()) {
|
|
50
|
+
const el = walker.currentNode;
|
|
51
|
+
const tag = el.tagName.toLowerCase();
|
|
52
|
+
if (!ALLOWED_TAGS.has(tag)) {
|
|
53
|
+
toRemove.push(el);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Remove dangerous attributes
|
|
57
|
+
for (const attr of Array.from(el.attributes)) {
|
|
58
|
+
const name = attr.name.toLowerCase();
|
|
59
|
+
const value = attr.value.trim().toLowerCase();
|
|
60
|
+
const isEvent = name.startsWith('on');
|
|
61
|
+
const isJsUrl = (name === 'href' || name === 'src') && value.startsWith('javascript:');
|
|
62
|
+
if (isEvent || isJsUrl) {
|
|
63
|
+
el.removeAttribute(attr.name);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Remove disallowed elements but keep their children
|
|
68
|
+
for (const el of toRemove) {
|
|
69
|
+
while (el.firstChild) {
|
|
70
|
+
el.parentNode?.insertBefore(el.firstChild, el);
|
|
71
|
+
}
|
|
72
|
+
el.remove();
|
|
73
|
+
}
|
|
74
|
+
return tpl.innerHTML;
|
|
75
|
+
}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive Content - Config Schema
|
|
3
|
+
*
|
|
4
|
+
* Zod schema for validating content app configuration.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
/**
|
|
8
|
+
* Content app config schema.
|
|
9
|
+
* Defines the structure for content modifications in a canvas config.
|
|
10
|
+
*/
|
|
11
|
+
export declare const configSchema: z.ZodObject<{
|
|
12
|
+
/** Text replacements */
|
|
13
|
+
textReplacements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
14
|
+
anchorId: z.ZodString;
|
|
15
|
+
text: z.ZodString;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
anchorId: string;
|
|
18
|
+
text: string;
|
|
19
|
+
}, {
|
|
20
|
+
anchorId: string;
|
|
21
|
+
text: string;
|
|
22
|
+
}>, "many">>;
|
|
23
|
+
/** Attribute modifications */
|
|
24
|
+
attributeChanges: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
25
|
+
anchorId: z.ZodString;
|
|
26
|
+
attr: z.ZodString;
|
|
27
|
+
value: z.ZodString;
|
|
28
|
+
}, "strip", z.ZodTypeAny, {
|
|
29
|
+
anchorId: string;
|
|
30
|
+
attr: string;
|
|
31
|
+
value: string;
|
|
32
|
+
}, {
|
|
33
|
+
anchorId: string;
|
|
34
|
+
attr: string;
|
|
35
|
+
value: string;
|
|
36
|
+
}>, "many">>;
|
|
37
|
+
/** Style modifications */
|
|
38
|
+
styleChanges: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
39
|
+
anchorId: z.ZodString;
|
|
40
|
+
styles: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
41
|
+
}, "strip", z.ZodTypeAny, {
|
|
42
|
+
anchorId: string;
|
|
43
|
+
styles: Record<string, string>;
|
|
44
|
+
}, {
|
|
45
|
+
anchorId: string;
|
|
46
|
+
styles: Record<string, string>;
|
|
47
|
+
}>, "many">>;
|
|
48
|
+
/** HTML insertions */
|
|
49
|
+
htmlInsertions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
50
|
+
anchorId: z.ZodString;
|
|
51
|
+
html: z.ZodString;
|
|
52
|
+
position: z.ZodEnum<["before", "after", "prepend", "append", "replace"]>;
|
|
53
|
+
}, "strip", z.ZodTypeAny, {
|
|
54
|
+
anchorId: string;
|
|
55
|
+
html: string;
|
|
56
|
+
position: "before" | "after" | "prepend" | "append" | "replace";
|
|
57
|
+
}, {
|
|
58
|
+
anchorId: string;
|
|
59
|
+
html: string;
|
|
60
|
+
position: "before" | "after" | "prepend" | "append" | "replace";
|
|
61
|
+
}>, "many">>;
|
|
62
|
+
/** Class additions */
|
|
63
|
+
classAdditions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
64
|
+
anchorId: z.ZodString;
|
|
65
|
+
className: z.ZodString;
|
|
66
|
+
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
anchorId: string;
|
|
68
|
+
className: string;
|
|
69
|
+
}, {
|
|
70
|
+
anchorId: string;
|
|
71
|
+
className: string;
|
|
72
|
+
}>, "many">>;
|
|
73
|
+
/** Class removals */
|
|
74
|
+
classRemovals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
75
|
+
anchorId: z.ZodString;
|
|
76
|
+
className: z.ZodString;
|
|
77
|
+
}, "strip", z.ZodTypeAny, {
|
|
78
|
+
anchorId: string;
|
|
79
|
+
className: string;
|
|
80
|
+
}, {
|
|
81
|
+
anchorId: string;
|
|
82
|
+
className: string;
|
|
83
|
+
}>, "many">>;
|
|
84
|
+
}, "strip", z.ZodTypeAny, {
|
|
85
|
+
textReplacements?: {
|
|
86
|
+
anchorId: string;
|
|
87
|
+
text: string;
|
|
88
|
+
}[] | undefined;
|
|
89
|
+
attributeChanges?: {
|
|
90
|
+
anchorId: string;
|
|
91
|
+
attr: string;
|
|
92
|
+
value: string;
|
|
93
|
+
}[] | undefined;
|
|
94
|
+
styleChanges?: {
|
|
95
|
+
anchorId: string;
|
|
96
|
+
styles: Record<string, string>;
|
|
97
|
+
}[] | undefined;
|
|
98
|
+
htmlInsertions?: {
|
|
99
|
+
anchorId: string;
|
|
100
|
+
html: string;
|
|
101
|
+
position: "before" | "after" | "prepend" | "append" | "replace";
|
|
102
|
+
}[] | undefined;
|
|
103
|
+
classAdditions?: {
|
|
104
|
+
anchorId: string;
|
|
105
|
+
className: string;
|
|
106
|
+
}[] | undefined;
|
|
107
|
+
classRemovals?: {
|
|
108
|
+
anchorId: string;
|
|
109
|
+
className: string;
|
|
110
|
+
}[] | undefined;
|
|
111
|
+
}, {
|
|
112
|
+
textReplacements?: {
|
|
113
|
+
anchorId: string;
|
|
114
|
+
text: string;
|
|
115
|
+
}[] | undefined;
|
|
116
|
+
attributeChanges?: {
|
|
117
|
+
anchorId: string;
|
|
118
|
+
attr: string;
|
|
119
|
+
value: string;
|
|
120
|
+
}[] | undefined;
|
|
121
|
+
styleChanges?: {
|
|
122
|
+
anchorId: string;
|
|
123
|
+
styles: Record<string, string>;
|
|
124
|
+
}[] | undefined;
|
|
125
|
+
htmlInsertions?: {
|
|
126
|
+
anchorId: string;
|
|
127
|
+
html: string;
|
|
128
|
+
position: "before" | "after" | "prepend" | "append" | "replace";
|
|
129
|
+
}[] | undefined;
|
|
130
|
+
classAdditions?: {
|
|
131
|
+
anchorId: string;
|
|
132
|
+
className: string;
|
|
133
|
+
}[] | undefined;
|
|
134
|
+
classRemovals?: {
|
|
135
|
+
anchorId: string;
|
|
136
|
+
className: string;
|
|
137
|
+
}[] | undefined;
|
|
138
|
+
}>;
|
|
139
|
+
export type ContentConfig = z.infer<typeof configSchema>;
|
|
140
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,YAAY;IACvB,wBAAwB;;;;;;;;;;;IAUxB,8BAA8B;;;;;;;;;;;;;;IAW9B,0BAA0B;;;;;;;;;;;IAU1B,sBAAsB;;;;;;;;;;;;;;IAWtB,sBAAsB;;;;;;;;;;;IAUtB,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASrB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive Content - Config Schema
|
|
3
|
+
*
|
|
4
|
+
* Zod schema for validating content app configuration.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
/**
|
|
8
|
+
* Content app config schema.
|
|
9
|
+
* Defines the structure for content modifications in a canvas config.
|
|
10
|
+
*/
|
|
11
|
+
export const configSchema = z.object({
|
|
12
|
+
/** Text replacements */
|
|
13
|
+
textReplacements: z
|
|
14
|
+
.array(z.object({
|
|
15
|
+
anchorId: z.string(),
|
|
16
|
+
text: z.string(),
|
|
17
|
+
}))
|
|
18
|
+
.optional(),
|
|
19
|
+
/** Attribute modifications */
|
|
20
|
+
attributeChanges: z
|
|
21
|
+
.array(z.object({
|
|
22
|
+
anchorId: z.string(),
|
|
23
|
+
attr: z.string(),
|
|
24
|
+
value: z.string(),
|
|
25
|
+
}))
|
|
26
|
+
.optional(),
|
|
27
|
+
/** Style modifications */
|
|
28
|
+
styleChanges: z
|
|
29
|
+
.array(z.object({
|
|
30
|
+
anchorId: z.string(),
|
|
31
|
+
styles: z.record(z.string()),
|
|
32
|
+
}))
|
|
33
|
+
.optional(),
|
|
34
|
+
/** HTML insertions */
|
|
35
|
+
htmlInsertions: z
|
|
36
|
+
.array(z.object({
|
|
37
|
+
anchorId: z.string(),
|
|
38
|
+
html: z.string(),
|
|
39
|
+
position: z.enum(['before', 'after', 'prepend', 'append', 'replace']),
|
|
40
|
+
}))
|
|
41
|
+
.optional(),
|
|
42
|
+
/** Class additions */
|
|
43
|
+
classAdditions: z
|
|
44
|
+
.array(z.object({
|
|
45
|
+
anchorId: z.string(),
|
|
46
|
+
className: z.string(),
|
|
47
|
+
}))
|
|
48
|
+
.optional(),
|
|
49
|
+
/** Class removals */
|
|
50
|
+
classRemovals: z
|
|
51
|
+
.array(z.object({
|
|
52
|
+
anchorId: z.string(),
|
|
53
|
+
className: z.string(),
|
|
54
|
+
}))
|
|
55
|
+
.optional(),
|
|
56
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types from @syntrologie/runtime-sdk
|
|
3
|
+
*
|
|
4
|
+
* Minimal type definitions for building this app independently.
|
|
5
|
+
* These match the types exported from @syntrologie/runtime-sdk/types.
|
|
6
|
+
*/
|
|
7
|
+
export interface EditorPanelProps {
|
|
8
|
+
config: Record<string, unknown>;
|
|
9
|
+
onChange: (config: Record<string, unknown>) => void;
|
|
10
|
+
editor: {
|
|
11
|
+
setDirty: (dirty: boolean) => void;
|
|
12
|
+
navigateHome: () => Promise<boolean>;
|
|
13
|
+
save: () => Promise<void>;
|
|
14
|
+
publish: (captureScreenshot?: boolean) => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
platformClient?: unknown;
|
|
17
|
+
}
|
|
18
|
+
export type InsertPosition = 'before' | 'after' | 'prepend' | 'append' | 'replace';
|
|
19
|
+
interface BaseAction {
|
|
20
|
+
label?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface InsertHtmlAction extends BaseAction {
|
|
23
|
+
kind: 'content:insertHtml';
|
|
24
|
+
anchorId: string;
|
|
25
|
+
html: string;
|
|
26
|
+
position: InsertPosition;
|
|
27
|
+
}
|
|
28
|
+
export interface SetTextAction extends BaseAction {
|
|
29
|
+
kind: 'content:setText';
|
|
30
|
+
anchorId: string;
|
|
31
|
+
text: string;
|
|
32
|
+
}
|
|
33
|
+
export interface SetAttrAction extends BaseAction {
|
|
34
|
+
kind: 'content:setAttr';
|
|
35
|
+
anchorId: string;
|
|
36
|
+
attr: string;
|
|
37
|
+
value: string;
|
|
38
|
+
}
|
|
39
|
+
export interface AddClassAction extends BaseAction {
|
|
40
|
+
kind: 'content:addClass';
|
|
41
|
+
anchorId: string;
|
|
42
|
+
className: string;
|
|
43
|
+
}
|
|
44
|
+
export interface RemoveClassAction extends BaseAction {
|
|
45
|
+
kind: 'content:removeClass';
|
|
46
|
+
anchorId: string;
|
|
47
|
+
className: string;
|
|
48
|
+
}
|
|
49
|
+
export interface SetStyleAction extends BaseAction {
|
|
50
|
+
kind: 'content:setStyle';
|
|
51
|
+
anchorId: string;
|
|
52
|
+
styles: Record<string, string>;
|
|
53
|
+
}
|
|
54
|
+
export type ExecutorCleanup = () => void | Promise<void>;
|
|
55
|
+
export type ExecutorUpdate = (changes: Record<string, unknown>) => void | Promise<void>;
|
|
56
|
+
export interface ExecutorResult {
|
|
57
|
+
cleanup: ExecutorCleanup;
|
|
58
|
+
updateFn?: ExecutorUpdate;
|
|
59
|
+
}
|
|
60
|
+
export interface ExecutorContext {
|
|
61
|
+
overlayRoot: HTMLElement;
|
|
62
|
+
resolveAnchor: (anchorId: string) => HTMLElement | null;
|
|
63
|
+
generateId: () => string;
|
|
64
|
+
publishEvent: (name: string, props?: Record<string, unknown>) => void;
|
|
65
|
+
adaptiveId?: string;
|
|
66
|
+
}
|
|
67
|
+
export type ActionExecutor<T> = (action: T, context: ExecutorContext) => Promise<ExecutorResult>;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpD,MAAM,EAAE;QACN,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;QACnC,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,EAAE,CAAC,iBAAiB,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACzD,CAAC;IACF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAMD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEnF,UAAU,UAAU;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,IAAI,EAAE,oBAAoB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,IAAI,EAAE,qBAAqB,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAMD,MAAM,MAAM,eAAe,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACzD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAExF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,WAAW,GAAG,IAAI,CAAC;IACxD,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC"}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@syntrologie/adapt-content",
|
|
3
|
+
"version": "0.0.0-semantically-released",
|
|
4
|
+
"description": "Adaptive Content app - DOM manipulation actions for text, attributes, and styles",
|
|
5
|
+
"license": "Proprietary",
|
|
6
|
+
"private": false,
|
|
7
|
+
"author": "Syntrologie <eng@syntrologie.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/SyntropyForge/amazing-demos.git",
|
|
11
|
+
"directory": "tech-core/sdks/adaptives/adaptive-content"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"exports": {
|
|
18
|
+
"./runtime": {
|
|
19
|
+
"types": "./dist/runtime.d.ts",
|
|
20
|
+
"import": "./dist/runtime.js"
|
|
21
|
+
},
|
|
22
|
+
"./schema": {
|
|
23
|
+
"types": "./dist/schema.d.ts",
|
|
24
|
+
"import": "./dist/schema.js"
|
|
25
|
+
},
|
|
26
|
+
"./editor": {
|
|
27
|
+
"types": "./dist/editor.d.ts",
|
|
28
|
+
"import": "./dist/editor.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc",
|
|
36
|
+
"clean": "rm -rf dist"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@syntrologie/runtime-sdk": "^2.0.0",
|
|
40
|
+
"react": ">=18.0.0",
|
|
41
|
+
"react-dom": ">=18.0.0",
|
|
42
|
+
"zod": "^3.0.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@floating-ui/dom": "^1.6.0",
|
|
46
|
+
"@types/react": "^18.0.0",
|
|
47
|
+
"typescript": "^5.0.0",
|
|
48
|
+
"zod": "^3.25.0"
|
|
49
|
+
}
|
|
50
|
+
}
|