trilium-api 1.0.1 → 1.0.2
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/dist/index.cjs +307 -0
- package/{src/generated/trilium.d.ts → dist/index.d.cts} +317 -5
- package/dist/index.d.ts +2070 -0
- package/dist/index.js +266 -0
- package/package.json +20 -3
- package/.github/workflows/ci.yml +0 -37
- package/.github/workflows/publish.yml +0 -84
- package/src/client.test.ts +0 -477
- package/src/client.ts +0 -91
- package/src/demo-mapper.ts +0 -166
- package/src/demo-search.ts +0 -108
- package/src/demo.ts +0 -126
- package/src/index.ts +0 -35
- package/src/mapper.test.ts +0 -638
- package/src/mapper.ts +0 -534
- package/tsconfig.json +0 -42
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
TriliumMapper: () => TriliumMapper,
|
|
34
|
+
buildSearchQuery: () => buildSearchQuery,
|
|
35
|
+
createClient: () => client_default,
|
|
36
|
+
createTriliumClient: () => createTriliumClient,
|
|
37
|
+
transforms: () => transforms
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
40
|
+
|
|
41
|
+
// src/client.ts
|
|
42
|
+
var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
|
|
43
|
+
|
|
44
|
+
// src/mapper.ts
|
|
45
|
+
function buildSearchQuery(helpers) {
|
|
46
|
+
if ("AND" in helpers && Array.isArray(helpers.AND)) {
|
|
47
|
+
return helpers.AND.map((h) => {
|
|
48
|
+
const query = buildSearchQuery(h);
|
|
49
|
+
return query.includes(" OR ") ? `(${query})` : query;
|
|
50
|
+
}).join(" AND ");
|
|
51
|
+
}
|
|
52
|
+
if ("OR" in helpers && Array.isArray(helpers.OR)) {
|
|
53
|
+
return helpers.OR.map((h) => {
|
|
54
|
+
const query = buildSearchQuery(h);
|
|
55
|
+
return query.includes(" AND ") || query.includes(" OR ") ? `(${query})` : query;
|
|
56
|
+
}).join(" OR ");
|
|
57
|
+
}
|
|
58
|
+
if ("NOT" in helpers && helpers.NOT !== void 0) {
|
|
59
|
+
const notValue = helpers.NOT;
|
|
60
|
+
if (typeof notValue === "object" && notValue !== null && !("value" in notValue)) {
|
|
61
|
+
const query = buildSearchQuery(notValue);
|
|
62
|
+
return `not(${query})`;
|
|
63
|
+
}
|
|
64
|
+
throw new Error("NOT operator requires a query object, not a simple value");
|
|
65
|
+
}
|
|
66
|
+
const parts = [];
|
|
67
|
+
for (const [key, value] of Object.entries(helpers)) {
|
|
68
|
+
if (value === void 0 || value === null) continue;
|
|
69
|
+
if (key.startsWith("#")) {
|
|
70
|
+
const labelName = key.slice(1);
|
|
71
|
+
if (labelName.includes(".")) {
|
|
72
|
+
if (typeof value === "object" && "value" in value) {
|
|
73
|
+
const operator = value.operator || "=";
|
|
74
|
+
const val = typeof value.value === "string" ? `'${value.value}'` : value.value;
|
|
75
|
+
parts.push(`${key} ${operator} ${val}`);
|
|
76
|
+
} else if (typeof value === "string") {
|
|
77
|
+
parts.push(`${key} = '${value}'`);
|
|
78
|
+
} else {
|
|
79
|
+
parts.push(`${key} = ${value}`);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
if (value === true) {
|
|
83
|
+
parts.push(`#${labelName}`);
|
|
84
|
+
} else if (value === false) {
|
|
85
|
+
parts.push(`#!${labelName}`);
|
|
86
|
+
} else if (typeof value === "object" && "value" in value) {
|
|
87
|
+
const operator = value.operator || "=";
|
|
88
|
+
const val = typeof value.value === "string" ? `'${value.value}'` : value.value;
|
|
89
|
+
parts.push(`#${labelName} ${operator} ${val}`);
|
|
90
|
+
} else if (typeof value === "string") {
|
|
91
|
+
parts.push(`#${labelName} = '${value}'`);
|
|
92
|
+
} else {
|
|
93
|
+
parts.push(`#${labelName} = ${value}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} else if (key.startsWith("~")) {
|
|
97
|
+
const relationName = key.slice(1);
|
|
98
|
+
if (relationName.includes(".")) {
|
|
99
|
+
if (typeof value === "object" && "value" in value) {
|
|
100
|
+
const operator = value.operator || "=";
|
|
101
|
+
const val = typeof value.value === "string" ? `'${value.value}'` : value.value;
|
|
102
|
+
parts.push(`${key} ${operator} ${val}`);
|
|
103
|
+
} else if (typeof value === "string") {
|
|
104
|
+
parts.push(`${key} = '${value}'`);
|
|
105
|
+
} else {
|
|
106
|
+
parts.push(`${key} = ${value}`);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
if (typeof value === "object" && "value" in value) {
|
|
110
|
+
const operator = value.operator || "*=*";
|
|
111
|
+
const val = typeof value.value === "string" ? `'${value.value}'` : value.value;
|
|
112
|
+
parts.push(`${key} ${operator} ${val}`);
|
|
113
|
+
} else if (typeof value === "string") {
|
|
114
|
+
parts.push(`${key} *=* '${value}'`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
const path = key.startsWith("note.") ? key : `note.${key}`;
|
|
119
|
+
if (typeof value === "object" && "value" in value) {
|
|
120
|
+
const operator = value.operator || "=";
|
|
121
|
+
const val = typeof value.value === "string" ? `'${value.value}'` : value.value;
|
|
122
|
+
parts.push(`${path} ${operator} ${val}`);
|
|
123
|
+
} else if (typeof value === "string") {
|
|
124
|
+
parts.push(`${path} = '${value}'`);
|
|
125
|
+
} else if (typeof value === "boolean") {
|
|
126
|
+
parts.push(`${path} = ${value}`);
|
|
127
|
+
} else {
|
|
128
|
+
parts.push(`${path} = ${value}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return parts.join(" AND ");
|
|
133
|
+
}
|
|
134
|
+
var TriliumMapper = class {
|
|
135
|
+
/** The mapping configuration for this mapper */
|
|
136
|
+
config;
|
|
137
|
+
/**
|
|
138
|
+
* Creates a new TriliumMapper instance
|
|
139
|
+
* @param config - The mapping configuration defining how to map note fields to the target type
|
|
140
|
+
*/
|
|
141
|
+
constructor(config) {
|
|
142
|
+
this.config = config;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Merges multiple mapping configurations into a single configuration
|
|
146
|
+
* Later configs override earlier ones for the same keys
|
|
147
|
+
* Supports merging configs from base types into derived types
|
|
148
|
+
*
|
|
149
|
+
* @template T - The target type for the merged configuration
|
|
150
|
+
* @param configs - One or more mapping configurations to merge
|
|
151
|
+
* @returns A new merged mapping configuration
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* const merged = TriliumMapper.merge<BlogPost>(
|
|
155
|
+
* StandardNoteMapping,
|
|
156
|
+
* BlogSpecificMapping,
|
|
157
|
+
* OverrideMapping
|
|
158
|
+
* );
|
|
159
|
+
*/
|
|
160
|
+
static merge(...configs) {
|
|
161
|
+
return Object.assign({}, ...configs);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Maps one or more Trilium notes to the target type
|
|
165
|
+
* @param noteOrNotes - A single note or array of notes to map
|
|
166
|
+
* @returns A single mapped object or array of mapped objects
|
|
167
|
+
*/
|
|
168
|
+
map(noteOrNotes) {
|
|
169
|
+
return Array.isArray(noteOrNotes) ? noteOrNotes.map((note) => this.mapSingle(note)) : this.mapSingle(noteOrNotes);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Maps a single note to the target type using the configured field mappings
|
|
173
|
+
* Processes in two passes: first regular fields, then computed fields
|
|
174
|
+
* @param note - The Trilium note to map
|
|
175
|
+
* @returns The mapped object
|
|
176
|
+
* @throws Error if a required field is missing
|
|
177
|
+
* @private
|
|
178
|
+
*/
|
|
179
|
+
mapSingle(note) {
|
|
180
|
+
const result = {};
|
|
181
|
+
const computedFields = [];
|
|
182
|
+
for (const [key, fieldMapping] of Object.entries(this.config)) {
|
|
183
|
+
if (!fieldMapping) continue;
|
|
184
|
+
if (typeof fieldMapping === "object" && "computed" in fieldMapping) {
|
|
185
|
+
computedFields.push([key, fieldMapping]);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const mapping = typeof fieldMapping === "string" ? { from: fieldMapping } : fieldMapping;
|
|
189
|
+
let value = typeof mapping.from === "function" ? mapping.from(note) : this.extractValue(note, mapping.from);
|
|
190
|
+
if (mapping.transform) {
|
|
191
|
+
value = mapping.transform(value, note);
|
|
192
|
+
}
|
|
193
|
+
if (value === void 0 && mapping.default !== void 0) {
|
|
194
|
+
value = mapping.default;
|
|
195
|
+
}
|
|
196
|
+
if (mapping.required && value === void 0) {
|
|
197
|
+
throw new Error(`Required field '${String(key)}' missing from note ${note.noteId} (${note.title})`);
|
|
198
|
+
}
|
|
199
|
+
result[key] = value;
|
|
200
|
+
}
|
|
201
|
+
for (const [key, mapping] of computedFields) {
|
|
202
|
+
let value = mapping.computed(result, note);
|
|
203
|
+
if (value === void 0 && mapping.default !== void 0) {
|
|
204
|
+
value = mapping.default;
|
|
205
|
+
}
|
|
206
|
+
result[key] = value;
|
|
207
|
+
}
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Extracts a value from a note using a string path
|
|
212
|
+
*
|
|
213
|
+
* Supports:
|
|
214
|
+
* - Label attributes: #labelName
|
|
215
|
+
* - Relation attributes: ~relationName
|
|
216
|
+
* - Note properties: note.property.path
|
|
217
|
+
*
|
|
218
|
+
* @param note - The Trilium note to extract from
|
|
219
|
+
* @param path - The path string indicating where to extract the value
|
|
220
|
+
* @returns The extracted value or undefined if not found
|
|
221
|
+
* @private
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* extractValue(note, 'note.title') // => note.title
|
|
225
|
+
* extractValue(note, '#slug') // => label attribute 'slug'
|
|
226
|
+
* extractValue(note, '~template') // => relation attribute 'template'
|
|
227
|
+
*/
|
|
228
|
+
extractValue(note, path) {
|
|
229
|
+
if (!path) return void 0;
|
|
230
|
+
if (path.startsWith("#")) {
|
|
231
|
+
return note.attributes?.find((attr) => attr.type === "label" && attr.name === path.slice(1))?.value;
|
|
232
|
+
}
|
|
233
|
+
if (path.startsWith("~")) {
|
|
234
|
+
return note.attributes?.find((attr) => attr.type === "relation" && attr.name === path.slice(1))?.value;
|
|
235
|
+
}
|
|
236
|
+
if (path.startsWith("note.")) {
|
|
237
|
+
return path.slice(5).split(".").reduce((obj, key) => obj?.[key], note);
|
|
238
|
+
}
|
|
239
|
+
return void 0;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var transforms = {
|
|
243
|
+
/** Convert to number */
|
|
244
|
+
number: (value) => {
|
|
245
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
246
|
+
const num = Number(value);
|
|
247
|
+
return isNaN(num) ? void 0 : num;
|
|
248
|
+
},
|
|
249
|
+
/** Convert to boolean */
|
|
250
|
+
boolean: (value) => {
|
|
251
|
+
if (value === void 0 || value === null) return void 0;
|
|
252
|
+
if (typeof value === "boolean") return value;
|
|
253
|
+
if (typeof value === "string") {
|
|
254
|
+
const lower = value.toLowerCase();
|
|
255
|
+
if (lower === "true" || lower === "1" || lower === "yes") return true;
|
|
256
|
+
if (lower === "false" || lower === "0" || lower === "no") return false;
|
|
257
|
+
}
|
|
258
|
+
return void 0;
|
|
259
|
+
},
|
|
260
|
+
/** Split comma-separated string into array */
|
|
261
|
+
commaSeparated: (value) => {
|
|
262
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
263
|
+
if (typeof value !== "string") return void 0;
|
|
264
|
+
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
265
|
+
},
|
|
266
|
+
/** Parse JSON string */
|
|
267
|
+
json: (value) => {
|
|
268
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
269
|
+
if (typeof value !== "string") return void 0;
|
|
270
|
+
try {
|
|
271
|
+
return JSON.parse(value);
|
|
272
|
+
} catch {
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
/** Parse date string */
|
|
277
|
+
date: (value) => {
|
|
278
|
+
if (value === void 0 || value === null || value === "") return void 0;
|
|
279
|
+
const date = new Date(String(value));
|
|
280
|
+
return isNaN(date.getTime()) ? void 0 : date;
|
|
281
|
+
},
|
|
282
|
+
/** Trim whitespace from string */
|
|
283
|
+
trim: (value) => {
|
|
284
|
+
if (value === void 0 || value === null) return void 0;
|
|
285
|
+
return String(value).trim() || void 0;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/client.ts
|
|
290
|
+
function createTriliumClient(config) {
|
|
291
|
+
const baseUrl = config.baseUrl.endsWith("/") ? config.baseUrl.slice(0, -1) : config.baseUrl;
|
|
292
|
+
return (0, import_openapi_fetch.default)({
|
|
293
|
+
baseUrl: `${baseUrl}/etapi`,
|
|
294
|
+
headers: {
|
|
295
|
+
Authorization: config.apiKey
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
var client_default = createTriliumClient;
|
|
300
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
301
|
+
0 && (module.exports = {
|
|
302
|
+
TriliumMapper,
|
|
303
|
+
buildSearchQuery,
|
|
304
|
+
createClient,
|
|
305
|
+
createTriliumClient,
|
|
306
|
+
transforms
|
|
307
|
+
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import * as openapi_fetch from 'openapi-fetch';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* This file was auto-generated by openapi-typescript.
|
|
3
5
|
* Do not make direct changes to the file.
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
interface paths {
|
|
7
9
|
"/create-note": {
|
|
8
10
|
parameters: {
|
|
9
11
|
query?: never;
|
|
@@ -450,8 +452,7 @@ export interface paths {
|
|
|
450
452
|
trace?: never;
|
|
451
453
|
};
|
|
452
454
|
}
|
|
453
|
-
|
|
454
|
-
export interface components {
|
|
455
|
+
interface components {
|
|
455
456
|
schemas: {
|
|
456
457
|
CreateNoteDef: {
|
|
457
458
|
/** @description Note ID of the parent note in the tree */
|
|
@@ -644,8 +645,7 @@ export interface components {
|
|
|
644
645
|
headers: never;
|
|
645
646
|
pathItems: never;
|
|
646
647
|
}
|
|
647
|
-
|
|
648
|
-
export interface operations {
|
|
648
|
+
interface operations {
|
|
649
649
|
createNote: {
|
|
650
650
|
parameters: {
|
|
651
651
|
query?: never;
|
|
@@ -1756,3 +1756,315 @@ export interface operations {
|
|
|
1756
1756
|
};
|
|
1757
1757
|
};
|
|
1758
1758
|
}
|
|
1759
|
+
|
|
1760
|
+
/**
|
|
1761
|
+
* Trilium Note Mapper and Search Query Builder
|
|
1762
|
+
*
|
|
1763
|
+
* Provides utilities for mapping Trilium notes to strongly-typed objects
|
|
1764
|
+
* and building type-safe search queries.
|
|
1765
|
+
*/
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Comparison operators for search conditions
|
|
1769
|
+
*/
|
|
1770
|
+
type ComparisonOperator = '=' | '!=' | '<' | '<=' | '>' | '>=' | '*=' | '=*' | '*=*';
|
|
1771
|
+
/**
|
|
1772
|
+
* A value with an optional comparison operator
|
|
1773
|
+
*/
|
|
1774
|
+
interface ConditionValue<T = string | number | boolean> {
|
|
1775
|
+
value: T;
|
|
1776
|
+
operator?: ComparisonOperator;
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Simple value or condition with operator
|
|
1780
|
+
*/
|
|
1781
|
+
type SearchValue = string | number | boolean | ConditionValue;
|
|
1782
|
+
/**
|
|
1783
|
+
* Base search conditions for labels, relations, and note properties.
|
|
1784
|
+
* Use template literal keys for labels (#) and relations (~).
|
|
1785
|
+
* Regular string keys are treated as note properties.
|
|
1786
|
+
*/
|
|
1787
|
+
type TriliumSearchConditions = {
|
|
1788
|
+
/** Labels: use #labelName as key */
|
|
1789
|
+
[key: `#${string}`]: SearchValue | undefined;
|
|
1790
|
+
} & {
|
|
1791
|
+
/** Relations: use ~relationName as key */
|
|
1792
|
+
[key: `~${string}`]: SearchValue | undefined;
|
|
1793
|
+
} & {
|
|
1794
|
+
/** Note properties: use note.property as key or just property name */
|
|
1795
|
+
[key: string]: SearchValue | undefined;
|
|
1796
|
+
};
|
|
1797
|
+
/**
|
|
1798
|
+
* Logical operators for combining search conditions
|
|
1799
|
+
*/
|
|
1800
|
+
interface TriliumSearchLogical {
|
|
1801
|
+
/** Combine multiple conditions with AND */
|
|
1802
|
+
AND?: TriliumSearchHelpers[];
|
|
1803
|
+
/** Combine multiple conditions with OR */
|
|
1804
|
+
OR?: TriliumSearchHelpers[];
|
|
1805
|
+
/** Negate a condition */
|
|
1806
|
+
NOT?: TriliumSearchHelpers;
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Complete search helpers combining conditions and logical operators.
|
|
1810
|
+
* Can contain field conditions AND/OR logical operators.
|
|
1811
|
+
*/
|
|
1812
|
+
type TriliumSearchHelpers = TriliumSearchLogical | (TriliumSearchConditions & Partial<TriliumSearchLogical>);
|
|
1813
|
+
/**
|
|
1814
|
+
* Builds a Trilium search query string from a structured helper object
|
|
1815
|
+
*
|
|
1816
|
+
* @param helpers - The search conditions and logical operators
|
|
1817
|
+
* @returns A properly formatted Trilium search query string
|
|
1818
|
+
*
|
|
1819
|
+
* @example
|
|
1820
|
+
* // Simple label search
|
|
1821
|
+
* buildSearchQuery({ '#blog': true })
|
|
1822
|
+
* // => '#blog'
|
|
1823
|
+
*
|
|
1824
|
+
* @example
|
|
1825
|
+
* // Label with value
|
|
1826
|
+
* buildSearchQuery({ '#status': 'published' })
|
|
1827
|
+
* // => "#status = 'published'"
|
|
1828
|
+
*
|
|
1829
|
+
* @example
|
|
1830
|
+
* // Complex AND/OR conditions
|
|
1831
|
+
* buildSearchQuery({
|
|
1832
|
+
* AND: [
|
|
1833
|
+
* { '#blog': true },
|
|
1834
|
+
* { OR: [
|
|
1835
|
+
* { '#status': 'published' },
|
|
1836
|
+
* { '#status': 'featured' }
|
|
1837
|
+
* ]}
|
|
1838
|
+
* ]
|
|
1839
|
+
* })
|
|
1840
|
+
* // => "#blog AND (#status = 'published' OR #status = 'featured')"
|
|
1841
|
+
*
|
|
1842
|
+
* @example
|
|
1843
|
+
* // Note properties with operators
|
|
1844
|
+
* buildSearchQuery({
|
|
1845
|
+
* 'note.type': 'text',
|
|
1846
|
+
* '#wordCount': { value: 1000, operator: '>=' }
|
|
1847
|
+
* })
|
|
1848
|
+
* // => "note.type = 'text' AND #wordCount >= 1000"
|
|
1849
|
+
*/
|
|
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
|
+
/**
|
|
1858
|
+
* Computed function that calculates a value from the partially mapped object
|
|
1859
|
+
* @template T - The target object type
|
|
1860
|
+
* @template K - The specific key in the target type
|
|
1861
|
+
*/
|
|
1862
|
+
type ComputedFunction<T, K extends keyof T> = (partial: Partial<T>, note: TriliumNote) => T[K] | undefined;
|
|
1863
|
+
/**
|
|
1864
|
+
* Field mapping configuration for a single property
|
|
1865
|
+
* Can be a simple string path, a detailed configuration object, or a computed value
|
|
1866
|
+
*
|
|
1867
|
+
* @template T - The target object type
|
|
1868
|
+
* @template K - The specific key in the target type
|
|
1869
|
+
*
|
|
1870
|
+
* @example
|
|
1871
|
+
* // Shorthand string path
|
|
1872
|
+
* title: 'note.title'
|
|
1873
|
+
*
|
|
1874
|
+
* @example
|
|
1875
|
+
* // Full configuration
|
|
1876
|
+
* tags: {
|
|
1877
|
+
* from: '#tags',
|
|
1878
|
+
* transform: transforms.commaSeparated,
|
|
1879
|
+
* default: [],
|
|
1880
|
+
* required: false
|
|
1881
|
+
* }
|
|
1882
|
+
*
|
|
1883
|
+
* @example
|
|
1884
|
+
* // Computed value
|
|
1885
|
+
* readTimeMinutes: {
|
|
1886
|
+
* computed: (partial) => Math.ceil((partial.wordCount || 0) / 200)
|
|
1887
|
+
* }
|
|
1888
|
+
*/
|
|
1889
|
+
type FieldMapping<T, K extends keyof T = keyof T> = string | {
|
|
1890
|
+
/** Source path (string) or extractor function */
|
|
1891
|
+
from: string | ((note: TriliumNote) => unknown);
|
|
1892
|
+
/** Optional transform function to convert the raw value */
|
|
1893
|
+
transform?: TransformFunction<T, K>;
|
|
1894
|
+
/** Default value if extraction returns undefined */
|
|
1895
|
+
default?: T[K];
|
|
1896
|
+
/** Whether this field is required (throws if missing) */
|
|
1897
|
+
required?: boolean;
|
|
1898
|
+
} | {
|
|
1899
|
+
/** Computed function that calculates value from other mapped fields */
|
|
1900
|
+
computed: ComputedFunction<T, K>;
|
|
1901
|
+
/** Default value if computed returns undefined */
|
|
1902
|
+
default?: T[K];
|
|
1903
|
+
};
|
|
1904
|
+
/**
|
|
1905
|
+
* Complete mapping configuration for a type
|
|
1906
|
+
* Maps each property key to its field mapping configuration
|
|
1907
|
+
*
|
|
1908
|
+
* @template T - The target object type to map to
|
|
1909
|
+
*/
|
|
1910
|
+
type MappingConfig<T> = {
|
|
1911
|
+
[K in keyof T]?: FieldMapping<T, K>;
|
|
1912
|
+
};
|
|
1913
|
+
/**
|
|
1914
|
+
* Maps Trilium notes to strongly-typed objects using declarative field mappings
|
|
1915
|
+
*
|
|
1916
|
+
* Supports:
|
|
1917
|
+
* - Direct property paths (note.title, note.noteId)
|
|
1918
|
+
* - Label attributes (#labelName)
|
|
1919
|
+
* - Relation attributes (~relationName)
|
|
1920
|
+
* - Custom extractor functions
|
|
1921
|
+
* - Transform functions
|
|
1922
|
+
* - Computed values from other fields
|
|
1923
|
+
* - Default values
|
|
1924
|
+
* - Required field validation
|
|
1925
|
+
*
|
|
1926
|
+
* @template T - The target type to map notes to
|
|
1927
|
+
*
|
|
1928
|
+
* @example
|
|
1929
|
+
* const mapper = new TriliumMapper<BlogPost>({
|
|
1930
|
+
* title: 'note.title',
|
|
1931
|
+
* slug: { from: '#slug', required: true },
|
|
1932
|
+
* wordCount: { from: '#wordCount', transform: transforms.number, default: 0 },
|
|
1933
|
+
* readTimeMinutes: {
|
|
1934
|
+
* computed: (partial) => Math.ceil((partial.wordCount || 0) / 200)
|
|
1935
|
+
* }
|
|
1936
|
+
* });
|
|
1937
|
+
*
|
|
1938
|
+
* const posts = mapper.map(notes);
|
|
1939
|
+
*/
|
|
1940
|
+
declare class TriliumMapper<T> {
|
|
1941
|
+
/** The mapping configuration for this mapper */
|
|
1942
|
+
private readonly config;
|
|
1943
|
+
/**
|
|
1944
|
+
* Creates a new TriliumMapper instance
|
|
1945
|
+
* @param config - The mapping configuration defining how to map note fields to the target type
|
|
1946
|
+
*/
|
|
1947
|
+
constructor(config: MappingConfig<T>);
|
|
1948
|
+
/**
|
|
1949
|
+
* Merges multiple mapping configurations into a single configuration
|
|
1950
|
+
* Later configs override earlier ones for the same keys
|
|
1951
|
+
* Supports merging configs from base types into derived types
|
|
1952
|
+
*
|
|
1953
|
+
* @template T - The target type for the merged configuration
|
|
1954
|
+
* @param configs - One or more mapping configurations to merge
|
|
1955
|
+
* @returns A new merged mapping configuration
|
|
1956
|
+
*
|
|
1957
|
+
* @example
|
|
1958
|
+
* const merged = TriliumMapper.merge<BlogPost>(
|
|
1959
|
+
* StandardNoteMapping,
|
|
1960
|
+
* BlogSpecificMapping,
|
|
1961
|
+
* OverrideMapping
|
|
1962
|
+
* );
|
|
1963
|
+
*/
|
|
1964
|
+
static merge<T>(...configs: (Partial<MappingConfig<T>> | MappingConfig<unknown>)[]): MappingConfig<T>;
|
|
1965
|
+
/**
|
|
1966
|
+
* Maps a single note to the target type
|
|
1967
|
+
* @param note - The Trilium note to map
|
|
1968
|
+
* @returns The mapped object of type T
|
|
1969
|
+
*/
|
|
1970
|
+
map(note: TriliumNote): T;
|
|
1971
|
+
/**
|
|
1972
|
+
* Maps an array of notes to the target type
|
|
1973
|
+
* @param notes - The Trilium notes to map
|
|
1974
|
+
* @returns An array of mapped objects of type T
|
|
1975
|
+
*/
|
|
1976
|
+
map(notes: TriliumNote[]): T[];
|
|
1977
|
+
/**
|
|
1978
|
+
* Maps a single note to the target type using the configured field mappings
|
|
1979
|
+
* Processes in two passes: first regular fields, then computed fields
|
|
1980
|
+
* @param note - The Trilium note to map
|
|
1981
|
+
* @returns The mapped object
|
|
1982
|
+
* @throws Error if a required field is missing
|
|
1983
|
+
* @private
|
|
1984
|
+
*/
|
|
1985
|
+
private mapSingle;
|
|
1986
|
+
/**
|
|
1987
|
+
* Extracts a value from a note using a string path
|
|
1988
|
+
*
|
|
1989
|
+
* Supports:
|
|
1990
|
+
* - Label attributes: #labelName
|
|
1991
|
+
* - Relation attributes: ~relationName
|
|
1992
|
+
* - Note properties: note.property.path
|
|
1993
|
+
*
|
|
1994
|
+
* @param note - The Trilium note to extract from
|
|
1995
|
+
* @param path - The path string indicating where to extract the value
|
|
1996
|
+
* @returns The extracted value or undefined if not found
|
|
1997
|
+
* @private
|
|
1998
|
+
*
|
|
1999
|
+
* @example
|
|
2000
|
+
* extractValue(note, 'note.title') // => note.title
|
|
2001
|
+
* extractValue(note, '#slug') // => label attribute 'slug'
|
|
2002
|
+
* extractValue(note, '~template') // => relation attribute 'template'
|
|
2003
|
+
*/
|
|
2004
|
+
private extractValue;
|
|
2005
|
+
}
|
|
2006
|
+
/**
|
|
2007
|
+
* Common transform functions for use with TriliumMapper
|
|
2008
|
+
*/
|
|
2009
|
+
declare const transforms: {
|
|
2010
|
+
/** Convert to number */
|
|
2011
|
+
number: (value: unknown) => number | undefined;
|
|
2012
|
+
/** Convert to boolean */
|
|
2013
|
+
boolean: (value: unknown) => boolean | undefined;
|
|
2014
|
+
/** Split comma-separated string into array */
|
|
2015
|
+
commaSeparated: (value: unknown) => string[] | undefined;
|
|
2016
|
+
/** Parse JSON string */
|
|
2017
|
+
json: <T>(value: unknown) => T | undefined;
|
|
2018
|
+
/** Parse date string */
|
|
2019
|
+
date: (value: unknown) => Date | undefined;
|
|
2020
|
+
/** Trim whitespace from string */
|
|
2021
|
+
trim: (value: unknown) => string | undefined;
|
|
2022
|
+
};
|
|
2023
|
+
|
|
2024
|
+
type TriliumNote = components['schemas']['Note'];
|
|
2025
|
+
type TriliumBranch = components['schemas']['Branch'];
|
|
2026
|
+
type TriliumAttribute = components['schemas']['Attribute'];
|
|
2027
|
+
type TriliumAttachment = components['schemas']['Attachment'];
|
|
2028
|
+
type TriliumAppInfo = components['schemas']['AppInfo'];
|
|
2029
|
+
|
|
2030
|
+
interface TriliumClientConfig {
|
|
2031
|
+
baseUrl: string;
|
|
2032
|
+
apiKey: string;
|
|
2033
|
+
}
|
|
2034
|
+
/**
|
|
2035
|
+
* Create a type-safe Trilium API client
|
|
2036
|
+
*
|
|
2037
|
+
* @example
|
|
2038
|
+
* ```ts
|
|
2039
|
+
* const client = createTriliumClient({
|
|
2040
|
+
* baseUrl: 'http://localhost:37840',
|
|
2041
|
+
* apiKey: 'your-etapi-token'
|
|
2042
|
+
* });
|
|
2043
|
+
*
|
|
2044
|
+
* // Get app info
|
|
2045
|
+
* const { data, error } = await client.GET('/app-info');
|
|
2046
|
+
*
|
|
2047
|
+
* // Get a note by ID
|
|
2048
|
+
* const { data: note } = await client.GET('/notes/{noteId}', {
|
|
2049
|
+
* params: { path: { noteId: 'root' } }
|
|
2050
|
+
* });
|
|
2051
|
+
*
|
|
2052
|
+
* // Create a note
|
|
2053
|
+
* const { data: newNote } = await client.POST('/notes', {
|
|
2054
|
+
* body: {
|
|
2055
|
+
* parentNoteId: 'root',
|
|
2056
|
+
* title: 'My Note',
|
|
2057
|
+
* type: 'text',
|
|
2058
|
+
* content: '<p>Hello World</p>'
|
|
2059
|
+
* }
|
|
2060
|
+
* });
|
|
2061
|
+
*
|
|
2062
|
+
* // Search notes
|
|
2063
|
+
* const { data: searchResults } = await client.GET('/notes', {
|
|
2064
|
+
* params: { query: { search: '#blog' } }
|
|
2065
|
+
* });
|
|
2066
|
+
* ```
|
|
2067
|
+
*/
|
|
2068
|
+
declare function createTriliumClient(config: TriliumClientConfig): openapi_fetch.Client<paths, `${string}/${string}`>;
|
|
2069
|
+
|
|
2070
|
+
export { type ComparisonOperator, type ComputedFunction, type ConditionValue, type FieldMapping, type MappingConfig, type SearchValue, type TransformFunction, type TriliumAppInfo, type TriliumAttachment, type TriliumAttribute, type TriliumBranch, type TriliumClientConfig, TriliumMapper, type TriliumNote, type TriliumSearchConditions, type TriliumSearchHelpers, type TriliumSearchLogical, buildSearchQuery, type components, createTriliumClient as createClient, createTriliumClient, type operations, type paths, transforms };
|