trilium-api 1.0.2 → 1.0.4
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 +173 -59
- package/dist/index.cjs +80 -1
- package/dist/index.d.cts +168 -13
- package/dist/index.d.ts +168 -13
- package/dist/index.js +79 -1
- package/package.json +17 -3
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ A type-safe TypeScript client for the [Trilium Notes](https://github.com/Trilium
|
|
|
10
10
|
- [API Reference](#api-reference)
|
|
11
11
|
- [Search Query Builder](#search-query-builder)
|
|
12
12
|
- [Note Mapper](#note-mapper)
|
|
13
|
+
- [Search and Map](#search-and-map)
|
|
13
14
|
- [Types](#types)
|
|
14
15
|
- [Error Handling](#error-handling)
|
|
15
16
|
- [Demo](#demo)
|
|
@@ -23,6 +24,7 @@ A type-safe TypeScript client for the [Trilium Notes](https://github.com/Trilium
|
|
|
23
24
|
- **Lightweight** - Built on [openapi-fetch](https://openapi-ts.dev/openapi-fetch/) (~6kb)
|
|
24
25
|
- **Query Builder** - Type-safe search query construction
|
|
25
26
|
- **Mapper** - Declarative note-to-object mapping with transforms
|
|
27
|
+
- **StandardNote** - Consistent base fields (id, title, dates) on all mapped types
|
|
26
28
|
|
|
27
29
|
## Installation
|
|
28
30
|
|
|
@@ -38,7 +40,7 @@ pnpm add trilium-api
|
|
|
38
40
|
import { createTriliumClient } from 'trilium-api';
|
|
39
41
|
|
|
40
42
|
const client = createTriliumClient({
|
|
41
|
-
baseUrl: 'http://localhost:
|
|
43
|
+
baseUrl: 'http://localhost:8080',
|
|
42
44
|
apiKey: 'your-etapi-token',
|
|
43
45
|
});
|
|
44
46
|
|
|
@@ -65,7 +67,7 @@ const { data: results } = await client.GET('/notes', {
|
|
|
65
67
|
import { createTriliumClient } from 'trilium-api';
|
|
66
68
|
|
|
67
69
|
const client = createTriliumClient({
|
|
68
|
-
baseUrl: 'http://localhost:
|
|
70
|
+
baseUrl: 'http://localhost:8080', // Your Trilium server URL
|
|
69
71
|
apiKey: 'your-etapi-token', // ETAPI token from Trilium settings
|
|
70
72
|
});
|
|
71
73
|
```
|
|
@@ -261,54 +263,61 @@ const { data } = await client.GET('/notes', {
|
|
|
261
263
|
|
|
262
264
|
## Note Mapper
|
|
263
265
|
|
|
264
|
-
Map Trilium notes to strongly-typed objects using declarative field mappings
|
|
266
|
+
Map Trilium notes to strongly-typed objects using declarative field mappings.
|
|
267
|
+
|
|
268
|
+
### StandardNote Base Type
|
|
269
|
+
|
|
270
|
+
All mapped types should extend `StandardNote`, which provides consistent base fields:
|
|
265
271
|
|
|
266
272
|
```typescript
|
|
267
|
-
import {
|
|
273
|
+
import type { StandardNote } from 'trilium-api';
|
|
274
|
+
|
|
275
|
+
// StandardNote includes:
|
|
276
|
+
// - id: string (note ID)
|
|
277
|
+
// - title: string (note title)
|
|
278
|
+
// - dateCreatedUtc: Date
|
|
279
|
+
// - dateLastModifiedUtc: Date
|
|
268
280
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
281
|
+
interface BlogPost extends StandardNote {
|
|
282
|
+
slug: string;
|
|
283
|
+
tags: string[];
|
|
284
|
+
isPublished: boolean;
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Using TriliumMapper Directly
|
|
289
|
+
|
|
290
|
+
For standalone mapping (outside of `searchAndMap`), use `TriliumMapper`:
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
import { TriliumMapper, StandardNoteMapping, transforms, type StandardNote } from 'trilium-api';
|
|
294
|
+
|
|
295
|
+
interface BlogPost extends StandardNote {
|
|
273
296
|
slug: string;
|
|
274
|
-
publishDate: Date;
|
|
275
297
|
wordCount: number;
|
|
276
298
|
readTimeMinutes: number;
|
|
277
299
|
tags: string[];
|
|
278
300
|
isPublished: boolean;
|
|
279
301
|
}
|
|
280
302
|
|
|
281
|
-
//
|
|
282
|
-
const blogMapper = new TriliumMapper<BlogPost>(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
// Computed field based on other mapped values
|
|
297
|
-
readTimeMinutes: {
|
|
298
|
-
computed: (partial) => Math.ceil((partial.wordCount || 0) / 200),
|
|
299
|
-
},
|
|
300
|
-
|
|
301
|
-
// Transform comma-separated string to array
|
|
302
|
-
tags: { from: '#tags', transform: transforms.commaSeparated, default: [] },
|
|
303
|
-
|
|
304
|
-
// Transform to boolean
|
|
305
|
-
isPublished: { from: '#published', transform: transforms.boolean, default: false },
|
|
306
|
-
});
|
|
303
|
+
// Merge StandardNoteMapping with your custom fields
|
|
304
|
+
const blogMapper = new TriliumMapper<BlogPost>(
|
|
305
|
+
TriliumMapper.merge(
|
|
306
|
+
StandardNoteMapping,
|
|
307
|
+
{
|
|
308
|
+
slug: { from: '#slug', required: true },
|
|
309
|
+
wordCount: { from: '#wordCount', transform: transforms.number, default: 0 },
|
|
310
|
+
readTimeMinutes: {
|
|
311
|
+
computed: (partial) => Math.ceil((partial.wordCount || 0) / 200),
|
|
312
|
+
},
|
|
313
|
+
tags: { from: '#tags', transform: transforms.commaSeparated, default: [] },
|
|
314
|
+
isPublished: { from: '#published', transform: transforms.boolean, default: false },
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
);
|
|
307
318
|
|
|
308
|
-
// Map
|
|
319
|
+
// Map notes
|
|
309
320
|
const post = blogMapper.map(note);
|
|
310
|
-
|
|
311
|
-
// Map an array of notes
|
|
312
321
|
const posts = blogMapper.map(notes);
|
|
313
322
|
```
|
|
314
323
|
|
|
@@ -369,44 +378,149 @@ const posts = blogMapper.map(notes);
|
|
|
369
378
|
| `transforms.date` | Parse date string | `"2024-01-15"` → `Date` |
|
|
370
379
|
| `transforms.trim` | Trim whitespace | `" hello "` → `"hello"` |
|
|
371
380
|
|
|
372
|
-
|
|
381
|
+
## Search and Map
|
|
373
382
|
|
|
374
|
-
|
|
383
|
+
The `searchAndMap` method combines searching and mapping in a single call. It **automatically includes `StandardNoteMapping`**, so you only need to define your custom fields!
|
|
375
384
|
|
|
376
385
|
```typescript
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
};
|
|
386
|
+
import { createTriliumClient, transforms, type StandardNote, type CustomMapping } from 'trilium-api';
|
|
387
|
+
|
|
388
|
+
const client = createTriliumClient({
|
|
389
|
+
baseUrl: 'http://localhost:8080',
|
|
390
|
+
apiKey: 'your-etapi-token',
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Extend StandardNote with your custom fields
|
|
394
|
+
interface BlogPost extends StandardNote {
|
|
395
|
+
slug: string;
|
|
396
|
+
published: boolean;
|
|
397
|
+
}
|
|
383
398
|
|
|
384
|
-
//
|
|
385
|
-
const blogMapping = {
|
|
399
|
+
// Use CustomMapping<T> for clean typing - excludes StandardNote fields automatically
|
|
400
|
+
const blogMapping: CustomMapping<BlogPost> = {
|
|
386
401
|
slug: '#slug',
|
|
387
|
-
|
|
402
|
+
published: { from: '#published', transform: transforms.boolean, default: false },
|
|
388
403
|
};
|
|
389
404
|
|
|
390
|
-
//
|
|
391
|
-
const
|
|
392
|
-
|
|
405
|
+
// Just pass your custom mapping - StandardNoteMapping is auto-merged!
|
|
406
|
+
const { data, failures } = await client.searchAndMap<BlogPost>({
|
|
407
|
+
query: { '#blog': true, '#published': true },
|
|
408
|
+
mapping: blogMapping,
|
|
409
|
+
limit: 10,
|
|
410
|
+
orderBy: 'dateModified',
|
|
411
|
+
orderDirection: 'desc',
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Each post has: id, title, dateCreatedUtc, dateLastModifiedUtc, slug, published
|
|
415
|
+
data.forEach(post => {
|
|
416
|
+
console.log(`${post.title} (${post.id}) - ${post.slug}`);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Check for mapping failures
|
|
420
|
+
if (failures.length > 0) {
|
|
421
|
+
console.warn(`${failures.length} notes failed to map:`);
|
|
422
|
+
failures.forEach(f => console.warn(` - ${f.noteTitle}: ${f.reason}`));
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Options
|
|
427
|
+
|
|
428
|
+
| Option | Type | Description |
|
|
429
|
+
|--------|------|-------------|
|
|
430
|
+
| `query` | `string \| object` | Search query string or structured query object |
|
|
431
|
+
| `mapping` | `CustomMapping<T>` | Field mapping for your custom fields (StandardNote fields auto-merged) |
|
|
432
|
+
| `limit` | `number` | Maximum number of results |
|
|
433
|
+
| `orderBy` | `string` | Field to order by (e.g., `'dateModified'`, `'title'`) |
|
|
434
|
+
| `orderDirection` | `'asc' \| 'desc'` | Sort direction |
|
|
435
|
+
| `fastSearch` | `boolean` | Enable fast search mode (less accurate but faster) |
|
|
436
|
+
|
|
437
|
+
### Return Value
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
{
|
|
441
|
+
data: T[], // Successfully mapped objects
|
|
442
|
+
failures: MappingFailure[] // Notes that failed to map
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Handling Failures
|
|
447
|
+
|
|
448
|
+
When a note fails to map (e.g., missing required field, transform error), it's added to the `failures` array instead of throwing:
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
interface MappingFailure {
|
|
452
|
+
noteId: string; // The note ID that failed
|
|
453
|
+
noteTitle: string; // The note title for identification
|
|
454
|
+
reason: string; // Error message explaining the failure
|
|
455
|
+
note: TriliumNote; // The original note object for debugging
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
This allows you to process partial results while still knowing which notes had issues:
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
interface BlogPost extends StandardNote {
|
|
463
|
+
slug: string;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const { data, failures } = await client.searchAndMap<BlogPost>({
|
|
467
|
+
query: '#blog',
|
|
468
|
+
mapping: {
|
|
469
|
+
slug: { from: '#slug', required: true }, // Will fail if missing
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// data contains all successfully mapped posts
|
|
474
|
+
// failures contains notes missing the required #slug label
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Error Handling
|
|
478
|
+
|
|
479
|
+
API or network errors throw an exception:
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
try {
|
|
483
|
+
const { data, failures } = await client.searchAndMap<BlogPost>({
|
|
484
|
+
query: '#blog',
|
|
485
|
+
mapping: blogMapping,
|
|
486
|
+
});
|
|
487
|
+
} catch (err) {
|
|
488
|
+
console.error('Search failed:', err);
|
|
489
|
+
}
|
|
393
490
|
```
|
|
394
491
|
|
|
395
492
|
## Types
|
|
396
493
|
|
|
397
|
-
The package exports
|
|
494
|
+
The package exports a focused set of types for common use cases:
|
|
398
495
|
|
|
399
496
|
```typescript
|
|
400
|
-
|
|
497
|
+
// Main imports for typical usage
|
|
498
|
+
import {
|
|
499
|
+
createTriliumClient,
|
|
500
|
+
transforms,
|
|
501
|
+
buildSearchQuery,
|
|
502
|
+
} from 'trilium-api';
|
|
503
|
+
|
|
504
|
+
import type {
|
|
505
|
+
// Your mapped types should extend this
|
|
506
|
+
StandardNote,
|
|
507
|
+
// For typing your custom field mappings
|
|
508
|
+
CustomMapping,
|
|
509
|
+
// For typing query objects
|
|
510
|
+
TriliumSearchHelpers,
|
|
511
|
+
// For error handling
|
|
512
|
+
MappingFailure,
|
|
513
|
+
// Trilium entity types (for API responses)
|
|
401
514
|
TriliumNote,
|
|
402
515
|
TriliumBranch,
|
|
403
516
|
TriliumAttribute,
|
|
404
517
|
TriliumAttachment,
|
|
405
518
|
TriliumAppInfo,
|
|
406
|
-
paths,
|
|
407
|
-
components,
|
|
408
|
-
operations,
|
|
409
519
|
} from 'trilium-api';
|
|
520
|
+
|
|
521
|
+
// Advanced: for standalone TriliumMapper usage (outside searchAndMap)
|
|
522
|
+
import { TriliumMapper, StandardNoteMapping } from 'trilium-api';
|
|
523
|
+
import type { MappingConfig } from 'trilium-api';
|
|
410
524
|
```
|
|
411
525
|
|
|
412
526
|
## Error Handling
|
|
@@ -620,7 +734,7 @@ function createMockResponse(body: any, status = 200, contentType = 'application/
|
|
|
620
734
|
|
|
621
735
|
describe('my new feature', () => {
|
|
622
736
|
const config = {
|
|
623
|
-
baseUrl: 'http://localhost:
|
|
737
|
+
baseUrl: 'http://localhost:8080',
|
|
624
738
|
apiKey: 'test-api-key',
|
|
625
739
|
};
|
|
626
740
|
|
|
@@ -647,7 +761,7 @@ describe('my new feature', () => {
|
|
|
647
761
|
|
|
648
762
|
// 4. Verify the request (openapi-fetch uses Request objects)
|
|
649
763
|
const request = mockFetch.mock.calls[0]![0] as Request;
|
|
650
|
-
expect(request.url).toBe('http://localhost:
|
|
764
|
+
expect(request.url).toBe('http://localhost:8080/etapi/notes/test123');
|
|
651
765
|
expect(request.method).toBe('GET');
|
|
652
766
|
expect(request.headers.get('Authorization')).toBe('test-api-key');
|
|
653
767
|
});
|
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
StandardNoteMapping: () => StandardNoteMapping,
|
|
33
34
|
TriliumMapper: () => TriliumMapper,
|
|
34
35
|
buildSearchQuery: () => buildSearchQuery,
|
|
35
36
|
createClient: () => client_default,
|
|
@@ -285,20 +286,98 @@ var transforms = {
|
|
|
285
286
|
return String(value).trim() || void 0;
|
|
286
287
|
}
|
|
287
288
|
};
|
|
289
|
+
var StandardNoteMapping = {
|
|
290
|
+
id: {
|
|
291
|
+
from: "note.noteId",
|
|
292
|
+
required: true
|
|
293
|
+
},
|
|
294
|
+
title: {
|
|
295
|
+
from: "note.title",
|
|
296
|
+
required: true
|
|
297
|
+
},
|
|
298
|
+
dateCreatedUtc: {
|
|
299
|
+
from: "note.utcDateCreated",
|
|
300
|
+
transform: transforms.date,
|
|
301
|
+
required: true
|
|
302
|
+
},
|
|
303
|
+
dateLastModifiedUtc: {
|
|
304
|
+
from: "note.utcDateModified",
|
|
305
|
+
transform: transforms.date,
|
|
306
|
+
required: true
|
|
307
|
+
}
|
|
308
|
+
};
|
|
288
309
|
|
|
289
310
|
// src/client.ts
|
|
290
311
|
function createTriliumClient(config) {
|
|
291
312
|
const baseUrl = config.baseUrl.endsWith("/") ? config.baseUrl.slice(0, -1) : config.baseUrl;
|
|
292
|
-
|
|
313
|
+
const client = (0, import_openapi_fetch.default)({
|
|
293
314
|
baseUrl: `${baseUrl}/etapi`,
|
|
294
315
|
headers: {
|
|
295
316
|
Authorization: config.apiKey
|
|
296
317
|
}
|
|
297
318
|
});
|
|
319
|
+
const searchAndMap = async (options) => {
|
|
320
|
+
const searchQuery = typeof options.query === "string" ? options.query : buildSearchQuery(options.query);
|
|
321
|
+
const params = [];
|
|
322
|
+
if (options.orderBy) {
|
|
323
|
+
params.push(`orderBy:${options.orderBy}`);
|
|
324
|
+
if (options.orderDirection) {
|
|
325
|
+
params.push(options.orderDirection);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (options.limit) {
|
|
329
|
+
params.push(`limit:${options.limit}`);
|
|
330
|
+
}
|
|
331
|
+
if (options.fastSearch) {
|
|
332
|
+
params.push("fastSearch");
|
|
333
|
+
}
|
|
334
|
+
const fullQuery = params.length > 0 ? `${searchQuery} ${params.join(" ")}` : searchQuery;
|
|
335
|
+
const { data, error } = await client.GET("/notes", {
|
|
336
|
+
params: { query: { search: fullQuery } }
|
|
337
|
+
});
|
|
338
|
+
if (error) {
|
|
339
|
+
throw error;
|
|
340
|
+
}
|
|
341
|
+
if (!data?.results) {
|
|
342
|
+
throw new Error("No results returned from search");
|
|
343
|
+
}
|
|
344
|
+
const fullMapping = TriliumMapper.merge(
|
|
345
|
+
StandardNoteMapping,
|
|
346
|
+
options.mapping
|
|
347
|
+
);
|
|
348
|
+
const mapper = new TriliumMapper(fullMapping);
|
|
349
|
+
const mappedData = [];
|
|
350
|
+
const failures = [];
|
|
351
|
+
for (const note of data.results) {
|
|
352
|
+
try {
|
|
353
|
+
const [mapped] = mapper.map([note]);
|
|
354
|
+
if (mapped !== void 0) {
|
|
355
|
+
mappedData.push(mapped);
|
|
356
|
+
} else {
|
|
357
|
+
failures.push({
|
|
358
|
+
noteId: note.noteId ?? "unknown",
|
|
359
|
+
noteTitle: note.title ?? "Untitled",
|
|
360
|
+
reason: "Mapping returned undefined",
|
|
361
|
+
note
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
} catch (err) {
|
|
365
|
+
failures.push({
|
|
366
|
+
noteId: note.noteId ?? "unknown",
|
|
367
|
+
noteTitle: note.title ?? "Untitled",
|
|
368
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
369
|
+
note
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return { data: mappedData, failures };
|
|
374
|
+
};
|
|
375
|
+
return Object.assign(client, { searchAndMap });
|
|
298
376
|
}
|
|
299
377
|
var client_default = createTriliumClient;
|
|
300
378
|
// Annotate the CommonJS export names for ESM import in node:
|
|
301
379
|
0 && (module.exports = {
|
|
380
|
+
StandardNoteMapping,
|
|
302
381
|
TriliumMapper,
|
|
303
382
|
buildSearchQuery,
|
|
304
383
|
createClient,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Client } from 'openapi-fetch';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* This file was auto-generated by openapi-typescript.
|
|
@@ -1848,12 +1848,6 @@ type TriliumSearchHelpers = TriliumSearchLogical | (TriliumSearchConditions & Pa
|
|
|
1848
1848
|
* // => "note.type = 'text' AND #wordCount >= 1000"
|
|
1849
1849
|
*/
|
|
1850
1850
|
declare function buildSearchQuery(helpers: TriliumSearchHelpers): string;
|
|
1851
|
-
/**
|
|
1852
|
-
* Transform function that converts a raw value into the target type
|
|
1853
|
-
* @template T - The target object type
|
|
1854
|
-
* @template K - The specific key in the target type
|
|
1855
|
-
*/
|
|
1856
|
-
type TransformFunction<T, K extends keyof T> = (value: unknown, note: TriliumNote) => T[K] | undefined;
|
|
1857
1851
|
/**
|
|
1858
1852
|
* Computed function that calculates a value from the partially mapped object
|
|
1859
1853
|
* @template T - The target object type
|
|
@@ -1889,8 +1883,8 @@ type ComputedFunction<T, K extends keyof T> = (partial: Partial<T>, note: Triliu
|
|
|
1889
1883
|
type FieldMapping<T, K extends keyof T = keyof T> = string | {
|
|
1890
1884
|
/** Source path (string) or extractor function */
|
|
1891
1885
|
from: string | ((note: TriliumNote) => unknown);
|
|
1892
|
-
/** Optional transform function to convert the raw value */
|
|
1893
|
-
transform?:
|
|
1886
|
+
/** Optional transform function to convert the raw value - accepts any input type */
|
|
1887
|
+
transform?: (value: any, note: TriliumNote) => T[K] | undefined;
|
|
1894
1888
|
/** Default value if extraction returns undefined */
|
|
1895
1889
|
default?: T[K];
|
|
1896
1890
|
/** Whether this field is required (throws if missing) */
|
|
@@ -1939,7 +1933,7 @@ type MappingConfig<T> = {
|
|
|
1939
1933
|
*/
|
|
1940
1934
|
declare class TriliumMapper<T> {
|
|
1941
1935
|
/** The mapping configuration for this mapper */
|
|
1942
|
-
|
|
1936
|
+
readonly config: MappingConfig<T>;
|
|
1943
1937
|
/**
|
|
1944
1938
|
* Creates a new TriliumMapper instance
|
|
1945
1939
|
* @param config - The mapping configuration defining how to map note fields to the target type
|
|
@@ -2020,6 +2014,83 @@ declare const transforms: {
|
|
|
2020
2014
|
/** Trim whitespace from string */
|
|
2021
2015
|
trim: (value: unknown) => string | undefined;
|
|
2022
2016
|
};
|
|
2017
|
+
/**
|
|
2018
|
+
* Standard note fields that all mapped types must include.
|
|
2019
|
+
* Extend this interface when creating your own mapped types.
|
|
2020
|
+
*
|
|
2021
|
+
* @example
|
|
2022
|
+
* ```ts
|
|
2023
|
+
* interface BlogPost extends StandardNote {
|
|
2024
|
+
* slug: string;
|
|
2025
|
+
* published: boolean;
|
|
2026
|
+
* }
|
|
2027
|
+
* ```
|
|
2028
|
+
*/
|
|
2029
|
+
interface StandardNote {
|
|
2030
|
+
/** The unique note ID */
|
|
2031
|
+
id: string;
|
|
2032
|
+
/** The note title */
|
|
2033
|
+
title: string;
|
|
2034
|
+
/** UTC date when the note was created */
|
|
2035
|
+
dateCreatedUtc: Date;
|
|
2036
|
+
/** UTC date when the note was last modified */
|
|
2037
|
+
dateLastModifiedUtc: Date;
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* Standard mapping configuration for StandardNote fields.
|
|
2041
|
+
* Use with TriliumMapper.merge() to create mappings for types extending StandardNote.
|
|
2042
|
+
*
|
|
2043
|
+
* @example
|
|
2044
|
+
* ```ts
|
|
2045
|
+
* interface BlogPost extends StandardNote {
|
|
2046
|
+
* slug: string;
|
|
2047
|
+
* published: boolean;
|
|
2048
|
+
* }
|
|
2049
|
+
*
|
|
2050
|
+
* const blogMapping = TriliumMapper.merge<BlogPost>(
|
|
2051
|
+
* StandardNoteMapping,
|
|
2052
|
+
* {
|
|
2053
|
+
* slug: '#slug',
|
|
2054
|
+
* published: { from: '#published', transform: transforms.boolean, default: false },
|
|
2055
|
+
* }
|
|
2056
|
+
* );
|
|
2057
|
+
* ```
|
|
2058
|
+
*/
|
|
2059
|
+
declare const StandardNoteMapping: MappingConfig<StandardNote>;
|
|
2060
|
+
/**
|
|
2061
|
+
* Helper type for defining custom field mappings.
|
|
2062
|
+
* Use this when defining mappings for types that extend StandardNote.
|
|
2063
|
+
* It automatically excludes StandardNote fields since they're auto-merged.
|
|
2064
|
+
*
|
|
2065
|
+
* @template T - Your custom type that extends StandardNote
|
|
2066
|
+
*
|
|
2067
|
+
* @example
|
|
2068
|
+
* ```ts
|
|
2069
|
+
* interface BlogPost extends StandardNote {
|
|
2070
|
+
* slug: string;
|
|
2071
|
+
* published: boolean;
|
|
2072
|
+
* }
|
|
2073
|
+
*
|
|
2074
|
+
* // Clean type - no need for verbose Omit<>
|
|
2075
|
+
* const blogMapping: CustomMapping<BlogPost> = {
|
|
2076
|
+
* slug: '#slug',
|
|
2077
|
+
* published: { from: '#published', transform: transforms.boolean, default: false },
|
|
2078
|
+
* };
|
|
2079
|
+
*
|
|
2080
|
+
* const { data } = await client.searchAndMap<BlogPost>({
|
|
2081
|
+
* query: '#blog',
|
|
2082
|
+
* mapping: blogMapping,
|
|
2083
|
+
* });
|
|
2084
|
+
* ```
|
|
2085
|
+
*/
|
|
2086
|
+
type CustomMapping<T extends StandardNote> = MappingConfig<Omit<T, keyof StandardNote>>;
|
|
2087
|
+
|
|
2088
|
+
/**
|
|
2089
|
+
* Trilium API Client using openapi-fetch
|
|
2090
|
+
*
|
|
2091
|
+
* This provides a type-safe client for the Trilium ETAPI.
|
|
2092
|
+
* Types are auto-generated from the OpenAPI specification.
|
|
2093
|
+
*/
|
|
2023
2094
|
|
|
2024
2095
|
type TriliumNote = components['schemas']['Note'];
|
|
2025
2096
|
type TriliumBranch = components['schemas']['Branch'];
|
|
@@ -2031,13 +2102,88 @@ interface TriliumClientConfig {
|
|
|
2031
2102
|
baseUrl: string;
|
|
2032
2103
|
apiKey: string;
|
|
2033
2104
|
}
|
|
2105
|
+
interface SearchAndMapOptions<T extends StandardNote> {
|
|
2106
|
+
/** Search query - either a string or structured search helpers */
|
|
2107
|
+
query: string | TriliumSearchHelpers;
|
|
2108
|
+
/**
|
|
2109
|
+
* Mapping configuration for your custom fields only.
|
|
2110
|
+
* StandardNoteMapping (id, title, dates) is automatically merged.
|
|
2111
|
+
*/
|
|
2112
|
+
mapping: CustomMapping<T>;
|
|
2113
|
+
/** Optional: limit number of results */
|
|
2114
|
+
limit?: number;
|
|
2115
|
+
/** Optional: order by field (e.g., 'dateModified', 'title') */
|
|
2116
|
+
orderBy?: string;
|
|
2117
|
+
/** Optional: order direction */
|
|
2118
|
+
orderDirection?: 'asc' | 'desc';
|
|
2119
|
+
/** Optional: fast search mode (less accurate but faster) */
|
|
2120
|
+
fastSearch?: boolean;
|
|
2121
|
+
}
|
|
2122
|
+
/** Details about a note that failed to map */
|
|
2123
|
+
interface MappingFailure {
|
|
2124
|
+
/** The note ID that failed to map */
|
|
2125
|
+
noteId: string;
|
|
2126
|
+
/** The note title for easier identification */
|
|
2127
|
+
noteTitle: string;
|
|
2128
|
+
/** The error message explaining why mapping failed */
|
|
2129
|
+
reason: string;
|
|
2130
|
+
/** The original note object */
|
|
2131
|
+
note: TriliumNote;
|
|
2132
|
+
}
|
|
2133
|
+
interface SearchAndMapResult<T extends StandardNote> {
|
|
2134
|
+
/** Mapped results as typed objects */
|
|
2135
|
+
data: T[];
|
|
2136
|
+
/** Notes that failed to map (e.g., missing required fields) */
|
|
2137
|
+
failures: MappingFailure[];
|
|
2138
|
+
}
|
|
2139
|
+
/** Extended Trilium client with search and map helper */
|
|
2140
|
+
interface TriliumClient extends Client<paths> {
|
|
2141
|
+
/**
|
|
2142
|
+
* Search notes and automatically map results to typed objects.
|
|
2143
|
+
* Type T must extend StandardNote to ensure consistent base fields.
|
|
2144
|
+
* StandardNoteMapping is automatically included - just define your custom fields!
|
|
2145
|
+
* Throws on API/network errors.
|
|
2146
|
+
*
|
|
2147
|
+
* @see {@link https://triliumnext.github.io/Docs/Wiki/search.html} for Trilium search syntax
|
|
2148
|
+
*
|
|
2149
|
+
* @example
|
|
2150
|
+
* ```ts
|
|
2151
|
+
* interface BlogPost extends StandardNote {
|
|
2152
|
+
* slug: string;
|
|
2153
|
+
* published: boolean;
|
|
2154
|
+
* }
|
|
2155
|
+
*
|
|
2156
|
+
* // Just define your custom fields - StandardNoteMapping is auto-merged!
|
|
2157
|
+
* const { data: posts, failures } = await client.searchAndMap<BlogPost>({
|
|
2158
|
+
* query: { '#blog': true, '#published': true },
|
|
2159
|
+
* mapping: {
|
|
2160
|
+
* slug: '#slug',
|
|
2161
|
+
* published: { from: '#published', transform: transforms.boolean, default: false },
|
|
2162
|
+
* },
|
|
2163
|
+
* limit: 10,
|
|
2164
|
+
* orderBy: 'dateModified',
|
|
2165
|
+
* orderDirection: 'desc',
|
|
2166
|
+
* });
|
|
2167
|
+
*
|
|
2168
|
+
* // Each post has id, title, dateCreatedUtc, dateLastModifiedUtc + your custom fields
|
|
2169
|
+
* posts.forEach(post => {
|
|
2170
|
+
* console.log(`${post.title} (${post.slug}) - ${post.id}`);
|
|
2171
|
+
* });
|
|
2172
|
+
*
|
|
2173
|
+
* if (failures.length > 0) {
|
|
2174
|
+
* console.warn(`${failures.length} notes failed to map`);
|
|
2175
|
+
* }
|
|
2176
|
+
* ```
|
|
2177
|
+
*/
|
|
2178
|
+
searchAndMap<T extends StandardNote>(options: SearchAndMapOptions<T>): Promise<SearchAndMapResult<T>>;
|
|
2179
|
+
}
|
|
2034
2180
|
/**
|
|
2035
2181
|
* Create a type-safe Trilium API client
|
|
2036
2182
|
*
|
|
2037
2183
|
* @example
|
|
2038
2184
|
* ```ts
|
|
2039
2185
|
* const client = createTriliumClient({
|
|
2040
|
-
* baseUrl: 'http://localhost:
|
|
2186
|
+
* baseUrl: 'http://localhost:8080',
|
|
2041
2187
|
* apiKey: 'your-etapi-token'
|
|
2042
2188
|
* });
|
|
2043
2189
|
*
|
|
@@ -2063,8 +2209,17 @@ interface TriliumClientConfig {
|
|
|
2063
2209
|
* const { data: searchResults } = await client.GET('/notes', {
|
|
2064
2210
|
* params: { query: { search: '#blog' } }
|
|
2065
2211
|
* });
|
|
2212
|
+
*
|
|
2213
|
+
* // Search and map to typed objects
|
|
2214
|
+
* const { data: posts } = await client.searchAndMap<BlogPost>({
|
|
2215
|
+
* query: { '#blog': true },
|
|
2216
|
+
* mapping: {
|
|
2217
|
+
* title: 'note.title',
|
|
2218
|
+
* slug: '#slug',
|
|
2219
|
+
* },
|
|
2220
|
+
* });
|
|
2066
2221
|
* ```
|
|
2067
2222
|
*/
|
|
2068
|
-
declare function createTriliumClient(config: TriliumClientConfig):
|
|
2223
|
+
declare function createTriliumClient(config: TriliumClientConfig): TriliumClient;
|
|
2069
2224
|
|
|
2070
|
-
export { type
|
|
2225
|
+
export { type CustomMapping, type MappingConfig, type MappingFailure, type StandardNote, StandardNoteMapping, type TriliumAppInfo, type TriliumAttachment, type TriliumAttribute, type TriliumBranch, type TriliumClientConfig, TriliumMapper, type TriliumNote, type TriliumSearchHelpers, buildSearchQuery, type components, createTriliumClient as createClient, createTriliumClient, type operations, type paths, transforms };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Client } from 'openapi-fetch';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* This file was auto-generated by openapi-typescript.
|
|
@@ -1848,12 +1848,6 @@ type TriliumSearchHelpers = TriliumSearchLogical | (TriliumSearchConditions & Pa
|
|
|
1848
1848
|
* // => "note.type = 'text' AND #wordCount >= 1000"
|
|
1849
1849
|
*/
|
|
1850
1850
|
declare function buildSearchQuery(helpers: TriliumSearchHelpers): string;
|
|
1851
|
-
/**
|
|
1852
|
-
* Transform function that converts a raw value into the target type
|
|
1853
|
-
* @template T - The target object type
|
|
1854
|
-
* @template K - The specific key in the target type
|
|
1855
|
-
*/
|
|
1856
|
-
type TransformFunction<T, K extends keyof T> = (value: unknown, note: TriliumNote) => T[K] | undefined;
|
|
1857
1851
|
/**
|
|
1858
1852
|
* Computed function that calculates a value from the partially mapped object
|
|
1859
1853
|
* @template T - The target object type
|
|
@@ -1889,8 +1883,8 @@ type ComputedFunction<T, K extends keyof T> = (partial: Partial<T>, note: Triliu
|
|
|
1889
1883
|
type FieldMapping<T, K extends keyof T = keyof T> = string | {
|
|
1890
1884
|
/** Source path (string) or extractor function */
|
|
1891
1885
|
from: string | ((note: TriliumNote) => unknown);
|
|
1892
|
-
/** Optional transform function to convert the raw value */
|
|
1893
|
-
transform?:
|
|
1886
|
+
/** Optional transform function to convert the raw value - accepts any input type */
|
|
1887
|
+
transform?: (value: any, note: TriliumNote) => T[K] | undefined;
|
|
1894
1888
|
/** Default value if extraction returns undefined */
|
|
1895
1889
|
default?: T[K];
|
|
1896
1890
|
/** Whether this field is required (throws if missing) */
|
|
@@ -1939,7 +1933,7 @@ type MappingConfig<T> = {
|
|
|
1939
1933
|
*/
|
|
1940
1934
|
declare class TriliumMapper<T> {
|
|
1941
1935
|
/** The mapping configuration for this mapper */
|
|
1942
|
-
|
|
1936
|
+
readonly config: MappingConfig<T>;
|
|
1943
1937
|
/**
|
|
1944
1938
|
* Creates a new TriliumMapper instance
|
|
1945
1939
|
* @param config - The mapping configuration defining how to map note fields to the target type
|
|
@@ -2020,6 +2014,83 @@ declare const transforms: {
|
|
|
2020
2014
|
/** Trim whitespace from string */
|
|
2021
2015
|
trim: (value: unknown) => string | undefined;
|
|
2022
2016
|
};
|
|
2017
|
+
/**
|
|
2018
|
+
* Standard note fields that all mapped types must include.
|
|
2019
|
+
* Extend this interface when creating your own mapped types.
|
|
2020
|
+
*
|
|
2021
|
+
* @example
|
|
2022
|
+
* ```ts
|
|
2023
|
+
* interface BlogPost extends StandardNote {
|
|
2024
|
+
* slug: string;
|
|
2025
|
+
* published: boolean;
|
|
2026
|
+
* }
|
|
2027
|
+
* ```
|
|
2028
|
+
*/
|
|
2029
|
+
interface StandardNote {
|
|
2030
|
+
/** The unique note ID */
|
|
2031
|
+
id: string;
|
|
2032
|
+
/** The note title */
|
|
2033
|
+
title: string;
|
|
2034
|
+
/** UTC date when the note was created */
|
|
2035
|
+
dateCreatedUtc: Date;
|
|
2036
|
+
/** UTC date when the note was last modified */
|
|
2037
|
+
dateLastModifiedUtc: Date;
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* Standard mapping configuration for StandardNote fields.
|
|
2041
|
+
* Use with TriliumMapper.merge() to create mappings for types extending StandardNote.
|
|
2042
|
+
*
|
|
2043
|
+
* @example
|
|
2044
|
+
* ```ts
|
|
2045
|
+
* interface BlogPost extends StandardNote {
|
|
2046
|
+
* slug: string;
|
|
2047
|
+
* published: boolean;
|
|
2048
|
+
* }
|
|
2049
|
+
*
|
|
2050
|
+
* const blogMapping = TriliumMapper.merge<BlogPost>(
|
|
2051
|
+
* StandardNoteMapping,
|
|
2052
|
+
* {
|
|
2053
|
+
* slug: '#slug',
|
|
2054
|
+
* published: { from: '#published', transform: transforms.boolean, default: false },
|
|
2055
|
+
* }
|
|
2056
|
+
* );
|
|
2057
|
+
* ```
|
|
2058
|
+
*/
|
|
2059
|
+
declare const StandardNoteMapping: MappingConfig<StandardNote>;
|
|
2060
|
+
/**
|
|
2061
|
+
* Helper type for defining custom field mappings.
|
|
2062
|
+
* Use this when defining mappings for types that extend StandardNote.
|
|
2063
|
+
* It automatically excludes StandardNote fields since they're auto-merged.
|
|
2064
|
+
*
|
|
2065
|
+
* @template T - Your custom type that extends StandardNote
|
|
2066
|
+
*
|
|
2067
|
+
* @example
|
|
2068
|
+
* ```ts
|
|
2069
|
+
* interface BlogPost extends StandardNote {
|
|
2070
|
+
* slug: string;
|
|
2071
|
+
* published: boolean;
|
|
2072
|
+
* }
|
|
2073
|
+
*
|
|
2074
|
+
* // Clean type - no need for verbose Omit<>
|
|
2075
|
+
* const blogMapping: CustomMapping<BlogPost> = {
|
|
2076
|
+
* slug: '#slug',
|
|
2077
|
+
* published: { from: '#published', transform: transforms.boolean, default: false },
|
|
2078
|
+
* };
|
|
2079
|
+
*
|
|
2080
|
+
* const { data } = await client.searchAndMap<BlogPost>({
|
|
2081
|
+
* query: '#blog',
|
|
2082
|
+
* mapping: blogMapping,
|
|
2083
|
+
* });
|
|
2084
|
+
* ```
|
|
2085
|
+
*/
|
|
2086
|
+
type CustomMapping<T extends StandardNote> = MappingConfig<Omit<T, keyof StandardNote>>;
|
|
2087
|
+
|
|
2088
|
+
/**
|
|
2089
|
+
* Trilium API Client using openapi-fetch
|
|
2090
|
+
*
|
|
2091
|
+
* This provides a type-safe client for the Trilium ETAPI.
|
|
2092
|
+
* Types are auto-generated from the OpenAPI specification.
|
|
2093
|
+
*/
|
|
2023
2094
|
|
|
2024
2095
|
type TriliumNote = components['schemas']['Note'];
|
|
2025
2096
|
type TriliumBranch = components['schemas']['Branch'];
|
|
@@ -2031,13 +2102,88 @@ interface TriliumClientConfig {
|
|
|
2031
2102
|
baseUrl: string;
|
|
2032
2103
|
apiKey: string;
|
|
2033
2104
|
}
|
|
2105
|
+
interface SearchAndMapOptions<T extends StandardNote> {
|
|
2106
|
+
/** Search query - either a string or structured search helpers */
|
|
2107
|
+
query: string | TriliumSearchHelpers;
|
|
2108
|
+
/**
|
|
2109
|
+
* Mapping configuration for your custom fields only.
|
|
2110
|
+
* StandardNoteMapping (id, title, dates) is automatically merged.
|
|
2111
|
+
*/
|
|
2112
|
+
mapping: CustomMapping<T>;
|
|
2113
|
+
/** Optional: limit number of results */
|
|
2114
|
+
limit?: number;
|
|
2115
|
+
/** Optional: order by field (e.g., 'dateModified', 'title') */
|
|
2116
|
+
orderBy?: string;
|
|
2117
|
+
/** Optional: order direction */
|
|
2118
|
+
orderDirection?: 'asc' | 'desc';
|
|
2119
|
+
/** Optional: fast search mode (less accurate but faster) */
|
|
2120
|
+
fastSearch?: boolean;
|
|
2121
|
+
}
|
|
2122
|
+
/** Details about a note that failed to map */
|
|
2123
|
+
interface MappingFailure {
|
|
2124
|
+
/** The note ID that failed to map */
|
|
2125
|
+
noteId: string;
|
|
2126
|
+
/** The note title for easier identification */
|
|
2127
|
+
noteTitle: string;
|
|
2128
|
+
/** The error message explaining why mapping failed */
|
|
2129
|
+
reason: string;
|
|
2130
|
+
/** The original note object */
|
|
2131
|
+
note: TriliumNote;
|
|
2132
|
+
}
|
|
2133
|
+
interface SearchAndMapResult<T extends StandardNote> {
|
|
2134
|
+
/** Mapped results as typed objects */
|
|
2135
|
+
data: T[];
|
|
2136
|
+
/** Notes that failed to map (e.g., missing required fields) */
|
|
2137
|
+
failures: MappingFailure[];
|
|
2138
|
+
}
|
|
2139
|
+
/** Extended Trilium client with search and map helper */
|
|
2140
|
+
interface TriliumClient extends Client<paths> {
|
|
2141
|
+
/**
|
|
2142
|
+
* Search notes and automatically map results to typed objects.
|
|
2143
|
+
* Type T must extend StandardNote to ensure consistent base fields.
|
|
2144
|
+
* StandardNoteMapping is automatically included - just define your custom fields!
|
|
2145
|
+
* Throws on API/network errors.
|
|
2146
|
+
*
|
|
2147
|
+
* @see {@link https://triliumnext.github.io/Docs/Wiki/search.html} for Trilium search syntax
|
|
2148
|
+
*
|
|
2149
|
+
* @example
|
|
2150
|
+
* ```ts
|
|
2151
|
+
* interface BlogPost extends StandardNote {
|
|
2152
|
+
* slug: string;
|
|
2153
|
+
* published: boolean;
|
|
2154
|
+
* }
|
|
2155
|
+
*
|
|
2156
|
+
* // Just define your custom fields - StandardNoteMapping is auto-merged!
|
|
2157
|
+
* const { data: posts, failures } = await client.searchAndMap<BlogPost>({
|
|
2158
|
+
* query: { '#blog': true, '#published': true },
|
|
2159
|
+
* mapping: {
|
|
2160
|
+
* slug: '#slug',
|
|
2161
|
+
* published: { from: '#published', transform: transforms.boolean, default: false },
|
|
2162
|
+
* },
|
|
2163
|
+
* limit: 10,
|
|
2164
|
+
* orderBy: 'dateModified',
|
|
2165
|
+
* orderDirection: 'desc',
|
|
2166
|
+
* });
|
|
2167
|
+
*
|
|
2168
|
+
* // Each post has id, title, dateCreatedUtc, dateLastModifiedUtc + your custom fields
|
|
2169
|
+
* posts.forEach(post => {
|
|
2170
|
+
* console.log(`${post.title} (${post.slug}) - ${post.id}`);
|
|
2171
|
+
* });
|
|
2172
|
+
*
|
|
2173
|
+
* if (failures.length > 0) {
|
|
2174
|
+
* console.warn(`${failures.length} notes failed to map`);
|
|
2175
|
+
* }
|
|
2176
|
+
* ```
|
|
2177
|
+
*/
|
|
2178
|
+
searchAndMap<T extends StandardNote>(options: SearchAndMapOptions<T>): Promise<SearchAndMapResult<T>>;
|
|
2179
|
+
}
|
|
2034
2180
|
/**
|
|
2035
2181
|
* Create a type-safe Trilium API client
|
|
2036
2182
|
*
|
|
2037
2183
|
* @example
|
|
2038
2184
|
* ```ts
|
|
2039
2185
|
* const client = createTriliumClient({
|
|
2040
|
-
* baseUrl: 'http://localhost:
|
|
2186
|
+
* baseUrl: 'http://localhost:8080',
|
|
2041
2187
|
* apiKey: 'your-etapi-token'
|
|
2042
2188
|
* });
|
|
2043
2189
|
*
|
|
@@ -2063,8 +2209,17 @@ interface TriliumClientConfig {
|
|
|
2063
2209
|
* const { data: searchResults } = await client.GET('/notes', {
|
|
2064
2210
|
* params: { query: { search: '#blog' } }
|
|
2065
2211
|
* });
|
|
2212
|
+
*
|
|
2213
|
+
* // Search and map to typed objects
|
|
2214
|
+
* const { data: posts } = await client.searchAndMap<BlogPost>({
|
|
2215
|
+
* query: { '#blog': true },
|
|
2216
|
+
* mapping: {
|
|
2217
|
+
* title: 'note.title',
|
|
2218
|
+
* slug: '#slug',
|
|
2219
|
+
* },
|
|
2220
|
+
* });
|
|
2066
2221
|
* ```
|
|
2067
2222
|
*/
|
|
2068
|
-
declare function createTriliumClient(config: TriliumClientConfig):
|
|
2223
|
+
declare function createTriliumClient(config: TriliumClientConfig): TriliumClient;
|
|
2069
2224
|
|
|
2070
|
-
export { type
|
|
2225
|
+
export { type CustomMapping, type MappingConfig, type MappingFailure, type StandardNote, StandardNoteMapping, type TriliumAppInfo, type TriliumAttachment, type TriliumAttribute, type TriliumBranch, type TriliumClientConfig, TriliumMapper, type TriliumNote, type TriliumSearchHelpers, buildSearchQuery, type components, createTriliumClient as createClient, createTriliumClient, type operations, type paths, transforms };
|
package/dist/index.js
CHANGED
|
@@ -245,19 +245,97 @@ var transforms = {
|
|
|
245
245
|
return String(value).trim() || void 0;
|
|
246
246
|
}
|
|
247
247
|
};
|
|
248
|
+
var StandardNoteMapping = {
|
|
249
|
+
id: {
|
|
250
|
+
from: "note.noteId",
|
|
251
|
+
required: true
|
|
252
|
+
},
|
|
253
|
+
title: {
|
|
254
|
+
from: "note.title",
|
|
255
|
+
required: true
|
|
256
|
+
},
|
|
257
|
+
dateCreatedUtc: {
|
|
258
|
+
from: "note.utcDateCreated",
|
|
259
|
+
transform: transforms.date,
|
|
260
|
+
required: true
|
|
261
|
+
},
|
|
262
|
+
dateLastModifiedUtc: {
|
|
263
|
+
from: "note.utcDateModified",
|
|
264
|
+
transform: transforms.date,
|
|
265
|
+
required: true
|
|
266
|
+
}
|
|
267
|
+
};
|
|
248
268
|
|
|
249
269
|
// src/client.ts
|
|
250
270
|
function createTriliumClient(config) {
|
|
251
271
|
const baseUrl = config.baseUrl.endsWith("/") ? config.baseUrl.slice(0, -1) : config.baseUrl;
|
|
252
|
-
|
|
272
|
+
const client = createClient({
|
|
253
273
|
baseUrl: `${baseUrl}/etapi`,
|
|
254
274
|
headers: {
|
|
255
275
|
Authorization: config.apiKey
|
|
256
276
|
}
|
|
257
277
|
});
|
|
278
|
+
const searchAndMap = async (options) => {
|
|
279
|
+
const searchQuery = typeof options.query === "string" ? options.query : buildSearchQuery(options.query);
|
|
280
|
+
const params = [];
|
|
281
|
+
if (options.orderBy) {
|
|
282
|
+
params.push(`orderBy:${options.orderBy}`);
|
|
283
|
+
if (options.orderDirection) {
|
|
284
|
+
params.push(options.orderDirection);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (options.limit) {
|
|
288
|
+
params.push(`limit:${options.limit}`);
|
|
289
|
+
}
|
|
290
|
+
if (options.fastSearch) {
|
|
291
|
+
params.push("fastSearch");
|
|
292
|
+
}
|
|
293
|
+
const fullQuery = params.length > 0 ? `${searchQuery} ${params.join(" ")}` : searchQuery;
|
|
294
|
+
const { data, error } = await client.GET("/notes", {
|
|
295
|
+
params: { query: { search: fullQuery } }
|
|
296
|
+
});
|
|
297
|
+
if (error) {
|
|
298
|
+
throw error;
|
|
299
|
+
}
|
|
300
|
+
if (!data?.results) {
|
|
301
|
+
throw new Error("No results returned from search");
|
|
302
|
+
}
|
|
303
|
+
const fullMapping = TriliumMapper.merge(
|
|
304
|
+
StandardNoteMapping,
|
|
305
|
+
options.mapping
|
|
306
|
+
);
|
|
307
|
+
const mapper = new TriliumMapper(fullMapping);
|
|
308
|
+
const mappedData = [];
|
|
309
|
+
const failures = [];
|
|
310
|
+
for (const note of data.results) {
|
|
311
|
+
try {
|
|
312
|
+
const [mapped] = mapper.map([note]);
|
|
313
|
+
if (mapped !== void 0) {
|
|
314
|
+
mappedData.push(mapped);
|
|
315
|
+
} else {
|
|
316
|
+
failures.push({
|
|
317
|
+
noteId: note.noteId ?? "unknown",
|
|
318
|
+
noteTitle: note.title ?? "Untitled",
|
|
319
|
+
reason: "Mapping returned undefined",
|
|
320
|
+
note
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
} catch (err) {
|
|
324
|
+
failures.push({
|
|
325
|
+
noteId: note.noteId ?? "unknown",
|
|
326
|
+
noteTitle: note.title ?? "Untitled",
|
|
327
|
+
reason: err instanceof Error ? err.message : String(err),
|
|
328
|
+
note
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return { data: mappedData, failures };
|
|
333
|
+
};
|
|
334
|
+
return Object.assign(client, { searchAndMap });
|
|
258
335
|
}
|
|
259
336
|
var client_default = createTriliumClient;
|
|
260
337
|
export {
|
|
338
|
+
StandardNoteMapping,
|
|
261
339
|
TriliumMapper,
|
|
262
340
|
buildSearchQuery,
|
|
263
341
|
client_default as createClient,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trilium-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "A type-safe TypeScript client for the Trilium Notes ETAPI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -33,9 +33,23 @@
|
|
|
33
33
|
"test:ts": "tsc --noEmit",
|
|
34
34
|
"prepublishOnly": "pnpm build"
|
|
35
35
|
},
|
|
36
|
-
"keywords": [
|
|
37
|
-
|
|
36
|
+
"keywords": [
|
|
37
|
+
"trilium",
|
|
38
|
+
"trilium-notes",
|
|
39
|
+
"etapi",
|
|
40
|
+
"api-client",
|
|
41
|
+
"typescript"
|
|
42
|
+
],
|
|
43
|
+
"author": "lzinga",
|
|
38
44
|
"license": "AGPL-3.0",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/lzinga/trilium-api"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/lzinga/trilium-api/issues"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://github.com/lzinga/trilium-api#readme",
|
|
39
53
|
"packageManager": "pnpm@10.25.0",
|
|
40
54
|
"devDependencies": {
|
|
41
55
|
"@types/node": "^25.0.3",
|