flightdeck 0.2.3 → 0.2.5

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.
@@ -0,0 +1,1558 @@
1
+ import { z } from "zod";
2
+
3
+ export const lnavFormatSchema = z
4
+ .object({
5
+ regex: z
6
+ .record(
7
+ z.union([
8
+ z
9
+ .object({
10
+ pattern: z
11
+ .string()
12
+ .min(1)
13
+ .describe(
14
+ "The regular expression to match a log message and capture fields.",
15
+ )
16
+ .optional(),
17
+ "module-format": z
18
+ .boolean()
19
+ .describe(
20
+ "If true, this pattern will only be used to parse message bodies of container formats, like syslog",
21
+ )
22
+ .optional(),
23
+ })
24
+ .strict()
25
+ .describe("The set of patterns used to match log messages"),
26
+ z.never(),
27
+ ]),
28
+ )
29
+ .superRefine((value, ctx) => {
30
+ for (const key in value) {
31
+ let evaluated = false;
32
+ if (key.match(/^(.+)$/)) {
33
+ evaluated = true;
34
+ const result = z
35
+ .object({
36
+ pattern: z
37
+ .string()
38
+ .min(1)
39
+ .describe(
40
+ "The regular expression to match a log message and capture fields.",
41
+ )
42
+ .optional(),
43
+ "module-format": z
44
+ .boolean()
45
+ .describe(
46
+ "If true, this pattern will only be used to parse message bodies of container formats, like syslog",
47
+ )
48
+ .optional(),
49
+ })
50
+ .strict()
51
+ .describe("The set of patterns used to match log messages")
52
+ .safeParse(value[key]);
53
+ if (!result.success) {
54
+ ctx.addIssue({
55
+ path: [...ctx.path, key],
56
+ code: "custom",
57
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
58
+ params: {
59
+ issues: result.error.issues,
60
+ },
61
+ });
62
+ }
63
+ }
64
+ if (!evaluated) {
65
+ const result = z.never().safeParse(value[key]);
66
+ if (!result.success) {
67
+ ctx.addIssue({
68
+ path: [...ctx.path, key],
69
+ code: "custom",
70
+ message: "Invalid input: must match catchall schema",
71
+ params: {
72
+ issues: result.error.issues,
73
+ },
74
+ });
75
+ }
76
+ }
77
+ }
78
+ })
79
+ .describe("The set of regular expressions used to match log messages")
80
+ .optional(),
81
+ json: z
82
+ .boolean()
83
+ .describe(
84
+ 'Indicates that log files are JSON-encoded (deprecated, use "file-type": "json")',
85
+ )
86
+ .optional(),
87
+ "convert-to-local-time": z
88
+ .boolean()
89
+ .describe(
90
+ "Indicates that displayed timestamps should automatically be converted to local time",
91
+ )
92
+ .optional(),
93
+ "hide-extra": z
94
+ .boolean()
95
+ .describe(
96
+ "Specifies whether extra values in JSON logs should be displayed",
97
+ )
98
+ .optional(),
99
+ multiline: z
100
+ .boolean()
101
+ .describe("Indicates that log messages can span multiple lines")
102
+ .optional(),
103
+ "timestamp-divisor": z
104
+ .union([
105
+ z
106
+ .number()
107
+ .int()
108
+ .describe(
109
+ "The value to divide a numeric timestamp by in a JSON log.",
110
+ ),
111
+ z
112
+ .number()
113
+ .describe(
114
+ "The value to divide a numeric timestamp by in a JSON log.",
115
+ ),
116
+ ])
117
+ .describe("The value to divide a numeric timestamp by in a JSON log.")
118
+ .optional(),
119
+ "file-pattern": z
120
+ .string()
121
+ .describe(
122
+ "A regular expression that restricts this format to log files with a matching name",
123
+ )
124
+ .optional(),
125
+ converter: z
126
+ .object({
127
+ type: z.string().describe("The MIME type").optional(),
128
+ header: z
129
+ .object({
130
+ expr: z
131
+ .record(
132
+ z.union([z.string().describe("SQLite expression"), z.never()]),
133
+ )
134
+ .superRefine((value, ctx) => {
135
+ for (const key in value) {
136
+ let evaluated = false;
137
+ if (key.match(/^(\w+)$/)) {
138
+ evaluated = true;
139
+ const result = z
140
+ .string()
141
+ .describe("SQLite expression")
142
+ .safeParse(value[key]);
143
+ if (!result.success) {
144
+ ctx.addIssue({
145
+ path: [...ctx.path, key],
146
+ code: "custom",
147
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
148
+ params: {
149
+ issues: result.error.issues,
150
+ },
151
+ });
152
+ }
153
+ }
154
+ if (!evaluated) {
155
+ const result = z.never().safeParse(value[key]);
156
+ if (!result.success) {
157
+ ctx.addIssue({
158
+ path: [...ctx.path, key],
159
+ code: "custom",
160
+ message: "Invalid input: must match catchall schema",
161
+ params: {
162
+ issues: result.error.issues,
163
+ },
164
+ });
165
+ }
166
+ }
167
+ }
168
+ })
169
+ .describe(
170
+ "The expressions used to check if a file header matches this file format",
171
+ )
172
+ .optional(),
173
+ size: z
174
+ .number()
175
+ .int()
176
+ .describe("The minimum size required for this header type")
177
+ .optional(),
178
+ })
179
+ .strict()
180
+ .describe("File header detection definitions")
181
+ .optional(),
182
+ command: z
183
+ .string()
184
+ .regex(/[\w.-]+/)
185
+ .describe("The script used to convert the file")
186
+ .optional(),
187
+ })
188
+ .strict()
189
+ .describe(
190
+ "Describes how the file format can be detected and converted to a log that can be understood by lnav",
191
+ )
192
+ .optional(),
193
+ "level-field": z
194
+ .string()
195
+ .describe("The name of the level field in the log message pattern")
196
+ .optional(),
197
+ "level-pointer": z
198
+ .string()
199
+ .describe(
200
+ "A regular-expression that matches the JSON-pointer of the level property",
201
+ )
202
+ .optional(),
203
+ "timestamp-field": z
204
+ .string()
205
+ .describe("The name of the timestamp field in the log message pattern")
206
+ .optional(),
207
+ "subsecond-field": z
208
+ .string()
209
+ .describe(
210
+ "The path to the property in a JSON-lines log message that contains the sub-second time value",
211
+ )
212
+ .optional(),
213
+ "subsecond-units": z
214
+ .enum(["milli", "micro", "nano"])
215
+ .describe("The units of the subsecond-field property value")
216
+ .optional(),
217
+ "time-field": z
218
+ .string()
219
+ .describe(
220
+ "The name of the time field in the log message pattern. This field should only be specified if the timestamp field only contains a date.",
221
+ )
222
+ .optional(),
223
+ "body-field": z
224
+ .string()
225
+ .describe("The name of the body field in the log message pattern")
226
+ .optional(),
227
+ url: z
228
+ .union([
229
+ z
230
+ .array(z.string())
231
+ .describe("A URL with more information about this log format"),
232
+ z
233
+ .string()
234
+ .describe("A URL with more information about this log format"),
235
+ ])
236
+ .describe("A URL with more information about this log format")
237
+ .optional(),
238
+ title: z
239
+ .string()
240
+ .describe("The human-readable name for this log format")
241
+ .optional(),
242
+ description: z
243
+ .string()
244
+ .describe("A longer description of this log format")
245
+ .optional(),
246
+ "timestamp-format": z
247
+ .array(z.string())
248
+ .describe("An array of strptime(3)-like timestamp formats")
249
+ .optional(),
250
+ "module-field": z
251
+ .string()
252
+ .describe("The name of the module field in the log message pattern")
253
+ .optional(),
254
+ "opid-field": z
255
+ .string()
256
+ .describe("The name of the operation-id field in the log message pattern")
257
+ .optional(),
258
+ opid: z
259
+ .object({
260
+ subid: z
261
+ .string()
262
+ .describe("The field that holds the ID for a sub-operation")
263
+ .optional(),
264
+ description: z
265
+ .record(
266
+ z.union([
267
+ z
268
+ .object({
269
+ format: z
270
+ .array(
271
+ z
272
+ .object({
273
+ field: z
274
+ .string()
275
+ .describe(
276
+ "The field to include in the operation description",
277
+ )
278
+ .optional(),
279
+ extractor: z
280
+ .string()
281
+ .describe(
282
+ "The regex used to extract content for the operation description",
283
+ )
284
+ .optional(),
285
+ prefix: z
286
+ .string()
287
+ .describe(
288
+ "A string to prepend to this field in the description",
289
+ )
290
+ .optional(),
291
+ suffix: z
292
+ .string()
293
+ .describe(
294
+ "A string to append to this field in the description",
295
+ )
296
+ .optional(),
297
+ joiner: z
298
+ .string()
299
+ .describe(
300
+ "A string to insert between instances of this field when the field is found more than once",
301
+ )
302
+ .optional(),
303
+ })
304
+ .strict(),
305
+ )
306
+ .describe(
307
+ "Defines the elements of this operation description",
308
+ )
309
+ .optional(),
310
+ })
311
+ .strict()
312
+ .describe("A type of description for this operation"),
313
+ z.never(),
314
+ ]),
315
+ )
316
+ .superRefine((value, ctx) => {
317
+ for (const key in value) {
318
+ let evaluated = false;
319
+ if (key.match(/^([\w.-]+)$/)) {
320
+ evaluated = true;
321
+ const result = z
322
+ .object({
323
+ format: z
324
+ .array(
325
+ z
326
+ .object({
327
+ field: z
328
+ .string()
329
+ .describe(
330
+ "The field to include in the operation description",
331
+ )
332
+ .optional(),
333
+ extractor: z
334
+ .string()
335
+ .describe(
336
+ "The regex used to extract content for the operation description",
337
+ )
338
+ .optional(),
339
+ prefix: z
340
+ .string()
341
+ .describe(
342
+ "A string to prepend to this field in the description",
343
+ )
344
+ .optional(),
345
+ suffix: z
346
+ .string()
347
+ .describe(
348
+ "A string to append to this field in the description",
349
+ )
350
+ .optional(),
351
+ joiner: z
352
+ .string()
353
+ .describe(
354
+ "A string to insert between instances of this field when the field is found more than once",
355
+ )
356
+ .optional(),
357
+ })
358
+ .strict(),
359
+ )
360
+ .describe(
361
+ "Defines the elements of this operation description",
362
+ )
363
+ .optional(),
364
+ })
365
+ .strict()
366
+ .describe("A type of description for this operation")
367
+ .safeParse(value[key]);
368
+ if (!result.success) {
369
+ ctx.addIssue({
370
+ path: [...ctx.path, key],
371
+ code: "custom",
372
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
373
+ params: {
374
+ issues: result.error.issues,
375
+ },
376
+ });
377
+ }
378
+ }
379
+ if (!evaluated) {
380
+ const result = z.never().safeParse(value[key]);
381
+ if (!result.success) {
382
+ ctx.addIssue({
383
+ path: [...ctx.path, key],
384
+ code: "custom",
385
+ message: "Invalid input: must match catchall schema",
386
+ params: {
387
+ issues: result.error.issues,
388
+ },
389
+ });
390
+ }
391
+ }
392
+ }
393
+ })
394
+ .describe("Define how to construct a description of an operation")
395
+ .optional(),
396
+ "sub-description": z
397
+ .record(
398
+ z.union([
399
+ z
400
+ .object({
401
+ format: z
402
+ .array(
403
+ z
404
+ .object({
405
+ field: z
406
+ .string()
407
+ .describe(
408
+ "The field to include in the operation description",
409
+ )
410
+ .optional(),
411
+ extractor: z
412
+ .string()
413
+ .describe(
414
+ "The regex used to extract content for the operation description",
415
+ )
416
+ .optional(),
417
+ prefix: z
418
+ .string()
419
+ .describe(
420
+ "A string to prepend to this field in the description",
421
+ )
422
+ .optional(),
423
+ suffix: z
424
+ .string()
425
+ .describe(
426
+ "A string to append to this field in the description",
427
+ )
428
+ .optional(),
429
+ joiner: z
430
+ .string()
431
+ .describe(
432
+ "A string to insert between instances of this field when the field is found more than once",
433
+ )
434
+ .optional(),
435
+ })
436
+ .strict(),
437
+ )
438
+ .describe(
439
+ "Defines the elements of this operation description",
440
+ )
441
+ .optional(),
442
+ })
443
+ .strict()
444
+ .describe("A type of description for this sub-operation"),
445
+ z.never(),
446
+ ]),
447
+ )
448
+ .superRefine((value, ctx) => {
449
+ for (const key in value) {
450
+ let evaluated = false;
451
+ if (key.match(/^([\w.-]+)$/)) {
452
+ evaluated = true;
453
+ const result = z
454
+ .object({
455
+ format: z
456
+ .array(
457
+ z
458
+ .object({
459
+ field: z
460
+ .string()
461
+ .describe(
462
+ "The field to include in the operation description",
463
+ )
464
+ .optional(),
465
+ extractor: z
466
+ .string()
467
+ .describe(
468
+ "The regex used to extract content for the operation description",
469
+ )
470
+ .optional(),
471
+ prefix: z
472
+ .string()
473
+ .describe(
474
+ "A string to prepend to this field in the description",
475
+ )
476
+ .optional(),
477
+ suffix: z
478
+ .string()
479
+ .describe(
480
+ "A string to append to this field in the description",
481
+ )
482
+ .optional(),
483
+ joiner: z
484
+ .string()
485
+ .describe(
486
+ "A string to insert between instances of this field when the field is found more than once",
487
+ )
488
+ .optional(),
489
+ })
490
+ .strict(),
491
+ )
492
+ .describe(
493
+ "Defines the elements of this operation description",
494
+ )
495
+ .optional(),
496
+ })
497
+ .strict()
498
+ .describe("A type of description for this sub-operation")
499
+ .safeParse(value[key]);
500
+ if (!result.success) {
501
+ ctx.addIssue({
502
+ path: [...ctx.path, key],
503
+ code: "custom",
504
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
505
+ params: {
506
+ issues: result.error.issues,
507
+ },
508
+ });
509
+ }
510
+ }
511
+ if (!evaluated) {
512
+ const result = z.never().safeParse(value[key]);
513
+ if (!result.success) {
514
+ ctx.addIssue({
515
+ path: [...ctx.path, key],
516
+ code: "custom",
517
+ message: "Invalid input: must match catchall schema",
518
+ params: {
519
+ issues: result.error.issues,
520
+ },
521
+ });
522
+ }
523
+ }
524
+ }
525
+ })
526
+ .describe("Define how to construct a description of a sub-operation")
527
+ .optional(),
528
+ })
529
+ .strict()
530
+ .describe("Definitions related to operations found in logs")
531
+ .optional(),
532
+ "ordered-by-time": z
533
+ .boolean()
534
+ .describe(
535
+ "Indicates that the order of messages in the file is time-based.",
536
+ )
537
+ .optional(),
538
+ level: z
539
+ .record(
540
+ z.union([
541
+ z
542
+ .union([
543
+ z
544
+ .number()
545
+ .int()
546
+ .describe(
547
+ "The regular expression used to match the log text for this level. For JSON logs with numeric levels, this should be the number for the corresponding level.",
548
+ ),
549
+ z
550
+ .string()
551
+ .describe(
552
+ "The regular expression used to match the log text for this level. For JSON logs with numeric levels, this should be the number for the corresponding level.",
553
+ ),
554
+ ])
555
+ .describe(
556
+ "The regular expression used to match the log text for this level. For JSON logs with numeric levels, this should be the number for the corresponding level.",
557
+ ),
558
+ z.never(),
559
+ ]),
560
+ )
561
+ .superRefine((value, ctx) => {
562
+ for (const key in value) {
563
+ let evaluated = false;
564
+ if (
565
+ key.match(
566
+ /^(trace|debug[2345]?|info|stats|notice|warning|error|critical|fatal)$/,
567
+ )
568
+ ) {
569
+ evaluated = true;
570
+ const result = z
571
+ .union([
572
+ z
573
+ .number()
574
+ .int()
575
+ .describe(
576
+ "The regular expression used to match the log text for this level. For JSON logs with numeric levels, this should be the number for the corresponding level.",
577
+ ),
578
+ z
579
+ .string()
580
+ .describe(
581
+ "The regular expression used to match the log text for this level. For JSON logs with numeric levels, this should be the number for the corresponding level.",
582
+ ),
583
+ ])
584
+ .describe(
585
+ "The regular expression used to match the log text for this level. For JSON logs with numeric levels, this should be the number for the corresponding level.",
586
+ )
587
+ .safeParse(value[key]);
588
+ if (!result.success) {
589
+ ctx.addIssue({
590
+ path: [...ctx.path, key],
591
+ code: "custom",
592
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
593
+ params: {
594
+ issues: result.error.issues,
595
+ },
596
+ });
597
+ }
598
+ }
599
+ if (!evaluated) {
600
+ const result = z.never().safeParse(value[key]);
601
+ if (!result.success) {
602
+ ctx.addIssue({
603
+ path: [...ctx.path, key],
604
+ code: "custom",
605
+ message: "Invalid input: must match catchall schema",
606
+ params: {
607
+ issues: result.error.issues,
608
+ },
609
+ });
610
+ }
611
+ }
612
+ }
613
+ })
614
+ .describe("The map of level names to patterns or integer values")
615
+ .optional(),
616
+ value: z
617
+ .record(
618
+ z.union([
619
+ z
620
+ .object({
621
+ kind: z
622
+ .enum([
623
+ "string",
624
+ "integer",
625
+ "float",
626
+ "boolean",
627
+ "json",
628
+ "struct",
629
+ "quoted",
630
+ "xml",
631
+ ])
632
+ .describe("The type of data in the field")
633
+ .optional(),
634
+ collate: z
635
+ .string()
636
+ .describe("The collating function to use for this column")
637
+ .optional(),
638
+ unit: z
639
+ .object({
640
+ field: z
641
+ .string()
642
+ .describe(
643
+ "The name of the field that contains the units for this field",
644
+ )
645
+ .optional(),
646
+ "scaling-factor": z
647
+ .record(
648
+ z.union([
649
+ z
650
+ .object({
651
+ op: z
652
+ .enum(["identity", "multiply", "divide"])
653
+ .optional(),
654
+ value: z.number().optional(),
655
+ })
656
+ .strict(),
657
+ z.never(),
658
+ ]),
659
+ )
660
+ .superRefine((value, ctx) => {
661
+ for (const key in value) {
662
+ let evaluated = false;
663
+ if (key.match(/^(.+)$/)) {
664
+ evaluated = true;
665
+ const result = z
666
+ .object({
667
+ op: z
668
+ .enum(["identity", "multiply", "divide"])
669
+ .optional(),
670
+ value: z.number().optional(),
671
+ })
672
+ .strict()
673
+ .safeParse(value[key]);
674
+ if (!result.success) {
675
+ ctx.addIssue({
676
+ path: [...ctx.path, key],
677
+ code: "custom",
678
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
679
+ params: {
680
+ issues: result.error.issues,
681
+ },
682
+ });
683
+ }
684
+ }
685
+ if (!evaluated) {
686
+ const result = z.never().safeParse(value[key]);
687
+ if (!result.success) {
688
+ ctx.addIssue({
689
+ path: [...ctx.path, key],
690
+ code: "custom",
691
+ message: "Invalid input: must match catchall schema",
692
+ params: {
693
+ issues: result.error.issues,
694
+ },
695
+ });
696
+ }
697
+ }
698
+ }
699
+ })
700
+ .describe(
701
+ "Transforms the numeric value by the given factor",
702
+ )
703
+ .optional(),
704
+ })
705
+ .strict()
706
+ .describe("Unit definitions for this field")
707
+ .optional(),
708
+ identifier: z
709
+ .boolean()
710
+ .describe(
711
+ "Indicates whether or not this field contains an identifier that should be highlighted",
712
+ )
713
+ .optional(),
714
+ "foreign-key": z
715
+ .boolean()
716
+ .describe(
717
+ "Indicates whether or not this field should be treated as a foreign key for row in another table",
718
+ )
719
+ .optional(),
720
+ hidden: z
721
+ .boolean()
722
+ .describe(
723
+ "Indicates whether or not this field should be hidden",
724
+ )
725
+ .optional(),
726
+ "action-list": z
727
+ .array(z.string())
728
+ .describe("Actions to execute when this field is clicked on")
729
+ .optional(),
730
+ rewriter: z
731
+ .string()
732
+ .describe(
733
+ "A command that will rewrite this field when pretty-printing",
734
+ )
735
+ .optional(),
736
+ description: z
737
+ .string()
738
+ .describe("A description of the field")
739
+ .optional(),
740
+ })
741
+ .strict()
742
+ .describe("The set of values captured by the log message patterns"),
743
+ z.never(),
744
+ ]),
745
+ )
746
+ .superRefine((value, ctx) => {
747
+ for (const key in value) {
748
+ let evaluated = false;
749
+ if (key.match(/^(.+)$/)) {
750
+ evaluated = true;
751
+ const result = z
752
+ .object({
753
+ kind: z
754
+ .enum([
755
+ "string",
756
+ "integer",
757
+ "float",
758
+ "boolean",
759
+ "json",
760
+ "struct",
761
+ "quoted",
762
+ "xml",
763
+ ])
764
+ .describe("The type of data in the field")
765
+ .optional(),
766
+ collate: z
767
+ .string()
768
+ .describe("The collating function to use for this column")
769
+ .optional(),
770
+ unit: z
771
+ .object({
772
+ field: z
773
+ .string()
774
+ .describe(
775
+ "The name of the field that contains the units for this field",
776
+ )
777
+ .optional(),
778
+ "scaling-factor": z
779
+ .record(
780
+ z.union([
781
+ z
782
+ .object({
783
+ op: z
784
+ .enum(["identity", "multiply", "divide"])
785
+ .optional(),
786
+ value: z.number().optional(),
787
+ })
788
+ .strict(),
789
+ z.never(),
790
+ ]),
791
+ )
792
+ .superRefine((value, ctx) => {
793
+ for (const key in value) {
794
+ let evaluated = false;
795
+ if (key.match(/^(.+)$/)) {
796
+ evaluated = true;
797
+ const result = z
798
+ .object({
799
+ op: z
800
+ .enum(["identity", "multiply", "divide"])
801
+ .optional(),
802
+ value: z.number().optional(),
803
+ })
804
+ .strict()
805
+ .safeParse(value[key]);
806
+ if (!result.success) {
807
+ ctx.addIssue({
808
+ path: [...ctx.path, key],
809
+ code: "custom",
810
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
811
+ params: {
812
+ issues: result.error.issues,
813
+ },
814
+ });
815
+ }
816
+ }
817
+ if (!evaluated) {
818
+ const result = z.never().safeParse(value[key]);
819
+ if (!result.success) {
820
+ ctx.addIssue({
821
+ path: [...ctx.path, key],
822
+ code: "custom",
823
+ message: "Invalid input: must match catchall schema",
824
+ params: {
825
+ issues: result.error.issues,
826
+ },
827
+ });
828
+ }
829
+ }
830
+ }
831
+ })
832
+ .describe(
833
+ "Transforms the numeric value by the given factor",
834
+ )
835
+ .optional(),
836
+ })
837
+ .strict()
838
+ .describe("Unit definitions for this field")
839
+ .optional(),
840
+ identifier: z
841
+ .boolean()
842
+ .describe(
843
+ "Indicates whether or not this field contains an identifier that should be highlighted",
844
+ )
845
+ .optional(),
846
+ "foreign-key": z
847
+ .boolean()
848
+ .describe(
849
+ "Indicates whether or not this field should be treated as a foreign key for row in another table",
850
+ )
851
+ .optional(),
852
+ hidden: z
853
+ .boolean()
854
+ .describe(
855
+ "Indicates whether or not this field should be hidden",
856
+ )
857
+ .optional(),
858
+ "action-list": z
859
+ .array(z.string())
860
+ .describe("Actions to execute when this field is clicked on")
861
+ .optional(),
862
+ rewriter: z
863
+ .string()
864
+ .describe(
865
+ "A command that will rewrite this field when pretty-printing",
866
+ )
867
+ .optional(),
868
+ description: z
869
+ .string()
870
+ .describe("A description of the field")
871
+ .optional(),
872
+ })
873
+ .strict()
874
+ .describe(
875
+ "The set of values captured by the log message patterns",
876
+ )
877
+ .safeParse(value[key]);
878
+ if (!result.success) {
879
+ ctx.addIssue({
880
+ path: [...ctx.path, key],
881
+ code: "custom",
882
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
883
+ params: {
884
+ issues: result.error.issues,
885
+ },
886
+ });
887
+ }
888
+ }
889
+ if (!evaluated) {
890
+ const result = z.never().safeParse(value[key]);
891
+ if (!result.success) {
892
+ ctx.addIssue({
893
+ path: [...ctx.path, key],
894
+ code: "custom",
895
+ message: "Invalid input: must match catchall schema",
896
+ params: {
897
+ issues: result.error.issues,
898
+ },
899
+ });
900
+ }
901
+ }
902
+ }
903
+ })
904
+ .describe("The set of value definitions")
905
+ .optional(),
906
+ tags: z
907
+ .record(
908
+ z.union([
909
+ z
910
+ .object({
911
+ paths: z
912
+ .array(
913
+ z
914
+ .object({
915
+ glob: z
916
+ .string()
917
+ .describe("The glob to match against file paths")
918
+ .optional(),
919
+ })
920
+ .strict(),
921
+ )
922
+ .describe("Restrict tagging to the given paths")
923
+ .optional(),
924
+ pattern: z
925
+ .string()
926
+ .describe(
927
+ "The regular expression to match against the body of the log message",
928
+ )
929
+ .optional(),
930
+ description: z
931
+ .string()
932
+ .describe("A description of this tag")
933
+ .optional(),
934
+ level: z
935
+ .enum([
936
+ "trace",
937
+ "debug5",
938
+ "debug4",
939
+ "debug3",
940
+ "debug2",
941
+ "debug",
942
+ "info",
943
+ "stats",
944
+ "notice",
945
+ "warning",
946
+ "error",
947
+ "critical",
948
+ "fatal",
949
+ ])
950
+ .describe("Constrain hits to log messages with this level")
951
+ .optional(),
952
+ })
953
+ .strict()
954
+ .describe("The name of the tag to apply"),
955
+ z.never(),
956
+ ]),
957
+ )
958
+ .superRefine((value, ctx) => {
959
+ for (const key in value) {
960
+ let evaluated = false;
961
+ if (key.match(/^([\w:;._-]+)$/)) {
962
+ evaluated = true;
963
+ const result = z
964
+ .object({
965
+ paths: z
966
+ .array(
967
+ z
968
+ .object({
969
+ glob: z
970
+ .string()
971
+ .describe("The glob to match against file paths")
972
+ .optional(),
973
+ })
974
+ .strict(),
975
+ )
976
+ .describe("Restrict tagging to the given paths")
977
+ .optional(),
978
+ pattern: z
979
+ .string()
980
+ .describe(
981
+ "The regular expression to match against the body of the log message",
982
+ )
983
+ .optional(),
984
+ description: z
985
+ .string()
986
+ .describe("A description of this tag")
987
+ .optional(),
988
+ level: z
989
+ .enum([
990
+ "trace",
991
+ "debug5",
992
+ "debug4",
993
+ "debug3",
994
+ "debug2",
995
+ "debug",
996
+ "info",
997
+ "stats",
998
+ "notice",
999
+ "warning",
1000
+ "error",
1001
+ "critical",
1002
+ "fatal",
1003
+ ])
1004
+ .describe("Constrain hits to log messages with this level")
1005
+ .optional(),
1006
+ })
1007
+ .strict()
1008
+ .describe("The name of the tag to apply")
1009
+ .safeParse(value[key]);
1010
+ if (!result.success) {
1011
+ ctx.addIssue({
1012
+ path: [...ctx.path, key],
1013
+ code: "custom",
1014
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
1015
+ params: {
1016
+ issues: result.error.issues,
1017
+ },
1018
+ });
1019
+ }
1020
+ }
1021
+ if (!evaluated) {
1022
+ const result = z.never().safeParse(value[key]);
1023
+ if (!result.success) {
1024
+ ctx.addIssue({
1025
+ path: [...ctx.path, key],
1026
+ code: "custom",
1027
+ message: "Invalid input: must match catchall schema",
1028
+ params: {
1029
+ issues: result.error.issues,
1030
+ },
1031
+ });
1032
+ }
1033
+ }
1034
+ }
1035
+ })
1036
+ .describe("The tags to automatically apply to log messages")
1037
+ .optional(),
1038
+ partitions: z
1039
+ .record(
1040
+ z.union([
1041
+ z
1042
+ .object({
1043
+ paths: z
1044
+ .array(
1045
+ z
1046
+ .object({
1047
+ glob: z
1048
+ .string()
1049
+ .describe("The glob to match against file paths")
1050
+ .optional(),
1051
+ })
1052
+ .strict(),
1053
+ )
1054
+ .describe("Restrict partitioning to the given paths")
1055
+ .optional(),
1056
+ pattern: z
1057
+ .string()
1058
+ .describe(
1059
+ "The regular expression to match against the body of the log message",
1060
+ )
1061
+ .optional(),
1062
+ description: z
1063
+ .string()
1064
+ .describe("A description of this partition")
1065
+ .optional(),
1066
+ level: z
1067
+ .enum([
1068
+ "trace",
1069
+ "debug5",
1070
+ "debug4",
1071
+ "debug3",
1072
+ "debug2",
1073
+ "debug",
1074
+ "info",
1075
+ "stats",
1076
+ "notice",
1077
+ "warning",
1078
+ "error",
1079
+ "critical",
1080
+ "fatal",
1081
+ ])
1082
+ .describe("Constrain hits to log messages with this level")
1083
+ .optional(),
1084
+ })
1085
+ .strict()
1086
+ .describe("The type of partition to apply"),
1087
+ z.never(),
1088
+ ]),
1089
+ )
1090
+ .superRefine((value, ctx) => {
1091
+ for (const key in value) {
1092
+ let evaluated = false;
1093
+ if (key.match(/^([\w:;._-]+)$/)) {
1094
+ evaluated = true;
1095
+ const result = z
1096
+ .object({
1097
+ paths: z
1098
+ .array(
1099
+ z
1100
+ .object({
1101
+ glob: z
1102
+ .string()
1103
+ .describe("The glob to match against file paths")
1104
+ .optional(),
1105
+ })
1106
+ .strict(),
1107
+ )
1108
+ .describe("Restrict partitioning to the given paths")
1109
+ .optional(),
1110
+ pattern: z
1111
+ .string()
1112
+ .describe(
1113
+ "The regular expression to match against the body of the log message",
1114
+ )
1115
+ .optional(),
1116
+ description: z
1117
+ .string()
1118
+ .describe("A description of this partition")
1119
+ .optional(),
1120
+ level: z
1121
+ .enum([
1122
+ "trace",
1123
+ "debug5",
1124
+ "debug4",
1125
+ "debug3",
1126
+ "debug2",
1127
+ "debug",
1128
+ "info",
1129
+ "stats",
1130
+ "notice",
1131
+ "warning",
1132
+ "error",
1133
+ "critical",
1134
+ "fatal",
1135
+ ])
1136
+ .describe("Constrain hits to log messages with this level")
1137
+ .optional(),
1138
+ })
1139
+ .strict()
1140
+ .describe("The type of partition to apply")
1141
+ .safeParse(value[key]);
1142
+ if (!result.success) {
1143
+ ctx.addIssue({
1144
+ path: [...ctx.path, key],
1145
+ code: "custom",
1146
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
1147
+ params: {
1148
+ issues: result.error.issues,
1149
+ },
1150
+ });
1151
+ }
1152
+ }
1153
+ if (!evaluated) {
1154
+ const result = z.never().safeParse(value[key]);
1155
+ if (!result.success) {
1156
+ ctx.addIssue({
1157
+ path: [...ctx.path, key],
1158
+ code: "custom",
1159
+ message: "Invalid input: must match catchall schema",
1160
+ params: {
1161
+ issues: result.error.issues,
1162
+ },
1163
+ });
1164
+ }
1165
+ }
1166
+ }
1167
+ })
1168
+ .describe("The partitions to automatically apply to log messages")
1169
+ .optional(),
1170
+ action: z
1171
+ .record(
1172
+ z.union([
1173
+ z.union([
1174
+ z.string(),
1175
+ z
1176
+ .object({
1177
+ label: z.string().optional(),
1178
+ "capture-output": z.boolean().optional(),
1179
+ cmd: z.array(z.string()).optional(),
1180
+ })
1181
+ .strict(),
1182
+ ]),
1183
+ z.never(),
1184
+ ]),
1185
+ )
1186
+ .superRefine((value, ctx) => {
1187
+ for (const key in value) {
1188
+ let evaluated = false;
1189
+ if (key.match(/^(\w+)$/)) {
1190
+ evaluated = true;
1191
+ const result = z
1192
+ .union([
1193
+ z.string(),
1194
+ z
1195
+ .object({
1196
+ label: z.string().optional(),
1197
+ "capture-output": z.boolean().optional(),
1198
+ cmd: z.array(z.string()).optional(),
1199
+ })
1200
+ .strict(),
1201
+ ])
1202
+ .safeParse(value[key]);
1203
+ if (!result.success) {
1204
+ ctx.addIssue({
1205
+ path: [...ctx.path, key],
1206
+ code: "custom",
1207
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
1208
+ params: {
1209
+ issues: result.error.issues,
1210
+ },
1211
+ });
1212
+ }
1213
+ }
1214
+ if (!evaluated) {
1215
+ const result = z.never().safeParse(value[key]);
1216
+ if (!result.success) {
1217
+ ctx.addIssue({
1218
+ path: [...ctx.path, key],
1219
+ code: "custom",
1220
+ message: "Invalid input: must match catchall schema",
1221
+ params: {
1222
+ issues: result.error.issues,
1223
+ },
1224
+ });
1225
+ }
1226
+ }
1227
+ }
1228
+ })
1229
+ .optional(),
1230
+ sample: z
1231
+ .array(
1232
+ z
1233
+ .object({
1234
+ description: z
1235
+ .string()
1236
+ .describe("A description of this sample.")
1237
+ .optional(),
1238
+ line: z
1239
+ .string()
1240
+ .describe(
1241
+ "A sample log line that should match a pattern in this format.",
1242
+ )
1243
+ .optional(),
1244
+ level: z
1245
+ .enum([
1246
+ "trace",
1247
+ "debug5",
1248
+ "debug4",
1249
+ "debug3",
1250
+ "debug2",
1251
+ "debug",
1252
+ "info",
1253
+ "stats",
1254
+ "notice",
1255
+ "warning",
1256
+ "error",
1257
+ "critical",
1258
+ "fatal",
1259
+ ])
1260
+ .describe("The expected level for this sample log line.")
1261
+ .optional(),
1262
+ })
1263
+ .strict(),
1264
+ )
1265
+ .describe(
1266
+ "An array of sample log messages to be tested against the log message patterns",
1267
+ )
1268
+ .optional(),
1269
+ "line-format": z
1270
+ .array(
1271
+ z.union([
1272
+ z.string(),
1273
+ z
1274
+ .object({
1275
+ field: z
1276
+ .string()
1277
+ .describe(
1278
+ "The name of the field to substitute at this position",
1279
+ )
1280
+ .optional(),
1281
+ "default-value": z
1282
+ .string()
1283
+ .describe(
1284
+ "The default value for this position if the field is null",
1285
+ )
1286
+ .optional(),
1287
+ "timestamp-format": z
1288
+ .string()
1289
+ .min(1)
1290
+ .describe("The strftime(3) format for this field")
1291
+ .optional(),
1292
+ "min-width": z
1293
+ .number()
1294
+ .int()
1295
+ .gte(0)
1296
+ .describe("The minimum width of the field")
1297
+ .optional(),
1298
+ "auto-width": z
1299
+ .boolean()
1300
+ .describe(
1301
+ "Automatically detect the necessary width of the field based on the observed values",
1302
+ )
1303
+ .optional(),
1304
+ "max-width": z
1305
+ .number()
1306
+ .int()
1307
+ .gte(0)
1308
+ .describe("The maximum width of the field")
1309
+ .optional(),
1310
+ align: z
1311
+ .enum(["left", "right"])
1312
+ .describe(
1313
+ "Align the text in the column to the left or right side",
1314
+ )
1315
+ .optional(),
1316
+ overflow: z
1317
+ .enum(["abbrev", "truncate", "dot-dot", "last-word"])
1318
+ .describe("Overflow style")
1319
+ .optional(),
1320
+ "text-transform": z
1321
+ .enum(["none", "uppercase", "lowercase", "capitalize"])
1322
+ .describe("Text transformation")
1323
+ .optional(),
1324
+ prefix: z
1325
+ .string()
1326
+ .describe("Text to prepend to the value")
1327
+ .optional(),
1328
+ suffix: z
1329
+ .string()
1330
+ .describe("Text to append to the value")
1331
+ .optional(),
1332
+ })
1333
+ .strict(),
1334
+ ]),
1335
+ )
1336
+ .describe("The display format for JSON-encoded log messages")
1337
+ .optional(),
1338
+ "search-table": z
1339
+ .record(
1340
+ z.union([
1341
+ z
1342
+ .object({
1343
+ pattern: z
1344
+ .string()
1345
+ .describe("The regular expression for this search table.")
1346
+ .optional(),
1347
+ glob: z
1348
+ .string()
1349
+ .describe(
1350
+ "Glob pattern used to constrain hits to messages that match the given pattern.",
1351
+ )
1352
+ .optional(),
1353
+ level: z
1354
+ .enum([
1355
+ "trace",
1356
+ "debug5",
1357
+ "debug4",
1358
+ "debug3",
1359
+ "debug2",
1360
+ "debug",
1361
+ "info",
1362
+ "stats",
1363
+ "notice",
1364
+ "warning",
1365
+ "error",
1366
+ "critical",
1367
+ "fatal",
1368
+ ])
1369
+ .describe("Constrain hits to log messages with this level")
1370
+ .optional(),
1371
+ })
1372
+ .strict()
1373
+ .describe("The set of search tables to be automatically defined"),
1374
+ z.never(),
1375
+ ]),
1376
+ )
1377
+ .superRefine((value, ctx) => {
1378
+ for (const key in value) {
1379
+ let evaluated = false;
1380
+ if (key.match(/^(\w+)$/)) {
1381
+ evaluated = true;
1382
+ const result = z
1383
+ .object({
1384
+ pattern: z
1385
+ .string()
1386
+ .describe("The regular expression for this search table.")
1387
+ .optional(),
1388
+ glob: z
1389
+ .string()
1390
+ .describe(
1391
+ "Glob pattern used to constrain hits to messages that match the given pattern.",
1392
+ )
1393
+ .optional(),
1394
+ level: z
1395
+ .enum([
1396
+ "trace",
1397
+ "debug5",
1398
+ "debug4",
1399
+ "debug3",
1400
+ "debug2",
1401
+ "debug",
1402
+ "info",
1403
+ "stats",
1404
+ "notice",
1405
+ "warning",
1406
+ "error",
1407
+ "critical",
1408
+ "fatal",
1409
+ ])
1410
+ .describe("Constrain hits to log messages with this level")
1411
+ .optional(),
1412
+ })
1413
+ .strict()
1414
+ .describe("The set of search tables to be automatically defined")
1415
+ .safeParse(value[key]);
1416
+ if (!result.success) {
1417
+ ctx.addIssue({
1418
+ path: [...ctx.path, key],
1419
+ code: "custom",
1420
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
1421
+ params: {
1422
+ issues: result.error.issues,
1423
+ },
1424
+ });
1425
+ }
1426
+ }
1427
+ if (!evaluated) {
1428
+ const result = z.never().safeParse(value[key]);
1429
+ if (!result.success) {
1430
+ ctx.addIssue({
1431
+ path: [...ctx.path, key],
1432
+ code: "custom",
1433
+ message: "Invalid input: must match catchall schema",
1434
+ params: {
1435
+ issues: result.error.issues,
1436
+ },
1437
+ });
1438
+ }
1439
+ }
1440
+ }
1441
+ })
1442
+ .describe("Search tables to automatically define for this log format")
1443
+ .optional(),
1444
+ highlights: z
1445
+ .record(
1446
+ z.union([
1447
+ z
1448
+ .object({
1449
+ pattern: z
1450
+ .string()
1451
+ .describe(
1452
+ "A regular expression to highlight in logs of this format.",
1453
+ )
1454
+ .optional(),
1455
+ color: z
1456
+ .string()
1457
+ .describe("The color to use when highlighting this pattern.")
1458
+ .optional(),
1459
+ "background-color": z
1460
+ .string()
1461
+ .describe(
1462
+ "The background color to use when highlighting this pattern.",
1463
+ )
1464
+ .optional(),
1465
+ underline: z
1466
+ .boolean()
1467
+ .describe("Highlight this pattern with an underline.")
1468
+ .optional(),
1469
+ blink: z
1470
+ .boolean()
1471
+ .describe("Highlight this pattern by blinking.")
1472
+ .optional(),
1473
+ })
1474
+ .strict()
1475
+ .describe("The definition of a highlight"),
1476
+ z.never(),
1477
+ ]),
1478
+ )
1479
+ .superRefine((value, ctx) => {
1480
+ for (const key in value) {
1481
+ let evaluated = false;
1482
+ if (key.match(/^(.+)$/)) {
1483
+ evaluated = true;
1484
+ const result = z
1485
+ .object({
1486
+ pattern: z
1487
+ .string()
1488
+ .describe(
1489
+ "A regular expression to highlight in logs of this format.",
1490
+ )
1491
+ .optional(),
1492
+ color: z
1493
+ .string()
1494
+ .describe("The color to use when highlighting this pattern.")
1495
+ .optional(),
1496
+ "background-color": z
1497
+ .string()
1498
+ .describe(
1499
+ "The background color to use when highlighting this pattern.",
1500
+ )
1501
+ .optional(),
1502
+ underline: z
1503
+ .boolean()
1504
+ .describe("Highlight this pattern with an underline.")
1505
+ .optional(),
1506
+ blink: z
1507
+ .boolean()
1508
+ .describe("Highlight this pattern by blinking.")
1509
+ .optional(),
1510
+ })
1511
+ .strict()
1512
+ .describe("The definition of a highlight")
1513
+ .safeParse(value[key]);
1514
+ if (!result.success) {
1515
+ ctx.addIssue({
1516
+ path: [...ctx.path, key],
1517
+ code: "custom",
1518
+ message: `Invalid input: Key matching regex /${key}/ must match schema`,
1519
+ params: {
1520
+ issues: result.error.issues,
1521
+ },
1522
+ });
1523
+ }
1524
+ }
1525
+ if (!evaluated) {
1526
+ const result = z.never().safeParse(value[key]);
1527
+ if (!result.success) {
1528
+ ctx.addIssue({
1529
+ path: [...ctx.path, key],
1530
+ code: "custom",
1531
+ message: "Invalid input: must match catchall schema",
1532
+ params: {
1533
+ issues: result.error.issues,
1534
+ },
1535
+ });
1536
+ }
1537
+ }
1538
+ }
1539
+ })
1540
+ .describe("The set of highlight definitions")
1541
+ .optional(),
1542
+ "file-type": z
1543
+ .enum(["text", "json", "csv"])
1544
+ .describe("The type of file that contains the log messages")
1545
+ .optional(),
1546
+ "max-unrecognized-lines": z
1547
+ .number()
1548
+ .int()
1549
+ .gte(1)
1550
+ .describe(
1551
+ "The maximum number of lines in a file to use when detecting the format",
1552
+ )
1553
+ .optional(),
1554
+ })
1555
+ .strict()
1556
+ .describe("The definition of a log file format.");
1557
+
1558
+ export type LnavFormat = z.infer<typeof lnavFormatSchema>;