easyeda-mcp-pro 0.3.2 → 0.5.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/README.md +369 -52
- package/dist/bom-quality/adapter.d.ts +90 -0
- package/dist/bom-quality/adapter.js +295 -0
- package/dist/bom-quality/adapter.js.map +1 -0
- package/dist/bom-quality/index.d.ts +10 -0
- package/dist/bom-quality/index.js +9 -0
- package/dist/bom-quality/index.js.map +1 -0
- package/dist/bom-quality/quality.d.ts +28 -0
- package/dist/bom-quality/quality.js +179 -0
- package/dist/bom-quality/quality.js.map +1 -0
- package/dist/bom-quality/types.d.ts +94 -0
- package/dist/bom-quality/types.js +12 -0
- package/dist/bom-quality/types.js.map +1 -0
- package/dist/bridge/manager.d.ts +41 -0
- package/dist/bridge/manager.js +334 -47
- package/dist/bridge/manager.js.map +1 -1
- package/dist/bridge/protocol.d.ts +48 -1
- package/dist/bridge/protocol.js +43 -1
- package/dist/bridge/protocol.js.map +1 -1
- package/dist/bridge/types.d.ts +6 -0
- package/dist/bridge/types.js +6 -0
- package/dist/bridge/types.js.map +1 -1
- package/dist/catalog/errors.d.ts +49 -0
- package/dist/catalog/errors.js +60 -0
- package/dist/catalog/errors.js.map +1 -0
- package/dist/catalog/index.d.ts +15 -0
- package/dist/catalog/index.js +17 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog/schema.d.ts +268 -0
- package/dist/catalog/schema.js +245 -0
- package/dist/catalog/schema.js.map +1 -0
- package/dist/catalog/starter.d.ts +159 -0
- package/dist/catalog/starter.js +579 -0
- package/dist/catalog/starter.js.map +1 -0
- package/dist/catalog/validation.d.ts +48 -0
- package/dist/catalog/validation.js +263 -0
- package/dist/catalog/validation.js.map +1 -0
- package/dist/circuit/circuit-ir.d.ts +460 -0
- package/dist/circuit/circuit-ir.js +292 -0
- package/dist/circuit/circuit-ir.js.map +1 -0
- package/dist/circuit/compiler.d.ts +55 -0
- package/dist/circuit/compiler.js +197 -0
- package/dist/circuit/compiler.js.map +1 -0
- package/dist/circuit/design-intent.d.ts +94 -0
- package/dist/circuit/design-intent.js +118 -0
- package/dist/circuit/design-intent.js.map +1 -0
- package/dist/circuit/errors.d.ts +50 -0
- package/dist/circuit/errors.js +61 -0
- package/dist/circuit/errors.js.map +1 -0
- package/dist/circuit/index.d.ts +17 -0
- package/dist/circuit/index.js +18 -0
- package/dist/circuit/index.js.map +1 -0
- package/dist/circuit/types.d.ts +186 -0
- package/dist/circuit/types.js +123 -0
- package/dist/circuit/types.js.map +1 -0
- package/dist/cli/auto-setup.d.ts +5 -0
- package/dist/cli/auto-setup.js +355 -0
- package/dist/cli/auto-setup.js.map +1 -0
- package/dist/cli/client-definitions.d.ts +34 -0
- package/dist/cli/client-definitions.js +194 -0
- package/dist/cli/client-definitions.js.map +1 -0
- package/dist/cli/local-setup.d.ts +5 -1
- package/dist/cli/local-setup.js +40 -6
- package/dist/cli/local-setup.js.map +1 -1
- package/dist/config/env.d.ts +6 -1
- package/dist/config/env.js +93 -5
- package/dist/config/env.js.map +1 -1
- package/dist/config/profiles.js +4 -4
- package/dist/config/version.d.ts +1 -1
- package/dist/config/version.js +1 -1
- package/dist/export-manifest/errors.d.ts +55 -0
- package/dist/export-manifest/errors.js +69 -0
- package/dist/export-manifest/errors.js.map +1 -0
- package/dist/export-manifest/index.d.ts +10 -0
- package/dist/export-manifest/index.js +9 -0
- package/dist/export-manifest/index.js.map +1 -0
- package/dist/export-manifest/types.d.ts +170 -0
- package/dist/export-manifest/types.js +36 -0
- package/dist/export-manifest/types.js.map +1 -0
- package/dist/export-manifest/validation.d.ts +39 -0
- package/dist/export-manifest/validation.js +298 -0
- package/dist/export-manifest/validation.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/dist/net-validation/errors.d.ts +89 -0
- package/dist/net-validation/errors.js +69 -0
- package/dist/net-validation/errors.js.map +1 -0
- package/dist/net-validation/fixtures.d.ts +38 -0
- package/dist/net-validation/fixtures.js +215 -0
- package/dist/net-validation/fixtures.js.map +1 -0
- package/dist/net-validation/index.d.ts +10 -0
- package/dist/net-validation/index.js +9 -0
- package/dist/net-validation/index.js.map +1 -0
- package/dist/net-validation/schema.d.ts +118 -0
- package/dist/net-validation/schema.js +140 -0
- package/dist/net-validation/schema.js.map +1 -0
- package/dist/net-validation/validation.d.ts +45 -0
- package/dist/net-validation/validation.js +369 -0
- package/dist/net-validation/validation.js.map +1 -0
- package/dist/pcb-constraints/errors.d.ts +39 -0
- package/dist/pcb-constraints/errors.js +133 -0
- package/dist/pcb-constraints/errors.js.map +1 -0
- package/dist/pcb-constraints/index.d.ts +9 -0
- package/dist/pcb-constraints/index.js +9 -0
- package/dist/pcb-constraints/index.js.map +1 -0
- package/dist/pcb-constraints/types.d.ts +102 -0
- package/dist/pcb-constraints/types.js +7 -0
- package/dist/pcb-constraints/types.js.map +1 -0
- package/dist/pcb-constraints/validation.d.ts +70 -0
- package/dist/pcb-constraints/validation.js +309 -0
- package/dist/pcb-constraints/validation.js.map +1 -0
- package/dist/server/factory.js +2 -0
- package/dist/server/factory.js.map +1 -1
- package/dist/server/transports/http.d.ts +20 -1
- package/dist/server/transports/http.js +156 -34
- package/dist/server/transports/http.js.map +1 -1
- package/dist/storage/database.d.ts +25 -0
- package/dist/storage/database.js +126 -51
- package/dist/storage/database.js.map +1 -1
- package/dist/tools/{L0_diagnostics.d.ts → L0_diagnostics_api.d.ts} +2 -2
- package/dist/tools/L0_diagnostics_api.js +152 -0
- package/dist/tools/L0_diagnostics_api.js.map +1 -0
- package/dist/tools/L0_diagnostics_core.d.ts +6 -0
- package/dist/tools/{L0_diagnostics.js → L0_diagnostics_core.js} +50 -124
- package/dist/tools/L0_diagnostics_core.js.map +1 -0
- package/dist/tools/L1_board.js +20 -4
- package/dist/tools/L1_board.js.map +1 -1
- package/dist/tools/{L1_bom.d.ts → L1_bom_core.d.ts} +2 -2
- package/dist/tools/{L1_bom.js → L1_bom_core.js} +21 -101
- package/dist/tools/L1_bom_core.js.map +1 -0
- package/dist/tools/{L1_schematic.d.ts → L1_bom_sourcing.d.ts} +2 -2
- package/dist/tools/L1_bom_sourcing.js +265 -0
- package/dist/tools/L1_bom_sourcing.js.map +1 -0
- package/dist/tools/L1_drc_erc.js +15 -3
- package/dist/tools/L1_drc_erc.js.map +1 -1
- package/dist/tools/L1_export.js +20 -4
- package/dist/tools/L1_export.js.map +1 -1
- package/dist/tools/L1_pcb_constraints.d.ts +6 -0
- package/dist/tools/L1_pcb_constraints.js +234 -0
- package/dist/tools/L1_pcb_constraints.js.map +1 -0
- package/dist/tools/L1_pcb_write.js +26 -12
- package/dist/tools/L1_pcb_write.js.map +1 -1
- package/dist/tools/L1_schematic_read.d.ts +6 -0
- package/dist/tools/{L1_schematic.js → L1_schematic_read.js} +125 -190
- package/dist/tools/L1_schematic_read.js.map +1 -0
- package/dist/tools/L1_schematic_write.d.ts +6 -0
- package/dist/tools/L1_schematic_write.js +516 -0
- package/dist/tools/L1_schematic_write.js.map +1 -0
- package/dist/tools/register.js +15 -7
- package/dist/tools/register.js.map +1 -1
- package/dist/tools/registry.d.ts +41 -7
- package/dist/tools/registry.js +111 -12
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/types.d.ts +16 -0
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/vendors/base-http-client.d.ts +48 -0
- package/dist/vendors/base-http-client.js +75 -0
- package/dist/vendors/base-http-client.js.map +1 -0
- package/dist/vendors/digikey/client.js +10 -19
- package/dist/vendors/digikey/client.js.map +1 -1
- package/dist/vendors/jlcpcb/client.js +41 -70
- package/dist/vendors/jlcpcb/client.js.map +1 -1
- package/dist/vendors/lcsc/client.js +5 -18
- package/dist/vendors/lcsc/client.js.map +1 -1
- package/dist/vendors/mouser/client.js +4 -12
- package/dist/vendors/mouser/client.js.map +1 -1
- package/easyeda-bridge-extension.eext +0 -0
- package/package.json +41 -26
- package/dist/tools/L0_diagnostics.js.map +0 -1
- package/dist/tools/L1_bom.js.map +0 -1
- package/dist/tools/L1_schematic.js.map +0 -1
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — supplier adapter layer.
|
|
3
|
+
*
|
|
4
|
+
* Provides a common {@link SupplierAdapter} interface over each vendor
|
|
5
|
+
* client so quality checks can query any configured supplier uniformly.
|
|
6
|
+
*
|
|
7
|
+
* Each adapter:
|
|
8
|
+
* - normalises part data into {@link SupplierQueryResult}
|
|
9
|
+
* - records a query timestamp for provenance
|
|
10
|
+
* - wraps transient errors with an exponential-backoff retry
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { EasyEdaMcpError } from '../schemas/common.js';
|
|
15
|
+
import { getLogger } from '../utils/logger.js';
|
|
16
|
+
// ── Retry helper ───────────────────────────────────────────────────────────
|
|
17
|
+
const RETRY_BASE_MS = 200;
|
|
18
|
+
const RETRY_MAX_MS = 2_000;
|
|
19
|
+
const RETRY_ATTEMPTS = 2;
|
|
20
|
+
async function withRetry(label, fn, logger, attempts = RETRY_ATTEMPTS) {
|
|
21
|
+
let lastError;
|
|
22
|
+
for (let i = 0; i <= attempts; i++) {
|
|
23
|
+
try {
|
|
24
|
+
return await fn(i);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
lastError = err;
|
|
28
|
+
// Only retry on retryable errors (rate limits, 5xx)
|
|
29
|
+
const retryable = err instanceof EasyEdaMcpError ? err.retryable === true : true; // unknown errors are not retried
|
|
30
|
+
if (!retryable || i === attempts) {
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
const delay = Math.min(RETRY_BASE_MS * 2 ** i, RETRY_MAX_MS);
|
|
34
|
+
logger.debug({ delay, attempt: i + 1, label }, 'retrying supplier query');
|
|
35
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
throw lastError;
|
|
39
|
+
}
|
|
40
|
+
function toLifecycle(raw) {
|
|
41
|
+
if (typeof raw === 'boolean')
|
|
42
|
+
return raw ? 'discontinued' : 'active';
|
|
43
|
+
if (typeof raw === 'string') {
|
|
44
|
+
const lc = raw.toLowerCase();
|
|
45
|
+
if (lc === 'active' || lc === 'production')
|
|
46
|
+
return 'active';
|
|
47
|
+
if (lc.includes('discon') || lc.includes('obsolete') || lc === 'eol')
|
|
48
|
+
return 'discontinued';
|
|
49
|
+
}
|
|
50
|
+
return 'unknown';
|
|
51
|
+
}
|
|
52
|
+
// ── LCSC adapter ───────────────────────────────────────────────────────────
|
|
53
|
+
export class LcscAdapter {
|
|
54
|
+
kind = 'lcsc';
|
|
55
|
+
displayName = 'LCSC';
|
|
56
|
+
client;
|
|
57
|
+
logger;
|
|
58
|
+
constructor(client) {
|
|
59
|
+
this.client = client;
|
|
60
|
+
this.logger = getLogger();
|
|
61
|
+
}
|
|
62
|
+
isAvailable() {
|
|
63
|
+
return this.client !== null;
|
|
64
|
+
}
|
|
65
|
+
buildFoundResult(detail, now) {
|
|
66
|
+
const unitPrice = detail.priceBreaks?.[0]?.unitPrice ??
|
|
67
|
+
(typeof detail.price === 'number'
|
|
68
|
+
? detail.price
|
|
69
|
+
: typeof detail.price === 'string'
|
|
70
|
+
? parseFloat(detail.price)
|
|
71
|
+
: undefined);
|
|
72
|
+
return {
|
|
73
|
+
supplier: 'lcsc',
|
|
74
|
+
found: true,
|
|
75
|
+
lcsc: detail.lcsc,
|
|
76
|
+
mpn: detail.manufacturer || undefined,
|
|
77
|
+
manufacturer: detail.manufacturer || undefined,
|
|
78
|
+
description: detail.description || undefined,
|
|
79
|
+
lifecycle: detail.discontinued ? 'discontinued' : 'active',
|
|
80
|
+
stock: detail.stockCount ?? detail.stock ?? 0,
|
|
81
|
+
unitPrice,
|
|
82
|
+
currency: 'USD',
|
|
83
|
+
leadTimeDays: detail.leadTime,
|
|
84
|
+
queriedAt: now,
|
|
85
|
+
confidence: 'high',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async queryPart(identifier) {
|
|
89
|
+
const client = this.client;
|
|
90
|
+
if (!client)
|
|
91
|
+
return null;
|
|
92
|
+
if (!identifier.lcsc && !identifier.mpn)
|
|
93
|
+
return null;
|
|
94
|
+
const lcscCode = identifier.lcsc;
|
|
95
|
+
if (!lcscCode)
|
|
96
|
+
return null; // LCSC requires an LCSC code
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
try {
|
|
99
|
+
const detail = await withRetry(`lcsc.getPartDetail(${lcscCode})`, () => client.getPartDetail(lcscCode), this.logger);
|
|
100
|
+
if (!detail) {
|
|
101
|
+
return {
|
|
102
|
+
supplier: 'lcsc',
|
|
103
|
+
found: false,
|
|
104
|
+
lifecycle: 'unknown',
|
|
105
|
+
stock: 0,
|
|
106
|
+
queriedAt: now,
|
|
107
|
+
confidence: 'medium',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return this.buildFoundResult(detail, now);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
this.logger.warn({ err, lcscCode }, 'lcsc adapter query failed');
|
|
114
|
+
// Return an "unavailable" result rather than throwing
|
|
115
|
+
return {
|
|
116
|
+
supplier: 'lcsc',
|
|
117
|
+
found: false,
|
|
118
|
+
lifecycle: 'unknown',
|
|
119
|
+
stock: 0,
|
|
120
|
+
queriedAt: now,
|
|
121
|
+
confidence: 'low',
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ── Mouser adapter ─────────────────────────────────────────────────────────
|
|
127
|
+
export class MouserAdapter {
|
|
128
|
+
kind = 'mouser';
|
|
129
|
+
displayName = 'Mouser';
|
|
130
|
+
client;
|
|
131
|
+
logger;
|
|
132
|
+
constructor(client) {
|
|
133
|
+
this.client = client;
|
|
134
|
+
this.logger = getLogger();
|
|
135
|
+
}
|
|
136
|
+
isAvailable() {
|
|
137
|
+
return this.client !== null;
|
|
138
|
+
}
|
|
139
|
+
buildFoundResult(part, now) {
|
|
140
|
+
return {
|
|
141
|
+
supplier: 'mouser',
|
|
142
|
+
found: true,
|
|
143
|
+
mpn: part.manufacturer || undefined,
|
|
144
|
+
manufacturer: part.manufacturer || undefined,
|
|
145
|
+
description: part.description || undefined,
|
|
146
|
+
lifecycle: 'active',
|
|
147
|
+
stock: part.availability ?? 0,
|
|
148
|
+
unitPrice: part.priceBreaks?.[0]?.price,
|
|
149
|
+
currency: 'USD',
|
|
150
|
+
leadTimeDays: part.leadTime ? parseInt(part.leadTime, 10) || undefined : undefined,
|
|
151
|
+
queriedAt: now,
|
|
152
|
+
confidence: 'high',
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
async queryPart(identifier) {
|
|
156
|
+
const client = this.client;
|
|
157
|
+
if (!client)
|
|
158
|
+
return null;
|
|
159
|
+
const mpn = identifier.mpn;
|
|
160
|
+
if (!mpn)
|
|
161
|
+
return null; // Mouser requires an MPN
|
|
162
|
+
const now = new Date().toISOString();
|
|
163
|
+
try {
|
|
164
|
+
const results = await withRetry(`mouser.searchByPartNumber(${mpn})`, () => client.searchByPartNumber(mpn), this.logger);
|
|
165
|
+
if (!results || results.length === 0) {
|
|
166
|
+
return {
|
|
167
|
+
supplier: 'mouser',
|
|
168
|
+
found: false,
|
|
169
|
+
lifecycle: 'unknown',
|
|
170
|
+
stock: 0,
|
|
171
|
+
queriedAt: now,
|
|
172
|
+
confidence: 'medium',
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const part = results[0];
|
|
176
|
+
if (!part) {
|
|
177
|
+
return {
|
|
178
|
+
supplier: 'mouser',
|
|
179
|
+
found: false,
|
|
180
|
+
lifecycle: 'unknown',
|
|
181
|
+
stock: 0,
|
|
182
|
+
queriedAt: now,
|
|
183
|
+
confidence: 'medium',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return this.buildFoundResult(part, now);
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
this.logger.warn({ err, mpn }, 'mouser adapter query failed');
|
|
190
|
+
return {
|
|
191
|
+
supplier: 'mouser',
|
|
192
|
+
found: false,
|
|
193
|
+
lifecycle: 'unknown',
|
|
194
|
+
stock: 0,
|
|
195
|
+
queriedAt: now,
|
|
196
|
+
confidence: 'low',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// ── DigiKey adapter ────────────────────────────────────────────────────────
|
|
202
|
+
export class DigiKeyAdapter {
|
|
203
|
+
kind = 'digikey';
|
|
204
|
+
displayName = 'DigiKey';
|
|
205
|
+
client;
|
|
206
|
+
logger;
|
|
207
|
+
constructor(client) {
|
|
208
|
+
this.client = client;
|
|
209
|
+
this.logger = getLogger();
|
|
210
|
+
}
|
|
211
|
+
isAvailable() {
|
|
212
|
+
return this.client !== null;
|
|
213
|
+
}
|
|
214
|
+
buildFoundResult(part, mpn, now) {
|
|
215
|
+
return {
|
|
216
|
+
supplier: 'digikey',
|
|
217
|
+
found: true,
|
|
218
|
+
mpn: part.manufacturerPartNumber || undefined,
|
|
219
|
+
manufacturer: part.manufacturer || undefined,
|
|
220
|
+
description: part.description || undefined,
|
|
221
|
+
lifecycle: toLifecycle(part.rohsStatus), // RoHS active is a loose proxy
|
|
222
|
+
stock: part.quantityAvailable ?? 0,
|
|
223
|
+
unitPrice: part.unitPrice || undefined,
|
|
224
|
+
currency: 'USD',
|
|
225
|
+
queriedAt: now,
|
|
226
|
+
confidence: part.manufacturerPartNumber?.toLowerCase() === mpn.toLowerCase() ? 'high' : 'medium',
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
async queryPart(identifier) {
|
|
230
|
+
const client = this.client;
|
|
231
|
+
if (!client)
|
|
232
|
+
return null;
|
|
233
|
+
const mpn = identifier.mpn;
|
|
234
|
+
if (!mpn)
|
|
235
|
+
return null; // DigiKey requires MPN or keyword
|
|
236
|
+
const now = new Date().toISOString();
|
|
237
|
+
try {
|
|
238
|
+
// Use keyword search as a proxy — DigiKey doesn't expose a
|
|
239
|
+
// direct MPN-lookup endpoint in the current client.
|
|
240
|
+
const results = await withRetry(`digikey.searchByKeyword(${mpn})`, () => client.searchByKeyword(mpn), this.logger);
|
|
241
|
+
if (!results || results.length === 0) {
|
|
242
|
+
return {
|
|
243
|
+
supplier: 'digikey',
|
|
244
|
+
found: false,
|
|
245
|
+
lifecycle: 'unknown',
|
|
246
|
+
stock: 0,
|
|
247
|
+
queriedAt: now,
|
|
248
|
+
confidence: 'medium',
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
// Take the first result — keyword search returns best match first
|
|
252
|
+
const part = results[0];
|
|
253
|
+
if (!part) {
|
|
254
|
+
return {
|
|
255
|
+
supplier: 'digikey',
|
|
256
|
+
found: false,
|
|
257
|
+
lifecycle: 'unknown',
|
|
258
|
+
stock: 0,
|
|
259
|
+
queriedAt: now,
|
|
260
|
+
confidence: 'medium',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return this.buildFoundResult(part, mpn, now);
|
|
264
|
+
}
|
|
265
|
+
catch (err) {
|
|
266
|
+
this.logger.warn({ err, mpn }, 'digikey adapter query failed');
|
|
267
|
+
return {
|
|
268
|
+
supplier: 'digikey',
|
|
269
|
+
found: false,
|
|
270
|
+
lifecycle: 'unknown',
|
|
271
|
+
stock: 0,
|
|
272
|
+
queriedAt: now,
|
|
273
|
+
confidence: 'low',
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Build the adapter map from a ToolContext vendors object.
|
|
280
|
+
* Each adapter wraps the corresponding vendor client (or null if disabled).
|
|
281
|
+
*/
|
|
282
|
+
export function createAdapters(vendors) {
|
|
283
|
+
return {
|
|
284
|
+
lcsc: new LcscAdapter(vendors.lcsc),
|
|
285
|
+
mouser: new MouserAdapter(vendors.mouser),
|
|
286
|
+
digikey: new DigiKeyAdapter(vendors.digikey),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Return the subset of adapters that are currently configured / available.
|
|
291
|
+
*/
|
|
292
|
+
export function availableAdapters(adapters) {
|
|
293
|
+
return Object.values(adapters).filter((a) => a.isAvailable());
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/bom-quality/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — public API barrel.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
export type { SupplierKind, PartLifecycle, BomEntry, SupplierQueryResult, BomQualityIssueType, BomQualityIssue, BomQualityReport, BomQualityConfig, } from './types.js';
|
|
7
|
+
export { DEFAULT_BOM_QUALITY_CONFIG } from './types.js';
|
|
8
|
+
export type { SupplierAdapter, AdapterMap } from './adapter.js';
|
|
9
|
+
export { LcscAdapter, MouserAdapter, DigiKeyAdapter, createAdapters, availableAdapters, } from './adapter.js';
|
|
10
|
+
export { generateBomQualityReport } from './quality.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — public API barrel.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
export { DEFAULT_BOM_QUALITY_CONFIG } from './types.js';
|
|
7
|
+
export { LcscAdapter, MouserAdapter, DigiKeyAdapter, createAdapters, availableAdapters, } from './adapter.js';
|
|
8
|
+
export { generateBomQualityReport } from './quality.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bom-quality/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAGxD,OAAO,EACL,WAAW,EACX,aAAa,EACb,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — report generation.
|
|
3
|
+
*
|
|
4
|
+
* Analyses BOM entries against supplier data to surface issues:
|
|
5
|
+
* 1. **Unavailable** — part not found or discontinued at any supplier.
|
|
6
|
+
* 2. **Single-source** — part found at exactly one supplier.
|
|
7
|
+
* 3. **Missing MPN** — no manufacturer part number.
|
|
8
|
+
* 4. **Missing footprint** — no package / footprint.
|
|
9
|
+
* 5. **Low stock** — stock below threshold at every supplier.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import type { BomEntry, BomQualityReport, BomQualityConfig } from './types.js';
|
|
14
|
+
import type { AdapterMap } from './adapter.js';
|
|
15
|
+
/**
|
|
16
|
+
* Generate a BOM quality report for the given entries.
|
|
17
|
+
*
|
|
18
|
+
* For each entry the function:
|
|
19
|
+
* 1. Queries every available supplier that can handle the entry.
|
|
20
|
+
* 2. Collects supplier results (with error resilience).
|
|
21
|
+
* 3. Runs the five quality checks.
|
|
22
|
+
* 4. Returns a structured report with a summary.
|
|
23
|
+
*
|
|
24
|
+
* Supplier failures are caught gracefully — the report always succeeds
|
|
25
|
+
* (non-null), with `hasSupplierErrors` set to `true` and any affected
|
|
26
|
+
* entries marked via their issues.
|
|
27
|
+
*/
|
|
28
|
+
export declare function generateBomQualityReport(bomId: string, entries: BomEntry[], adapters: AdapterMap, config?: BomQualityConfig): Promise<BomQualityReport>;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — report generation.
|
|
3
|
+
*
|
|
4
|
+
* Analyses BOM entries against supplier data to surface issues:
|
|
5
|
+
* 1. **Unavailable** — part not found or discontinued at any supplier.
|
|
6
|
+
* 2. **Single-source** — part found at exactly one supplier.
|
|
7
|
+
* 3. **Missing MPN** — no manufacturer part number.
|
|
8
|
+
* 4. **Missing footprint** — no package / footprint.
|
|
9
|
+
* 5. **Low stock** — stock below threshold at every supplier.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { DEFAULT_BOM_QUALITY_CONFIG } from './types.js';
|
|
14
|
+
import { availableAdapters } from './adapter.js';
|
|
15
|
+
import { getLogger } from '../utils/logger.js';
|
|
16
|
+
// ── Issue factory ──────────────────────────────────────────────────────────
|
|
17
|
+
function issue(type, severity, reference, message, details) {
|
|
18
|
+
return { type, severity, reference, message, details };
|
|
19
|
+
}
|
|
20
|
+
function unavailableIssue(ref, supplier, reason) {
|
|
21
|
+
return issue('unavailable', 'error', ref, `Part not available at ${supplier}: ${reason}`, {
|
|
22
|
+
supplier,
|
|
23
|
+
reason,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function singleSourceIssue(ref, suppliers) {
|
|
27
|
+
return issue('single_source', 'warning', ref, `Part is single-sourced (only found at ${suppliers.join(', ')})`, { suppliers });
|
|
28
|
+
}
|
|
29
|
+
function missingMpnIssue(ref) {
|
|
30
|
+
return issue('missing_mpn', 'warning', ref, 'No manufacturer part number (MPN) specified — replaceability is limited');
|
|
31
|
+
}
|
|
32
|
+
function missingFootprintIssue(ref) {
|
|
33
|
+
return issue('missing_footprint', 'warning', ref, 'No footprint / package specified — PCB layout verification is not possible');
|
|
34
|
+
}
|
|
35
|
+
function lowStockIssue(ref, supplier, stock) {
|
|
36
|
+
return issue('low_stock', 'warning', ref, `Low stock at ${supplier}: ${stock} units`, {
|
|
37
|
+
supplier,
|
|
38
|
+
stock,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// ── Supplier query scope ───────────────────────────────────────────────────
|
|
42
|
+
/**
|
|
43
|
+
* Determine which supplier identifiers to query based on what the entry has.
|
|
44
|
+
* - If an LCSC code is present, query LCSC.
|
|
45
|
+
* - If an MPN is present, query Mouser and DigiKey.
|
|
46
|
+
*/
|
|
47
|
+
function queryTargets(entry) {
|
|
48
|
+
const targets = [];
|
|
49
|
+
if (entry.lcsc) {
|
|
50
|
+
targets.push({ supplier: 'lcsc', identifier: { lcsc: entry.lcsc } });
|
|
51
|
+
}
|
|
52
|
+
if (entry.mpn) {
|
|
53
|
+
targets.push({ supplier: 'mouser', identifier: { mpn: entry.mpn } });
|
|
54
|
+
targets.push({ supplier: 'digikey', identifier: { mpn: entry.mpn } });
|
|
55
|
+
}
|
|
56
|
+
return targets;
|
|
57
|
+
}
|
|
58
|
+
// ── Supplier query helper ────────────────────────────────────────────────
|
|
59
|
+
async function querySuppliersForEntry(entry, adapterByKind, _logger) {
|
|
60
|
+
const targets = queryTargets(entry);
|
|
61
|
+
const supplierData = [];
|
|
62
|
+
let hasErrors = false;
|
|
63
|
+
for (const target of targets) {
|
|
64
|
+
const adapter = adapterByKind.get(target.supplier);
|
|
65
|
+
if (!adapter)
|
|
66
|
+
continue;
|
|
67
|
+
try {
|
|
68
|
+
const result = await adapter.queryPart(target.identifier);
|
|
69
|
+
if (result) {
|
|
70
|
+
supplierData.push(result);
|
|
71
|
+
if (result.confidence === 'low')
|
|
72
|
+
hasErrors = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Should not happen (adapters catch internally), but safeguard
|
|
77
|
+
hasErrors = true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { supplierData, hasErrors, queriedCount: targets.length };
|
|
81
|
+
}
|
|
82
|
+
// ── Main entry point ───────────────────────────────────────────────────────
|
|
83
|
+
/**
|
|
84
|
+
* Generate a BOM quality report for the given entries.
|
|
85
|
+
*
|
|
86
|
+
* For each entry the function:
|
|
87
|
+
* 1. Queries every available supplier that can handle the entry.
|
|
88
|
+
* 2. Collects supplier results (with error resilience).
|
|
89
|
+
* 3. Runs the five quality checks.
|
|
90
|
+
* 4. Returns a structured report with a summary.
|
|
91
|
+
*
|
|
92
|
+
* Supplier failures are caught gracefully — the report always succeeds
|
|
93
|
+
* (non-null), with `hasSupplierErrors` set to `true` and any affected
|
|
94
|
+
* entries marked via their issues.
|
|
95
|
+
*/
|
|
96
|
+
export async function generateBomQualityReport(bomId, entries, adapters, config = DEFAULT_BOM_QUALITY_CONFIG) {
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
let hasSupplierErrors = false;
|
|
99
|
+
// Resolve available adapters once
|
|
100
|
+
const adapterList = availableAdapters(adapters);
|
|
101
|
+
const adapterByKind = new Map(adapterList.map((a) => [a.kind, a]));
|
|
102
|
+
const logger = getLogger();
|
|
103
|
+
const reportEntries = await Promise.all(entries.map(async (entry) => {
|
|
104
|
+
// ── 1. Query applicable suppliers ──────────────────────────────────
|
|
105
|
+
const { supplierData, hasErrors, queriedCount } = await querySuppliersForEntry(entry, adapterByKind, logger);
|
|
106
|
+
if (hasErrors)
|
|
107
|
+
hasSupplierErrors = true;
|
|
108
|
+
// ── 2. Run quality checks ──────────────────────────────────────────
|
|
109
|
+
const issues = [];
|
|
110
|
+
// Check: unavailable (not found or discontinued at any queried supplier)
|
|
111
|
+
const foundSuppliers = supplierData.filter((s) => s.found);
|
|
112
|
+
const discontinuedSuppliers = supplierData.filter((s) => s.found && s.lifecycle === 'discontinued');
|
|
113
|
+
if (supplierData.length > 0 && foundSuppliers.length === 0) {
|
|
114
|
+
// Queried at least one supplier, none had it
|
|
115
|
+
const queried = supplierData.map((s) => s.supplier).join(', ');
|
|
116
|
+
issues.push(unavailableIssue(entry.reference, queried, 'not found at any supplier'));
|
|
117
|
+
}
|
|
118
|
+
for (const ds of discontinuedSuppliers) {
|
|
119
|
+
issues.push(unavailableIssue(entry.reference, ds.supplier, 'discontinued / obsolete'));
|
|
120
|
+
}
|
|
121
|
+
// Check: single-source
|
|
122
|
+
const uniqueFoundSuppliers = [...new Set(foundSuppliers.map((s) => s.supplier))];
|
|
123
|
+
if (uniqueFoundSuppliers.length === 1 && queriedCount > 1) {
|
|
124
|
+
// Only flag single-source when we actually queried more than one supplier
|
|
125
|
+
// (i.e. the entry had identifiers for multiple suppliers)
|
|
126
|
+
issues.push(singleSourceIssue(entry.reference, uniqueFoundSuppliers));
|
|
127
|
+
}
|
|
128
|
+
// Check: missing MPN
|
|
129
|
+
if (config.requireMpn && !entry.mpn && !entry.manufacturer) {
|
|
130
|
+
issues.push(missingMpnIssue(entry.reference));
|
|
131
|
+
}
|
|
132
|
+
// Check: missing footprint
|
|
133
|
+
if (config.requireFootprint && !entry.footprint) {
|
|
134
|
+
issues.push(missingFootprintIssue(entry.reference));
|
|
135
|
+
}
|
|
136
|
+
// Check: low stock (at every found supplier)
|
|
137
|
+
if (foundSuppliers.length > 0) {
|
|
138
|
+
const allLow = foundSuppliers.every((s) => s.stock < config.lowStockThreshold);
|
|
139
|
+
if (allLow) {
|
|
140
|
+
for (const fs of foundSuppliers) {
|
|
141
|
+
issues.push(lowStockIssue(entry.reference, fs.supplier, fs.stock));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
reference: entry.reference,
|
|
147
|
+
description: entry.value ?? '',
|
|
148
|
+
footprint: entry.footprint ?? '',
|
|
149
|
+
quantity: entry.quantity,
|
|
150
|
+
lcsc: entry.lcsc,
|
|
151
|
+
mpn: entry.mpn,
|
|
152
|
+
manufacturer: entry.manufacturer,
|
|
153
|
+
supplierData,
|
|
154
|
+
issues,
|
|
155
|
+
};
|
|
156
|
+
}));
|
|
157
|
+
// ── 3. Aggregate summary ────────────────────────────────────────────────
|
|
158
|
+
const allIssues = reportEntries.flatMap((e) => e.issues);
|
|
159
|
+
const summary = {
|
|
160
|
+
totalIssues: allIssues.length,
|
|
161
|
+
errors: allIssues.filter((i) => i.severity === 'error').length,
|
|
162
|
+
warnings: allIssues.filter((i) => i.severity === 'warning').length,
|
|
163
|
+
info: allIssues.filter((i) => i.severity === 'info').length,
|
|
164
|
+
unavailableCount: allIssues.filter((i) => i.type === 'unavailable').length,
|
|
165
|
+
singleSourceCount: allIssues.filter((i) => i.type === 'single_source').length,
|
|
166
|
+
missingMpnCount: allIssues.filter((i) => i.type === 'missing_mpn').length,
|
|
167
|
+
missingFootprintCount: allIssues.filter((i) => i.type === 'missing_footprint').length,
|
|
168
|
+
lowStockCount: allIssues.filter((i) => i.type === 'low_stock').length,
|
|
169
|
+
};
|
|
170
|
+
return {
|
|
171
|
+
bomId,
|
|
172
|
+
generatedAt: now,
|
|
173
|
+
totalEntries: entries.length,
|
|
174
|
+
entries: reportEntries,
|
|
175
|
+
summary,
|
|
176
|
+
hasSupplierErrors,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/bom-quality/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,8EAA8E;AAE9E,SAAS,KAAK,CACZ,IAAyB,EACzB,QAAsC,EACtC,SAAiB,EACjB,OAAe,EACf,OAAiC;IAEjC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AACzD,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW,EAAE,QAAgB,EAAE,MAAc;IACrE,OAAO,KAAK,CAAC,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE,yBAAyB,QAAQ,KAAK,MAAM,EAAE,EAAE;QACxF,QAAQ;QACR,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW,EAAE,SAAyB;IAC/D,OAAO,KAAK,CACV,eAAe,EACf,SAAS,EACT,GAAG,EACH,yCAAyC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAChE,EAAE,SAAS,EAAE,CACd,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAW;IAClC,OAAO,KAAK,CACV,aAAa,EACb,SAAS,EACT,GAAG,EACH,yEAAyE,CAC1E,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,GAAW;IACxC,OAAO,KAAK,CACV,mBAAmB,EACnB,SAAS,EACT,GAAG,EACH,4EAA4E,CAC7E,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAW,EAAE,QAAgB,EAAE,KAAa;IACjE,OAAO,KAAK,CAAC,WAAW,EAAE,SAAS,EAAE,GAAG,EAAE,gBAAgB,QAAQ,KAAK,KAAK,QAAQ,EAAE;QACpF,QAAQ;QACR,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,YAAY,CACnB,KAAe;IAEf,MAAM,OAAO,GAGR,EAAE,CAAC;IAER,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,4EAA4E;AAE5E,KAAK,UAAU,sBAAsB,CACnC,KAAe,EACf,aAAiD,EACjD,OAAoB;IAEpB,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,YAAY,GAA0B,EAAE,CAAC;IAC/C,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC1D,IAAI,MAAM,EAAE,CAAC;gBACX,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC1B,IAAI,MAAM,CAAC,UAAU,KAAK,KAAK;oBAAE,SAAS,GAAG,IAAI,CAAC;YACpD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;AACnE,CAAC;AAED,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAAa,EACb,OAAmB,EACnB,QAAoB,EACpB,SAA2B,0BAA0B;IAErD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAE9B,kCAAkC;IAClC,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,GAAG,CACrC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC1B,sEAAsE;QACtE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,sBAAsB,CAC5E,KAAK,EACL,aAAa,EACb,MAAM,CACP,CAAC;QACF,IAAI,SAAS;YAAE,iBAAiB,GAAG,IAAI,CAAC;QAExC,sEAAsE;QACtE,MAAM,MAAM,GAAsB,EAAE,CAAC;QAErC,yEAAyE;QACzE,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3D,MAAM,qBAAqB,GAAG,YAAY,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,SAAS,KAAK,cAAc,CACjD,CAAC;QAEF,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3D,6CAA6C;YAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,2BAA2B,CAAC,CAAC,CAAC;QACvF,CAAC;QAED,KAAK,MAAM,EAAE,IAAI,qBAAqB,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,EAAE,yBAAyB,CAAC,CAAC,CAAC;QACzF,CAAC;QAED,uBAAuB;QACvB,MAAM,oBAAoB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACjF,IAAI,oBAAoB,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YAC1D,0EAA0E;YAC1E,0DAA0D;YAC1D,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACxE,CAAC;QAED,qBAAqB;QACrB,IAAI,MAAM,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAChD,CAAC;QAED,2BAA2B;QAC3B,IAAI,MAAM,CAAC,gBAAgB,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;YAChD,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QACtD,CAAC;QAED,6CAA6C;QAC7C,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;YAC/E,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;oBAChC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;gBACrE,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,WAAW,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;YAC9B,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,EAAE;YAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,YAAY;YACZ,MAAM;SACP,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEF,2EAA2E;IAC3E,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG;QACd,WAAW,EAAE,SAAS,CAAC,MAAM;QAC7B,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;QAC9D,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM;QAClE,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM;QAC3D,gBAAgB,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,MAAM;QAC1E,iBAAiB,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,MAAM;QAC7E,eAAe,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,MAAM;QACzE,qBAAqB,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,mBAAmB,CAAC,CAAC,MAAM;QACrF,aAAa,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,MAAM;KACtE,CAAC;IAEF,OAAO;QACL,KAAK;QACL,WAAW,EAAE,GAAG;QAChB,YAAY,EAAE,OAAO,CAAC,MAAM;QAC5B,OAAO,EAAE,aAAa;QACtB,OAAO;QACP,iBAAiB;KAClB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — core type definitions.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/** Supported supplier identifiers. */
|
|
7
|
+
export type SupplierKind = 'lcsc' | 'mouser' | 'digikey' | 'jlcpcb';
|
|
8
|
+
/** Lifecycle / status of a part at a supplier. */
|
|
9
|
+
export type PartLifecycle = 'active' | 'discontinued' | 'unknown';
|
|
10
|
+
/** BOM entry as passed to quality check, extended with metadata. */
|
|
11
|
+
export interface BomEntry {
|
|
12
|
+
reference: string;
|
|
13
|
+
value?: string;
|
|
14
|
+
footprint?: string;
|
|
15
|
+
lcsc?: string;
|
|
16
|
+
mpn?: string;
|
|
17
|
+
manufacturer?: string;
|
|
18
|
+
quantity: number;
|
|
19
|
+
/** Source of this entry (e.g. 'bridge', 'manual'). */
|
|
20
|
+
source: string;
|
|
21
|
+
/** ISO-8601 timestamp when this entry was obtained. */
|
|
22
|
+
fetchedAt: string;
|
|
23
|
+
}
|
|
24
|
+
/** Normalised result from a single supplier query. */
|
|
25
|
+
export interface SupplierQueryResult {
|
|
26
|
+
supplier: SupplierKind;
|
|
27
|
+
found: boolean;
|
|
28
|
+
lcsc?: string;
|
|
29
|
+
mpn?: string;
|
|
30
|
+
manufacturer?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
lifecycle: PartLifecycle;
|
|
33
|
+
stock: number;
|
|
34
|
+
unitPrice?: number;
|
|
35
|
+
currency?: string;
|
|
36
|
+
leadTimeDays?: number;
|
|
37
|
+
/** ISO-8601 timestamp of this supplier response. */
|
|
38
|
+
queriedAt: string;
|
|
39
|
+
/** Human-readable confidence (e.g. 'high', 'medium', 'low'). */
|
|
40
|
+
confidence: 'high' | 'medium' | 'low';
|
|
41
|
+
}
|
|
42
|
+
/** Issue type identifiers for the BOM quality report. */
|
|
43
|
+
export type BomQualityIssueType = 'unavailable' | 'single_source' | 'missing_mpn' | 'missing_footprint' | 'low_stock';
|
|
44
|
+
/** A single quality issue found for a BOM entry. */
|
|
45
|
+
export interface BomQualityIssue {
|
|
46
|
+
type: BomQualityIssueType;
|
|
47
|
+
severity: 'error' | 'warning' | 'info';
|
|
48
|
+
reference: string;
|
|
49
|
+
message: string;
|
|
50
|
+
details?: Record<string, unknown>;
|
|
51
|
+
}
|
|
52
|
+
/** Complete BOM quality report. */
|
|
53
|
+
export interface BomQualityReport {
|
|
54
|
+
bomId: string;
|
|
55
|
+
generatedAt: string;
|
|
56
|
+
totalEntries: number;
|
|
57
|
+
entries: Array<{
|
|
58
|
+
reference: string;
|
|
59
|
+
description: string;
|
|
60
|
+
footprint: string;
|
|
61
|
+
quantity: number;
|
|
62
|
+
lcsc?: string;
|
|
63
|
+
mpn?: string;
|
|
64
|
+
manufacturer?: string;
|
|
65
|
+
/** Supplier-specific data collected during the check. */
|
|
66
|
+
supplierData: SupplierQueryResult[];
|
|
67
|
+
issues: BomQualityIssue[];
|
|
68
|
+
}>;
|
|
69
|
+
summary: {
|
|
70
|
+
totalIssues: number;
|
|
71
|
+
errors: number;
|
|
72
|
+
warnings: number;
|
|
73
|
+
info: number;
|
|
74
|
+
unavailableCount: number;
|
|
75
|
+
singleSourceCount: number;
|
|
76
|
+
missingMpnCount: number;
|
|
77
|
+
missingFootprintCount: number;
|
|
78
|
+
lowStockCount: number;
|
|
79
|
+
};
|
|
80
|
+
/** Whether any suppliers returned errors during the check. */
|
|
81
|
+
hasSupplierErrors: boolean;
|
|
82
|
+
}
|
|
83
|
+
/** Configuration for BOM quality checking. */
|
|
84
|
+
export interface BomQualityConfig {
|
|
85
|
+
/** Stock threshold below which a part is considered low-stock. */
|
|
86
|
+
lowStockThreshold: number;
|
|
87
|
+
/** Whether to treat a missing LCSC code as an error. */
|
|
88
|
+
requireLcsc: boolean;
|
|
89
|
+
/** Whether to treat a missing MPN as a warning. */
|
|
90
|
+
requireMpn: boolean;
|
|
91
|
+
/** Whether to treat a missing footprint as a warning. */
|
|
92
|
+
requireFootprint: boolean;
|
|
93
|
+
}
|
|
94
|
+
export declare const DEFAULT_BOM_QUALITY_CONFIG: BomQualityConfig;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/bom-quality/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuGH,MAAM,CAAC,MAAM,0BAA0B,GAAqB;IAC1D,iBAAiB,EAAE,GAAG;IACtB,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,IAAI;IAChB,gBAAgB,EAAE,IAAI;CACvB,CAAC"}
|