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.
Files changed (57) hide show
  1. package/.env.example +49 -0
  2. package/LICENSE +21 -0
  3. package/README.md +525 -0
  4. package/agents/decorator-pattern-agent.ts +368 -0
  5. package/agents/factory-pattern-agent.ts +253 -0
  6. package/agents/langchain-agent.ts +146 -0
  7. package/edit/edit-decorator.ts +178 -0
  8. package/edit/edit-factory.ts +138 -0
  9. package/edit/edit-langchain.ts +292 -0
  10. package/execute/execute-decorator.ts +49 -0
  11. package/execute/execute-factory.ts +46 -0
  12. package/execute/execute-langchain.ts +232 -0
  13. package/github/github-decorator.ts +326 -0
  14. package/github/github-factory.ts +355 -0
  15. package/github/github-langchain.ts +206 -0
  16. package/github/github-with-approval.ts +228 -0
  17. package/gmail/README.md +345 -0
  18. package/gmail/gmail-decorator.ts +216 -0
  19. package/gmail/gmail-factory.ts +231 -0
  20. package/gmail/gmail-langchain.ts +201 -0
  21. package/hubspot/README.md +316 -0
  22. package/hubspot/hubspot-decorator.ts +180 -0
  23. package/hubspot/hubspot-factory.ts +188 -0
  24. package/hubspot/hubspot-langchain.ts +222 -0
  25. package/logger-example.ts +40 -0
  26. package/mailchimp/README.md +321 -0
  27. package/mailchimp/mailchimp-decorator.ts +277 -0
  28. package/mailchimp/mailchimp-factory.ts +187 -0
  29. package/mailchimp/mailchimp-langchain.ts +155 -0
  30. package/notion/README.md +293 -0
  31. package/notion/notion-decorator.ts +275 -0
  32. package/notion/notion-factory.ts +256 -0
  33. package/notion/notion-langchain.ts +237 -0
  34. package/package.json +79 -0
  35. package/postgres/README.md +188 -0
  36. package/postgres/postgres-decorator.ts +198 -0
  37. package/postgres/postgres-factory.ts +180 -0
  38. package/postgres/postgres-langchain.ts +213 -0
  39. package/postgres/postgres-with-approval.ts +344 -0
  40. package/read/read-decorator.ts +154 -0
  41. package/read/read-factory.ts +121 -0
  42. package/read/read-langchain.ts +273 -0
  43. package/search/search-decorator.ts +206 -0
  44. package/search/search-factory.ts +146 -0
  45. package/search/search-langchain.ts +255 -0
  46. package/slack/README.md +339 -0
  47. package/slack/slack-decorator.ts +245 -0
  48. package/slack/slack-factory.ts +226 -0
  49. package/slack/slack-langchain.ts +242 -0
  50. package/tsconfig.json +20 -0
  51. package/twilio/README.md +309 -0
  52. package/twilio/twilio-decorator.ts +288 -0
  53. package/twilio/twilio-factory.ts +238 -0
  54. package/twilio/twilio-langchain.ts +218 -0
  55. package/web/web-decorator.ts +52 -0
  56. package/web/web-factory.ts +70 -0
  57. package/web/web-langchain.ts +163 -0
@@ -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);