matimo-examples 0.1.0-alpha.11
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/.env.example +49 -0
- package/LICENSE +21 -0
- package/README.md +525 -0
- package/agents/decorator-pattern-agent.ts +368 -0
- package/agents/factory-pattern-agent.ts +253 -0
- package/agents/langchain-agent.ts +146 -0
- package/edit/edit-decorator.ts +178 -0
- package/edit/edit-factory.ts +138 -0
- package/edit/edit-langchain.ts +292 -0
- package/execute/execute-decorator.ts +49 -0
- package/execute/execute-factory.ts +46 -0
- package/execute/execute-langchain.ts +232 -0
- package/github/github-decorator.ts +326 -0
- package/github/github-factory.ts +355 -0
- package/github/github-langchain.ts +206 -0
- package/github/github-with-approval.ts +228 -0
- package/gmail/README.md +345 -0
- package/gmail/gmail-decorator.ts +216 -0
- package/gmail/gmail-factory.ts +231 -0
- package/gmail/gmail-langchain.ts +201 -0
- package/hubspot/README.md +316 -0
- package/hubspot/hubspot-decorator.ts +180 -0
- package/hubspot/hubspot-factory.ts +188 -0
- package/hubspot/hubspot-langchain.ts +222 -0
- package/logger-example.ts +40 -0
- package/mailchimp/README.md +321 -0
- package/mailchimp/mailchimp-decorator.ts +277 -0
- package/mailchimp/mailchimp-factory.ts +187 -0
- package/mailchimp/mailchimp-langchain.ts +155 -0
- package/notion/README.md +293 -0
- package/notion/notion-decorator.ts +275 -0
- package/notion/notion-factory.ts +256 -0
- package/notion/notion-langchain.ts +237 -0
- package/package.json +79 -0
- package/postgres/README.md +188 -0
- package/postgres/postgres-decorator.ts +198 -0
- package/postgres/postgres-factory.ts +180 -0
- package/postgres/postgres-langchain.ts +213 -0
- package/postgres/postgres-with-approval.ts +344 -0
- package/read/read-decorator.ts +154 -0
- package/read/read-factory.ts +121 -0
- package/read/read-langchain.ts +273 -0
- package/search/search-decorator.ts +206 -0
- package/search/search-factory.ts +146 -0
- package/search/search-langchain.ts +255 -0
- package/slack/README.md +339 -0
- package/slack/slack-decorator.ts +245 -0
- package/slack/slack-factory.ts +226 -0
- package/slack/slack-langchain.ts +242 -0
- package/tsconfig.json +20 -0
- package/twilio/README.md +309 -0
- package/twilio/twilio-decorator.ts +288 -0
- package/twilio/twilio-factory.ts +238 -0
- package/twilio/twilio-langchain.ts +218 -0
- package/web/web-decorator.ts +52 -0
- package/web/web-factory.ts +70 -0
- package/web/web-langchain.ts +163 -0
package/notion/README.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Notion Tools Examples
|
|
2
|
+
|
|
3
|
+
Example directory contains **3 example patterns** showing different ways to use Matimo's Notion tools:
|
|
4
|
+
1. **Factory Pattern** - Direct SDK execution (simplest)
|
|
5
|
+
2. **Decorator Pattern** - Class-based with @tool decorators
|
|
6
|
+
3. **LangChain Pattern** - AI-driven with OpenAI agent
|
|
7
|
+
|
|
8
|
+
All examples are **fully working** and demonstrate real Notion operations (creating pages, querying databases, updating pages, etc.).
|
|
9
|
+
|
|
10
|
+
## π Quick Start
|
|
11
|
+
|
|
12
|
+
### 1. Create a Notion Integration
|
|
13
|
+
|
|
14
|
+
1. Go to [notion.com/my-integrations](https://www.notion.com/my-integrations)
|
|
15
|
+
2. Click "Create new integration"
|
|
16
|
+
3. Give it a name like "Matimo"
|
|
17
|
+
4. Select "Internal Integration"
|
|
18
|
+
5. Accept the guidelines and click "Create integration"
|
|
19
|
+
|
|
20
|
+
OR Create an internal integration by visiting - https://www.notion.so/profile/integrations/internal
|
|
21
|
+
|
|
22
|
+
### 2. Get Your API Key
|
|
23
|
+
|
|
24
|
+
- Copy the **Internal Integration Token** (starts with `ntn_`)
|
|
25
|
+
- This is your `NOTION_API_KEY`
|
|
26
|
+
|
|
27
|
+
### 3. Share Databases with Integration
|
|
28
|
+
|
|
29
|
+
1. Open any Notion database you want Matimo to access
|
|
30
|
+
2. Click **Share** in the top-right
|
|
31
|
+
3. Select your integration from the dropdown and click "Invite"
|
|
32
|
+
4. Confirm the invitation
|
|
33
|
+
|
|
34
|
+
### 4. Set Up Environment
|
|
35
|
+
|
|
36
|
+
Create a `.env` file in `examples/tools/`:
|
|
37
|
+
|
|
38
|
+
```env
|
|
39
|
+
NOTION_API_KEY=secret_your-notion-api-key-here
|
|
40
|
+
OPENAI_API_KEY=sk-your-openai-key-here
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 5. Run Examples
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Factory Pattern (simplest, direct API calls)
|
|
47
|
+
pnpm notion:factory
|
|
48
|
+
|
|
49
|
+
# Decorator Pattern (class-based OOP approach)
|
|
50
|
+
pnpm notion:decorator
|
|
51
|
+
|
|
52
|
+
# LangChain Pattern (AI-driven agent with OpenAI)
|
|
53
|
+
pnpm notion:langchain
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## π Examples Overview
|
|
57
|
+
|
|
58
|
+
### 1. Factory Pattern (`notion-factory.ts`)
|
|
59
|
+
|
|
60
|
+
**Best for:** Scripts, quick tests, CLI tools
|
|
61
|
+
|
|
62
|
+
**What it does:**
|
|
63
|
+
- β
Direct tool execution with `matimo.execute()`
|
|
64
|
+
- β
Automatically discovers accessible databases
|
|
65
|
+
- β
Queries database for pages
|
|
66
|
+
- β
Creates new pages with content
|
|
67
|
+
- β
Updates pages with icons
|
|
68
|
+
- β
Simplest implementation
|
|
69
|
+
|
|
70
|
+
**Run it:**
|
|
71
|
+
```bash
|
|
72
|
+
pnpm notion:factory
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Key Code:**
|
|
76
|
+
```typescript
|
|
77
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
78
|
+
|
|
79
|
+
// List databases
|
|
80
|
+
const databases = await matimo.execute('notion_list_databases', { page_size: 10 });
|
|
81
|
+
|
|
82
|
+
// Query a database
|
|
83
|
+
const pages = await matimo.execute('notion_query_database', {
|
|
84
|
+
database_id: 'db-id-here'
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Create a page
|
|
88
|
+
const newPage = await matimo.execute('notion_create_page', {
|
|
89
|
+
parent: { database_id: 'db-id-here' },
|
|
90
|
+
markdown: '# New Page\n\nContent here'
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**File:** [notion-factory.ts](notion-factory.ts)
|
|
95
|
+
|
|
96
|
+
### 2. Decorator Pattern (`notion-decorator.ts`)
|
|
97
|
+
|
|
98
|
+
**Best for:** Object-oriented design, class-based applications
|
|
99
|
+
|
|
100
|
+
**What it does:**
|
|
101
|
+
- β
Class methods decorated with `@tool`
|
|
102
|
+
- β
Automatic tool execution via decorators
|
|
103
|
+
- β
Multiple operations in organized class
|
|
104
|
+
- β
Creates and updates pages automatically
|
|
105
|
+
- β
OOP-friendly approach
|
|
106
|
+
|
|
107
|
+
**Run it:**
|
|
108
|
+
```bash
|
|
109
|
+
pnpm notion:decorator
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Key Code:**
|
|
113
|
+
```typescript
|
|
114
|
+
class NotionAgent {
|
|
115
|
+
@tool('notion_list_databases')
|
|
116
|
+
async listDatabases() {
|
|
117
|
+
// Decorator auto-executes tool
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@tool('notion_create_page')
|
|
121
|
+
async createPage(parent: any, markdown: string) {
|
|
122
|
+
// Also auto-executed
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const agent = new NotionAgent();
|
|
127
|
+
await agent.listDatabases();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**File:** [notion-decorator.ts](notion-decorator.ts)
|
|
131
|
+
|
|
132
|
+
### 3. LangChain AI Agent (`notion-langchain.ts`)
|
|
133
|
+
|
|
134
|
+
**Best for:** True autonomous agents with AI reasoning
|
|
135
|
+
|
|
136
|
+
**What it does:**
|
|
137
|
+
- β
AI agent (OpenAI GPT-4o-mini) decides which tools to use
|
|
138
|
+
- β
Takes natural language instructions
|
|
139
|
+
- β
Automatically discovers databases
|
|
140
|
+
- β
Executes Notion tools autonomously
|
|
141
|
+
- β
Processes results and responds naturally
|
|
142
|
+
- β
Multi-step reasoning
|
|
143
|
+
|
|
144
|
+
**Run it:**
|
|
145
|
+
```bash
|
|
146
|
+
pnpm notion:langchain
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Example Conversation:**
|
|
150
|
+
```
|
|
151
|
+
User: "Explore my Notion workspace and tell me what databases you find"
|
|
152
|
+
AI Agent: I'll explore your workspace and list the databases...
|
|
153
|
+
[AI calls notion_list_databases tool]
|
|
154
|
+
AI Agent: I found 3 databases:
|
|
155
|
+
1. Product Roadmap
|
|
156
|
+
2. Projects
|
|
157
|
+
3. Tasks
|
|
158
|
+
|
|
159
|
+
User: "Create a new page with the title 'Meeting Notes'"
|
|
160
|
+
AI Agent: I'll create a new page for you...
|
|
161
|
+
[AI calls notion_create_page tool with discovered database]
|
|
162
|
+
AI Agent: Done! I've created a new page titled 'Meeting Notes'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Key Code:**
|
|
166
|
+
```typescript
|
|
167
|
+
// Discover database first
|
|
168
|
+
const listResult = await matimo.execute('notion_list_databases', { page_size: 5 });
|
|
169
|
+
const selectedDatabase = listResult.data.results[0];
|
|
170
|
+
|
|
171
|
+
// Create agent with database context
|
|
172
|
+
const agent = await createAgent({
|
|
173
|
+
model: new ChatOpenAI({ modelName: 'gpt-4o-mini' }),
|
|
174
|
+
tools: langchainTools
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// AI decides which tools to use
|
|
178
|
+
const response = await agent.invoke({
|
|
179
|
+
messages: [{ role: 'user', content: 'Create a new page' }]
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**File:** [notion-langchain.ts](notion-langchain.ts)
|
|
184
|
+
|
|
185
|
+
## π― Available Notion Tools
|
|
186
|
+
|
|
187
|
+
All patterns have access to these core Notion tools:
|
|
188
|
+
|
|
189
|
+
### Database Operations
|
|
190
|
+
- `notion_list_databases` - List all accessible databases
|
|
191
|
+
- `notion_query_database` - Query pages in a database with filters
|
|
192
|
+
|
|
193
|
+
### Page Operations
|
|
194
|
+
- `notion_create_page` - Create new page in a database or as child page
|
|
195
|
+
- `notion_update_page` - Update page properties and icon
|
|
196
|
+
- `notion_get_page` - Retrieve page details
|
|
197
|
+
|
|
198
|
+
### Comments
|
|
199
|
+
- `notion_create_comment` - Add comments to pages
|
|
200
|
+
|
|
201
|
+
### Search
|
|
202
|
+
- `notion_search` - Search workspace for pages and databases
|
|
203
|
+
|
|
204
|
+
## π Common Patterns
|
|
205
|
+
|
|
206
|
+
### Discovering Available Databases
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
const result = await matimo.execute('notion_list_databases', {
|
|
210
|
+
page_size: 10
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
const databases = result.data.results; // Array of database objects
|
|
214
|
+
databases.forEach(db => {
|
|
215
|
+
const title = db.title[0]?.plain_text || 'Untitled';
|
|
216
|
+
console.log(`π ${title} (${db.id})`);
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Creating Pages with Markdown
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
const newPage = await matimo.execute('notion_create_page', {
|
|
224
|
+
parent: { database_id: 'your-db-id' },
|
|
225
|
+
icon: { type: 'emoji', emoji: 'β
' },
|
|
226
|
+
markdown: '# Page Title\n\n## Section\n\nContent here'
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Querying Database for Pages
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
const result = await matimo.execute('notion_query_database', {
|
|
234
|
+
database_id: 'your-db-id',
|
|
235
|
+
page_size: 10,
|
|
236
|
+
filter: {
|
|
237
|
+
property: 'Status',
|
|
238
|
+
status: { equals: 'Done' }
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const pages = result.data.results;
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## π Resources
|
|
246
|
+
|
|
247
|
+
- **Notion API Documentation:** [developers.notion.com](https://developers.notion.com)
|
|
248
|
+
- **Create Integration:** [notion.com/my-integrations](https://www.notion.com/my-integrations)
|
|
249
|
+
- **Matimo Notion Tools:** [packages/notion](../../packages/notion)
|
|
250
|
+
- **Matimo Documentation:** [docs/](../../docs)
|
|
251
|
+
|
|
252
|
+
## β οΈ Important Notes
|
|
253
|
+
|
|
254
|
+
### 1. Database Sharing Required
|
|
255
|
+
Tools can only access databases that have been **explicitly shared** with your integration. Use the Share button in Notion to grant access.
|
|
256
|
+
|
|
257
|
+
### 2. Destructive Operations
|
|
258
|
+
Tools like `notion_create_page` and `notion_update_page` make real changes to your Notion workspace. Be careful with credentials.
|
|
259
|
+
|
|
260
|
+
### 3. LangChain Pattern Limitations
|
|
261
|
+
The LangChain AI agent example:
|
|
262
|
+
- Automatically discovers and uses the first available database
|
|
263
|
+
- Does not support multi-step operations (e.g., create page then add comment) in a single request
|
|
264
|
+
- For complex workflows, use Factory or Decorator patterns
|
|
265
|
+
|
|
266
|
+
### 4. API Rate Limits
|
|
267
|
+
Notion API has rate limits. Long-running operations may need to retry. See [rate limiting docs](https://developers.notion.com/reference/node-sdk#rate-limits).
|
|
268
|
+
|
|
269
|
+
## π¨ Troubleshooting
|
|
270
|
+
|
|
271
|
+
### "Not Authorized to Access This Resource"
|
|
272
|
+
- Ensure the database is **shared** with your integration
|
|
273
|
+
- Check the integration has the correct permissions
|
|
274
|
+
|
|
275
|
+
### "Notion API Error"
|
|
276
|
+
- Verify `NOTION_API_KEY` is set correctly
|
|
277
|
+
- Check the integration token hasn't expired
|
|
278
|
+
|
|
279
|
+
### "Database Not Found"
|
|
280
|
+
- Confirm the database ID is correct
|
|
281
|
+
- Ensure the database is shared with the integration
|
|
282
|
+
|
|
283
|
+
### No Databases Returned
|
|
284
|
+
- Create a database in Notion first
|
|
285
|
+
- Share it with your integration
|
|
286
|
+
- Run `notion:factory` to test discovery
|
|
287
|
+
|
|
288
|
+
## π Support
|
|
289
|
+
|
|
290
|
+
For issues with:
|
|
291
|
+
- **Matimo tools:** See [packages/notion/README.md](../../packages/notion/README.md)
|
|
292
|
+
- **Notion API:** Visit [developers.notion.com/reference](https://developers.notion.com/reference)
|
|
293
|
+
- **LangChain:** Check [langchain.com/docs](https://docs.langchain.com)
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* NOTION TOOLS - DECORATOR PATTERN EXAMPLE
|
|
5
|
+
* ============================================================================
|
|
6
|
+
*
|
|
7
|
+
* PATTERN: Class Decorator Pattern
|
|
8
|
+
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
9
|
+
* Using @tool() decorators for class-based tool execution.
|
|
10
|
+
*
|
|
11
|
+
* Use this pattern when:
|
|
12
|
+
* β
Building class-based agents
|
|
13
|
+
* β
Organizing tools by domain (NotionManager, SlackHelper, etc.)
|
|
14
|
+
* β
Integrating with frameworks like LangChain, CrewAI
|
|
15
|
+
* β
Want method signatures to match tool interfaces
|
|
16
|
+
*
|
|
17
|
+
* SETUP:
|
|
18
|
+
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
19
|
+
* 1. Set NOTION_API_KEY environment variable
|
|
20
|
+
* 2. Share Notion databases/pages with your integration
|
|
21
|
+
* 3. Global Matimo instance must be set: setGlobalMatimoInstance(matimo)
|
|
22
|
+
*
|
|
23
|
+
* USAGE:
|
|
24
|
+
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
25
|
+
* export NOTION_API_KEY=secret_xxxx
|
|
26
|
+
* npm run notion:decorator
|
|
27
|
+
*
|
|
28
|
+
* ============================================================================
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import 'dotenv/config';
|
|
32
|
+
import { MatimoInstance, setGlobalMatimoInstance, tool } from '@matimo/core';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Notion Manager - Class-based interface to Notion tools
|
|
36
|
+
* Each method is decorated with @tool() which auto-executes via Matimo
|
|
37
|
+
*
|
|
38
|
+
* MATIMO DESIGN: Structured Parameters (Objects/Arrays)
|
|
39
|
+
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
40
|
+
* Note: This example passes structured JavaScript objects and arrays
|
|
41
|
+
* (like { database_id: '123' }, [{ type: 'text', ... }]) directly to methods.
|
|
42
|
+
*
|
|
43
|
+
* The decorator converts these to matimo.execute() calls, and the HTTP executor
|
|
44
|
+
* properly embeds them as JSON in request bodiesβthey are NOT stringified.
|
|
45
|
+
*
|
|
46
|
+
* This works because:
|
|
47
|
+
* 1. Each parameter is defined in YAML with its type (object, array, string, etc.)
|
|
48
|
+
* 2. The HTTP executor uses this type information to decide how to embed the value
|
|
49
|
+
* 3. For type:object and type:array, values are embedded directly as JSON structures
|
|
50
|
+
* 4. For type:string, values are templated as strings
|
|
51
|
+
*
|
|
52
|
+
* Example YAML parameter definition:
|
|
53
|
+
* ```yaml
|
|
54
|
+
* parameters:
|
|
55
|
+
* parent:
|
|
56
|
+
* type: object
|
|
57
|
+
* description: Parent database or page
|
|
58
|
+
* rich_text:
|
|
59
|
+
* type: array
|
|
60
|
+
* description: Array of rich text objects
|
|
61
|
+
* markdown:
|
|
62
|
+
* type: string
|
|
63
|
+
* description: Markdown content
|
|
64
|
+
*
|
|
65
|
+
* body:
|
|
66
|
+
* parent: "{parent}" # Embedded as JSON object
|
|
67
|
+
* rich_text: "{rich_text}" # Embedded as JSON array
|
|
68
|
+
* markdown: "{markdown}" # Embedded as string
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* Result: The API receives proper JSON structures, not stringified "[object Object]".
|
|
72
|
+
*/
|
|
73
|
+
class NotionManager {
|
|
74
|
+
/**
|
|
75
|
+
* List all databases in the workspace
|
|
76
|
+
* No API knowledge needed - just call it!
|
|
77
|
+
*/
|
|
78
|
+
@tool('notion_list_databases')
|
|
79
|
+
async listDatabases(page_size?: number): Promise<any> {
|
|
80
|
+
// Decorator intercepts β auto-executes via matimo.execute()
|
|
81
|
+
throw new Error('Should not be called - decorator handles execution');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Query a database for pages matching optional filters
|
|
86
|
+
* database_id parameter is clear and self-documenting
|
|
87
|
+
*/
|
|
88
|
+
@tool('notion_query_database')
|
|
89
|
+
async queryDatabase(
|
|
90
|
+
database_id: string,
|
|
91
|
+
sorts?: Array<Record<string, any>>,
|
|
92
|
+
filter?: Record<string, any>,
|
|
93
|
+
page_size?: number
|
|
94
|
+
): Promise<any> {
|
|
95
|
+
// Method body ignored - @tool decorator handles execution
|
|
96
|
+
throw new Error('Should not be called - decorator handles execution');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create a new page with markdown content
|
|
101
|
+
* Simplest way to add content - works with any database
|
|
102
|
+
*/
|
|
103
|
+
@tool('notion_create_page')
|
|
104
|
+
async createPage(
|
|
105
|
+
parent: Record<string, string>,
|
|
106
|
+
markdown?: string,
|
|
107
|
+
icon?: Record<string, string>
|
|
108
|
+
): Promise<any> {
|
|
109
|
+
// Decorator intercepts β auto-executes via matimo.execute()
|
|
110
|
+
throw new Error('Should not be called - decorator handles execution');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Update an existing page (icon, status, etc.)
|
|
115
|
+
*/
|
|
116
|
+
@tool('notion_update_page')
|
|
117
|
+
async updatePage(page_id: string, icon?: Record<string, string>): Promise<any> {
|
|
118
|
+
// Method body ignored - @tool decorator handles execution
|
|
119
|
+
throw new Error('Should not be called - decorator handles execution');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Add a comment to a page
|
|
124
|
+
*/
|
|
125
|
+
@tool('notion_create_comment')
|
|
126
|
+
async addComment(
|
|
127
|
+
parent: Record<string, string>,
|
|
128
|
+
rich_text?: Array<Record<string, any>>
|
|
129
|
+
): Promise<any> {
|
|
130
|
+
// Method body ignored - @tool decorator handles execution
|
|
131
|
+
throw new Error('Should not be called - decorator handles execution');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Demonstration of decorator pattern usage with REAL operations
|
|
137
|
+
*/
|
|
138
|
+
async function demonstrateDecoratorPattern() {
|
|
139
|
+
console.info('\nββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ');
|
|
140
|
+
console.info('β Notion Tools - Decorator Pattern β');
|
|
141
|
+
console.info('β (Class-based execution with REAL operations) β');
|
|
142
|
+
console.info('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
|
|
143
|
+
|
|
144
|
+
const apiKey = process.env.NOTION_API_KEY;
|
|
145
|
+
if (!apiKey) {
|
|
146
|
+
console.error('β Error: NOTION_API_KEY not set in .env');
|
|
147
|
+
console.info(' Set it: export NOTION_API_KEY="secret_xxxx"');
|
|
148
|
+
console.info(' Get one from: https://www.notion.so/my-integrations');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// Step 1: Initialize Matimo
|
|
154
|
+
console.info('π Initializing Matimo...');
|
|
155
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
156
|
+
|
|
157
|
+
// Step 2: Set global instance for decorators to use
|
|
158
|
+
console.info('π Setting up decorator support...');
|
|
159
|
+
setGlobalMatimoInstance(matimo);
|
|
160
|
+
|
|
161
|
+
console.info('β
NotionManager initialized with decorators\n');
|
|
162
|
+
|
|
163
|
+
// Step 3: Create manager instance
|
|
164
|
+
const manager = new NotionManager();
|
|
165
|
+
|
|
166
|
+
console.info('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
|
|
167
|
+
console.info('Testing @tool() Decorator - Verifying Tool Execution:');
|
|
168
|
+
console.info('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
|
|
169
|
+
|
|
170
|
+
// Test 1: Verify decorator intercepts and calls matimo.execute()
|
|
171
|
+
console.info('1οΈβ£ Testing @tool("notion_list_databases") decorator...');
|
|
172
|
+
console.info(' β Calling: manager.listDatabases(10)');
|
|
173
|
+
console.info(' β Decorator should intercept and call matimo.execute()...\n');
|
|
174
|
+
|
|
175
|
+
let listResult: any;
|
|
176
|
+
try {
|
|
177
|
+
listResult = await manager.listDatabases(10);
|
|
178
|
+
console.info(` π¨ Raw result received: ${JSON.stringify(listResult).substring(0, 100)}...`);
|
|
179
|
+
const databases = listResult.results || listResult.data?.results || [];
|
|
180
|
+
console.info(` β
Decorator executed tool successfully`);
|
|
181
|
+
console.info(` π Got response with ${databases.length} databases\n`);
|
|
182
|
+
|
|
183
|
+
if (databases.length > 0) {
|
|
184
|
+
const foundDatabase = databases[0];
|
|
185
|
+
console.info('2οΈβ£ Testing @tool("notion_query_database") decorator...');
|
|
186
|
+
console.info(` β Calling: manager.queryDatabase("${foundDatabase.id}", ...)`);
|
|
187
|
+
|
|
188
|
+
const queryResult = await manager.queryDatabase(foundDatabase.id, undefined, undefined, 5);
|
|
189
|
+
const queryPages = queryResult.results || queryResult.data?.results || [];
|
|
190
|
+
console.info(` β
Query decorator executed successfully`);
|
|
191
|
+
console.info(` π Got response with ${queryPages.length} pages\n`);
|
|
192
|
+
|
|
193
|
+
// Test 3: Try creating a page
|
|
194
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
195
|
+
console.info('3οΈβ£ Testing @tool("notion_create_page") decorator...');
|
|
196
|
+
console.info(' β Calling: manager.createPage({...}, markdown, icon)');
|
|
197
|
+
console.info(
|
|
198
|
+
' β Note: Structured params (objects/arrays) are properly embedded in HTTP body'
|
|
199
|
+
);
|
|
200
|
+
console.info(' as JSON, not stringifiedβthis is handled by HttpExecutor\n');
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const createResult = await manager.createPage(
|
|
204
|
+
{ database_id: foundDatabase.id }, // Object param β embedded as JSON
|
|
205
|
+
`# Decorator Test Page\n\nCreated at ${timestamp}`, // String param
|
|
206
|
+
{ type: 'emoji', emoji: 'π§' } // Object param β embedded as JSON
|
|
207
|
+
);
|
|
208
|
+
console.info(` β
Create decorator executed`);
|
|
209
|
+
console.info(` π¨ Got response: ${JSON.stringify(createResult).substring(0, 100)}...`);
|
|
210
|
+
|
|
211
|
+
if (createResult.id) {
|
|
212
|
+
console.info(` β
Successfully created page: ${createResult.id}\n`);
|
|
213
|
+
|
|
214
|
+
// Try updating
|
|
215
|
+
console.info('4οΈβ£ Testing @tool("notion_update_page") decorator...');
|
|
216
|
+
try {
|
|
217
|
+
const updateResult = await manager.updatePage(createResult.id, {
|
|
218
|
+
type: 'emoji',
|
|
219
|
+
emoji: 'β¨',
|
|
220
|
+
});
|
|
221
|
+
console.info(` β
Update decorator executed\n`);
|
|
222
|
+
} catch (e) {
|
|
223
|
+
console.info(` β οΈ Update skipped (expected if permission limited): ${e}\n`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Try commenting
|
|
227
|
+
console.info('5οΈβ£ Testing @tool("notion_create_comment") decorator...');
|
|
228
|
+
console.info(' β Calling: manager.addComment(parent, rich_text_array)');
|
|
229
|
+
console.info(
|
|
230
|
+
' β Note: Array param is properly embedded as JSON array in HTTP body\n'
|
|
231
|
+
);
|
|
232
|
+
try {
|
|
233
|
+
const commentResult = await manager.addComment(
|
|
234
|
+
{ page_id: createResult.id }, // Object param β embedded as JSON
|
|
235
|
+
[
|
|
236
|
+
// Array param β embedded as JSON array
|
|
237
|
+
{ type: 'text', text: { content: `Added at ${timestamp} via decorator!` } },
|
|
238
|
+
]
|
|
239
|
+
);
|
|
240
|
+
console.info(` β
Comment decorator executed\n`);
|
|
241
|
+
} catch (e) {
|
|
242
|
+
console.info(` β οΈ Comment skipped (expected if permission limited): ${e}\n`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} catch (createError) {
|
|
246
|
+
console.info(` β οΈ Create failed (expected if permission limited): ${createError}\n`);
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
console.info(' π No databases accessible - cannot test further operations');
|
|
250
|
+
console.info(' π Share a Notion database with your integration to test full workflow\n');
|
|
251
|
+
}
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.error(` β Decorator test failed: ${error}\n`);
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
console.info('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
|
|
258
|
+
console.info('β
Decorator Pattern Verification Complete!');
|
|
259
|
+
console.info('ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n');
|
|
260
|
+
console.info('π Key Points:');
|
|
261
|
+
console.info(' β
@tool() decorator intercepts method calls');
|
|
262
|
+
console.info(' β
Decorator calls matimo.execute() with the tool name');
|
|
263
|
+
console.info(' β
Method bodies are ignored (not executed)');
|
|
264
|
+
console.info(' β
Works seamlessly - developers just call methods!\n');
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.error('\nβ Error:', error instanceof Error ? error.message : String(error));
|
|
267
|
+
if (error instanceof Error && error.message.includes('NOTION_API_KEY')) {
|
|
268
|
+
console.error('\nπ Set environment variable:');
|
|
269
|
+
console.error(' export NOTION_API_KEY=secret_xxxxx');
|
|
270
|
+
}
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
demonstrateDecoratorPattern().catch(console.error);
|