trilium-api 1.0.0 → 1.0.1

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/src/client.ts CHANGED
@@ -1,91 +1,91 @@
1
- /**
2
- * Trilium API Client using openapi-fetch
3
- *
4
- * This provides a type-safe client for the Trilium ETAPI.
5
- * Types are auto-generated from the OpenAPI specification.
6
- */
7
-
8
- import createClient from 'openapi-fetch';
9
- import type { paths, components } from './generated/trilium.js';
10
-
11
- // Re-export common types for convenience
12
- export type TriliumNote = components['schemas']['Note'];
13
- export type TriliumBranch = components['schemas']['Branch'];
14
- export type TriliumAttribute = components['schemas']['Attribute'];
15
- export type TriliumAttachment = components['schemas']['Attachment'];
16
- export type TriliumAppInfo = components['schemas']['AppInfo'];
17
-
18
- // Export the paths type for advanced usage
19
- export type { paths, components };
20
-
21
- // Re-export mapper utilities
22
- export {
23
- TriliumMapper,
24
- buildSearchQuery,
25
- transforms,
26
- type MappingConfig,
27
- type FieldMapping,
28
- type TransformFunction,
29
- type ComputedFunction,
30
- type TriliumSearchHelpers,
31
- type TriliumSearchConditions,
32
- type TriliumSearchLogical,
33
- type ComparisonOperator,
34
- type ConditionValue,
35
- type SearchValue,
36
- } from './mapper.js';
37
-
38
- export interface TriliumClientConfig {
39
- baseUrl: string;
40
- apiKey: string;
41
- }
42
-
43
- /**
44
- * Create a type-safe Trilium API client
45
- *
46
- * @example
47
- * ```ts
48
- * const client = createTriliumClient({
49
- * baseUrl: 'http://localhost:37840',
50
- * apiKey: 'your-etapi-token'
51
- * });
52
- *
53
- * // Get app info
54
- * const { data, error } = await client.GET('/app-info');
55
- *
56
- * // Get a note by ID
57
- * const { data: note } = await client.GET('/notes/{noteId}', {
58
- * params: { path: { noteId: 'root' } }
59
- * });
60
- *
61
- * // Create a note
62
- * const { data: newNote } = await client.POST('/notes', {
63
- * body: {
64
- * parentNoteId: 'root',
65
- * title: 'My Note',
66
- * type: 'text',
67
- * content: '<p>Hello World</p>'
68
- * }
69
- * });
70
- *
71
- * // Search notes
72
- * const { data: searchResults } = await client.GET('/notes', {
73
- * params: { query: { search: '#blog' } }
74
- * });
75
- * ```
76
- */
77
- export function createTriliumClient(config: TriliumClientConfig) {
78
- const baseUrl = config.baseUrl.endsWith('/')
79
- ? config.baseUrl.slice(0, -1)
80
- : config.baseUrl;
81
-
82
- return createClient<paths>({
83
- baseUrl: `${baseUrl}/etapi`,
84
- headers: {
85
- Authorization: config.apiKey,
86
- },
87
- });
88
- }
89
-
90
- // Default export for convenience
91
- export default createTriliumClient;
1
+ /**
2
+ * Trilium API Client using openapi-fetch
3
+ *
4
+ * This provides a type-safe client for the Trilium ETAPI.
5
+ * Types are auto-generated from the OpenAPI specification.
6
+ */
7
+
8
+ import createClient from 'openapi-fetch';
9
+ import type { paths, components } from './generated/trilium.js';
10
+
11
+ // Re-export common types for convenience
12
+ export type TriliumNote = components['schemas']['Note'];
13
+ export type TriliumBranch = components['schemas']['Branch'];
14
+ export type TriliumAttribute = components['schemas']['Attribute'];
15
+ export type TriliumAttachment = components['schemas']['Attachment'];
16
+ export type TriliumAppInfo = components['schemas']['AppInfo'];
17
+
18
+ // Export the paths type for advanced usage
19
+ export type { paths, components };
20
+
21
+ // Re-export mapper utilities
22
+ export {
23
+ TriliumMapper,
24
+ buildSearchQuery,
25
+ transforms,
26
+ type MappingConfig,
27
+ type FieldMapping,
28
+ type TransformFunction,
29
+ type ComputedFunction,
30
+ type TriliumSearchHelpers,
31
+ type TriliumSearchConditions,
32
+ type TriliumSearchLogical,
33
+ type ComparisonOperator,
34
+ type ConditionValue,
35
+ type SearchValue,
36
+ } from './mapper.js';
37
+
38
+ export interface TriliumClientConfig {
39
+ baseUrl: string;
40
+ apiKey: string;
41
+ }
42
+
43
+ /**
44
+ * Create a type-safe Trilium API client
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const client = createTriliumClient({
49
+ * baseUrl: 'http://localhost:37840',
50
+ * apiKey: 'your-etapi-token'
51
+ * });
52
+ *
53
+ * // Get app info
54
+ * const { data, error } = await client.GET('/app-info');
55
+ *
56
+ * // Get a note by ID
57
+ * const { data: note } = await client.GET('/notes/{noteId}', {
58
+ * params: { path: { noteId: 'root' } }
59
+ * });
60
+ *
61
+ * // Create a note
62
+ * const { data: newNote } = await client.POST('/notes', {
63
+ * body: {
64
+ * parentNoteId: 'root',
65
+ * title: 'My Note',
66
+ * type: 'text',
67
+ * content: '<p>Hello World</p>'
68
+ * }
69
+ * });
70
+ *
71
+ * // Search notes
72
+ * const { data: searchResults } = await client.GET('/notes', {
73
+ * params: { query: { search: '#blog' } }
74
+ * });
75
+ * ```
76
+ */
77
+ export function createTriliumClient(config: TriliumClientConfig) {
78
+ const baseUrl = config.baseUrl.endsWith('/')
79
+ ? config.baseUrl.slice(0, -1)
80
+ : config.baseUrl;
81
+
82
+ return createClient<paths>({
83
+ baseUrl: `${baseUrl}/etapi`,
84
+ headers: {
85
+ Authorization: config.apiKey,
86
+ },
87
+ });
88
+ }
89
+
90
+ // Default export for convenience
91
+ export default createTriliumClient;
@@ -1,166 +1,166 @@
1
- /**
2
- * Demo script for the Note Mapper
3
- *
4
- * This demonstrates how to use TriliumMapper to map Trilium notes
5
- * to strongly-typed objects.
6
- *
7
- * Usage:
8
- * pnpm tsx src/demo-mapper.ts
9
- *
10
- * With a real Trilium instance:
11
- * TRILIUM_API_KEY=your-token pnpm tsx src/demo-mapper.ts
12
- */
13
-
14
- import { TriliumMapper, transforms, type TriliumNote } from './client.js';
15
-
16
- console.log('Note Mapper Demo');
17
- console.log('='.repeat(50));
18
- console.log();
19
-
20
- // Define a sample blog post type
21
- interface BlogPost {
22
- id: string;
23
- title: string;
24
- slug: string;
25
- status: 'draft' | 'published' | 'archived';
26
- wordCount: number;
27
- tags: string[];
28
- publishedAt: Date | null;
29
- readTimeMinutes: number;
30
- }
31
-
32
- // Create a mapper configuration
33
- const blogMapper = new TriliumMapper<BlogPost>({
34
- // Simple property mapping
35
- id: 'note.noteId',
36
- title: 'note.title',
37
-
38
- // Required label
39
- slug: { from: '#slug', required: true },
40
-
41
- // Label with default value
42
- status: { from: '#status', default: 'draft' },
43
-
44
- // Label with transform
45
- wordCount: { from: '#wordCount', transform: transforms.number, default: 0 },
46
-
47
- // Label with array transform
48
- tags: { from: '#tags', transform: transforms.commaSeparated, default: [] },
49
-
50
- // Label with date transform
51
- publishedAt: { from: '#publishedAt', transform: transforms.date, default: null },
52
-
53
- // Computed value based on other fields
54
- readTimeMinutes: {
55
- computed: (partial) => Math.ceil((partial.wordCount || 0) / 200),
56
- },
57
- });
58
-
59
- // Create sample Trilium notes (simulating API response)
60
- const sampleNotes: TriliumNote[] = [
61
- {
62
- noteId: 'note1',
63
- title: 'Getting Started with TypeScript',
64
- type: 'text',
65
- mime: 'text/html',
66
- isProtected: false,
67
- blobId: 'blob1',
68
- dateCreated: '2024-01-15T10:00:00.000Z',
69
- dateModified: '2024-01-20T15:30:00.000Z',
70
- utcDateCreated: '2024-01-15T10:00:00.000Z',
71
- utcDateModified: '2024-01-20T15:30:00.000Z',
72
- attributes: [
73
- { attributeId: 'attr1', noteId: 'note1', type: 'label', name: 'slug', value: 'getting-started-typescript', isInheritable: false },
74
- { attributeId: 'attr2', noteId: 'note1', type: 'label', name: 'status', value: 'published', isInheritable: false },
75
- { attributeId: 'attr3', noteId: 'note1', type: 'label', name: 'wordCount', value: '1500', isInheritable: false },
76
- { attributeId: 'attr4', noteId: 'note1', type: 'label', name: 'tags', value: 'typescript,programming,tutorial', isInheritable: false },
77
- { attributeId: 'attr5', noteId: 'note1', type: 'label', name: 'publishedAt', value: '2024-01-20', isInheritable: false },
78
- ],
79
- },
80
- {
81
- noteId: 'note2',
82
- title: 'Advanced Patterns in Node.js',
83
- type: 'text',
84
- mime: 'text/html',
85
- isProtected: false,
86
- blobId: 'blob2',
87
- dateCreated: '2024-02-01T09:00:00.000Z',
88
- dateModified: '2024-02-05T14:00:00.000Z',
89
- utcDateCreated: '2024-02-01T09:00:00.000Z',
90
- utcDateModified: '2024-02-05T14:00:00.000Z',
91
- attributes: [
92
- { attributeId: 'attr6', noteId: 'note2', type: 'label', name: 'slug', value: 'advanced-nodejs-patterns', isInheritable: false },
93
- { attributeId: 'attr7', noteId: 'note2', type: 'label', name: 'status', value: 'draft', isInheritable: false },
94
- { attributeId: 'attr8', noteId: 'note2', type: 'label', name: 'wordCount', value: '2400', isInheritable: false },
95
- { attributeId: 'attr9', noteId: 'note2', type: 'label', name: 'tags', value: 'nodejs,javascript,backend', isInheritable: false },
96
- ],
97
- },
98
- {
99
- noteId: 'note3',
100
- title: 'Quick Tips for VS Code',
101
- type: 'text',
102
- mime: 'text/html',
103
- isProtected: false,
104
- blobId: 'blob3',
105
- dateCreated: '2024-03-01T11:00:00.000Z',
106
- dateModified: '2024-03-01T11:30:00.000Z',
107
- utcDateCreated: '2024-03-01T11:00:00.000Z',
108
- utcDateModified: '2024-03-01T11:30:00.000Z',
109
- attributes: [
110
- { attributeId: 'attr10', noteId: 'note3', type: 'label', name: 'slug', value: 'vscode-tips', isInheritable: false },
111
- // No status - will use default 'draft'
112
- // No wordCount - will use default 0
113
- // No tags - will use default []
114
- ],
115
- },
116
- ];
117
-
118
- console.log('Mapper Configuration:');
119
- console.log('-'.repeat(50));
120
- console.log(`
121
- const blogMapper = new TriliumMapper<BlogPost>({
122
- id: 'note.noteId',
123
- title: 'note.title',
124
- slug: { from: '#slug', required: true },
125
- status: { from: '#status', default: 'draft' },
126
- wordCount: { from: '#wordCount', transform: transforms.number, default: 0 },
127
- tags: { from: '#tags', transform: transforms.commaSeparated, default: [] },
128
- publishedAt: { from: '#publishedAt', transform: transforms.date, default: null },
129
- readTimeMinutes: {
130
- computed: (partial) => Math.ceil((partial.wordCount || 0) / 200),
131
- },
132
- });
133
- `);
134
-
135
- console.log('Mapping Results:');
136
- console.log('-'.repeat(50));
137
-
138
- // Map all notes
139
- const blogPosts = blogMapper.map(sampleNotes);
140
-
141
- for (const post of blogPosts) {
142
- console.log();
143
- console.log(`Title: ${post.title}`);
144
- console.log(` ID: ${post.id}`);
145
- console.log(` Slug: ${post.slug}`);
146
- console.log(` Status: ${post.status}`);
147
- console.log(` Word Count: ${post.wordCount}`);
148
- console.log(` Tags: [${post.tags.join(', ')}]`);
149
- console.log(` Published: ${post.publishedAt?.toISOString() || 'Not published'}`);
150
- console.log(` Read Time: ${post.readTimeMinutes} min`);
151
- }
152
-
153
- console.log();
154
- console.log('='.repeat(50));
155
- console.log();
156
-
157
- // Demonstrate single note mapping
158
- console.log('Single Note Mapping:');
159
- console.log('-'.repeat(50));
160
- console.log('const singlePost = blogMapper.map(notes[0]);');
161
- const singlePost = blogMapper.map(sampleNotes[0]!);
162
- console.log('Result:', JSON.stringify(singlePost, null, 2));
163
- console.log();
164
-
165
- console.log('='.repeat(50));
166
- console.log('Demo completed!');
1
+ /**
2
+ * Demo script for the Note Mapper
3
+ *
4
+ * This demonstrates how to use TriliumMapper to map Trilium notes
5
+ * to strongly-typed objects.
6
+ *
7
+ * Usage:
8
+ * pnpm tsx src/demo-mapper.ts
9
+ *
10
+ * With a real Trilium instance:
11
+ * TRILIUM_API_KEY=your-token pnpm tsx src/demo-mapper.ts
12
+ */
13
+
14
+ import { TriliumMapper, transforms, type TriliumNote } from './client.js';
15
+
16
+ console.log('Note Mapper Demo');
17
+ console.log('='.repeat(50));
18
+ console.log();
19
+
20
+ // Define a sample blog post type
21
+ interface BlogPost {
22
+ id: string;
23
+ title: string;
24
+ slug: string;
25
+ status: 'draft' | 'published' | 'archived';
26
+ wordCount: number;
27
+ tags: string[];
28
+ publishedAt: Date | null;
29
+ readTimeMinutes: number;
30
+ }
31
+
32
+ // Create a mapper configuration
33
+ const blogMapper = new TriliumMapper<BlogPost>({
34
+ // Simple property mapping
35
+ id: 'note.noteId',
36
+ title: 'note.title',
37
+
38
+ // Required label
39
+ slug: { from: '#slug', required: true },
40
+
41
+ // Label with default value
42
+ status: { from: '#status', default: 'draft' },
43
+
44
+ // Label with transform
45
+ wordCount: { from: '#wordCount', transform: transforms.number, default: 0 },
46
+
47
+ // Label with array transform
48
+ tags: { from: '#tags', transform: transforms.commaSeparated, default: [] },
49
+
50
+ // Label with date transform
51
+ publishedAt: { from: '#publishedAt', transform: transforms.date, default: null },
52
+
53
+ // Computed value based on other fields
54
+ readTimeMinutes: {
55
+ computed: (partial) => Math.ceil((partial.wordCount || 0) / 200),
56
+ },
57
+ });
58
+
59
+ // Create sample Trilium notes (simulating API response)
60
+ const sampleNotes: TriliumNote[] = [
61
+ {
62
+ noteId: 'note1',
63
+ title: 'Getting Started with TypeScript',
64
+ type: 'text',
65
+ mime: 'text/html',
66
+ isProtected: false,
67
+ blobId: 'blob1',
68
+ dateCreated: '2024-01-15T10:00:00.000Z',
69
+ dateModified: '2024-01-20T15:30:00.000Z',
70
+ utcDateCreated: '2024-01-15T10:00:00.000Z',
71
+ utcDateModified: '2024-01-20T15:30:00.000Z',
72
+ attributes: [
73
+ { attributeId: 'attr1', noteId: 'note1', type: 'label', name: 'slug', value: 'getting-started-typescript', isInheritable: false },
74
+ { attributeId: 'attr2', noteId: 'note1', type: 'label', name: 'status', value: 'published', isInheritable: false },
75
+ { attributeId: 'attr3', noteId: 'note1', type: 'label', name: 'wordCount', value: '1500', isInheritable: false },
76
+ { attributeId: 'attr4', noteId: 'note1', type: 'label', name: 'tags', value: 'typescript,programming,tutorial', isInheritable: false },
77
+ { attributeId: 'attr5', noteId: 'note1', type: 'label', name: 'publishedAt', value: '2024-01-20', isInheritable: false },
78
+ ],
79
+ },
80
+ {
81
+ noteId: 'note2',
82
+ title: 'Advanced Patterns in Node.js',
83
+ type: 'text',
84
+ mime: 'text/html',
85
+ isProtected: false,
86
+ blobId: 'blob2',
87
+ dateCreated: '2024-02-01T09:00:00.000Z',
88
+ dateModified: '2024-02-05T14:00:00.000Z',
89
+ utcDateCreated: '2024-02-01T09:00:00.000Z',
90
+ utcDateModified: '2024-02-05T14:00:00.000Z',
91
+ attributes: [
92
+ { attributeId: 'attr6', noteId: 'note2', type: 'label', name: 'slug', value: 'advanced-nodejs-patterns', isInheritable: false },
93
+ { attributeId: 'attr7', noteId: 'note2', type: 'label', name: 'status', value: 'draft', isInheritable: false },
94
+ { attributeId: 'attr8', noteId: 'note2', type: 'label', name: 'wordCount', value: '2400', isInheritable: false },
95
+ { attributeId: 'attr9', noteId: 'note2', type: 'label', name: 'tags', value: 'nodejs,javascript,backend', isInheritable: false },
96
+ ],
97
+ },
98
+ {
99
+ noteId: 'note3',
100
+ title: 'Quick Tips for VS Code',
101
+ type: 'text',
102
+ mime: 'text/html',
103
+ isProtected: false,
104
+ blobId: 'blob3',
105
+ dateCreated: '2024-03-01T11:00:00.000Z',
106
+ dateModified: '2024-03-01T11:30:00.000Z',
107
+ utcDateCreated: '2024-03-01T11:00:00.000Z',
108
+ utcDateModified: '2024-03-01T11:30:00.000Z',
109
+ attributes: [
110
+ { attributeId: 'attr10', noteId: 'note3', type: 'label', name: 'slug', value: 'vscode-tips', isInheritable: false },
111
+ // No status - will use default 'draft'
112
+ // No wordCount - will use default 0
113
+ // No tags - will use default []
114
+ ],
115
+ },
116
+ ];
117
+
118
+ console.log('Mapper Configuration:');
119
+ console.log('-'.repeat(50));
120
+ console.log(`
121
+ const blogMapper = new TriliumMapper<BlogPost>({
122
+ id: 'note.noteId',
123
+ title: 'note.title',
124
+ slug: { from: '#slug', required: true },
125
+ status: { from: '#status', default: 'draft' },
126
+ wordCount: { from: '#wordCount', transform: transforms.number, default: 0 },
127
+ tags: { from: '#tags', transform: transforms.commaSeparated, default: [] },
128
+ publishedAt: { from: '#publishedAt', transform: transforms.date, default: null },
129
+ readTimeMinutes: {
130
+ computed: (partial) => Math.ceil((partial.wordCount || 0) / 200),
131
+ },
132
+ });
133
+ `);
134
+
135
+ console.log('Mapping Results:');
136
+ console.log('-'.repeat(50));
137
+
138
+ // Map all notes
139
+ const blogPosts = blogMapper.map(sampleNotes);
140
+
141
+ for (const post of blogPosts) {
142
+ console.log();
143
+ console.log(`Title: ${post.title}`);
144
+ console.log(` ID: ${post.id}`);
145
+ console.log(` Slug: ${post.slug}`);
146
+ console.log(` Status: ${post.status}`);
147
+ console.log(` Word Count: ${post.wordCount}`);
148
+ console.log(` Tags: [${post.tags.join(', ')}]`);
149
+ console.log(` Published: ${post.publishedAt?.toISOString() || 'Not published'}`);
150
+ console.log(` Read Time: ${post.readTimeMinutes} min`);
151
+ }
152
+
153
+ console.log();
154
+ console.log('='.repeat(50));
155
+ console.log();
156
+
157
+ // Demonstrate single note mapping
158
+ console.log('Single Note Mapping:');
159
+ console.log('-'.repeat(50));
160
+ console.log('const singlePost = blogMapper.map(notes[0]);');
161
+ const singlePost = blogMapper.map(sampleNotes[0]!);
162
+ console.log('Result:', JSON.stringify(singlePost, null, 2));
163
+ console.log();
164
+
165
+ console.log('='.repeat(50));
166
+ console.log('Demo completed!');