@ilivemylife/graph-sdk 1.0.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 +725 -0
- package/bin/ilml +5 -0
- package/dist/cli.mjs +2890 -0
- package/dist/client.cjs +1212 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +607 -0
- package/dist/client.d.ts +607 -0
- package/dist/client.mjs +1138 -0
- package/dist/client.mjs.map +1 -0
- package/dist/mcp-server.mjs +1957 -0
- package/dist/queries.cjs +443 -0
- package/dist/queries.cjs.map +1 -0
- package/dist/queries.d.cts +201 -0
- package/dist/queries.d.ts +201 -0
- package/dist/queries.mjs +383 -0
- package/dist/queries.mjs.map +1 -0
- package/examples/README.md +143 -0
- package/examples/ask-lifebot.mjs +43 -0
- package/examples/error-handling.mjs +89 -0
- package/examples/getting-started.mjs +201 -0
- package/examples/manage-items.mjs +78 -0
- package/examples/messenger-basics.mjs +189 -0
- package/examples/subscriptions.mjs +60 -0
- package/package.json +68 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# SDK Usage Examples
|
|
2
|
+
|
|
3
|
+
Examples demonstrating how to use the iLiveMyLife Graph SDK.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# 1. Install dependencies (from project root)
|
|
9
|
+
npm install
|
|
10
|
+
|
|
11
|
+
# 2. Build the SDK
|
|
12
|
+
npm run build
|
|
13
|
+
|
|
14
|
+
# 3. Login to get your token
|
|
15
|
+
node dist/cli.mjs login
|
|
16
|
+
|
|
17
|
+
# 4. Run examples
|
|
18
|
+
node examples/getting-started.mjs
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or set token manually:
|
|
22
|
+
```bash
|
|
23
|
+
export ILML_TOKEN="your-access-token"
|
|
24
|
+
node examples/getting-started.mjs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Getting Your Token
|
|
28
|
+
|
|
29
|
+
**Option 1: CLI Login**
|
|
30
|
+
```bash
|
|
31
|
+
npx ilml login
|
|
32
|
+
# Token saved automatically to ~/.ilivemylife/config.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Option 2: Browser DevTools**
|
|
36
|
+
1. Open https://app.ilivemylife.io and log in
|
|
37
|
+
2. Open DevTools (F12) → Network tab
|
|
38
|
+
3. Make any action (refresh page, open a node)
|
|
39
|
+
4. Click any GraphQL request → Headers tab
|
|
40
|
+
5. Find `access-token` in Request Headers and copy its value
|
|
41
|
+
|
|
42
|
+
## Examples
|
|
43
|
+
|
|
44
|
+
### 1. Getting Started (Start Here!)
|
|
45
|
+
```bash
|
|
46
|
+
node examples/getting-started.mjs
|
|
47
|
+
```
|
|
48
|
+
**Works without NODE_ID!** Complete walkthrough:
|
|
49
|
+
- Connect with your token
|
|
50
|
+
- Navigate your "My Life" tree
|
|
51
|
+
- Read node fields (title, description, tags, etc.)
|
|
52
|
+
- Create nodes with tags (like `private`)
|
|
53
|
+
- Create child nodes
|
|
54
|
+
- Edit nodes (partial updates)
|
|
55
|
+
- Reorder children
|
|
56
|
+
- Understand eventual consistency
|
|
57
|
+
|
|
58
|
+
### 2. Messenger & Lifebot
|
|
59
|
+
```bash
|
|
60
|
+
node examples/messenger-basics.mjs
|
|
61
|
+
```
|
|
62
|
+
Working with messages and AI:
|
|
63
|
+
- Read messages from a node
|
|
64
|
+
- Send messages (without AI response)
|
|
65
|
+
- Ask Lifebot questions
|
|
66
|
+
- Ask Lifebot to create nodes
|
|
67
|
+
- Ask Lifebot to create structure (nested nodes)
|
|
68
|
+
|
|
69
|
+
### 3. Ask Lifebot (Simple)
|
|
70
|
+
```bash
|
|
71
|
+
export NODE_ID="your-node-id"
|
|
72
|
+
node examples/ask-lifebot.mjs
|
|
73
|
+
```
|
|
74
|
+
Focused example of AI interaction with error handling.
|
|
75
|
+
|
|
76
|
+
### 4. Manage Items
|
|
77
|
+
```bash
|
|
78
|
+
export NODE_ID="your-node-id"
|
|
79
|
+
node examples/manage-items.mjs
|
|
80
|
+
```
|
|
81
|
+
Creating, editing, reordering, archiving items.
|
|
82
|
+
|
|
83
|
+
### 5. Real-time Subscriptions
|
|
84
|
+
```bash
|
|
85
|
+
export NODE_ID="your-node-id"
|
|
86
|
+
node examples/subscriptions.mjs
|
|
87
|
+
```
|
|
88
|
+
Subscribing to message and item changes in real-time.
|
|
89
|
+
|
|
90
|
+
### 6. Error Handling
|
|
91
|
+
```bash
|
|
92
|
+
node examples/error-handling.mjs
|
|
93
|
+
```
|
|
94
|
+
Proper error handling patterns with typed exceptions.
|
|
95
|
+
|
|
96
|
+
## Finding Your Node ID
|
|
97
|
+
|
|
98
|
+
Node IDs are in the URL when viewing a node:
|
|
99
|
+
```
|
|
100
|
+
https://app.ilivemylife.io/item/00001191f13c5c81-ee4ae8284f820001
|
|
101
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
102
|
+
This is the node ID
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or get your root node ID programmatically:
|
|
106
|
+
```javascript
|
|
107
|
+
const me = await graph.me();
|
|
108
|
+
console.log(me.rootItemId); // Your "My Life" root node ID
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## What is Lifebot?
|
|
112
|
+
|
|
113
|
+
Lifebot is the AI assistant that lives inside your iLiveMyLife knowledge graph.
|
|
114
|
+
|
|
115
|
+
**What Lifebot can do:**
|
|
116
|
+
- Answer questions about your data
|
|
117
|
+
- Search and find information across nodes
|
|
118
|
+
- Create new nodes with content
|
|
119
|
+
- Organize information into structure
|
|
120
|
+
- Execute actions on your behalf
|
|
121
|
+
|
|
122
|
+
**How to use:**
|
|
123
|
+
```javascript
|
|
124
|
+
// Simple question
|
|
125
|
+
const answer = await graph.askLifebot(nodeId, 'Summarize this project');
|
|
126
|
+
|
|
127
|
+
// Ask to create something
|
|
128
|
+
const result = await graph.askLifebot(nodeId,
|
|
129
|
+
'Create a node called "Weekly Tasks" with 3 sub-tasks inside');
|
|
130
|
+
|
|
131
|
+
// Lifebot will create the node AND the children!
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Enable Lifebot:** Add `assist` tag to a node to enable Lifebot in that node.
|
|
135
|
+
|
|
136
|
+
## Eventual Consistency
|
|
137
|
+
|
|
138
|
+
When you write data (addItem, editItem, etc.):
|
|
139
|
+
1. Command is accepted immediately
|
|
140
|
+
2. You get confirmation (or error)
|
|
141
|
+
3. Data propagates across the system
|
|
142
|
+
|
|
143
|
+
**Important:** Reading immediately after write might return stale data. If you need real-time updates, use subscriptions.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask Lifebot Example
|
|
3
|
+
*
|
|
4
|
+
* Shows how to send a message and wait for AI response.
|
|
5
|
+
*
|
|
6
|
+
* Run: node examples/ask-lifebot.mjs
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
createGraphClient,
|
|
11
|
+
LifebotTimeoutError,
|
|
12
|
+
LifebotRateLimitError
|
|
13
|
+
} from '@ilivemylife/graph-sdk';
|
|
14
|
+
|
|
15
|
+
const graph = createGraphClient({
|
|
16
|
+
token: process.env.ILML_TOKEN,
|
|
17
|
+
// Optional: enable logging
|
|
18
|
+
logger: console
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const nodeId = process.env.NODE_ID;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
console.log('Asking Lifebot...');
|
|
25
|
+
|
|
26
|
+
const reply = await graph.askLifebot(nodeId, 'What is 2 + 2?', {
|
|
27
|
+
timeout: 30000 // 30 seconds timeout
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
console.log('Lifebot response:', reply.content);
|
|
31
|
+
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof LifebotTimeoutError) {
|
|
34
|
+
console.error('Lifebot did not respond in time');
|
|
35
|
+
} else if (error instanceof LifebotRateLimitError) {
|
|
36
|
+
console.error('Rate limit exceeded, try again later');
|
|
37
|
+
} else {
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
} finally {
|
|
41
|
+
// Free resources and close connections
|
|
42
|
+
graph.destroy();
|
|
43
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handling Example
|
|
3
|
+
*
|
|
4
|
+
* Shows how to properly handle SDK errors.
|
|
5
|
+
*
|
|
6
|
+
* Run: node examples/error-handling.mjs
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
createGraphClient,
|
|
11
|
+
GraphError,
|
|
12
|
+
GraphNetworkError,
|
|
13
|
+
GraphAuthError,
|
|
14
|
+
LifebotError,
|
|
15
|
+
LifebotRateLimitError,
|
|
16
|
+
LifebotTimeoutError,
|
|
17
|
+
GraphErrorCodes
|
|
18
|
+
} from '@ilivemylife/graph-sdk';
|
|
19
|
+
|
|
20
|
+
// Example 1: Missing token
|
|
21
|
+
try {
|
|
22
|
+
const client = createGraphClient({ token: '' });
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (error instanceof GraphError) {
|
|
25
|
+
console.log('Expected error - token required:', error.message);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Example 2: Working with a valid client
|
|
30
|
+
const graph = createGraphClient({
|
|
31
|
+
token: process.env.ILML_TOKEN
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Example 3: Handling API errors
|
|
35
|
+
async function safeGetItems(nodeId) {
|
|
36
|
+
try {
|
|
37
|
+
return await graph.items(nodeId);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (error instanceof GraphNetworkError) {
|
|
40
|
+
console.error('Network error - check your connection');
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
if (error instanceof GraphAuthError) {
|
|
44
|
+
console.error('Auth error - check your token');
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
throw error; // Re-throw unknown errors
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Example 4: Handling Lifebot errors
|
|
52
|
+
async function safeAskLifebot(nodeId, question) {
|
|
53
|
+
try {
|
|
54
|
+
return await graph.askLifebot(nodeId, question, { timeout: 30000 });
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error instanceof LifebotTimeoutError) {
|
|
57
|
+
console.error(`Timeout after ${error.timeout}ms`);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (error instanceof LifebotRateLimitError) {
|
|
61
|
+
console.error('Rate limited - waiting before retry');
|
|
62
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
63
|
+
return safeAskLifebot(nodeId, question); // Retry
|
|
64
|
+
}
|
|
65
|
+
if (error instanceof LifebotError) {
|
|
66
|
+
console.error('Lifebot error:', error.message);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Example 5: Using error codes
|
|
74
|
+
async function handleMutationError() {
|
|
75
|
+
try {
|
|
76
|
+
await graph.addItem('invalid-node-id', { title: 'Test' });
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error instanceof GraphError && error.code === GraphErrorCodes.MUTATION_FAILED) {
|
|
79
|
+
console.log('Mutation failed - check node ID');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Run examples
|
|
85
|
+
const nodeId = process.env.NODE_ID;
|
|
86
|
+
if (nodeId) {
|
|
87
|
+
const items = await safeGetItems(nodeId);
|
|
88
|
+
console.log('Items:', items.length);
|
|
89
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Getting Started - Complete Example
|
|
3
|
+
*
|
|
4
|
+
* Works with just ILML_TOKEN - no NODE_ID needed!
|
|
5
|
+
* Shows the core flow: navigate tree, create nodes, understand structure.
|
|
6
|
+
*
|
|
7
|
+
* Getting your token:
|
|
8
|
+
* Option 1: npx ilml login (then token saved automatically)
|
|
9
|
+
* Option 2: In browser app.ilivemylife.io → DevTools → Network tab →
|
|
10
|
+
* click any request → Headers → find "access-token"
|
|
11
|
+
*
|
|
12
|
+
* Run:
|
|
13
|
+
* node examples/getting-started.mjs
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createGraphClient } from '@ilivemylife/graph-sdk';
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Step 1: Create client
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
const graph = createGraphClient({
|
|
23
|
+
token: process.env.ILML_TOKEN
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
console.log('='.repeat(60));
|
|
27
|
+
console.log('iLiveMyLife Graph SDK - Getting Started');
|
|
28
|
+
console.log('='.repeat(60));
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Step 2: Get current user and root node
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
const me = await graph.me();
|
|
35
|
+
console.log('\n[Your Account]');
|
|
36
|
+
console.log(' Name:', me.displayName);
|
|
37
|
+
console.log(' Email:', me.email);
|
|
38
|
+
console.log(' Root Node ID:', me.rootItemId);
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Step 3: Navigate the tree - read root and children
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
// items() returns [node, ...children] - first element is the node itself
|
|
45
|
+
const rootItems = await graph.items(me.rootItemId);
|
|
46
|
+
const rootNode = rootItems[0];
|
|
47
|
+
const rootChildren = rootItems.slice(1);
|
|
48
|
+
|
|
49
|
+
console.log('\n[Your "My Life" (root) Node]');
|
|
50
|
+
console.log(' Title:', rootNode.title);
|
|
51
|
+
console.log(' Description:', rootNode.description || '(empty)');
|
|
52
|
+
console.log(' Tags:', rootNode.tags?.join(', ') || '(none)');
|
|
53
|
+
console.log(' Children:', rootChildren.length);
|
|
54
|
+
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// Step 4: Iterate through children - show all fields
|
|
57
|
+
// ============================================================================
|
|
58
|
+
|
|
59
|
+
console.log('\n[Root Children]');
|
|
60
|
+
if (rootChildren.length === 0) {
|
|
61
|
+
console.log(' (no children yet)');
|
|
62
|
+
} else {
|
|
63
|
+
rootChildren.slice(0, 5).forEach((item, i) => {
|
|
64
|
+
console.log(`\n ${i + 1}. "${item.title}"`);
|
|
65
|
+
console.log(` ID: ${item.id}`);
|
|
66
|
+
console.log(` Description: ${item.description || '(empty)'}`);
|
|
67
|
+
console.log(` Tags: ${item.tags?.join(', ') || '(none)'}`);
|
|
68
|
+
console.log(` Order: ${item.order}`);
|
|
69
|
+
console.log(` Created: ${new Date(parseInt(item.createdAt)).toLocaleString()}`);
|
|
70
|
+
console.log(` By: ${item.createdBy}`);
|
|
71
|
+
if (item.refId) {
|
|
72
|
+
console.log(` → Link to: ${item.refId}`);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
if (rootChildren.length > 5) {
|
|
76
|
+
console.log(`\n ... and ${rootChildren.length - 5} more`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// Step 5: Go deeper - read grandchildren (2 levels)
|
|
82
|
+
// ============================================================================
|
|
83
|
+
|
|
84
|
+
if (rootChildren.length > 0) {
|
|
85
|
+
const firstChild = rootChildren[0];
|
|
86
|
+
const childItems = await graph.items(firstChild.id);
|
|
87
|
+
const grandchildren = childItems.slice(1);
|
|
88
|
+
|
|
89
|
+
console.log(`\n[Inside "${firstChild.title}"]`);
|
|
90
|
+
console.log(' Children:', grandchildren.length);
|
|
91
|
+
grandchildren.slice(0, 3).forEach((item, i) => {
|
|
92
|
+
console.log(` ${i + 1}. ${item.title}`);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// Step 6: Create a new node
|
|
98
|
+
// ============================================================================
|
|
99
|
+
|
|
100
|
+
console.log('\n[Creating New Node]');
|
|
101
|
+
|
|
102
|
+
const newNode = await graph.addItem(me.rootItemId, {
|
|
103
|
+
title: 'SDK Demo',
|
|
104
|
+
description: 'This node was created via iLiveMyLife Graph SDK.\n\nIt demonstrates the `addItem()` method.',
|
|
105
|
+
tags: ['private']
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
console.log(' Created:', newNode.title);
|
|
109
|
+
console.log(' ID:', newNode.id);
|
|
110
|
+
console.log(' URL: https://app.ilivemylife.io/item/' + newNode.id);
|
|
111
|
+
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Step 7: Create child nodes inside it
|
|
114
|
+
// ============================================================================
|
|
115
|
+
|
|
116
|
+
console.log('\n[Creating Child Nodes]');
|
|
117
|
+
|
|
118
|
+
const child1 = await graph.addItem(newNode.id, {
|
|
119
|
+
title: 'First Task',
|
|
120
|
+
description: 'This is the first task in our demo project.'
|
|
121
|
+
});
|
|
122
|
+
console.log(' Created:', child1.title);
|
|
123
|
+
|
|
124
|
+
const child2 = await graph.addItem(newNode.id, {
|
|
125
|
+
title: 'Second Task',
|
|
126
|
+
description: 'This is the second task.'
|
|
127
|
+
});
|
|
128
|
+
console.log(' Created:', child2.title);
|
|
129
|
+
|
|
130
|
+
const child3 = await graph.addItem(newNode.id, {
|
|
131
|
+
title: 'Third Task',
|
|
132
|
+
description: 'This is the third task.'
|
|
133
|
+
});
|
|
134
|
+
console.log(' Created:', child3.title);
|
|
135
|
+
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// Note on Eventual Consistency
|
|
138
|
+
// ============================================================================
|
|
139
|
+
// When you call addItem/editItem, the command is accepted immediately.
|
|
140
|
+
// However, propagation across the system takes a moment.
|
|
141
|
+
// If you read right after write, you might get stale data.
|
|
142
|
+
// But once you receive confirmation (no error), data WILL propagate eventually.
|
|
143
|
+
//
|
|
144
|
+
// For real-time updates, use subscriptions (see subscriptions.mjs)
|
|
145
|
+
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Step 8: Edit a node
|
|
148
|
+
// ============================================================================
|
|
149
|
+
|
|
150
|
+
console.log('\n[Editing Node]');
|
|
151
|
+
// Only pass fields you want to change - omitted fields stay unchanged
|
|
152
|
+
const edited = await graph.editItem({
|
|
153
|
+
id: child1.id,
|
|
154
|
+
title: 'First Task (Updated)',
|
|
155
|
+
description: 'Description updated via SDK!'
|
|
156
|
+
// tags: not passed = tags stay unchanged
|
|
157
|
+
// dueDate: not passed = dueDate stays unchanged
|
|
158
|
+
});
|
|
159
|
+
console.log(' Updated:', edited.title);
|
|
160
|
+
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// Step 9: Reorder children
|
|
163
|
+
// ============================================================================
|
|
164
|
+
|
|
165
|
+
console.log('\n[Reordering]');
|
|
166
|
+
// Move last child (position 3) to first position (position 1)
|
|
167
|
+
const reordered = await graph.reorderChild(newNode.id, 3, 1);
|
|
168
|
+
console.log(' Moved "' + reordered.title + '" to position 1');
|
|
169
|
+
|
|
170
|
+
// Verify new order
|
|
171
|
+
const afterReorder = await graph.items(newNode.id);
|
|
172
|
+
console.log(' New order:', afterReorder.slice(1).map(i => i.title).join(' → '));
|
|
173
|
+
|
|
174
|
+
// ============================================================================
|
|
175
|
+
// Done!
|
|
176
|
+
// ============================================================================
|
|
177
|
+
|
|
178
|
+
console.log('\n' + '='.repeat(60));
|
|
179
|
+
console.log('Done! Summary:');
|
|
180
|
+
console.log('='.repeat(60));
|
|
181
|
+
console.log(`
|
|
182
|
+
What we did:
|
|
183
|
+
1. Connected with your token
|
|
184
|
+
2. Read your user info
|
|
185
|
+
3. Navigated the tree (root → children → grandchildren)
|
|
186
|
+
4. Created a new node with title, description, tags
|
|
187
|
+
5. Created child nodes inside it
|
|
188
|
+
6. Edited a node
|
|
189
|
+
7. Reordered children
|
|
190
|
+
|
|
191
|
+
View in app: https://app.ilivemylife.io/item/${newNode.id}
|
|
192
|
+
|
|
193
|
+
Next examples to try:
|
|
194
|
+
- messenger-basics.mjs - Send messages, chat in nodes
|
|
195
|
+
- ask-lifebot.mjs - Ask AI questions, let it create nodes
|
|
196
|
+
- subscriptions.mjs - Real-time updates
|
|
197
|
+
|
|
198
|
+
CLI commands:
|
|
199
|
+
npx ilml items ${newNode.id}
|
|
200
|
+
npx ilml tree ${newNode.id}
|
|
201
|
+
`);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Item Management Example
|
|
3
|
+
*
|
|
4
|
+
* Shows how to create, edit, and organize items.
|
|
5
|
+
*
|
|
6
|
+
* Run: node examples/manage-items.mjs
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createGraphClient } from '@ilivemylife/graph-sdk';
|
|
10
|
+
|
|
11
|
+
const graph = createGraphClient({
|
|
12
|
+
token: process.env.ILML_TOKEN
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const parentNodeId = process.env.NODE_ID;
|
|
16
|
+
|
|
17
|
+
// Create a new item (all fields optional)
|
|
18
|
+
const newItem = await graph.addItem(parentNodeId, {
|
|
19
|
+
title: 'My New Task',
|
|
20
|
+
description: 'This is a task created via SDK',
|
|
21
|
+
tags: ['sdk', 'example'],
|
|
22
|
+
dueDate: String(Date.now() + 7 * 24 * 60 * 60 * 1000) // timestamp string (ms)
|
|
23
|
+
});
|
|
24
|
+
console.log('Created item:', newItem.id, newItem.title);
|
|
25
|
+
|
|
26
|
+
// Create a reference (shortcut) to another node
|
|
27
|
+
// const ref = await graph.addItem(parentNodeId, {
|
|
28
|
+
// refId: 'target-node-id', // ID of the original node
|
|
29
|
+
// title: 'Custom Title', // optional: override original title
|
|
30
|
+
// description: 'Custom description' // optional: override original description
|
|
31
|
+
// });
|
|
32
|
+
// console.log('Created ref:', ref.id, '→', ref.refId);
|
|
33
|
+
|
|
34
|
+
// Edit the item
|
|
35
|
+
const editedItem = await graph.editItem({
|
|
36
|
+
id: newItem.id,
|
|
37
|
+
title: 'My Updated Task',
|
|
38
|
+
description: 'Description updated via SDK'
|
|
39
|
+
});
|
|
40
|
+
console.log('Updated item:', editedItem.title);
|
|
41
|
+
|
|
42
|
+
// Get all items to see current order
|
|
43
|
+
const items = await graph.items(parentNodeId);
|
|
44
|
+
const children = items.slice(1); // First item is the parent itself
|
|
45
|
+
console.log('Children count:', children.length);
|
|
46
|
+
|
|
47
|
+
// Resolve a node — if it has refId, follows it to get the original node.
|
|
48
|
+
// Returns the node itself if it has no refId.
|
|
49
|
+
if (children.length > 0) {
|
|
50
|
+
const firstChild = children[0];
|
|
51
|
+
const resolved = await graph.resolveRef(firstChild.id);
|
|
52
|
+
if (resolved) {
|
|
53
|
+
console.log('Resolved:', firstChild.title, firstChild.refId ? `→ ${resolved.title}` : '(not a ref)');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (children.length >= 2) {
|
|
58
|
+
// Move child from last position to position 2 (1-based)
|
|
59
|
+
const lastPosition = children.length;
|
|
60
|
+
const reordered = await graph.reorderChild(parentNodeId, lastPosition, 2);
|
|
61
|
+
console.log('Reordered to position 2:', reordered.title);
|
|
62
|
+
|
|
63
|
+
// Move specific node to position 1
|
|
64
|
+
const moved = await graph.setPosition(newItem.id, parentNodeId, 1);
|
|
65
|
+
console.log('Set position to 1:', moved.title);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Move item to a different parent
|
|
69
|
+
// await graph.moveItem(newItem.id, parentNodeId, otherParentId); // to the end
|
|
70
|
+
// await graph.moveItemToPosition(newItem.id, parentNodeId, otherParentId, 3); // to position 3
|
|
71
|
+
|
|
72
|
+
// Archive the item
|
|
73
|
+
await graph.archiveItem(newItem.id);
|
|
74
|
+
console.log('Item archived');
|
|
75
|
+
|
|
76
|
+
// Unarchive if needed
|
|
77
|
+
await graph.unarchiveItem(newItem.id);
|
|
78
|
+
console.log('Item unarchived');
|