@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
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@weave-apps/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SDK for building Weave Micro Apps",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"bin": {
|
|
11
|
+
"weave-init": "./bin/init.js",
|
|
12
|
+
"weave-build": "./bin/build.js",
|
|
13
|
+
"weave-compile": "./bin/compile.js"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"copy-sdk": "node scripts/copy-sdk-files.js",
|
|
17
|
+
"prebuild": "npm run copy-sdk",
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"prepare": "npm run build",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"weave",
|
|
25
|
+
"browser-extension",
|
|
26
|
+
"app-sdk",
|
|
27
|
+
"typescript"
|
|
28
|
+
],
|
|
29
|
+
"author": "Weave Platform",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"typescript": "^5.9.3"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^20.0.0"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"bin",
|
|
40
|
+
"scripts",
|
|
41
|
+
"templates",
|
|
42
|
+
"tsconfig.app.json",
|
|
43
|
+
"README.md"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copy SDK files from sidebar-loader to app-sdk
|
|
5
|
+
* This ensures the app-sdk has its own copy of the SDK files for distribution
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const sourceDir = path.join(__dirname, '../../sidebar-loader/src/sdk');
|
|
12
|
+
const targetDir = path.join(__dirname, '../src');
|
|
13
|
+
|
|
14
|
+
// Files to copy
|
|
15
|
+
const filesToCopy = [
|
|
16
|
+
'WeaveBaseApp.ts',
|
|
17
|
+
'WeaveDOMAPI.ts',
|
|
18
|
+
'WeaveAPIClient.ts',
|
|
19
|
+
'global.ts',
|
|
20
|
+
'app-template.js',
|
|
21
|
+
'README.md',
|
|
22
|
+
'API_GUIDE.md'
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
console.log('📦 Copying SDK files from sidebar-loader...\n');
|
|
26
|
+
|
|
27
|
+
filesToCopy.forEach(file => {
|
|
28
|
+
const sourcePath = path.join(sourceDir, file);
|
|
29
|
+
const targetPath = path.join(targetDir, file);
|
|
30
|
+
|
|
31
|
+
if (fs.existsSync(sourcePath)) {
|
|
32
|
+
// Special handling for global.ts - remove utils imports and references
|
|
33
|
+
if (file === 'global.ts') {
|
|
34
|
+
let content = fs.readFileSync(sourcePath, 'utf8');
|
|
35
|
+
|
|
36
|
+
// Remove utils imports
|
|
37
|
+
content = content.replace(/import htmlToMarkdown from ['"]\.\.\/utils\/htmlToMarkdown['"];?\n?/g, '');
|
|
38
|
+
content = content.replace(/import markdownToHtml from ['"]\.\.\/utils\/markdownToHtml['"];?\n?/g, '');
|
|
39
|
+
|
|
40
|
+
// Remove __weaveUtils from Window interface
|
|
41
|
+
content = content.replace(/\s+__weaveUtils:\s*\{[^}]+\};?\n?/g, '');
|
|
42
|
+
|
|
43
|
+
// Remove __weaveUtils assignment
|
|
44
|
+
content = content.replace(/\/\/ Make utilities available globally.*\n?window\.__weaveUtils\s*=\s*\{[^}]+\};?\n?/gs, '');
|
|
45
|
+
|
|
46
|
+
fs.writeFileSync(targetPath, content, 'utf8');
|
|
47
|
+
console.log(`✅ Copied (modified): ${file}`);
|
|
48
|
+
} else {
|
|
49
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
50
|
+
console.log(`✅ Copied: ${file}`);
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
console.warn(`⚠️ Warning: ${file} not found in sidebar-loader/src/sdk`);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
console.log('\n✨ SDK files copied successfully!\n');
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extract TypeScript interfaces and embed them as JSDoc comments
|
|
5
|
+
* This allows the enterprise console to extract settings schema without executing code
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const ts = require('typescript');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Extract interface definition from TypeScript AST
|
|
14
|
+
*/
|
|
15
|
+
function extractInterface(node, sourceFile, interfaceName) {
|
|
16
|
+
if (!ts.isInterfaceDeclaration(node) || node.name.text !== interfaceName) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const schema = [];
|
|
21
|
+
|
|
22
|
+
node.members.forEach((member) => {
|
|
23
|
+
if (ts.isPropertySignature(member) && member.name) {
|
|
24
|
+
const propertyName = member.name.getText(sourceFile);
|
|
25
|
+
const isOptional = !!member.questionToken;
|
|
26
|
+
|
|
27
|
+
// Extract type
|
|
28
|
+
let propertyType = 'string';
|
|
29
|
+
let options = undefined;
|
|
30
|
+
|
|
31
|
+
if (member.type) {
|
|
32
|
+
const typeText = member.type.getText(sourceFile);
|
|
33
|
+
|
|
34
|
+
// Handle union types (e.g., 'top' | 'bottom')
|
|
35
|
+
if (ts.isUnionTypeNode(member.type)) {
|
|
36
|
+
const literals = member.type.types
|
|
37
|
+
.filter(t => ts.isLiteralTypeNode(t))
|
|
38
|
+
.map(t => t.literal.getText(sourceFile).replace(/['"]/g, ''));
|
|
39
|
+
|
|
40
|
+
if (literals.length > 0) {
|
|
41
|
+
propertyType = 'select';
|
|
42
|
+
options = literals.map(val => ({ label: val, value: val }));
|
|
43
|
+
}
|
|
44
|
+
} else if (typeText === 'string') {
|
|
45
|
+
propertyType = 'string';
|
|
46
|
+
} else if (typeText === 'number') {
|
|
47
|
+
propertyType = 'number';
|
|
48
|
+
} else if (typeText === 'boolean') {
|
|
49
|
+
propertyType = 'boolean';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Extract JSDoc comment for description
|
|
54
|
+
const jsDocTags = ts.getJSDocTags(member);
|
|
55
|
+
let description = '';
|
|
56
|
+
let defaultValue = undefined;
|
|
57
|
+
|
|
58
|
+
jsDocTags.forEach(tag => {
|
|
59
|
+
if (tag.tagName.text === 'description' && tag.comment) {
|
|
60
|
+
description = typeof tag.comment === 'string' ? tag.comment : tag.comment.map(c => c.text).join('');
|
|
61
|
+
}
|
|
62
|
+
if (tag.tagName.text === 'default' && tag.comment) {
|
|
63
|
+
const defaultText = typeof tag.comment === 'string' ? tag.comment : tag.comment.map(c => c.text).join('');
|
|
64
|
+
// Try to parse as JSON, but handle string values carefully
|
|
65
|
+
try {
|
|
66
|
+
defaultValue = JSON.parse(defaultText);
|
|
67
|
+
} catch {
|
|
68
|
+
// If JSON.parse fails, it might be an unquoted string value
|
|
69
|
+
// Remove surrounding quotes if present (from JSDoc)
|
|
70
|
+
const trimmed = defaultText.trim();
|
|
71
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
72
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
73
|
+
// Remove outer quotes and use the inner value as-is
|
|
74
|
+
defaultValue = trimmed.slice(1, -1);
|
|
75
|
+
} else {
|
|
76
|
+
defaultValue = trimmed;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Generate human-readable label from property name
|
|
83
|
+
// Handles: camelCase, UPPER_CASE, PascalCase
|
|
84
|
+
let label = propertyName;
|
|
85
|
+
|
|
86
|
+
// Check if it's UPPER_CASE (all uppercase with underscores)
|
|
87
|
+
if (propertyName === propertyName.toUpperCase() && propertyName.includes('_')) {
|
|
88
|
+
// UPPER_CASE -> Upper Case
|
|
89
|
+
label = propertyName
|
|
90
|
+
.split('_')
|
|
91
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
92
|
+
.join(' ');
|
|
93
|
+
} else {
|
|
94
|
+
// camelCase or PascalCase -> Camel Case or Pascal Case
|
|
95
|
+
label = propertyName
|
|
96
|
+
.replace(/([A-Z])/g, ' $1') // Add space before capitals
|
|
97
|
+
.replace(/^./, str => str.toUpperCase()) // Capitalize first letter
|
|
98
|
+
.trim();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
schema.push({
|
|
102
|
+
key: propertyName,
|
|
103
|
+
label: label,
|
|
104
|
+
type: propertyType,
|
|
105
|
+
description: description || undefined,
|
|
106
|
+
required: !isOptional,
|
|
107
|
+
defaultValue,
|
|
108
|
+
options
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return schema;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Process TypeScript file and extract settings schema
|
|
118
|
+
*/
|
|
119
|
+
function processFile(filePath) {
|
|
120
|
+
const sourceCode = fs.readFileSync(filePath, 'utf-8');
|
|
121
|
+
const sourceFile = ts.createSourceFile(
|
|
122
|
+
filePath,
|
|
123
|
+
sourceCode,
|
|
124
|
+
ts.ScriptTarget.Latest,
|
|
125
|
+
true
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
let settingsSchema = null;
|
|
129
|
+
let settingsInterfaceName = null;
|
|
130
|
+
|
|
131
|
+
// Find the class that extends WeaveBaseApp and extract the generic type
|
|
132
|
+
function visit(node) {
|
|
133
|
+
// Find class declaration
|
|
134
|
+
if (ts.isClassDeclaration(node) && node.heritageClauses) {
|
|
135
|
+
node.heritageClauses.forEach(clause => {
|
|
136
|
+
clause.types.forEach(type => {
|
|
137
|
+
const exprText = type.expression.getText(sourceFile);
|
|
138
|
+
if (exprText === 'WeaveBaseApp' && type.typeArguments && type.typeArguments.length > 0) {
|
|
139
|
+
// First generic is TSettings
|
|
140
|
+
settingsInterfaceName = type.typeArguments[0].getText(sourceFile);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
ts.forEachChild(node, visit);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
visit(sourceFile);
|
|
150
|
+
|
|
151
|
+
// Now extract the interface
|
|
152
|
+
if (settingsInterfaceName) {
|
|
153
|
+
function findInterface(node) {
|
|
154
|
+
const extracted = extractInterface(node, sourceFile, settingsInterfaceName);
|
|
155
|
+
if (extracted) {
|
|
156
|
+
settingsSchema = extracted;
|
|
157
|
+
}
|
|
158
|
+
ts.forEachChild(node, findInterface);
|
|
159
|
+
}
|
|
160
|
+
findInterface(sourceFile);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return settingsSchema;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Inject schema as JSDoc comment into compiled JavaScript
|
|
168
|
+
*/
|
|
169
|
+
function injectSchemaIntoJS(jsFilePath, schema) {
|
|
170
|
+
if (!schema || schema.length === 0) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let jsCode = fs.readFileSync(jsFilePath, 'utf-8');
|
|
175
|
+
|
|
176
|
+
// Find the class definition
|
|
177
|
+
const classMatch = jsCode.match(/class\s+(\w+)\s+extends\s+WeaveBaseApp/);
|
|
178
|
+
if (!classMatch) {
|
|
179
|
+
console.warn('⚠️ Could not find class extending WeaveBaseApp');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const className = classMatch[1];
|
|
184
|
+
|
|
185
|
+
// Create JSDoc comment with schema
|
|
186
|
+
const schemaComment = `
|
|
187
|
+
/**
|
|
188
|
+
* @weave-settings-schema ${JSON.stringify(schema, null, 2)}
|
|
189
|
+
*/`;
|
|
190
|
+
|
|
191
|
+
// Inject before class definition
|
|
192
|
+
jsCode = jsCode.replace(
|
|
193
|
+
new RegExp(`(class\\s+${className}\\s+extends\\s+WeaveBaseApp)`, 'g'),
|
|
194
|
+
`${schemaComment}\n$1`
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
fs.writeFileSync(jsFilePath, jsCode, 'utf-8');
|
|
198
|
+
console.log(`✅ Injected settings schema into ${jsFilePath}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Main execution
|
|
203
|
+
*/
|
|
204
|
+
function main() {
|
|
205
|
+
const args = process.argv.slice(2);
|
|
206
|
+
|
|
207
|
+
if (args.length < 2) {
|
|
208
|
+
console.error('Usage: extract-settings-schema.js <input.ts> <output.js>');
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const [tsFile, jsFile] = args;
|
|
213
|
+
|
|
214
|
+
if (!fs.existsSync(tsFile)) {
|
|
215
|
+
console.error(`❌ TypeScript file not found: ${tsFile}`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (!fs.existsSync(jsFile)) {
|
|
220
|
+
console.error(`❌ JavaScript file not found: ${jsFile}`);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log(`📝 Extracting settings schema from ${tsFile}...`);
|
|
225
|
+
const schema = processFile(tsFile);
|
|
226
|
+
|
|
227
|
+
if (schema && schema.length > 0) {
|
|
228
|
+
console.log(`📦 Found ${schema.length} settings:`, schema.map(s => s.key).join(', '));
|
|
229
|
+
injectSchemaIntoJS(jsFile, schema);
|
|
230
|
+
} else {
|
|
231
|
+
console.log('ℹ️ No settings schema found');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
main();
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# {{APP_NAME_TITLE}}
|
|
2
|
+
|
|
3
|
+
A Weave app built with TypeScript.
|
|
4
|
+
|
|
5
|
+
## 🤖 AI-Powered Development
|
|
6
|
+
|
|
7
|
+
This project includes **SIDEKICK_SPEC.md** - a comprehensive specification document designed for AI assistants like Windsurf, Cursor, GitHub Copilot, and ChatGPT.
|
|
8
|
+
|
|
9
|
+
### How to Use with AI:
|
|
10
|
+
|
|
11
|
+
1. **Reference the spec in your prompts:**
|
|
12
|
+
```
|
|
13
|
+
"Read SIDEKICK_SPEC.md and create a feature that..."
|
|
14
|
+
"@SIDEKICK_SPEC.md help me build a form that updates the page title"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
2. **Let AI read it automatically:**
|
|
18
|
+
- In **Windsurf**: The spec is automatically available in context
|
|
19
|
+
- In **Cursor**: Use `@SIDEKICK_SPEC.md` to reference it
|
|
20
|
+
- In **GitHub Copilot**: Open the file to add it to context
|
|
21
|
+
|
|
22
|
+
3. **Get accurate code generation:**
|
|
23
|
+
- AI will understand the architecture constraints
|
|
24
|
+
- Generate code using proper TypeScript imports from `@weave/app-sdk`
|
|
25
|
+
- Follow security best practices automatically
|
|
26
|
+
- Include proper error handling and TypeScript types
|
|
27
|
+
|
|
28
|
+
**Pro Tip:** Keep SIDEKICK_SPEC.md open in a tab while developing. AI assistants work best when they can see the specification!
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 📝 TypeScript Development Guide
|
|
33
|
+
|
|
34
|
+
### ✅ CORRECT: Import Types from SDK
|
|
35
|
+
|
|
36
|
+
**ALWAYS** import types and classes from the SDK package:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import {
|
|
40
|
+
WeaveBaseApp,
|
|
41
|
+
type WeaveAppInfo,
|
|
42
|
+
type AIChatRequest,
|
|
43
|
+
type AIChatResponse,
|
|
44
|
+
type AppData,
|
|
45
|
+
type CreateAppDataRequest,
|
|
46
|
+
type UpdateAppDataRequest
|
|
47
|
+
} from '@weave/app-sdk';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### ❌ WRONG: Do NOT Copy/Paste Type Definitions
|
|
51
|
+
|
|
52
|
+
**NEVER** copy type definitions into your app code. The SDK provides all types you need.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## API Usage Guide
|
|
57
|
+
|
|
58
|
+
Your Weave app has access to two distinct APIs:
|
|
59
|
+
|
|
60
|
+
### 1. 🧠 Weave Backend API (`weaveAPI`)
|
|
61
|
+
|
|
62
|
+
Use `weaveAPI` to interact with **Weave backend services**:
|
|
63
|
+
|
|
64
|
+
#### AI Chat Service
|
|
65
|
+
```typescript
|
|
66
|
+
import { type AIChatRequest } from '@weave/app-sdk';
|
|
67
|
+
|
|
68
|
+
// Call the Weave AI service
|
|
69
|
+
// Note: Your app's UUID is automatically injected
|
|
70
|
+
const request: AIChatRequest = {
|
|
71
|
+
prompt: 'Summarize this text...',
|
|
72
|
+
context: 'User is working on a document'
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const response = await weaveAPI.ai.chat(request);
|
|
76
|
+
console.log(response.response);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### App Data Storage
|
|
80
|
+
```typescript
|
|
81
|
+
import { type CreateAppDataRequest } from '@weave/app-sdk';
|
|
82
|
+
|
|
83
|
+
// Save data to Weave backend
|
|
84
|
+
// Note: Your app's UUID is automatically injected
|
|
85
|
+
const request: CreateAppDataRequest = {
|
|
86
|
+
dataKey: 'user-preferences',
|
|
87
|
+
data: { theme: 'dark', language: 'en' }
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const saved = await weaveAPI.appData.create(request);
|
|
91
|
+
console.log('Saved with ID:', saved._id);
|
|
92
|
+
|
|
93
|
+
// Load all app data
|
|
94
|
+
const allData = await weaveAPI.appData.getAll();
|
|
95
|
+
|
|
96
|
+
// Update specific data
|
|
97
|
+
await weaveAPI.appData.update(saved._id, {
|
|
98
|
+
data: { theme: 'light' }
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Delete data
|
|
102
|
+
await weaveAPI.appData.delete(saved._id);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. 🌐 DOM Bridge API (`weaveDOM`)
|
|
106
|
+
|
|
107
|
+
Use `weaveDOM` to interact with the **parent page DOM**:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// Read from parent page
|
|
111
|
+
const title = await weaveDOM.getText('h1');
|
|
112
|
+
const hasClass = await weaveDOM.hasClass('.button', 'active');
|
|
113
|
+
|
|
114
|
+
// Write to parent page
|
|
115
|
+
await weaveDOM.setText('.status', 'Updated!');
|
|
116
|
+
await weaveDOM.addClass('.button', 'active');
|
|
117
|
+
await weaveDOM.setAttribute('input[name="email"]', 'value', 'test@example.com');
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### ⚠️ CRITICAL: Know Which API to Use
|
|
121
|
+
|
|
122
|
+
- **`weaveAPI`** → Weave backend (AI, data storage)
|
|
123
|
+
- **`weaveDOM`** → Parent page DOM manipulation
|
|
124
|
+
|
|
125
|
+
**Example - WRONG:**
|
|
126
|
+
```typescript
|
|
127
|
+
// ❌ DO NOT use weaveDOM to call AI
|
|
128
|
+
await weaveDOM.callAI(...); // This doesn't exist!
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Example - CORRECT:**
|
|
132
|
+
```typescript
|
|
133
|
+
// ✅ Use weaveAPI for AI calls (app UUID auto-injected)
|
|
134
|
+
await weaveAPI.ai.chat({ prompt: '...' });
|
|
135
|
+
|
|
136
|
+
// ✅ Use weaveDOM for page manipulation
|
|
137
|
+
await weaveDOM.setText('h1', 'New Title');
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Development
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Install dependencies
|
|
146
|
+
npm install
|
|
147
|
+
|
|
148
|
+
# Build the app
|
|
149
|
+
npm run build
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Upload to Weave
|
|
153
|
+
|
|
154
|
+
After building, upload the generated `dist/{{APP_NAME}}.js` file to the Weave Platform.
|
|
155
|
+
|
|
156
|
+
## Project Structure
|
|
157
|
+
|
|
158
|
+
- `src/app.ts` - Your app source code (TypeScript)
|
|
159
|
+
- `dist/{{APP_NAME}}.js` - Compiled JavaScript (upload this)
|
|
160
|
+
- `package.json` - Project configuration
|
|
161
|
+
- `tsconfig.json` - TypeScript config (extends SDK)
|
|
162
|
+
- `SIDEKICK_SPEC.md` - Complete specification for AI assistants
|
|
163
|
+
|
|
164
|
+
## Build Process
|
|
165
|
+
|
|
166
|
+
Running `npm run build` executes `weave-compile` which:
|
|
167
|
+
1. Compiles TypeScript using SDK's configuration
|
|
168
|
+
2. Removes import statements (runtime uses window globals)
|
|
169
|
+
3. Replaces SDK references with window globals
|
|
170
|
+
4. Generates clean, readable JavaScript
|
|
171
|
+
|
|
172
|
+
**Note:** During development, use TypeScript imports. The build process converts them to window globals for runtime.
|
|
173
|
+
|
|
174
|
+
## Runtime Globals
|
|
175
|
+
|
|
176
|
+
After compilation, your app accesses these via window globals:
|
|
177
|
+
|
|
178
|
+
- **`window.WeaveBaseApp`** - Base class for creating apps
|
|
179
|
+
- **`window.weaveDOM`** - DOM manipulation API for parent page
|
|
180
|
+
- **`window.weaveAPI`** - Backend API client
|
|
181
|
+
- `weaveAPI.ai.chat()` - AI chat service
|
|
182
|
+
- `weaveAPI.appData.create()` - Store app data
|
|
183
|
+
- `weaveAPI.appData.getAll()` - Retrieve app data
|
|
184
|
+
- `weaveAPI.appData.update()` - Update app data
|
|
185
|
+
- `weaveAPI.appData.delete()` - Delete app data
|
|
186
|
+
|
|
187
|
+
## Documentation
|
|
188
|
+
|
|
189
|
+
- **SIDEKICK_SPEC.md** - Complete specification for AI assistants (Windsurf, Cursor, etc.)
|
|
190
|
+
- [Weave App SDK](https://github.com/your-org/weave-app-sdk) - Full SDK documentation
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 🎯 Quick Reference for AI Assistants
|
|
195
|
+
|
|
196
|
+
When building features:
|
|
197
|
+
|
|
198
|
+
1. **Import types from SDK** - Never copy/paste type definitions
|
|
199
|
+
2. **Use `weaveAPI`** - For AI calls and data storage (backend)
|
|
200
|
+
3. **Use `weaveDOM`** - For parent page DOM manipulation only
|
|
201
|
+
4. **Extend `WeaveBaseApp`** - All apps must extend this class
|
|
202
|
+
5. **Follow TypeScript patterns** - Use proper imports during development
|