@fedpulse/sdk 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.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +331 -0
  3. package/dist/cjs/client.cjs +138 -0
  4. package/dist/cjs/errors.cjs +200 -0
  5. package/dist/cjs/http.cjs +449 -0
  6. package/dist/cjs/index.cjs +65 -0
  7. package/dist/cjs/resources/analytics.cjs +134 -0
  8. package/dist/cjs/resources/assistance.cjs +101 -0
  9. package/dist/cjs/resources/entities.cjs +149 -0
  10. package/dist/cjs/resources/exclusions.cjs +135 -0
  11. package/dist/cjs/resources/intelligence.cjs +96 -0
  12. package/dist/cjs/resources/opportunities.cjs +170 -0
  13. package/dist/cjs/resources/webhooks.cjs +262 -0
  14. package/dist/cjs/types/analytics.cjs +5 -0
  15. package/dist/cjs/types/assistance.cjs +5 -0
  16. package/dist/cjs/types/common.cjs +5 -0
  17. package/dist/cjs/types/entities.cjs +5 -0
  18. package/dist/cjs/types/exclusions.cjs +5 -0
  19. package/dist/cjs/types/index.cjs +5 -0
  20. package/dist/cjs/types/intelligence.cjs +5 -0
  21. package/dist/cjs/types/opportunities.cjs +5 -0
  22. package/dist/cjs/types/webhooks.cjs +5 -0
  23. package/dist/cjs/webhooks-verify.cjs +184 -0
  24. package/dist/esm/client.js +135 -0
  25. package/dist/esm/client.js.map +1 -0
  26. package/dist/esm/errors.js +187 -0
  27. package/dist/esm/errors.js.map +1 -0
  28. package/dist/esm/http.js +445 -0
  29. package/dist/esm/http.js.map +1 -0
  30. package/dist/esm/index.js +40 -0
  31. package/dist/esm/index.js.map +1 -0
  32. package/dist/esm/resources/analytics.js +131 -0
  33. package/dist/esm/resources/analytics.js.map +1 -0
  34. package/dist/esm/resources/assistance.js +98 -0
  35. package/dist/esm/resources/assistance.js.map +1 -0
  36. package/dist/esm/resources/entities.js +146 -0
  37. package/dist/esm/resources/entities.js.map +1 -0
  38. package/dist/esm/resources/exclusions.js +132 -0
  39. package/dist/esm/resources/exclusions.js.map +1 -0
  40. package/dist/esm/resources/intelligence.js +93 -0
  41. package/dist/esm/resources/intelligence.js.map +1 -0
  42. package/dist/esm/resources/opportunities.js +167 -0
  43. package/dist/esm/resources/opportunities.js.map +1 -0
  44. package/dist/esm/resources/webhooks.js +259 -0
  45. package/dist/esm/resources/webhooks.js.map +1 -0
  46. package/dist/esm/types/analytics.js +5 -0
  47. package/dist/esm/types/analytics.js.map +1 -0
  48. package/dist/esm/types/assistance.js +5 -0
  49. package/dist/esm/types/assistance.js.map +1 -0
  50. package/dist/esm/types/common.js +5 -0
  51. package/dist/esm/types/common.js.map +1 -0
  52. package/dist/esm/types/entities.js +5 -0
  53. package/dist/esm/types/entities.js.map +1 -0
  54. package/dist/esm/types/exclusions.js +5 -0
  55. package/dist/esm/types/exclusions.js.map +1 -0
  56. package/dist/esm/types/index.js +5 -0
  57. package/dist/esm/types/index.js.map +1 -0
  58. package/dist/esm/types/intelligence.js +5 -0
  59. package/dist/esm/types/intelligence.js.map +1 -0
  60. package/dist/esm/types/opportunities.js +5 -0
  61. package/dist/esm/types/opportunities.js.map +1 -0
  62. package/dist/esm/types/webhooks.js +5 -0
  63. package/dist/esm/types/webhooks.js.map +1 -0
  64. package/dist/esm/webhooks-verify.js +179 -0
  65. package/dist/esm/webhooks-verify.js.map +1 -0
  66. package/dist/types/client.d.cts +136 -0
  67. package/dist/types/client.d.ts +136 -0
  68. package/dist/types/client.d.ts.map +1 -0
  69. package/dist/types/errors.d.cts +139 -0
  70. package/dist/types/errors.d.ts +139 -0
  71. package/dist/types/errors.d.ts.map +1 -0
  72. package/dist/types/http.d.cts +137 -0
  73. package/dist/types/http.d.ts +137 -0
  74. package/dist/types/http.d.ts.map +1 -0
  75. package/dist/types/index.d.cts +39 -0
  76. package/dist/types/index.d.ts +39 -0
  77. package/dist/types/index.d.ts.map +1 -0
  78. package/dist/types/resources/analytics.d.cts +94 -0
  79. package/dist/types/resources/analytics.d.ts +94 -0
  80. package/dist/types/resources/analytics.d.ts.map +1 -0
  81. package/dist/types/resources/assistance.d.cts +66 -0
  82. package/dist/types/resources/assistance.d.ts +66 -0
  83. package/dist/types/resources/assistance.d.ts.map +1 -0
  84. package/dist/types/resources/entities.d.cts +101 -0
  85. package/dist/types/resources/entities.d.ts +101 -0
  86. package/dist/types/resources/entities.d.ts.map +1 -0
  87. package/dist/types/resources/exclusions.d.cts +84 -0
  88. package/dist/types/resources/exclusions.d.ts +84 -0
  89. package/dist/types/resources/exclusions.d.ts.map +1 -0
  90. package/dist/types/resources/intelligence.d.cts +66 -0
  91. package/dist/types/resources/intelligence.d.ts +66 -0
  92. package/dist/types/resources/intelligence.d.ts.map +1 -0
  93. package/dist/types/resources/opportunities.d.cts +116 -0
  94. package/dist/types/resources/opportunities.d.ts +116 -0
  95. package/dist/types/resources/opportunities.d.ts.map +1 -0
  96. package/dist/types/resources/webhooks.d.cts +180 -0
  97. package/dist/types/resources/webhooks.d.ts +180 -0
  98. package/dist/types/resources/webhooks.d.ts.map +1 -0
  99. package/dist/types/types/analytics.d.cts +85 -0
  100. package/dist/types/types/analytics.d.ts +85 -0
  101. package/dist/types/types/analytics.d.ts.map +1 -0
  102. package/dist/types/types/assistance.d.cts +55 -0
  103. package/dist/types/types/assistance.d.ts +55 -0
  104. package/dist/types/types/assistance.d.ts.map +1 -0
  105. package/dist/types/types/common.d.cts +58 -0
  106. package/dist/types/types/common.d.ts +58 -0
  107. package/dist/types/types/common.d.ts.map +1 -0
  108. package/dist/types/types/entities.d.cts +85 -0
  109. package/dist/types/types/entities.d.ts +85 -0
  110. package/dist/types/types/entities.d.ts.map +1 -0
  111. package/dist/types/types/exclusions.d.cts +81 -0
  112. package/dist/types/types/exclusions.d.ts +81 -0
  113. package/dist/types/types/exclusions.d.ts.map +1 -0
  114. package/dist/types/types/index.d.cts +12 -0
  115. package/dist/types/types/index.d.ts +12 -0
  116. package/dist/types/types/index.d.ts.map +1 -0
  117. package/dist/types/types/intelligence.d.cts +104 -0
  118. package/dist/types/types/intelligence.d.ts +104 -0
  119. package/dist/types/types/intelligence.d.ts.map +1 -0
  120. package/dist/types/types/opportunities.d.cts +149 -0
  121. package/dist/types/types/opportunities.d.ts +149 -0
  122. package/dist/types/types/opportunities.d.ts.map +1 -0
  123. package/dist/types/types/webhooks.d.cts +106 -0
  124. package/dist/types/types/webhooks.d.ts +106 -0
  125. package/dist/types/types/webhooks.d.ts.map +1 -0
  126. package/dist/types/webhooks-verify.d.cts +102 -0
  127. package/dist/types/webhooks-verify.d.ts +102 -0
  128. package/dist/types/webhooks-verify.d.ts.map +1 -0
  129. package/package.json +62 -0
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ /**
3
+ * Assistance Listings resource client.
4
+ *
5
+ * Wraps all /v1/assistance endpoints:
6
+ * - list GET /v1/assistance
7
+ * - stats GET /v1/assistance/stats
8
+ * - get GET /v1/assistance/:number (CFDA program number)
9
+ * - paginate auto-paginates over the list endpoint
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AssistanceResource = void 0;
13
+ class AssistanceResource {
14
+ http;
15
+ constructor(http) {
16
+ this.http = http;
17
+ }
18
+ /**
19
+ * Search and filter federal assistance listings (CFDA programs).
20
+ *
21
+ * @param params Filter and pagination parameters.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const result = await client.assistance.list({ agency: 'Department of Energy' });
26
+ * ```
27
+ */
28
+ async list(params = {}) {
29
+ return this.http.get('/v1/assistance', params);
30
+ }
31
+ /**
32
+ * Get aggregated statistics for assistance listings.
33
+ *
34
+ * @param params Optional filter parameters.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const stats = await client.assistance.stats();
39
+ * ```
40
+ */
41
+ async stats(params = {}) {
42
+ return this.http.get('/v1/assistance/stats', params);
43
+ }
44
+ /**
45
+ * Get a single assistance listing by its CFDA program number.
46
+ *
47
+ * @param programNumber CFDA program number in "XX.XXX" format (e.g. "17.002").
48
+ * @throws {NotFoundError} If the program number does not exist.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const listing = await client.assistance.get('84.048');
53
+ * console.log(listing.data.programTitle);
54
+ * ```
55
+ */
56
+ async get(programNumber) {
57
+ if (!programNumber || typeof programNumber !== 'string' || programNumber.trim() === '') {
58
+ throw new Error('programNumber must be a non-empty string');
59
+ }
60
+ const trimmed = programNumber.trim();
61
+ if (!/^\d{2}\.\d{3}$/.test(trimmed)) {
62
+ throw new Error('programNumber must be in "XX.XXX" format (e.g. "17.002")');
63
+ }
64
+ return this.http.get(`/v1/assistance/${encodeURIComponent(trimmed)}`);
65
+ }
66
+ /**
67
+ * Async generator that automatically paginates over all matching assistance listings.
68
+ *
69
+ * @param params Same filter parameters as `list()`. Do not pass `page`.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * for await (const page of client.assistance.paginate({ agency: 'HHS' })) {
74
+ * for (const listing of page.data) {
75
+ * console.log(listing.programNumber, listing.programTitle);
76
+ * }
77
+ * }
78
+ * ```
79
+ */
80
+ async *paginate(params) {
81
+ let page = 1;
82
+ let hasMore = true;
83
+ while (hasMore) {
84
+ const result = await this.list({ ...params, page });
85
+ yield result;
86
+ const pagination = result.pagination;
87
+ if (pagination === null) {
88
+ hasMore = false;
89
+ }
90
+ else if ('hasNextPage' in pagination) {
91
+ hasMore = pagination.hasNextPage;
92
+ if (hasMore)
93
+ page++;
94
+ }
95
+ else {
96
+ hasMore = false;
97
+ }
98
+ }
99
+ }
100
+ }
101
+ exports.AssistanceResource = AssistanceResource;
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /**
3
+ * Entities resource client.
4
+ *
5
+ * Wraps all /v1/entities endpoints:
6
+ * - list GET /v1/entities
7
+ * - get GET /v1/entities/:uei
8
+ * - opportunities GET /v1/entities/:uei/opportunities
9
+ * - exclusionCheck GET /v1/entities/:uei/exclusion-check
10
+ * - stats GET /v1/entities/stats
11
+ * - paginate auto-paginates over the list endpoint
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.EntitiesResource = void 0;
15
+ const errors_js_1 = require("../errors.cjs");
16
+ class EntitiesResource {
17
+ http;
18
+ constructor(http) {
19
+ this.http = http;
20
+ }
21
+ /**
22
+ * Search and filter SAM.gov registered entities (vendors).
23
+ *
24
+ * @param params Filter and pagination parameters.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const result = await client.entities.list({
29
+ * naics: '541512',
30
+ * certification: '8A',
31
+ * state: 'VA',
32
+ * });
33
+ * ```
34
+ */
35
+ async list(params = {}) {
36
+ return this.http.get('/v1/entities', params);
37
+ }
38
+ /**
39
+ * Get the full SAM.gov registration profile for a vendor by UEI.
40
+ *
41
+ * @param uei Unique Entity Identifier (12-char alphanumeric).
42
+ * @throws {NotFoundError} If the entity does not exist.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const entity = await client.entities.get('ABCDEF123456');
47
+ * console.log(entity.data.legalBusinessName);
48
+ * ```
49
+ */
50
+ async get(uei) {
51
+ validateUei(uei);
52
+ return this.http.get(`/v1/entities/${encodeURIComponent(uei.trim().toUpperCase())}`);
53
+ }
54
+ /**
55
+ * Get awarded contract opportunities linked to a vendor.
56
+ *
57
+ * @param uei Unique Entity Identifier.
58
+ * @param params Pagination parameters.
59
+ * @throws {NotFoundError} If the entity does not exist.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * const contracts = await client.entities.opportunities('ABCDEF123456', { limit: 10 });
64
+ * ```
65
+ */
66
+ async opportunities(uei, params = {}) {
67
+ validateUei(uei);
68
+ return this.http.get(`/v1/entities/${encodeURIComponent(uei.trim().toUpperCase())}/opportunities`, params);
69
+ }
70
+ /**
71
+ * Check whether a vendor is currently excluded (debarred) from federal contracts.
72
+ *
73
+ * @param uei Unique Entity Identifier.
74
+ * @throws {NotFoundError} If the entity does not exist.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const check = await client.entities.exclusionCheck('ABCDEF123456');
79
+ * if (check.data.excluded) {
80
+ * console.warn('Vendor is EXCLUDED!', check.data.exclusion);
81
+ * }
82
+ * ```
83
+ */
84
+ async exclusionCheck(uei) {
85
+ validateUei(uei);
86
+ return this.http.get(`/v1/entities/${encodeURIComponent(uei.trim().toUpperCase())}/exclusion-check`, {}, { cacheTtlMs: 0 } // Never cache exclusion checks — compliance-critical.
87
+ );
88
+ }
89
+ /**
90
+ * Get aggregated entity registration statistics.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const stats = await client.entities.stats();
95
+ * console.log('Total registered entities:', stats.data.total);
96
+ * ```
97
+ */
98
+ async stats() {
99
+ return this.http.get('/v1/entities/stats');
100
+ }
101
+ /**
102
+ * Async generator that automatically paginates over all matching entities.
103
+ *
104
+ * @param params Same filter parameters as `list()`. Do not pass `page`.
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * for await (const page of client.entities.paginate({ naics: '541512' })) {
109
+ * for (const entity of page.data) {
110
+ * console.log(entity.legalBusinessName);
111
+ * }
112
+ * }
113
+ * ```
114
+ */
115
+ async *paginate(params) {
116
+ let page = 1;
117
+ let hasMore = true;
118
+ while (hasMore) {
119
+ const result = await this.list({ ...params, page });
120
+ yield result;
121
+ const pagination = result.pagination;
122
+ if (pagination === null) {
123
+ hasMore = false;
124
+ }
125
+ else if ('hasNextPage' in pagination) {
126
+ hasMore = pagination.hasNextPage;
127
+ if (hasMore)
128
+ page++;
129
+ }
130
+ else {
131
+ hasMore = false;
132
+ }
133
+ }
134
+ }
135
+ }
136
+ exports.EntitiesResource = EntitiesResource;
137
+ // ── Helpers ────────────────────────────────────────────────────────────────────
138
+ /**
139
+ * Validate UEI format: 12-character alphanumeric string.
140
+ * @throws {Error} If UEI is invalid.
141
+ */
142
+ function validateUei(uei) {
143
+ if (!uei || typeof uei !== 'string' || uei.trim() === '') {
144
+ throw new errors_js_1.ValidationError({ message: 'uei must be a non-empty string', status: 400 });
145
+ }
146
+ if (!/^[A-Za-z0-9]{12}$/.test(uei.trim())) {
147
+ throw new errors_js_1.ValidationError({ message: 'uei must be a 12-character alphanumeric string (e.g. ABCDEF123456)', status: 400 });
148
+ }
149
+ }
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ /**
3
+ * Exclusions resource client.
4
+ *
5
+ * Wraps all /v1/exclusions endpoints:
6
+ * - list GET /v1/exclusions
7
+ * - get GET /v1/exclusions/:exclusionId
8
+ * - check POST /v1/exclusions/check (bulk compliance)
9
+ * - stats GET /v1/exclusions/stats
10
+ * - paginate auto-paginates over the list endpoint
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.ExclusionsResource = void 0;
14
+ const errors_js_1 = require("../errors.cjs");
15
+ class ExclusionsResource {
16
+ http;
17
+ constructor(http) {
18
+ this.http = http;
19
+ }
20
+ /**
21
+ * Search and filter the SAM.gov exclusions database.
22
+ *
23
+ * @param params Filter and pagination parameters.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const result = await client.exclusions.list({ uei: 'ABCDEF123456' });
28
+ * ```
29
+ */
30
+ async list(params = {}) {
31
+ return this.http.get('/v1/exclusions', params);
32
+ }
33
+ /**
34
+ * Get a single exclusion record by its unique ID.
35
+ *
36
+ * @param exclusionId Internal exclusion identifier.
37
+ * @throws {NotFoundError} If the exclusion record does not exist.
38
+ */
39
+ async get(exclusionId) {
40
+ if (!exclusionId || typeof exclusionId !== 'string' || exclusionId.trim() === '') {
41
+ throw new errors_js_1.ValidationError({ message: 'exclusionId must be a non-empty string', status: 400 });
42
+ }
43
+ return this.http.get(`/v1/exclusions/${encodeURIComponent(exclusionId.trim())}`);
44
+ }
45
+ /**
46
+ * Bulk compliance check — verify up to 100 entities against the exclusions database.
47
+ *
48
+ * Each entity must include at least one of: `uei`, `cage`, or `name`.
49
+ * When `fuzzyMatch` is true (default), name matching uses trigram similarity.
50
+ *
51
+ * @param params List of entities and fuzzy-match flag.
52
+ * @returns Per-entity exclusion status with match confidence scores.
53
+ * @throws {ValidationError} If more than 100 entities are provided.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const result = await client.exclusions.check({
58
+ * entities: [
59
+ * { uei: 'ABCDEF123456' },
60
+ * { name: 'Acme Corporation' },
61
+ * ],
62
+ * });
63
+ * for (const item of result.data) {
64
+ * console.log(item.input.name, '->', item.excluded ? 'EXCLUDED' : 'OK');
65
+ * }
66
+ * ```
67
+ */
68
+ async check(params) {
69
+ if (!Array.isArray(params.entities)) {
70
+ throw new errors_js_1.ValidationError({ message: 'entities must be an array', status: 400 });
71
+ }
72
+ if (params.entities.length === 0) {
73
+ throw new errors_js_1.ValidationError({ message: 'entities array must contain at least one entry', status: 400 });
74
+ }
75
+ if (params.entities.length > 100) {
76
+ throw new errors_js_1.ValidationError({ message: 'entities array must not exceed 100 entries', status: 400 });
77
+ }
78
+ for (const [i, entity] of params.entities.entries()) {
79
+ if (!entity.uei && !entity.cage && !entity.name) {
80
+ throw new errors_js_1.ValidationError({
81
+ message: `entities[${i}] must include at least one of: uei, cage, name`,
82
+ status: 400,
83
+ });
84
+ }
85
+ }
86
+ return this.http.post('/v1/exclusions/check', params);
87
+ }
88
+ /**
89
+ * Get aggregated exclusion statistics.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const stats = await client.exclusions.stats();
94
+ * console.log('Total active exclusions:', stats.data.active);
95
+ * ```
96
+ */
97
+ async stats() {
98
+ return this.http.get('/v1/exclusions/stats');
99
+ }
100
+ /**
101
+ * Async generator that automatically paginates over all matching exclusions.
102
+ *
103
+ * @param params Same filter parameters as `list()`. Do not pass `page`.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * for await (const page of client.exclusions.paginate({ agency: 'DEPT OF DEFENSE' })) {
108
+ * for (const exc of page.data) {
109
+ * console.log(exc.name, exc.effectiveDate);
110
+ * }
111
+ * }
112
+ * ```
113
+ */
114
+ async *paginate(params) {
115
+ let page = 1;
116
+ let hasMore = true;
117
+ while (hasMore) {
118
+ const result = await this.list({ ...params, page });
119
+ yield result;
120
+ const pagination = result.pagination;
121
+ if (pagination === null) {
122
+ hasMore = false;
123
+ }
124
+ else if ('hasNextPage' in pagination) {
125
+ hasMore = pagination.hasNextPage;
126
+ if (hasMore)
127
+ page++;
128
+ }
129
+ else {
130
+ hasMore = false;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ exports.ExclusionsResource = ExclusionsResource;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ /**
3
+ * Intelligence resource client.
4
+ *
5
+ * Wraps all /v1/intelligence endpoints:
6
+ * - entityProfile GET /v1/intelligence/entity/:uei
7
+ * - marketAnalysis GET /v1/intelligence/market/:naics
8
+ * - complianceCheck POST /v1/intelligence/compliance-check
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.IntelligenceResource = void 0;
12
+ const errors_js_1 = require("../errors.cjs");
13
+ class IntelligenceResource {
14
+ http;
15
+ constructor(http) {
16
+ this.http = http;
17
+ }
18
+ /**
19
+ * Get a comprehensive 360° intelligence profile for a vendor.
20
+ *
21
+ * Aggregates: contract history, agency relationships, certifications,
22
+ * exclusion status, and risk indicators into a single response.
23
+ *
24
+ * @param uei Unique Entity Identifier (12-char alphanumeric).
25
+ * @throws {NotFoundError} If the entity does not exist in SAM.gov.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const profile = await client.intelligence.entityProfile('ABCDEF123456');
30
+ * console.log('Contract count:', profile.data.contractCount);
31
+ * console.log('Risk:', profile.data.riskLevel);
32
+ * ```
33
+ */
34
+ async entityProfile(uei) {
35
+ if (!uei || typeof uei !== 'string' || uei.trim() === '') {
36
+ throw new errors_js_1.ValidationError({ message: 'uei must be a non-empty string', status: 400 });
37
+ }
38
+ if (!/^[A-Za-z0-9]{12}$/.test(uei.trim())) {
39
+ throw new errors_js_1.ValidationError({ message: 'uei must be a 12-character alphanumeric string', status: 400 });
40
+ }
41
+ return this.http.get(`/v1/intelligence/entity/${encodeURIComponent(uei.trim().toUpperCase())}`);
42
+ }
43
+ /**
44
+ * Get a market analysis for a specific NAICS code.
45
+ *
46
+ * Returns: top awardees, top agencies, set-aside breakdown, active solicitations,
47
+ * total market size, and recent award trends.
48
+ *
49
+ * @param naics 2–6 digit NAICS code (more digits = more specific market segment).
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const market = await client.intelligence.marketAnalysis('541512');
54
+ * console.log('Market size (cents):', market.data.totalMarketSize);
55
+ * console.log('Top awardee:', market.data.topAwardees[0]?.name);
56
+ * ```
57
+ */
58
+ async marketAnalysis(naics) {
59
+ if (!naics || typeof naics !== 'string' || naics.trim() === '') {
60
+ throw new errors_js_1.ValidationError({ message: 'naics must be a non-empty string', status: 400 });
61
+ }
62
+ if (!/^\d{2,6}$/.test(naics.trim())) {
63
+ throw new errors_js_1.ValidationError({ message: 'naics must be a numeric string of 2 to 6 digits (e.g. "541512")', status: 400 });
64
+ }
65
+ return this.http.get(`/v1/intelligence/market/${encodeURIComponent(naics.trim())}`);
66
+ }
67
+ /**
68
+ * Perform a full compliance check for a vendor.
69
+ *
70
+ * Returns: exclusion status, SAM.gov registration status, risk score,
71
+ * and risk indicators in one API call.
72
+ *
73
+ * @param params Object containing the UEI to check.
74
+ * @throws {NotFoundError} If the entity does not exist in SAM.gov.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * const compliance = await client.intelligence.complianceCheck({ uei: 'ABCDEF123456' });
79
+ * if (compliance.data.excluded || compliance.data.riskLevel === 'high') {
80
+ * console.warn('Do not contract with this vendor.');
81
+ * }
82
+ * ```
83
+ */
84
+ async complianceCheck(params) {
85
+ if (!params.uei || typeof params.uei !== 'string' || params.uei.trim() === '') {
86
+ throw new errors_js_1.ValidationError({ message: 'params.uei must be a non-empty string', status: 400 });
87
+ }
88
+ if (!/^[A-Za-z0-9]{12}$/.test(params.uei.trim())) {
89
+ throw new errors_js_1.ValidationError({ message: 'params.uei must be a 12-character alphanumeric string', status: 400 });
90
+ }
91
+ return this.http.post('/v1/intelligence/compliance-check', {
92
+ uei: params.uei.trim().toUpperCase(),
93
+ });
94
+ }
95
+ }
96
+ exports.IntelligenceResource = IntelligenceResource;
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ /**
3
+ * Opportunities resource client.
4
+ *
5
+ * Wraps all /v1/opportunities endpoints:
6
+ * - search (list) GET /v1/opportunities
7
+ * - stats GET /v1/opportunities/stats
8
+ * - get GET /v1/opportunities/:noticeId
9
+ * - createExport POST /v1/opportunities/export
10
+ * - getExport GET /v1/opportunities/export/:exportId
11
+ * - downloadExport GET /v1/opportunities/export/:exportId/download
12
+ * - paginate (generator) auto-paginates over the search endpoint
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.OpportunitiesResource = void 0;
16
+ class OpportunitiesResource {
17
+ http;
18
+ constructor(http) {
19
+ this.http = http;
20
+ }
21
+ /**
22
+ * Search and filter federal contract opportunities.
23
+ *
24
+ * @param params Filter and pagination parameters.
25
+ * @returns Paginated list of opportunities.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const result = await client.opportunities.list({
30
+ * q: 'cybersecurity',
31
+ * naics: '541512',
32
+ * postedAfter: '2025-01-01',
33
+ * limit: 50,
34
+ * });
35
+ * console.log(result.data[0].title);
36
+ * ```
37
+ */
38
+ async list(params = {}) {
39
+ return this.http.get('/v1/opportunities', params);
40
+ }
41
+ /**
42
+ * Get a single opportunity by its SAM.gov notice ID.
43
+ *
44
+ * @param noticeId The unique SAM.gov notice identifier.
45
+ * @throws {NotFoundError} If the opportunity does not exist.
46
+ */
47
+ async get(noticeId) {
48
+ if (!noticeId || typeof noticeId !== 'string' || noticeId.trim() === '') {
49
+ throw new Error('noticeId must be a non-empty string');
50
+ }
51
+ return this.http.get(`/v1/opportunities/${encodeURIComponent(noticeId.trim())}`);
52
+ }
53
+ /**
54
+ * Get aggregated statistics for opportunities.
55
+ *
56
+ * @param params Grouping and filter parameters.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * const stats = await client.opportunities.stats({ groupBy: 'naics', limit: 10 });
61
+ * ```
62
+ */
63
+ async stats(params = {}) {
64
+ return this.http.get('/v1/opportunities/stats', params);
65
+ }
66
+ /**
67
+ * Create a background export job for opportunities.
68
+ *
69
+ * Requires: Developer plan (CSV only) or Professional/Enterprise plan (all formats).
70
+ * Requires: `export` API key scope.
71
+ *
72
+ * @param params Export parameters (format + same filters as `list`).
73
+ * @returns Export job metadata.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * const job = await client.opportunities.createExport({ format: 'csv', agency: 'NASA' });
78
+ * // Poll getExport() until job.data.status === 'done', then call downloadExport().
79
+ * ```
80
+ */
81
+ async createExport(params) {
82
+ return this.http.post('/v1/opportunities/export', params);
83
+ }
84
+ /**
85
+ * Get the status of an export job.
86
+ *
87
+ * @param exportId UUID of the export job.
88
+ * @throws {NotFoundError} If the export job does not exist or belongs to another user.
89
+ */
90
+ async getExport(exportId) {
91
+ if (!exportId || typeof exportId !== 'string' || exportId.trim() === '') {
92
+ throw new Error('exportId must be a non-empty string');
93
+ }
94
+ return this.http.get(`/v1/opportunities/export/${encodeURIComponent(exportId.trim())}`, {}, { cacheTtlMs: 0 } // Never cache — status changes over time.
95
+ );
96
+ }
97
+ /**
98
+ * Download the output file of a completed export job.
99
+ *
100
+ * Returns the raw `Response` object so callers can stream or save the body.
101
+ * The response body will be CSV or NDJSON depending on the export format.
102
+ *
103
+ * @param exportId UUID of a **completed** export job.
104
+ * @returns Raw fetch `Response` with the file body.
105
+ * @throws {PermissionError} If the export is not complete.
106
+ * @throws {NotFoundError} If the export does not exist.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const response = await client.opportunities.downloadExport(exportId);
111
+ * const csv = await response.text();
112
+ * ```
113
+ */
114
+ async downloadExport(exportId) {
115
+ if (!exportId || typeof exportId !== 'string' || exportId.trim() === '') {
116
+ throw new Error('exportId must be a non-empty string');
117
+ }
118
+ return this.http.rawGet(`/v1/opportunities/export/${encodeURIComponent(exportId.trim())}/download`);
119
+ }
120
+ /**
121
+ * Async generator that automatically paginates over all matching opportunities.
122
+ *
123
+ * Uses cursor-based pagination when available, falling back to offset.
124
+ * Yields one page of results at a time.
125
+ *
126
+ * @param params Same filter parameters as `list()`. Do not pass `page` or `cursor`.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * for await (const page of client.opportunities.paginate({ naics: '541512' })) {
131
+ * for (const opp of page.data) {
132
+ * console.log(opp.title);
133
+ * }
134
+ * }
135
+ * ```
136
+ */
137
+ async *paginate(params) {
138
+ let cursor = undefined;
139
+ let page = 1;
140
+ let hasMore = true;
141
+ while (hasMore) {
142
+ const queryParams = {
143
+ ...params,
144
+ ...(cursor !== undefined ? { cursor } : { page }),
145
+ };
146
+ const result = await this.list(queryParams);
147
+ yield result;
148
+ const pagination = result.pagination;
149
+ if (pagination === null) {
150
+ hasMore = false;
151
+ }
152
+ else if ('nextCursor' in pagination) {
153
+ cursor = pagination.nextCursor ?? undefined;
154
+ hasMore = pagination.hasNextPage;
155
+ }
156
+ else if ('hasNextPage' in pagination) {
157
+ if (!pagination.hasNextPage) {
158
+ hasMore = false;
159
+ }
160
+ else {
161
+ page++;
162
+ }
163
+ }
164
+ else {
165
+ hasMore = false;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ exports.OpportunitiesResource = OpportunitiesResource;