@weave-apps/sdk 0.1.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/README.md +241 -0
- package/bin/build.js +81 -0
- package/bin/compile.js +109 -0
- package/bin/init.js +251 -0
- package/dist/SidekickAPIClient.d.ts +231 -0
- package/dist/SidekickAPIClient.d.ts.map +1 -0
- package/dist/SidekickAPIClient.js +274 -0
- package/dist/SidekickBaseApp.d.ts +177 -0
- package/dist/SidekickBaseApp.d.ts.map +1 -0
- package/dist/SidekickBaseApp.js +228 -0
- package/dist/SidekickDOMAPI.d.ts +433 -0
- package/dist/SidekickDOMAPI.d.ts.map +1 -0
- package/dist/SidekickDOMAPI.js +620 -0
- package/dist/WeaveAPIClient.d.ts +231 -0
- package/dist/WeaveAPIClient.d.ts.map +1 -0
- package/dist/WeaveAPIClient.js +274 -0
- package/dist/WeaveBaseApp.d.ts +177 -0
- package/dist/WeaveBaseApp.d.ts.map +1 -0
- package/dist/WeaveBaseApp.js +229 -0
- package/dist/WeaveDOMAPI.d.ts +433 -0
- package/dist/WeaveDOMAPI.d.ts.map +1 -0
- package/dist/WeaveDOMAPI.js +620 -0
- package/dist/global.d.ts +19 -0
- package/dist/global.d.ts.map +1 -0
- package/dist/global.js +17 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/package.json +45 -0
- package/scripts/copy-sdk-files.js +57 -0
- package/scripts/extract-settings-schema.js +235 -0
- package/templates/README.md +202 -0
- package/templates/WEAVE_SPEC.md +3703 -0
- package/tsconfig.app.json +17 -0
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weave DOM API
|
|
3
|
+
*
|
|
4
|
+
* Client-side API for iframe apps to interact with the parent page DOM
|
|
5
|
+
* through the secure DOM Bridge in the content script.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* DOM operation types (must match content script)
|
|
9
|
+
*/
|
|
10
|
+
var DOMOperation;
|
|
11
|
+
(function (DOMOperation) {
|
|
12
|
+
// Read operations
|
|
13
|
+
DOMOperation["QUERY"] = "QUERY";
|
|
14
|
+
DOMOperation["QUERY_ALL"] = "QUERY_ALL";
|
|
15
|
+
DOMOperation["GET_TEXT"] = "GET_TEXT";
|
|
16
|
+
DOMOperation["GET_ATTRIBUTE"] = "GET_ATTRIBUTE";
|
|
17
|
+
DOMOperation["GET_VALUE"] = "GET_VALUE";
|
|
18
|
+
DOMOperation["HAS_CLASS"] = "HAS_CLASS";
|
|
19
|
+
DOMOperation["GET_PAGE_URL"] = "GET_PAGE_URL";
|
|
20
|
+
// Write operations
|
|
21
|
+
DOMOperation["SET_TEXT"] = "SET_TEXT";
|
|
22
|
+
DOMOperation["SET_ATTRIBUTE"] = "SET_ATTRIBUTE";
|
|
23
|
+
DOMOperation["SET_VALUE"] = "SET_VALUE";
|
|
24
|
+
DOMOperation["ADD_CLASS"] = "ADD_CLASS";
|
|
25
|
+
DOMOperation["REMOVE_CLASS"] = "REMOVE_CLASS";
|
|
26
|
+
DOMOperation["TOGGLE_CLASS"] = "TOGGLE_CLASS";
|
|
27
|
+
DOMOperation["SET_STYLE"] = "SET_STYLE";
|
|
28
|
+
// DOM manipulation
|
|
29
|
+
DOMOperation["INSERT_HTML"] = "INSERT_HTML";
|
|
30
|
+
DOMOperation["REMOVE_ELEMENT"] = "REMOVE_ELEMENT";
|
|
31
|
+
// Element injection with event listeners
|
|
32
|
+
DOMOperation["INJECT_ELEMENT"] = "INJECT_ELEMENT";
|
|
33
|
+
DOMOperation["REMOVE_INJECTED_ELEMENT"] = "REMOVE_INJECTED_ELEMENT";
|
|
34
|
+
// Form operations
|
|
35
|
+
DOMOperation["GET_FORM_DATA"] = "GET_FORM_DATA";
|
|
36
|
+
DOMOperation["START_FORM_CLICK_LISTENER"] = "START_FORM_CLICK_LISTENER";
|
|
37
|
+
DOMOperation["STOP_FORM_CLICK_LISTENER"] = "STOP_FORM_CLICK_LISTENER";
|
|
38
|
+
DOMOperation["SET_FORM_FIELD_VALUE"] = "SET_FORM_FIELD_VALUE";
|
|
39
|
+
// Element click listener operations
|
|
40
|
+
DOMOperation["START_ELEMENT_CLICK_LISTENER"] = "START_ELEMENT_CLICK_LISTENER";
|
|
41
|
+
DOMOperation["STOP_ELEMENT_CLICK_LISTENER"] = "STOP_ELEMENT_CLICK_LISTENER";
|
|
42
|
+
// Click operation
|
|
43
|
+
DOMOperation["CLICK_ELEMENT"] = "CLICK_ELEMENT";
|
|
44
|
+
// Element watching operations
|
|
45
|
+
DOMOperation["WATCH_ELEMENT"] = "WATCH_ELEMENT";
|
|
46
|
+
DOMOperation["UNWATCH_ELEMENT"] = "UNWATCH_ELEMENT";
|
|
47
|
+
})(DOMOperation || (DOMOperation = {}));
|
|
48
|
+
/**
|
|
49
|
+
* Weave DOM API
|
|
50
|
+
* Provides methods for iframe apps to interact with parent page DOM
|
|
51
|
+
*/
|
|
52
|
+
export class WeaveDOMAPI {
|
|
53
|
+
constructor() {
|
|
54
|
+
this.pendingRequests = new Map();
|
|
55
|
+
this.messageListener = null;
|
|
56
|
+
this.requestCounter = 0;
|
|
57
|
+
this.timeout = 5000; // 5 second timeout
|
|
58
|
+
this.formClickCallback = null;
|
|
59
|
+
this.workflowSavedCallback = null;
|
|
60
|
+
this.triggerSavedCallback = null;
|
|
61
|
+
this.elementClickCallbacks = new Map();
|
|
62
|
+
this.elementSelectorClickCallbacks = new Map();
|
|
63
|
+
this.elementChangeCallbacks = new Map();
|
|
64
|
+
this.elementIdCounter = 0;
|
|
65
|
+
this.watcherIdCounter = 0;
|
|
66
|
+
this.initialize();
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Initialize the API and start listening for responses
|
|
70
|
+
*/
|
|
71
|
+
initialize() {
|
|
72
|
+
this.messageListener = (event) => {
|
|
73
|
+
this.handleResponse(event);
|
|
74
|
+
};
|
|
75
|
+
window.addEventListener('message', this.messageListener);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Cleanup
|
|
79
|
+
*/
|
|
80
|
+
destroy() {
|
|
81
|
+
if (this.messageListener) {
|
|
82
|
+
window.removeEventListener('message', this.messageListener);
|
|
83
|
+
this.messageListener = null;
|
|
84
|
+
}
|
|
85
|
+
this.pendingRequests.clear();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Handle response from content script
|
|
89
|
+
*/
|
|
90
|
+
handleResponse(event) {
|
|
91
|
+
const data = event.data;
|
|
92
|
+
// Only accept messages from parent (content script)
|
|
93
|
+
if (event.source !== window.parent) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Handle form click events
|
|
97
|
+
if (data?.type === 'WEAVE_FORM_CLICKED') {
|
|
98
|
+
if (this.formClickCallback) {
|
|
99
|
+
this.formClickCallback({
|
|
100
|
+
formData: data.formData,
|
|
101
|
+
clickedElement: data.clickedElement,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Handle workflow saved events
|
|
107
|
+
if (data?.type === 'WORKFLOW_SAVED') {
|
|
108
|
+
if (this.workflowSavedCallback) {
|
|
109
|
+
this.workflowSavedCallback(data.payload);
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Handle trigger saved events
|
|
114
|
+
if (data?.type === 'TRIGGER_SAVED') {
|
|
115
|
+
if (this.triggerSavedCallback) {
|
|
116
|
+
this.triggerSavedCallback(data.payload);
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// Handle element click events (for injected elements)
|
|
121
|
+
if (data?.type === 'WEAVE_ELEMENT_CLICKED') {
|
|
122
|
+
const callback = this.elementClickCallbacks.get(data.elementId);
|
|
123
|
+
if (callback) {
|
|
124
|
+
callback({
|
|
125
|
+
elementId: data.elementId,
|
|
126
|
+
event: data.event,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
// Handle element selector click events (for element click listeners)
|
|
132
|
+
if (data?.type === 'WEAVE_ELEMENT_SELECTOR_CLICKED') {
|
|
133
|
+
const callback = this.elementSelectorClickCallbacks.get(data.listenerId);
|
|
134
|
+
if (callback) {
|
|
135
|
+
callback({
|
|
136
|
+
element: data.element,
|
|
137
|
+
event: data.event,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// Handle element change events (for element watchers)
|
|
143
|
+
if (data?.type === 'WEAVE_ELEMENT_CHANGED') {
|
|
144
|
+
const callback = this.elementChangeCallbacks.get(data.watcherId);
|
|
145
|
+
if (callback) {
|
|
146
|
+
callback({
|
|
147
|
+
changeType: data.changeType,
|
|
148
|
+
element: data.element,
|
|
149
|
+
attributeName: data.attributeName,
|
|
150
|
+
attributeValue: data.attributeValue,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// Handle normal DOM operation responses
|
|
156
|
+
if (data?.type !== 'WEAVE_DOM_RESPONSE') {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const response = data;
|
|
160
|
+
const pending = this.pendingRequests.get(response.id);
|
|
161
|
+
if (!pending) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
this.pendingRequests.delete(response.id);
|
|
165
|
+
if (response.success) {
|
|
166
|
+
pending.resolve(response.data);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
pending.reject(new Error(response.error || 'Unknown error'));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Send request to content script
|
|
174
|
+
*/
|
|
175
|
+
sendRequest(operation, payload) {
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
const id = `dom-request-${++this.requestCounter}`;
|
|
178
|
+
const request = {
|
|
179
|
+
type: 'WEAVE_DOM_REQUEST',
|
|
180
|
+
id,
|
|
181
|
+
operation,
|
|
182
|
+
payload,
|
|
183
|
+
};
|
|
184
|
+
// Store pending request
|
|
185
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
186
|
+
// Set timeout
|
|
187
|
+
const timeoutId = setTimeout(() => {
|
|
188
|
+
this.pendingRequests.delete(id);
|
|
189
|
+
reject(new Error(`Request timeout: ${operation}`));
|
|
190
|
+
}, this.timeout);
|
|
191
|
+
// Clear timeout on resolve/reject
|
|
192
|
+
const originalResolve = resolve;
|
|
193
|
+
const originalReject = reject;
|
|
194
|
+
this.pendingRequests.set(id, {
|
|
195
|
+
resolve: (value) => {
|
|
196
|
+
clearTimeout(timeoutId);
|
|
197
|
+
originalResolve(value);
|
|
198
|
+
},
|
|
199
|
+
reject: (error) => {
|
|
200
|
+
clearTimeout(timeoutId);
|
|
201
|
+
originalReject(error);
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
// Send to parent window (content script will intercept)
|
|
205
|
+
window.parent.postMessage(request, '*');
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// Read Operations
|
|
210
|
+
// ============================================================================
|
|
211
|
+
/**
|
|
212
|
+
* Query a single element from parent page
|
|
213
|
+
*/
|
|
214
|
+
async query(selector) {
|
|
215
|
+
return this.sendRequest(DOMOperation.QUERY, { selector });
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Query all matching elements from parent page
|
|
219
|
+
*/
|
|
220
|
+
async queryAll(selector) {
|
|
221
|
+
return this.sendRequest(DOMOperation.QUERY_ALL, { selector });
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get text content of an element
|
|
225
|
+
*/
|
|
226
|
+
async getText(selector) {
|
|
227
|
+
return this.sendRequest(DOMOperation.GET_TEXT, { selector });
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get attribute value of an element
|
|
231
|
+
*/
|
|
232
|
+
async getAttribute(selector, attribute) {
|
|
233
|
+
return this.sendRequest(DOMOperation.GET_ATTRIBUTE, {
|
|
234
|
+
selector,
|
|
235
|
+
attribute
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get value of an input element
|
|
240
|
+
*/
|
|
241
|
+
async getValue(selector) {
|
|
242
|
+
return this.sendRequest(DOMOperation.GET_VALUE, { selector });
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Check if element has a class
|
|
246
|
+
*/
|
|
247
|
+
async hasClass(selector, className) {
|
|
248
|
+
return this.sendRequest(DOMOperation.HAS_CLASS, {
|
|
249
|
+
selector,
|
|
250
|
+
className
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get the current page URL
|
|
255
|
+
* Returns the parent page URL (not the iframe URL)
|
|
256
|
+
* @returns Promise with the current page URL
|
|
257
|
+
*/
|
|
258
|
+
async getPageUrl() {
|
|
259
|
+
return this.sendRequest(DOMOperation.GET_PAGE_URL, {});
|
|
260
|
+
}
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// Write Operations
|
|
263
|
+
// ============================================================================
|
|
264
|
+
/**
|
|
265
|
+
* Set text content of an element
|
|
266
|
+
*/
|
|
267
|
+
async setText(selector, text) {
|
|
268
|
+
return this.sendRequest(DOMOperation.SET_TEXT, { selector, text });
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Set attribute value of an element
|
|
272
|
+
*/
|
|
273
|
+
async setAttribute(selector, attribute, value) {
|
|
274
|
+
return this.sendRequest(DOMOperation.SET_ATTRIBUTE, {
|
|
275
|
+
selector,
|
|
276
|
+
attribute,
|
|
277
|
+
value
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Set value of an input element
|
|
282
|
+
*/
|
|
283
|
+
async setValue(selector, value) {
|
|
284
|
+
return this.sendRequest(DOMOperation.SET_VALUE, { selector, value });
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Add a class to an element
|
|
288
|
+
*/
|
|
289
|
+
async addClass(selector, className) {
|
|
290
|
+
return this.sendRequest(DOMOperation.ADD_CLASS, { selector, className });
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Remove a class from an element
|
|
294
|
+
*/
|
|
295
|
+
async removeClass(selector, className) {
|
|
296
|
+
return this.sendRequest(DOMOperation.REMOVE_CLASS, { selector, className });
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Toggle a class on an element
|
|
300
|
+
*/
|
|
301
|
+
async toggleClass(selector, className) {
|
|
302
|
+
return this.sendRequest(DOMOperation.TOGGLE_CLASS, { selector, className });
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Set a CSS style property on an element
|
|
306
|
+
*/
|
|
307
|
+
async setStyle(selector, property, value) {
|
|
308
|
+
return this.sendRequest(DOMOperation.SET_STYLE, {
|
|
309
|
+
selector,
|
|
310
|
+
property,
|
|
311
|
+
value
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Insert HTML relative to an element
|
|
316
|
+
*/
|
|
317
|
+
async insertHTML(selector, position, html) {
|
|
318
|
+
return this.sendRequest(DOMOperation.INSERT_HTML, {
|
|
319
|
+
selector,
|
|
320
|
+
position,
|
|
321
|
+
html
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Remove an element from the DOM
|
|
326
|
+
*/
|
|
327
|
+
async removeElement(selector) {
|
|
328
|
+
return this.sendRequest(DOMOperation.REMOVE_ELEMENT, { selector });
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Click an element on the parent page
|
|
332
|
+
*
|
|
333
|
+
* @param selector - CSS selector for the element to click
|
|
334
|
+
* @returns Promise that resolves when the click is complete
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* // Click a button
|
|
338
|
+
* await weaveDOM.clickElement('button#submit');
|
|
339
|
+
*
|
|
340
|
+
* // Click a link
|
|
341
|
+
* await weaveDOM.clickElement('a.nav-item[href="/dashboard"]');
|
|
342
|
+
*/
|
|
343
|
+
async clickElement(selector) {
|
|
344
|
+
return this.sendRequest(DOMOperation.CLICK_ELEMENT, { selector });
|
|
345
|
+
}
|
|
346
|
+
// ============================================================================
|
|
347
|
+
// Form Operations
|
|
348
|
+
// ============================================================================
|
|
349
|
+
/**
|
|
350
|
+
* Get form data from a form or an element inside a form
|
|
351
|
+
* @param selector - CSS selector for the form or an element inside the form
|
|
352
|
+
* @returns Promise with complete form data including all fields
|
|
353
|
+
*/
|
|
354
|
+
async getFormData(selector) {
|
|
355
|
+
return this.sendRequest(DOMOperation.GET_FORM_DATA, { selector });
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Start listening for clicks on form elements
|
|
359
|
+
* When a form element is clicked, the callback will be invoked with the form data
|
|
360
|
+
* @param callback - Function to call when a form element is clicked
|
|
361
|
+
*/
|
|
362
|
+
async startFormClickListener(callback) {
|
|
363
|
+
this.formClickCallback = callback;
|
|
364
|
+
return this.sendRequest(DOMOperation.START_FORM_CLICK_LISTENER, {});
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Stop listening for clicks on form elements
|
|
368
|
+
*/
|
|
369
|
+
async stopFormClickListener() {
|
|
370
|
+
this.formClickCallback = null;
|
|
371
|
+
return this.sendRequest(DOMOperation.STOP_FORM_CLICK_LISTENER, {});
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Start listening for clicks on elements matching a CSS selector
|
|
375
|
+
* When an element is clicked, the callback will be invoked with element data
|
|
376
|
+
*
|
|
377
|
+
* @param selector - CSS selector for elements to listen to (e.g., 'div.sortable-item[role="button"]')
|
|
378
|
+
* @param callback - Function to call when a matching element is clicked
|
|
379
|
+
* @param options - Optional configuration
|
|
380
|
+
* @param options.listenerId - Unique ID for this listener (auto-generated if not provided)
|
|
381
|
+
* @returns Promise<string> - The listener ID (for cleanup with stopElementClickListener)
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* // Listen to tab buttons
|
|
385
|
+
* const listenerId = await weaveDOM.startElementClickListener(
|
|
386
|
+
* 'div.sortable-item[role="button"]',
|
|
387
|
+
* (data) => {
|
|
388
|
+
* console.log('Tab clicked:', data.element.textContent);
|
|
389
|
+
* console.log('Element:', data.element);
|
|
390
|
+
* }
|
|
391
|
+
* );
|
|
392
|
+
*
|
|
393
|
+
* // Later, stop listening
|
|
394
|
+
* await weaveDOM.stopElementClickListener(listenerId);
|
|
395
|
+
*/
|
|
396
|
+
async startElementClickListener(selector, callback, options) {
|
|
397
|
+
const listenerId = options?.listenerId || `listener-${Date.now()}-${Math.random()}`;
|
|
398
|
+
// Store callback
|
|
399
|
+
this.elementSelectorClickCallbacks.set(listenerId, callback);
|
|
400
|
+
// Send request to content script
|
|
401
|
+
await this.sendRequest(DOMOperation.START_ELEMENT_CLICK_LISTENER, {
|
|
402
|
+
selector,
|
|
403
|
+
listenerId,
|
|
404
|
+
});
|
|
405
|
+
return listenerId;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Stop listening for clicks on elements
|
|
409
|
+
*
|
|
410
|
+
* @param listenerId - The ID of the listener to stop (returned from startElementClickListener)
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* const listenerId = await weaveDOM.startElementClickListener('button', callback);
|
|
414
|
+
* // ... later ...
|
|
415
|
+
* await weaveDOM.stopElementClickListener(listenerId);
|
|
416
|
+
*/
|
|
417
|
+
async stopElementClickListener(listenerId) {
|
|
418
|
+
// Remove callback
|
|
419
|
+
this.elementSelectorClickCallbacks.delete(listenerId);
|
|
420
|
+
// Send request to content script
|
|
421
|
+
return this.sendRequest(DOMOperation.STOP_ELEMENT_CLICK_LISTENER, {
|
|
422
|
+
listenerId,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Set the value of a form field
|
|
427
|
+
* Handles all input types (text, checkbox, radio, select, textarea, etc.)
|
|
428
|
+
* Automatically triggers validation events
|
|
429
|
+
*
|
|
430
|
+
* @param selector - CSS selector for the form field
|
|
431
|
+
* @param value - Value to set (string for text inputs, boolean for checkboxes, array for multi-selects)
|
|
432
|
+
* @param scrollIntoView - Optional: if true, scrolls element to center of viewport before setting value (default: false)
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* // Text input
|
|
436
|
+
* await weaveDOM.setFormFieldValue('input[name="email"]', 'user@example.com');
|
|
437
|
+
*
|
|
438
|
+
* // Checkbox with scroll
|
|
439
|
+
* await weaveDOM.setFormFieldValue('input[name="terms"]', true, true);
|
|
440
|
+
*
|
|
441
|
+
* // Radio button (set to the value of the radio to select)
|
|
442
|
+
* await weaveDOM.setFormFieldValue('input[name="gender"][value="female"]', 'female');
|
|
443
|
+
*
|
|
444
|
+
* // Select
|
|
445
|
+
* await weaveDOM.setFormFieldValue('select[name="country"]', 'US');
|
|
446
|
+
*
|
|
447
|
+
* // Multi-select with scroll to make it visible
|
|
448
|
+
* await weaveDOM.setFormFieldValue('select[name="interests"]', ['sports', 'music'], true);
|
|
449
|
+
*/
|
|
450
|
+
async setFormFieldValue(selector, value, scrollIntoView = false) {
|
|
451
|
+
return this.sendRequest(DOMOperation.SET_FORM_FIELD_VALUE, {
|
|
452
|
+
selector,
|
|
453
|
+
value,
|
|
454
|
+
scrollIntoView
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
// ============================================================================
|
|
458
|
+
// Event Listeners
|
|
459
|
+
// ============================================================================
|
|
460
|
+
/**
|
|
461
|
+
* Register a callback for when a workflow is saved
|
|
462
|
+
* @param callback - Function to call when a workflow is saved from the content script
|
|
463
|
+
*/
|
|
464
|
+
onWorkflowSaved(callback) {
|
|
465
|
+
this.workflowSavedCallback = callback;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Remove the workflow saved callback
|
|
469
|
+
*/
|
|
470
|
+
offWorkflowSaved() {
|
|
471
|
+
this.workflowSavedCallback = null;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Register a callback for when a trigger is saved
|
|
475
|
+
* @param callback - Function to call when a trigger is saved from the content script
|
|
476
|
+
*/
|
|
477
|
+
onTriggerSaved(callback) {
|
|
478
|
+
this.triggerSavedCallback = callback;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Remove the trigger saved callback
|
|
482
|
+
*/
|
|
483
|
+
offTriggerSaved() {
|
|
484
|
+
this.triggerSavedCallback = null;
|
|
485
|
+
}
|
|
486
|
+
// ============================================================================
|
|
487
|
+
// Element Injection Operations
|
|
488
|
+
// ============================================================================
|
|
489
|
+
/**
|
|
490
|
+
* Inject an element onto the parent page with optional click event listener
|
|
491
|
+
*
|
|
492
|
+
* @param targetSelector - CSS selector for the element to inject relative to
|
|
493
|
+
* @param position - Position relative to target ('beforebegin', 'afterbegin', 'beforeend', 'afterend')
|
|
494
|
+
* @param html - HTML string to inject (will be sanitized)
|
|
495
|
+
* @param options - Optional configuration
|
|
496
|
+
* @param options.onClick - Callback function to invoke when element is clicked
|
|
497
|
+
* @param options.elementId - Custom element ID (auto-generated if not provided)
|
|
498
|
+
* @returns Promise with the element ID
|
|
499
|
+
*
|
|
500
|
+
* @example
|
|
501
|
+
* // Inject a button with click handler
|
|
502
|
+
* const elementId = await weaveDOM.injectElement(
|
|
503
|
+
* 'body',
|
|
504
|
+
* 'beforeend',
|
|
505
|
+
* '<button class="my-button">Click Me</button>',
|
|
506
|
+
* {
|
|
507
|
+
* onClick: (data) => {
|
|
508
|
+
* console.log('Button clicked!', data);
|
|
509
|
+
* }
|
|
510
|
+
* }
|
|
511
|
+
* );
|
|
512
|
+
*
|
|
513
|
+
* // Later, remove the element
|
|
514
|
+
* await weaveDOM.removeInjectedElement(elementId);
|
|
515
|
+
*/
|
|
516
|
+
async injectElement(targetSelector, position, html, options) {
|
|
517
|
+
// Generate element ID if not provided
|
|
518
|
+
const elementId = options?.elementId || `weave-injected-${++this.elementIdCounter}`;
|
|
519
|
+
// Store click callback if provided
|
|
520
|
+
if (options?.onClick) {
|
|
521
|
+
this.elementClickCallbacks.set(elementId, options.onClick);
|
|
522
|
+
}
|
|
523
|
+
// Send injection request
|
|
524
|
+
const result = await this.sendRequest(DOMOperation.INJECT_ELEMENT, {
|
|
525
|
+
targetSelector,
|
|
526
|
+
position,
|
|
527
|
+
html,
|
|
528
|
+
elementId,
|
|
529
|
+
onClick: !!options?.onClick,
|
|
530
|
+
});
|
|
531
|
+
return result.elementId;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Remove an injected element from the parent page
|
|
535
|
+
*
|
|
536
|
+
* @param elementId - ID of the element to remove (returned from injectElement)
|
|
537
|
+
*
|
|
538
|
+
* @example
|
|
539
|
+
* await weaveDOM.removeInjectedElement('weave-injected-1');
|
|
540
|
+
*/
|
|
541
|
+
async removeInjectedElement(elementId) {
|
|
542
|
+
// Remove click callback if it exists
|
|
543
|
+
this.elementClickCallbacks.delete(elementId);
|
|
544
|
+
// Send removal request
|
|
545
|
+
return this.sendRequest(DOMOperation.REMOVE_INJECTED_ELEMENT, {
|
|
546
|
+
elementId,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
// ============================================================================
|
|
550
|
+
// Element Watching Operations
|
|
551
|
+
// ============================================================================
|
|
552
|
+
/**
|
|
553
|
+
* Watch an element for changes (attributes, removal, children)
|
|
554
|
+
*
|
|
555
|
+
* Sets up MutationObservers to monitor:
|
|
556
|
+
* - Attribute changes on the element
|
|
557
|
+
* - Element removal from DOM
|
|
558
|
+
* - Child node changes (optional)
|
|
559
|
+
*
|
|
560
|
+
* @param selector - CSS selector for the element to watch
|
|
561
|
+
* @param callback - Function to call when element changes
|
|
562
|
+
* @param options - Optional configuration
|
|
563
|
+
* @param options.watchAttributes - Watch for attribute changes (default: true)
|
|
564
|
+
* @param options.watchChildren - Watch for child node changes (default: false)
|
|
565
|
+
* @param options.attributeFilter - Optional array of specific attributes to watch
|
|
566
|
+
* @returns Promise with the watcher ID (use to stop watching)
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* // Watch for attribute changes
|
|
570
|
+
* const watcherId = await weaveDOM.watchElement(
|
|
571
|
+
* '#my-element',
|
|
572
|
+
* (data) => {
|
|
573
|
+
* if (data.changeType === 'attribute') {
|
|
574
|
+
* console.log(`Attribute ${data.attributeName} changed to: ${data.attributeValue}`);
|
|
575
|
+
* } else if (data.changeType === 'removed') {
|
|
576
|
+
* console.log('Element was removed from DOM');
|
|
577
|
+
* }
|
|
578
|
+
* },
|
|
579
|
+
* {
|
|
580
|
+
* watchAttributes: true,
|
|
581
|
+
* attributeFilter: ['class', 'data-status'] // Only watch specific attributes
|
|
582
|
+
* }
|
|
583
|
+
* );
|
|
584
|
+
*
|
|
585
|
+
* // Later, stop watching
|
|
586
|
+
* await weaveDOM.unwatchElement(watcherId);
|
|
587
|
+
*/
|
|
588
|
+
async watchElement(selector, callback, options) {
|
|
589
|
+
// Generate watcher ID
|
|
590
|
+
const watcherId = `weave-watcher-${++this.watcherIdCounter}`;
|
|
591
|
+
// Store callback
|
|
592
|
+
this.elementChangeCallbacks.set(watcherId, callback);
|
|
593
|
+
// Send watch request
|
|
594
|
+
await this.sendRequest(DOMOperation.WATCH_ELEMENT, {
|
|
595
|
+
selector,
|
|
596
|
+
watcherId,
|
|
597
|
+
watchAttributes: options?.watchAttributes,
|
|
598
|
+
watchChildren: options?.watchChildren,
|
|
599
|
+
attributeFilter: options?.attributeFilter,
|
|
600
|
+
});
|
|
601
|
+
return watcherId;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Stop watching an element
|
|
605
|
+
*
|
|
606
|
+
* @param watcherId - ID of the watcher to stop (returned from watchElement)
|
|
607
|
+
*
|
|
608
|
+
* @example
|
|
609
|
+
* await weaveDOM.unwatchElement('weave-watcher-1');
|
|
610
|
+
*/
|
|
611
|
+
async unwatchElement(watcherId) {
|
|
612
|
+
// Remove callback
|
|
613
|
+
this.elementChangeCallbacks.delete(watcherId);
|
|
614
|
+
// Send unwatch request
|
|
615
|
+
return this.sendRequest(DOMOperation.UNWATCH_ELEMENT, {
|
|
616
|
+
watcherId,
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
export default new WeaveDOMAPI();
|
package/dist/global.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global SDK Loader
|
|
3
|
+
*
|
|
4
|
+
* Makes the Weave SDK available globally for third-party apps
|
|
5
|
+
* that are loaded as JavaScript strings (not ES6 modules)
|
|
6
|
+
*/
|
|
7
|
+
import { WeaveBaseApp } from './WeaveBaseApp';
|
|
8
|
+
import { WeaveDOMAPI } from './WeaveDOMAPI';
|
|
9
|
+
import { WeaveAPIClient } from './WeaveAPIClient';
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {
|
|
12
|
+
WeaveBaseApp: typeof WeaveBaseApp;
|
|
13
|
+
WeaveDOMAPI: typeof WeaveDOMAPI;
|
|
14
|
+
weaveDOM: WeaveDOMAPI;
|
|
15
|
+
WeaveAPIClient: typeof WeaveAPIClient;
|
|
16
|
+
weaveAPI: WeaveAPIClient;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=global.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global.d.ts","sourceRoot":"","sources":["../src/global.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIlD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,YAAY,EAAE,OAAO,YAAY,CAAC;QAClC,WAAW,EAAE,OAAO,WAAW,CAAC;QAChC,QAAQ,EAAE,WAAW,CAAC;QACtB,cAAc,EAAE,OAAO,cAAc,CAAC;QACtC,QAAQ,EAAE,cAAc,CAAC;KAAG;CAC/B"}
|
package/dist/global.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global SDK Loader
|
|
3
|
+
*
|
|
4
|
+
* Makes the Weave SDK available globally for third-party apps
|
|
5
|
+
* that are loaded as JavaScript strings (not ES6 modules)
|
|
6
|
+
*/
|
|
7
|
+
import { WeaveBaseApp } from './WeaveBaseApp';
|
|
8
|
+
import { WeaveDOMAPI } from './WeaveDOMAPI';
|
|
9
|
+
import weavekDOM from './WeaveDOMAPI';
|
|
10
|
+
import { WeaveAPIClient } from './WeaveAPIClient';
|
|
11
|
+
import weaveAPI from './WeaveAPIClient';
|
|
12
|
+
// Make SDK available globally
|
|
13
|
+
window.WeaveBaseApp = WeaveBaseApp;
|
|
14
|
+
window.WeaveDOMAPI = WeaveDOMAPI;
|
|
15
|
+
window.weaveDOM = weavekDOM;
|
|
16
|
+
window.WeaveAPIClient = WeaveAPIClient;
|
|
17
|
+
window.weaveAPI = weaveAPI;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weave App SDK
|
|
3
|
+
*
|
|
4
|
+
* Main exports for third-party app development
|
|
5
|
+
*/
|
|
6
|
+
export { WeaveBaseApp, type WeaveAppInfo } from './WeaveBaseApp';
|
|
7
|
+
export { WeaveDOMAPI, type ElementSnapshot, type InsertPosition } from './WeaveDOMAPI';
|
|
8
|
+
export { default as weaveDOM } from './WeaveDOMAPI';
|
|
9
|
+
export { WeaveAPIClient, type AIChatRequest, type AIChatResponse, type AppData, type CreateAppDataRequest, type UpdateAppDataRequest } from './WeaveAPIClient';
|
|
10
|
+
export { default as weaveAPI } from './WeaveAPIClient';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EACL,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,OAAO,EACZ,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weave App SDK
|
|
3
|
+
*
|
|
4
|
+
* Main exports for third-party app development
|
|
5
|
+
*/
|
|
6
|
+
export { WeaveBaseApp } from './WeaveBaseApp';
|
|
7
|
+
export { WeaveDOMAPI } from './WeaveDOMAPI';
|
|
8
|
+
export { default as weaveDOM } from './WeaveDOMAPI';
|
|
9
|
+
export { WeaveAPIClient } from './WeaveAPIClient';
|
|
10
|
+
export { default as weaveAPI } from './WeaveAPIClient';
|