@thingd/cli 0.32.0 → 0.32.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/mcp/tools.js DELETED
@@ -1,568 +0,0 @@
1
- import { z } from "zod";
2
- import { appendMcpAuditEvent, resolveThingdMcpAuditOptions, } from "./audit.js";
3
- import { jsonResult } from "./result.js";
4
- const memoryObjectSchema = z.object({ id: z.string().min(1) }).catchall(z.unknown());
5
- const memoryEventSchema = z.object({ type: z.string().min(1) }).catchall(z.unknown());
6
- const objectPayloadSchema = z.record(z.string(), z.unknown());
7
- const auditInputSchema = {
8
- actor: z.string().min(1).optional(),
9
- source: z.string().min(1).optional(),
10
- };
11
- export function registerThingdTools(server, db, options = {}) {
12
- const audit = resolveThingdMcpAuditOptions(options.audit);
13
- const allowlist = options.hardening?.collectionAllowlist;
14
- const readOnly = options.hardening?.readOnly ?? false;
15
- /** Throw a tool-level error if the collection is not in the allowlist. */
16
- function assertCollectionAllowed(collection) {
17
- if (allowlist && !allowlist.has(collection)) {
18
- throw new Error(`Collection "${collection}" is not permitted by this thingd MCP server. Allowed: ${[...allowlist].join(", ")}.`);
19
- }
20
- }
21
- /** Throw a tool-level error if the server is in read-only mode. */
22
- function assertWriteAllowed() {
23
- if (readOnly) {
24
- throw new Error("This thingd MCP server is configured in read-only mode. Write operations are not permitted.");
25
- }
26
- }
27
- server.registerTool("thing_search", {
28
- title: "Search Memory",
29
- description: "Search thingd objects and events by full-text query. Returns matching items ranked by relevance using SQLite FTS5 with Porter word stemming. Use this to find previously stored memories, notes, or events by keyword or phrase. Accepts a query string and optional filter by collection names, metadata key-value pairs, and a result limit. Returns an array of matching objects with relevance scores.",
30
- inputSchema: {
31
- query: z.string().min(1),
32
- collections: z.array(z.string().min(1)).optional(),
33
- limit: z.number().int().positive().max(100).optional(),
34
- filter: z.record(z.string(), z.unknown()).optional(),
35
- },
36
- annotations: {
37
- readOnlyHint: true,
38
- destructiveHint: false,
39
- idempotentHint: true,
40
- openWorldHint: false,
41
- },
42
- }, async ({ query, collections, limit, filter }) => {
43
- if (collections) {
44
- for (const c of collections) {
45
- assertCollectionAllowed(c);
46
- }
47
- }
48
- return jsonResult(await db.search(query, { collections, limit, filter }));
49
- });
50
- server.registerTool("thing_get", {
51
- title: "Get Object",
52
- description: "Read one thingd object by collection name and id. Returns the full object if found, or null if not found. Use this to retrieve a specific stored record when you know its exact collection and id. Returns a single object or null.",
53
- inputSchema: {
54
- collection: z.string().min(1),
55
- id: z.string().min(1),
56
- },
57
- annotations: {
58
- readOnlyHint: true,
59
- destructiveHint: false,
60
- idempotentHint: true,
61
- openWorldHint: false,
62
- },
63
- }, async ({ collection, id }) => {
64
- assertCollectionAllowed(collection);
65
- return jsonResult(await db.get(collection, id));
66
- });
67
- server.registerTool("thing_put", {
68
- title: "Put Object",
69
- description: "Create or replace one object-shaped memory record in a collection. The object must have an 'id' field. If an object with the same id already exists in the collection, it is replaced. Use this to store memories, notes, tasks, or any structured data. Returns the stored object with collection, version, and timestamps.",
70
- inputSchema: {
71
- collection: z.string().min(1),
72
- object: memoryObjectSchema,
73
- ...auditInputSchema,
74
- },
75
- annotations: {
76
- readOnlyHint: false,
77
- destructiveHint: false,
78
- idempotentHint: false,
79
- openWorldHint: false,
80
- },
81
- }, async ({ collection, object, actor, source }) => {
82
- assertWriteAllowed();
83
- assertCollectionAllowed(collection);
84
- const stored = await db.put(collection, object);
85
- await appendMcpAuditEvent(db, audit, {
86
- action: "objects.put",
87
- target: {
88
- collection,
89
- id: stored.id,
90
- },
91
- metadata: auditMetadata(actor, source),
92
- result: {
93
- collection: stored.collection,
94
- id: stored.id,
95
- version: stored.version,
96
- },
97
- });
98
- return jsonResult(stored);
99
- });
100
- server.registerTool("thing_delete", {
101
- title: "Delete Object",
102
- description: "Delete one thingd object by collection name and id. Permanently removes the object from the store. Returns a result indicating whether the deletion was successful. Use this to remove outdated or incorrect records.",
103
- inputSchema: {
104
- collection: z.string().min(1),
105
- id: z.string().min(1),
106
- ...auditInputSchema,
107
- },
108
- annotations: {
109
- readOnlyHint: false,
110
- destructiveHint: true,
111
- idempotentHint: true,
112
- openWorldHint: false,
113
- },
114
- }, async ({ collection, id, actor, source }) => {
115
- assertWriteAllowed();
116
- assertCollectionAllowed(collection);
117
- const result = await db.delete(collection, id);
118
- await appendMcpAuditEvent(db, audit, {
119
- action: "objects.delete",
120
- target: {
121
- collection,
122
- id,
123
- },
124
- metadata: auditMetadata(actor, source),
125
- result,
126
- });
127
- return jsonResult(result);
128
- });
129
- server.registerTool("thing_events_append", {
130
- title: "Append Event",
131
- description: "Append an event to a named event stream. Events are append-only, ordered records with a 'type' field and arbitrary payload. Use this to record occurrences, state changes, or audit entries. Each event gets an auto-incremented sequence id. Returns the stored event with id, stream, and timestamp.",
132
- inputSchema: {
133
- stream: z.string().min(1),
134
- event: memoryEventSchema,
135
- ...auditInputSchema,
136
- },
137
- annotations: {
138
- readOnlyHint: false,
139
- destructiveHint: false,
140
- idempotentHint: false,
141
- openWorldHint: false,
142
- },
143
- }, async ({ stream, event, actor, source }) => {
144
- assertWriteAllowed();
145
- const stored = await db.events.append(stream, event);
146
- await appendMcpAuditEvent(db, audit, {
147
- action: "events.append",
148
- target: {
149
- stream,
150
- eventType: stored.type,
151
- eventId: stored.id,
152
- },
153
- metadata: auditMetadata(actor, source),
154
- result: {
155
- id: stored.id,
156
- stream: stored.stream,
157
- },
158
- });
159
- return jsonResult(stored);
160
- });
161
- server.registerTool("thing_events_list", {
162
- title: "List Events",
163
- description: "List events from a thingd stream, optionally filtered by stream name, starting from a specific sequence number, with a configurable limit. Use this to review recent activity, replay events, or audit changes. Returns an array of events ordered by sequence.",
164
- inputSchema: {
165
- stream: z.string().min(1).optional(),
166
- fromSequence: z.number().int().positive().optional(),
167
- limit: z.number().int().positive().optional(),
168
- },
169
- annotations: {
170
- readOnlyHint: true,
171
- destructiveHint: false,
172
- idempotentHint: true,
173
- openWorldHint: false,
174
- },
175
- }, async ({ stream, fromSequence, limit }) => jsonResult(await db.events.list(stream, { fromSequence, limit })));
176
- server.registerTool("thing_queue_push", {
177
- title: "Push Queue Job",
178
- description: "Push a durable job onto a named queue. Jobs have a JSON payload and can include an idempotency key, max retry attempts, and a delay before the job becomes ready. Use this to schedule background work like processing, notifications, or data pipelines. Returns the created job with id, queue, and status.",
179
- inputSchema: {
180
- queue: z.string().min(1),
181
- payload: objectPayloadSchema,
182
- idempotencyKey: z.string().min(1).optional(),
183
- maxAttempts: z.number().int().positive().max(100).optional(),
184
- delayMs: z.number().int().min(0).optional(),
185
- ...auditInputSchema,
186
- },
187
- annotations: {
188
- readOnlyHint: false,
189
- destructiveHint: false,
190
- idempotentHint: false,
191
- openWorldHint: false,
192
- },
193
- }, async ({ queue, payload, idempotencyKey, maxAttempts, delayMs, actor, source }) => {
194
- assertWriteAllowed();
195
- const job = await db.queue(queue).push(payload, {
196
- idempotencyKey,
197
- maxAttempts,
198
- delayMs,
199
- });
200
- await appendMcpAuditEvent(db, audit, {
201
- action: "queue.push",
202
- target: {
203
- queue,
204
- id: job.id,
205
- },
206
- metadata: auditMetadata(actor, source),
207
- result: {
208
- id: job.id,
209
- queue: job.queue,
210
- status: job.status,
211
- },
212
- });
213
- return jsonResult(job);
214
- });
215
- server.registerTool("thing_queue_claim", {
216
- title: "Claim Queue Job",
217
- description: "Claim the next ready job from a queue. The job is leased for a configurable duration (default 30s). If not acked or nacked before the lease expires, it returns to the ready state. Returns the claimed job with payload, or null if no jobs are ready. Use this to process queue work in a worker loop.",
218
- inputSchema: {
219
- queue: z.string().min(1),
220
- leaseMs: z.number().int().optional(),
221
- ...auditInputSchema,
222
- },
223
- annotations: {
224
- readOnlyHint: false,
225
- destructiveHint: false,
226
- idempotentHint: false,
227
- openWorldHint: false,
228
- },
229
- }, async ({ queue, leaseMs, actor, source }) => {
230
- assertWriteAllowed();
231
- const job = await db.queue(queue).claim({ leaseMs });
232
- if (job) {
233
- await appendMcpAuditEvent(db, audit, {
234
- action: "queue.claim",
235
- target: {
236
- queue,
237
- id: job.id,
238
- },
239
- metadata: auditMetadata(actor, source),
240
- result: {
241
- id: job.id,
242
- queue: job.queue,
243
- status: job.status,
244
- attempts: job.attempts,
245
- },
246
- });
247
- }
248
- return jsonResult(job);
249
- });
250
- server.registerTool("thing_queue_ack", {
251
- title: "Acknowledge Queue Job",
252
- description: "Mark one leased queue job as completed. This removes the job from the queue permanently. Call this after successfully processing a claimed job. Returns a result with ok status and the final job status.",
253
- inputSchema: {
254
- queue: z.string().min(1),
255
- id: z.string().min(1),
256
- ...auditInputSchema,
257
- },
258
- annotations: {
259
- readOnlyHint: false,
260
- destructiveHint: false,
261
- idempotentHint: false,
262
- openWorldHint: false,
263
- },
264
- }, async ({ queue, id, actor, source }) => {
265
- assertWriteAllowed();
266
- const result = await db.queue(queue).ack(id);
267
- if (result.ok) {
268
- await appendMcpAuditEvent(db, audit, {
269
- action: "queue.ack",
270
- target: {
271
- queue,
272
- id,
273
- },
274
- metadata: auditMetadata(actor, source),
275
- result: {
276
- ok: true,
277
- status: result.job.status,
278
- },
279
- });
280
- }
281
- return jsonResult(result);
282
- });
283
- server.registerTool("thing_queue_nack", {
284
- title: "Reject Queue Job",
285
- description: "Reject a leased queue job for retry or dead-letter routing. If the job has remaining attempts, it goes back to ready (optionally after a delay). If attempts are exhausted, it moves to the dead-letter list. Optionally attach an error message. Returns a result with ok status and the updated job status.",
286
- inputSchema: {
287
- queue: z.string().min(1),
288
- id: z.string().min(1),
289
- delayMs: z.number().int().min(0).optional(),
290
- error: z.string().optional(),
291
- ...auditInputSchema,
292
- },
293
- annotations: {
294
- readOnlyHint: false,
295
- destructiveHint: false,
296
- idempotentHint: false,
297
- openWorldHint: false,
298
- },
299
- }, async ({ queue, id, delayMs, error, actor, source }) => {
300
- assertWriteAllowed();
301
- const result = await db.queue(queue).nack(id, { delayMs, error });
302
- if (result.ok) {
303
- await appendMcpAuditEvent(db, audit, {
304
- action: "queue.nack",
305
- target: {
306
- queue,
307
- id,
308
- },
309
- metadata: auditMetadata(actor, source),
310
- result: {
311
- ok: true,
312
- status: result.job.status,
313
- },
314
- });
315
- }
316
- return jsonResult(result);
317
- });
318
- server.registerTool("thing_queue_list", {
319
- title: "List Queue Jobs",
320
- description: "List all jobs in a queue across all states (ready, leased, dead-letter). Use this to inspect queue contents, monitor backlog, or debug stuck jobs. Returns an array of job objects with id, payload, status, attempts, and timestamps.",
321
- inputSchema: {
322
- queue: z.string().min(1),
323
- },
324
- annotations: {
325
- readOnlyHint: true,
326
- destructiveHint: false,
327
- idempotentHint: true,
328
- openWorldHint: false,
329
- },
330
- }, async ({ queue }) => jsonResult(await db.queue(queue).list()));
331
- server.registerTool("thing_queue_dead", {
332
- title: "List Dead Queue Jobs",
333
- description: "List dead-letter jobs in a queue. These are jobs that exhausted all retry attempts. Use this to inspect failed work, diagnose errors, or decide whether to retry or discard. Returns an array of dead-letter job objects.",
334
- inputSchema: {
335
- queue: z.string().min(1),
336
- },
337
- annotations: {
338
- readOnlyHint: true,
339
- destructiveHint: false,
340
- idempotentHint: true,
341
- openWorldHint: false,
342
- },
343
- }, async ({ queue }) => jsonResult(await db.queue(queue).dead()));
344
- server.registerTool("thing_objects_list", {
345
- title: "List Objects",
346
- description: "List objects in a collection with optional filtering, sorting, limit, and offset. Returns an array of objects. Use sortBy.field to sort by id, collection, created_at, updated_at, or version.",
347
- inputSchema: {
348
- collection: z.string().min(1),
349
- filter: z.record(z.string(), z.unknown()).optional(),
350
- sortBy: z
351
- .object({
352
- field: z.enum(["id", "collection", "created_at", "updated_at", "version"]),
353
- direction: z.enum(["asc", "desc"]).default("asc"),
354
- })
355
- .optional(),
356
- limit: z.number().int().positive().optional(),
357
- offset: z.number().int().nonnegative().optional(),
358
- },
359
- annotations: {
360
- readOnlyHint: true,
361
- destructiveHint: false,
362
- idempotentHint: true,
363
- openWorldHint: false,
364
- },
365
- }, async ({ collection, filter, sortBy, limit, offset }) => {
366
- assertCollectionAllowed(collection);
367
- return jsonResult(await db.listObjects(collection, { filter, sortBy, limit, offset }));
368
- });
369
- server.registerTool("thing_count_objects", {
370
- title: "Count Objects",
371
- description: "Count all objects stored across all collections. Returns a single number representing the total object count. Use this for quick inventory checks or monitoring storage usage.",
372
- inputSchema: {},
373
- annotations: {
374
- readOnlyHint: true,
375
- destructiveHint: false,
376
- idempotentHint: true,
377
- openWorldHint: false,
378
- },
379
- }, async () => jsonResult(await db.countObjects()));
380
- server.registerTool("thing_count_events", {
381
- title: "Count Events",
382
- description: "Count all events across all streams. Returns a single number representing the total event count. Use this to monitor event volume or check stream activity.",
383
- inputSchema: {},
384
- annotations: {
385
- readOnlyHint: true,
386
- destructiveHint: false,
387
- idempotentHint: true,
388
- openWorldHint: false,
389
- },
390
- }, async () => jsonResult(await db.countEvents()));
391
- server.registerTool("thing_count_active_jobs", {
392
- title: "Count Active Jobs",
393
- description: "Count all active (non-dead) queue jobs across all queues. Includes ready, leased, and delayed jobs. Use this to monitor queue depth and worker load.",
394
- inputSchema: {},
395
- annotations: {
396
- readOnlyHint: true,
397
- destructiveHint: false,
398
- idempotentHint: true,
399
- openWorldHint: false,
400
- },
401
- }, async () => jsonResult(await db.countActiveJobs()));
402
- server.registerTool("thing_count_dead_jobs", {
403
- title: "Count Dead Jobs",
404
- description: "Count all dead-letter queue jobs across all queues. These are jobs that failed all retry attempts. Use this to monitor failure rates and decide when to investigate or discard.",
405
- inputSchema: {},
406
- annotations: {
407
- readOnlyHint: true,
408
- destructiveHint: false,
409
- idempotentHint: true,
410
- openWorldHint: false,
411
- },
412
- }, async () => jsonResult(await db.countDeadJobs()));
413
- server.registerTool("thing_list_collections", {
414
- title: "List Collections",
415
- description: "List all object collection names in the store. Returns an array of collection name strings. Use this to discover what data is stored before searching or querying.",
416
- inputSchema: {},
417
- annotations: {
418
- readOnlyHint: true,
419
- destructiveHint: false,
420
- idempotentHint: true,
421
- openWorldHint: false,
422
- },
423
- }, async () => jsonResult(await db.listCollections()));
424
- server.registerTool("thing_list_streams", {
425
- title: "List Streams",
426
- description: "List all event stream names in the store. Returns an array of stream name strings. Use this to discover available event streams before listing or appending events.",
427
- inputSchema: {},
428
- annotations: {
429
- readOnlyHint: true,
430
- destructiveHint: false,
431
- idempotentHint: true,
432
- openWorldHint: false,
433
- },
434
- }, async () => jsonResult(await db.listStreams()));
435
- server.registerTool("thing_list_queues", {
436
- title: "List Queues",
437
- description: "List all queue names in the store. Returns an array of queue name strings. Use this to discover available queues before pushing or claiming jobs.",
438
- inputSchema: {},
439
- annotations: {
440
- readOnlyHint: true,
441
- destructiveHint: false,
442
- idempotentHint: true,
443
- openWorldHint: false,
444
- },
445
- }, async () => jsonResult(await db.listQueues()));
446
- server.registerTool("thing_objects_put_batch", {
447
- title: "Put Objects Batch",
448
- description: "Create or replace multiple objects in a collection in a single operation. More efficient than calling thing_put repeatedly. Returns the array of stored objects.",
449
- inputSchema: {
450
- collection: z.string().min(1),
451
- objects: z
452
- .array(z.object({ id: z.string() }).passthrough())
453
- .min(1)
454
- .max(1000),
455
- },
456
- annotations: {
457
- readOnlyHint: false,
458
- destructiveHint: false,
459
- idempotentHint: false,
460
- openWorldHint: false,
461
- },
462
- }, async ({ collection, objects }) => {
463
- assertWriteAllowed();
464
- assertCollectionAllowed(collection);
465
- return jsonResult(await db.putBatch(collection, objects));
466
- });
467
- server.registerTool("thing_objects_delete_batch", {
468
- title: "Delete Objects Batch",
469
- description: "Delete multiple objects by ID in a single operation. Returns the count of deleted objects.",
470
- inputSchema: {
471
- collection: z.string().min(1),
472
- ids: z.array(z.string().min(1)).min(1).max(1000),
473
- },
474
- annotations: {
475
- readOnlyHint: false,
476
- destructiveHint: true,
477
- idempotentHint: true,
478
- openWorldHint: false,
479
- },
480
- }, async ({ collection, ids }) => {
481
- assertWriteAllowed();
482
- assertCollectionAllowed(collection);
483
- const deleted = await db.deleteBatch(collection, ids);
484
- return jsonResult({ deleted });
485
- });
486
- server.registerTool("thing_link_create", {
487
- title: "Create Link",
488
- description: "Create a directed graph link between two references (e.g., thingd objects, external URLs). You can optionally assign a linkType (e.g., 'parent', 'related_to'), weight, and metadata JSON string.",
489
- inputSchema: {
490
- fromRef: z.string().min(1),
491
- linkType: z.string().min(1),
492
- toRef: z.string().min(1),
493
- weight: z.number().optional(),
494
- metadataJson: z.string().optional(),
495
- },
496
- annotations: {
497
- readOnlyHint: false,
498
- destructiveHint: false,
499
- idempotentHint: false,
500
- openWorldHint: false,
501
- },
502
- }, async ({ fromRef, linkType, toRef, weight, metadataJson }) => {
503
- assertWriteAllowed();
504
- return jsonResult(await db.links.create(fromRef, linkType, toRef, weight, metadataJson));
505
- });
506
- server.registerTool("thing_link_delete", {
507
- title: "Delete Link",
508
- description: "Delete a graph link by its id. Returns an object with a deleted boolean.",
509
- inputSchema: {
510
- id: z.string().min(1),
511
- },
512
- annotations: {
513
- readOnlyHint: false,
514
- destructiveHint: true,
515
- idempotentHint: true,
516
- openWorldHint: false,
517
- },
518
- }, async ({ id }) => {
519
- assertWriteAllowed();
520
- return jsonResult({ deleted: await db.links.delete(id) });
521
- });
522
- server.registerTool("thing_link_get", {
523
- title: "Get Link",
524
- description: "Get a graph link by its id.",
525
- inputSchema: {
526
- id: z.string().min(1),
527
- },
528
- annotations: {
529
- readOnlyHint: true,
530
- destructiveHint: false,
531
- idempotentHint: true,
532
- openWorldHint: false,
533
- },
534
- }, async ({ id }) => jsonResult(await db.links.get(id)));
535
- server.registerTool("thing_link_neighbors", {
536
- title: "Get Link Neighbors",
537
- description: "Get all links connected to a specific reference. You can filter by direction (Outgoing, Incoming, Both) and linkType.",
538
- inputSchema: {
539
- reference: z.string().min(1),
540
- direction: z.enum(["Outgoing", "Incoming", "Both"]).optional(),
541
- linkType: z.string().optional(),
542
- limit: z.number().int().positive().optional(),
543
- },
544
- annotations: {
545
- readOnlyHint: true,
546
- destructiveHint: false,
547
- idempotentHint: true,
548
- openWorldHint: false,
549
- },
550
- }, async ({ reference, direction, linkType, limit }) => jsonResult(await db.links.neighbors(reference, direction, { linkType, limit })));
551
- server.registerTool("thing_link_count", {
552
- title: "Count Links",
553
- description: "Count all graph links in the store.",
554
- inputSchema: {},
555
- annotations: {
556
- readOnlyHint: true,
557
- destructiveHint: false,
558
- idempotentHint: true,
559
- openWorldHint: false,
560
- },
561
- }, async () => jsonResult(await db.countLinks()));
562
- }
563
- function auditMetadata(actor, source) {
564
- return {
565
- actor,
566
- source,
567
- };
568
- }
@@ -1,17 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from "node:http";
2
- type SortField = "id" | "collection" | "created_at" | "updated_at" | "version";
3
- type SortDirection = "asc" | "desc";
4
- type LocalSortBy = {
5
- field: SortField;
6
- direction?: SortDirection;
7
- };
8
- export declare function readBody(req: IncomingMessage): Promise<string>;
9
- export declare function sendJson(res: ServerResponse, status: number, data: unknown): void;
10
- export declare function sendData(res: ServerResponse, data: unknown): void;
11
- export declare function sendDataList(res: ServerResponse, data: unknown[], total?: number): void;
12
- export declare function sendError(res: ServerResponse, status: number, code: string, message: string): void;
13
- export declare function parseSortBy(params: URLSearchParams): LocalSortBy | undefined;
14
- export declare function parseFilter(params: URLSearchParams): Record<string, unknown> | undefined;
15
- export declare function parseIntParam(value: string | null): number | undefined;
16
- export {};
17
- //# sourceMappingURL=helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/rest/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE,KAAK,SAAS,GAAG,IAAI,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,SAAS,CAAC;AAC/E,KAAK,aAAa,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpC,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B,CAAC;AAEF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAS9D;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAGjF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAEjE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAEvF;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,cAAc,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,IAAI,CAEN;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,WAAW,GAAG,SAAS,CAY5E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAWxF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAMtE"}
@@ -1,55 +0,0 @@
1
- export function readBody(req) {
2
- return new Promise((resolve, reject) => {
3
- let body = "";
4
- req.on("data", (chunk) => {
5
- body += chunk.toString();
6
- });
7
- req.on("end", () => resolve(body));
8
- req.on("error", reject);
9
- });
10
- }
11
- export function sendJson(res, status, data) {
12
- res.writeHead(status, { "Content-Type": "application/json" });
13
- res.end(JSON.stringify(data));
14
- }
15
- export function sendData(res, data) {
16
- sendJson(res, 200, { data });
17
- }
18
- export function sendDataList(res, data, total) {
19
- sendJson(res, 200, { data, ...(total !== undefined ? { total } : {}) });
20
- }
21
- export function sendError(res, status, code, message) {
22
- sendJson(res, status, { error: { code, message } });
23
- }
24
- export function parseSortBy(params) {
25
- const sort = params.get("sortBy");
26
- if (!sort) {
27
- return undefined;
28
- }
29
- const parts = sort.split(":");
30
- const field = parts[0];
31
- const dir = parts[1] ?? "asc";
32
- if (!field) {
33
- return undefined;
34
- }
35
- return { field: field, direction: dir };
36
- }
37
- export function parseFilter(params) {
38
- const filter = {};
39
- let hasFilter = false;
40
- params.forEach((value, key) => {
41
- if (key.startsWith("filter.")) {
42
- const field = key.slice(7);
43
- filter[field] = value;
44
- hasFilter = true;
45
- }
46
- });
47
- return hasFilter ? filter : undefined;
48
- }
49
- export function parseIntParam(value) {
50
- if (!value) {
51
- return undefined;
52
- }
53
- const n = Number(value);
54
- return Number.isNaN(n) ? undefined : n;
55
- }
@@ -1,4 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from "node:http";
2
- import type { ThingD } from "thingd";
3
- export declare function handleRestRequest(db: ThingD, req: IncomingMessage, res: ServerResponse, pathname: string): Promise<void>;
4
- //# sourceMappingURL=server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/rest/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAwCrC,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA2Uf"}