cwe-api-client 0.0.1 → 1.0.0

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,594 @@
1
+ /**
2
+ * A related weakness reference within a CWE entry.
3
+ */
4
+ interface CweRelatedWeakness {
5
+ /** Relationship nature (e.g. `'ChildOf'`, `'CanPrecede'`, `'PeerOf'`) */
6
+ Nature: string;
7
+ /** Related CWE identifier */
8
+ CweID: string;
9
+ /** View context for this relationship */
10
+ ViewID: string;
11
+ /** Ordinal designation (e.g. `'Primary'`) */
12
+ Ordinal?: string;
13
+ }
14
+ /**
15
+ * Weakness ordinality entry.
16
+ */
17
+ interface CweWeaknessOrdinality {
18
+ /** Ordinality value (e.g. `'Resultant'`, `'Primary'`) */
19
+ Ordinality: string;
20
+ }
21
+ /**
22
+ * An applicable platform entry for a weakness.
23
+ */
24
+ interface CweApplicablePlatform {
25
+ /** Platform type (e.g. `'Language'`, `'Technology'`, `'Operating System'`) */
26
+ Type: string;
27
+ /** Platform class (e.g. `'Not Language-Specific'`, `'Web Based'`) */
28
+ Class?: string;
29
+ /** Platform name (e.g. `'Java'`, `'AI/ML'`) */
30
+ Name?: string;
31
+ /** Prevalence (e.g. `'Often'`, `'Sometimes'`, `'Undetermined'`) */
32
+ Prevalence: string;
33
+ }
34
+ /**
35
+ * An alternate term or synonym for a weakness.
36
+ */
37
+ interface CweAlternateTerm {
38
+ /** Alternate term string */
39
+ Term: string;
40
+ /** Description of when/how this term is used */
41
+ Description: string;
42
+ }
43
+ /**
44
+ * Full weakness entry returned by `GET /cwe/weakness/{id}`.
45
+ */
46
+ interface CweWeakness {
47
+ /** CWE identifier string (e.g. `'79'`) */
48
+ ID: string;
49
+ /** Weakness name */
50
+ Name: string;
51
+ /** Abstraction level (e.g. `'Pillar'`, `'Class'`, `'Base'`, `'Variant'`) */
52
+ Abstraction: string;
53
+ /** Structure type (e.g. `'Simple'`, `'Composite'`, `'Chain'`) */
54
+ Structure: string;
55
+ /** Status (e.g. `'Stable'`, `'Draft'`, `'Incomplete'`, `'Deprecated'`) */
56
+ Status: string;
57
+ /** Path to a diagram image, if available */
58
+ Diagram?: string;
59
+ /** Short description of the weakness */
60
+ Description: string;
61
+ /** Extended description with additional details */
62
+ ExtendedDescription?: string;
63
+ /** Likelihood of exploitation (e.g. `'High'`, `'Medium'`, `'Low'`) */
64
+ LikelihoodOfExploit?: string;
65
+ /** References to related weaknesses */
66
+ RelatedWeaknesses?: CweRelatedWeakness[];
67
+ /** Ordinality of this weakness */
68
+ WeaknessOrdinalities?: CweWeaknessOrdinality[];
69
+ /** Platforms to which this weakness applies */
70
+ ApplicablePlatforms?: CweApplicablePlatform[];
71
+ /** Background context paragraphs */
72
+ BackgroundDetails?: string[];
73
+ /** Alternate names or terms for this weakness */
74
+ AlternateTerms?: CweAlternateTerm[];
75
+ }
76
+
77
+ /**
78
+ * A CWE entry as represented in hierarchy relationship responses.
79
+ */
80
+ interface CweRelationEntry {
81
+ /** Entry type (e.g. `'pillar_weakness'`, `'class_weakness'`, `'view'`) */
82
+ Type: string;
83
+ /** CWE identifier string */
84
+ ID: string;
85
+ /** View context for this relationship */
86
+ ViewID: string;
87
+ /** Whether this is the primary parent (present on parent entries) */
88
+ Primary_Parent?: boolean;
89
+ }
90
+ /**
91
+ * A node in the ancestor tree returned by `GET /cwe/{id}/ancestors`.
92
+ * Each node references its parent chain recursively up to the view root.
93
+ */
94
+ interface CweAncestorNode {
95
+ /** This node's CWE entry data */
96
+ Data: CweRelationEntry;
97
+ /** Parent nodes, or `null` if this node is the root */
98
+ Parents: CweAncestorNode[] | null;
99
+ }
100
+ /**
101
+ * A node in the descendant tree returned by `GET /cwe/{id}/descendants`.
102
+ * Each node references its children recursively down to leaf entries.
103
+ */
104
+ interface CweDescendantNode {
105
+ /** This node's CWE entry data */
106
+ Data: CweRelationEntry;
107
+ /** Child nodes, or `null` if this node is a leaf */
108
+ Children: CweDescendantNode[] | null;
109
+ }
110
+
111
+ /** @internal */
112
+ type RequestFn = <T>(path: string, params?: Record<string, string | number | boolean>) => Promise<T>;
113
+ /**
114
+ * Represents a CWE weakness resource, providing access to weakness details
115
+ * and its position in the CWE hierarchy.
116
+ *
117
+ * Implements `PromiseLike<CweWeakness>` so it can be awaited directly to
118
+ * fetch the full weakness, while also exposing hierarchy methods.
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * // Await directly to get full weakness data
123
+ * const weakness = await cwe.weakness(79);
124
+ *
125
+ * // Or call .get() explicitly
126
+ * const weakness = await cwe.weakness(79).get();
127
+ *
128
+ * // Navigate the hierarchy
129
+ * const parents = await cwe.weakness(74).parents(1000);
130
+ * const children = await cwe.weakness(74).children(1000);
131
+ * const ancestors = await cwe.weakness(74).ancestors(1000);
132
+ * const descendants = await cwe.weakness(74).descendants(1000);
133
+ * ```
134
+ */
135
+ declare class WeaknessResource implements PromiseLike<CweWeakness> {
136
+ private readonly request;
137
+ private readonly id;
138
+ /** @internal */
139
+ constructor(request: RequestFn, id: number);
140
+ /**
141
+ * Allows the resource to be awaited directly, resolving with the full weakness.
142
+ * Delegates to {@link WeaknessResource.get}.
143
+ */
144
+ then<TResult1 = CweWeakness, TResult2 = never>(onfulfilled?: ((value: CweWeakness) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
145
+ /**
146
+ * Fetches the full weakness entry.
147
+ *
148
+ * `GET /cwe/weakness/{id}`
149
+ *
150
+ * @returns The weakness object
151
+ */
152
+ get(): Promise<CweWeakness>;
153
+ /**
154
+ * Fetches the direct parents of this weakness in a given view.
155
+ *
156
+ * `GET /cwe/{id}/parents?view={viewId}`
157
+ *
158
+ * @param viewId - CWE view ID to scope the hierarchy (e.g. `1000`)
159
+ * @returns Array of direct parent entries
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * const parents = await cwe.weakness(74).parents(1000);
164
+ * ```
165
+ */
166
+ parents(viewId?: number): Promise<CweRelationEntry[]>;
167
+ /**
168
+ * Fetches the direct children of this weakness in a given view.
169
+ *
170
+ * `GET /cwe/{id}/children?view={viewId}`
171
+ *
172
+ * @param viewId - CWE view ID to scope the hierarchy (e.g. `1000`)
173
+ * @returns Array of direct child entries
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const children = await cwe.weakness(74).children(1000);
178
+ * ```
179
+ */
180
+ children(viewId?: number): Promise<CweRelationEntry[]>;
181
+ /**
182
+ * Fetches the full ancestor tree of this weakness in a given view.
183
+ *
184
+ * `GET /cwe/{id}/ancestors?view={viewId}`
185
+ *
186
+ * @param viewId - CWE view ID to scope the hierarchy (e.g. `1000`)
187
+ * @returns Recursive ancestor tree from this node up to the view root
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const tree = await cwe.weakness(74).ancestors(1000);
192
+ * ```
193
+ */
194
+ ancestors(viewId?: number): Promise<CweAncestorNode[]>;
195
+ /**
196
+ * Fetches the full descendant tree of this weakness in a given view.
197
+ *
198
+ * `GET /cwe/{id}/descendants?view={viewId}`
199
+ *
200
+ * @param viewId - CWE view ID to scope the hierarchy (e.g. `1000`)
201
+ * @returns Recursive descendant tree from this node down to leaf entries
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * const tree = await cwe.weakness(74).descendants(1000);
206
+ * ```
207
+ */
208
+ descendants(viewId?: number): Promise<CweDescendantNode[]>;
209
+ }
210
+
211
+ /**
212
+ * A taxonomy mapping entry linking a category to an external standard.
213
+ */
214
+ interface CweTaxonomyMapping {
215
+ /** Name of the external taxonomy (e.g. `'SEI CERT Perl Coding Standard'`) */
216
+ TaxonomyName: string;
217
+ /** Entry identifier within the taxonomy */
218
+ EntryID?: string;
219
+ /** Entry name within the taxonomy */
220
+ EntryName: string;
221
+ /** How well the mapping fits (e.g. `'CWE More Abstract'`, `'Exact'`) */
222
+ MappingFit?: string;
223
+ }
224
+ /**
225
+ * A member relationship entry within a category.
226
+ */
227
+ interface CweCategoryRelationship {
228
+ /** CWE identifier of the member */
229
+ CweID: string;
230
+ /** View context for this membership */
231
+ ViewID: string;
232
+ }
233
+ /**
234
+ * An external reference cited by a category.
235
+ */
236
+ interface CweCategoryReference {
237
+ /** External reference identifier (e.g. `'REF-1287'`) */
238
+ ExternalReferenceID: string;
239
+ }
240
+ /**
241
+ * Full category entry returned by `GET /cwe/category/{id}`.
242
+ */
243
+ interface CweCategory {
244
+ /** CWE identifier string (e.g. `'189'`) */
245
+ ID: string;
246
+ /** Category name */
247
+ Name: string;
248
+ /** Status (e.g. `'Draft'`, `'Stable'`, `'Deprecated'`) */
249
+ Status: string;
250
+ /** Short summary of what this category covers */
251
+ Summary: string;
252
+ /** Mappings to external taxonomies */
253
+ TaxonomyMappings?: CweTaxonomyMapping[];
254
+ /** Weaknesses that belong to this category */
255
+ Relationships?: CweCategoryRelationship[];
256
+ /** External references */
257
+ References?: CweCategoryReference[];
258
+ }
259
+
260
+ /**
261
+ * Represents a CWE category resource, providing access to category details.
262
+ *
263
+ * Implements `PromiseLike<CweCategory>` so it can be awaited directly.
264
+ *
265
+ * @example
266
+ * ```typescript
267
+ * // Await directly to get full category data
268
+ * const category = await cwe.category(189);
269
+ *
270
+ * // Or call .get() explicitly
271
+ * const category = await cwe.category(189).get();
272
+ * ```
273
+ */
274
+ declare class CategoryResource implements PromiseLike<CweCategory> {
275
+ private readonly request;
276
+ private readonly id;
277
+ /** @internal */
278
+ constructor(request: RequestFn, id: number);
279
+ /**
280
+ * Allows the resource to be awaited directly, resolving with the full category.
281
+ * Delegates to {@link CategoryResource.get}.
282
+ */
283
+ then<TResult1 = CweCategory, TResult2 = never>(onfulfilled?: ((value: CweCategory) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
284
+ /**
285
+ * Fetches the full category entry.
286
+ *
287
+ * `GET /cwe/category/{id}`
288
+ *
289
+ * @returns The category object
290
+ */
291
+ get(): Promise<CweCategory>;
292
+ }
293
+
294
+ /**
295
+ * An audience entry describing who a view is relevant for.
296
+ */
297
+ interface CweViewAudience {
298
+ /** Audience type (e.g. `'Software Developers'`, `'Educators'`) */
299
+ Type: string;
300
+ /** Description of how this view is relevant to this audience */
301
+ Description: string;
302
+ }
303
+ /**
304
+ * A member entry within a view.
305
+ */
306
+ interface CweViewMember {
307
+ /** CWE identifier of the member */
308
+ CweID: string;
309
+ /** View identifier this membership belongs to */
310
+ ViewID: string;
311
+ }
312
+ /**
313
+ * Full view entry returned by `GET /cwe/view/{id}`.
314
+ */
315
+ interface CweView {
316
+ /** CWE identifier string (e.g. `'1425'`) */
317
+ ID: string;
318
+ /** View name */
319
+ Name: string;
320
+ /** View type (e.g. `'Graph'`, `'Explicit'`, `'Implicit'`) */
321
+ Type: string;
322
+ /** Status (e.g. `'Draft'`, `'Stable'`, `'Deprecated'`) */
323
+ Status: string;
324
+ /** Objective description of the view */
325
+ Objective?: string;
326
+ /** Intended audiences for this view */
327
+ Audience?: CweViewAudience[];
328
+ /** CWE entries that are members of this view */
329
+ Members?: CweViewMember[];
330
+ }
331
+
332
+ /**
333
+ * Represents a CWE view resource, providing access to view details.
334
+ *
335
+ * Implements `PromiseLike<CweView>` so it can be awaited directly.
336
+ *
337
+ * @example
338
+ * ```typescript
339
+ * // Await directly to get full view data
340
+ * const view = await cwe.view(1425);
341
+ *
342
+ * // Or call .get() explicitly
343
+ * const view = await cwe.view(1425).get();
344
+ * ```
345
+ */
346
+ declare class ViewResource implements PromiseLike<CweView> {
347
+ private readonly request;
348
+ private readonly id;
349
+ /** @internal */
350
+ constructor(request: RequestFn, id: number);
351
+ /**
352
+ * Allows the resource to be awaited directly, resolving with the full view.
353
+ * Delegates to {@link ViewResource.get}.
354
+ */
355
+ then<TResult1 = CweView, TResult2 = never>(onfulfilled?: ((value: CweView) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
356
+ /**
357
+ * Fetches the full view entry.
358
+ *
359
+ * `GET /cwe/view/{id}`
360
+ *
361
+ * @returns The view object
362
+ */
363
+ get(): Promise<CweView>;
364
+ }
365
+
366
+ /**
367
+ * CWE content version metadata returned by `GET /cwe/version`.
368
+ */
369
+ interface CweVersion {
370
+ /** CWE content version string (e.g. `'4.19.1'`) */
371
+ ContentVersion: string;
372
+ /** Date the content was published (e.g. `'2026-01-21'`) */
373
+ ContentDate: string;
374
+ /** Total number of weaknesses in this release */
375
+ TotalWeaknesses: number;
376
+ /** Total number of categories in this release */
377
+ TotalCategories: number;
378
+ /** Total number of views in this release */
379
+ TotalViews: number;
380
+ }
381
+
382
+ /**
383
+ * CWE entry type string.
384
+ */
385
+ type CweEntryType = 'pillar_weakness' | 'class_weakness' | 'base_weakness' | 'variant_weakness' | 'compound_element' | 'category' | 'view';
386
+ /**
387
+ * Lightweight CWE entry returned by the multi-ID lookup endpoint
388
+ * (`GET /cwe/{ids}`).
389
+ */
390
+ interface CweEntry {
391
+ /** CWE entry type (e.g. `'base_weakness'`, `'category'`, `'view'`) */
392
+ Type: CweEntryType;
393
+ /** CWE identifier string (e.g. `'79'`) */
394
+ ID: string;
395
+ }
396
+
397
+ /**
398
+ * Payload emitted on every HTTP request made by {@link CweClient}.
399
+ */
400
+ interface RequestEvent {
401
+ /** Full URL that was requested */
402
+ url: string;
403
+ /** HTTP method used */
404
+ method: 'GET';
405
+ /** Timestamp when the request started */
406
+ startedAt: Date;
407
+ /** Timestamp when the request finished (success or error) */
408
+ finishedAt: Date;
409
+ /** Total duration in milliseconds */
410
+ durationMs: number;
411
+ /** HTTP status code returned by the server, if a response was received */
412
+ statusCode?: number;
413
+ /** Error thrown, if the request failed */
414
+ error?: Error;
415
+ }
416
+ /** Map of supported client events to their callback signatures */
417
+ interface CweClientEvents {
418
+ request: (event: RequestEvent) => void;
419
+ }
420
+ /**
421
+ * Constructor options for {@link CweClient}.
422
+ */
423
+ interface CweClientOptions {
424
+ /**
425
+ * Base URL for the CWE API (default: `'https://cwe-api.mitre.org/api/v1'`).
426
+ * Override for mirrors or local instances.
427
+ */
428
+ baseUrl?: string;
429
+ }
430
+ /**
431
+ * Main entry point for the MITRE CWE API client.
432
+ *
433
+ * @example
434
+ * ```typescript
435
+ * import { CweClient } from 'cwe-api-client';
436
+ *
437
+ * const cwe = new CweClient();
438
+ *
439
+ * // Get content version metadata
440
+ * const version = await cwe.version();
441
+ *
442
+ * // Look up multiple CWEs at once
443
+ * const entries = await cwe.lookup([74, 79]);
444
+ *
445
+ * // Get full weakness details
446
+ * const weakness = await cwe.weakness(79);
447
+ *
448
+ * // Navigate the hierarchy
449
+ * const parents = await cwe.weakness(74).parents(1000);
450
+ * const descendants = await cwe.weakness(74).descendants(1000);
451
+ *
452
+ * // Get category and view details
453
+ * const category = await cwe.category(189);
454
+ * const view = await cwe.view(1425);
455
+ * ```
456
+ */
457
+ declare class CweClient {
458
+ private readonly baseUrl;
459
+ private readonly listeners;
460
+ /**
461
+ * @param options - Optional configuration for the API base URL
462
+ */
463
+ constructor(options?: CweClientOptions);
464
+ /**
465
+ * Subscribes to a client event.
466
+ *
467
+ * @example
468
+ * ```typescript
469
+ * cwe.on('request', (event) => {
470
+ * console.log(`${event.method} ${event.url} — ${event.durationMs}ms`);
471
+ * if (event.error) console.error('Request failed:', event.error);
472
+ * });
473
+ * ```
474
+ */
475
+ on<K extends keyof CweClientEvents>(event: K, callback: CweClientEvents[K]): this;
476
+ private emit;
477
+ /**
478
+ * Performs a GET request to the CWE API.
479
+ *
480
+ * @param path - Path to append to the base URL (e.g. `/cwe/version`)
481
+ * @param params - Optional query parameters
482
+ * @internal
483
+ */
484
+ request<T>(path: string, params?: Record<string, string | number | boolean>): Promise<T>;
485
+ /**
486
+ * Fetches CWE content version metadata.
487
+ *
488
+ * `GET /cwe/version`
489
+ *
490
+ * @returns Version metadata including content version, date, and counts
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * const v = await cwe.version();
495
+ * console.log(v.ContentVersion); // '4.19.1'
496
+ * console.log(v.TotalWeaknesses); // 969
497
+ * ```
498
+ */
499
+ version(): Promise<CweVersion>;
500
+ /**
501
+ * Looks up multiple CWE entries by their numeric IDs in a single request.
502
+ *
503
+ * `GET /cwe/{ids}` (comma-separated)
504
+ *
505
+ * @param ids - Array of CWE numeric IDs (e.g. `[74, 79]`)
506
+ * @returns Array of lightweight CWE entries with type and ID
507
+ *
508
+ * @example
509
+ * ```typescript
510
+ * const entries = await cwe.lookup([74, 79]);
511
+ * entries.forEach(e => console.log(e.ID, e.Type));
512
+ * ```
513
+ */
514
+ lookup(ids: number[]): Promise<CweEntry[]>;
515
+ /**
516
+ * Returns a {@link WeaknessResource} for a given CWE weakness ID, providing
517
+ * access to weakness details and its hierarchy (parents, children, ancestors,
518
+ * descendants).
519
+ *
520
+ * The returned resource can be awaited directly to fetch the full weakness,
521
+ * or chained to access hierarchy methods.
522
+ *
523
+ * @param id - The CWE weakness numeric ID (e.g. `79`)
524
+ * @returns A chainable weakness resource
525
+ *
526
+ * @example
527
+ * ```typescript
528
+ * const weakness = await cwe.weakness(79);
529
+ * const parents = await cwe.weakness(74).parents(1000);
530
+ * const tree = await cwe.weakness(74).descendants(1000);
531
+ * ```
532
+ */
533
+ weakness(id: number): WeaknessResource;
534
+ /**
535
+ * Returns a {@link CategoryResource} for a given CWE category ID, providing
536
+ * access to category details.
537
+ *
538
+ * The returned resource can be awaited directly to fetch the full category.
539
+ *
540
+ * @param id - The CWE category numeric ID (e.g. `189`)
541
+ * @returns A chainable category resource
542
+ *
543
+ * @example
544
+ * ```typescript
545
+ * const category = await cwe.category(189);
546
+ * console.log(category.Name); // 'Numeric Errors'
547
+ * ```
548
+ */
549
+ category(id: number): CategoryResource;
550
+ /**
551
+ * Returns a {@link ViewResource} for a given CWE view ID, providing access
552
+ * to view details.
553
+ *
554
+ * The returned resource can be awaited directly to fetch the full view.
555
+ *
556
+ * @param id - The CWE view numeric ID (e.g. `1425`)
557
+ * @returns A chainable view resource
558
+ *
559
+ * @example
560
+ * ```typescript
561
+ * const view = await cwe.view(1425);
562
+ * console.log(view.Name); // 'Weaknesses in the 2023 CWE Top 25...'
563
+ * ```
564
+ */
565
+ view(id: number): ViewResource;
566
+ }
567
+
568
+ /**
569
+ * Thrown when the CWE API returns a non-2xx response.
570
+ *
571
+ * @example
572
+ * ```typescript
573
+ * import { CweApiError } from 'cwe-api-client';
574
+ *
575
+ * try {
576
+ * await cwe.weakness(99999).get();
577
+ * } catch (err) {
578
+ * if (err instanceof CweApiError) {
579
+ * console.log(err.status); // 404
580
+ * console.log(err.statusText); // 'Not Found'
581
+ * console.log(err.message); // 'CWE API error: 404 Not Found'
582
+ * }
583
+ * }
584
+ * ```
585
+ */
586
+ declare class CweApiError extends Error {
587
+ /** HTTP status code (e.g. `404`, `400`, `500`) */
588
+ readonly status: number;
589
+ /** HTTP status text (e.g. `'Not Found'`, `'Bad Request'`) */
590
+ readonly statusText: string;
591
+ constructor(status: number, statusText: string);
592
+ }
593
+
594
+ export { CategoryResource, type CweAlternateTerm, type CweAncestorNode, CweApiError, type CweApplicablePlatform, type CweCategory, type CweCategoryReference, type CweCategoryRelationship, CweClient, type CweClientEvents, type CweClientOptions, type CweDescendantNode, type CweEntry, type CweEntryType, type CweRelatedWeakness, type CweRelationEntry, type CweTaxonomyMapping, type CweVersion, type CweView, type CweViewAudience, type CweViewMember, type CweWeakness, type CweWeaknessOrdinality, type RequestEvent, ViewResource, WeaknessResource };