diff --git a/deploy/cloudflare/bearings-codebook/README.md b/deploy/cloudflare/bearings-codebook/README.md new file mode 100644 index 0000000..6a5437a --- /dev/null +++ b/deploy/cloudflare/bearings-codebook/README.md @@ -0,0 +1,17 @@ +# EVEREST Cloudflare Worker — codebook only (staging) + +This separate, not-deployed Worker snapshots 55 manufacturer-scoped code definitions from verified_manufacturer_codes.csv, keeping the source URL and OEM scope. It **does not infer ГОСТ↔ISO product interchangeability**. + +- GET /health +- GET /v1/lookup?brand=SKF&code=2RSH +- POST /v1/decode {"brand":"SKF","suffix":"2RSH/C3"} +- POST /v1/compare {"left":{"brand":"NSK","suffix":"DDU"},"right":{"brand":"NTN","suffix":"LLU"}} + +Every route returns auto_replace_allowed=false. No customer catalogue, pricing, CRM, 1C, databases, credentials or approval endpoints. Unknown codes and unfamiliar brands trigger review; INA does not inherit FAG suffixes. + +Read-only **proof of concept**, not a substitute for PR #187 engineering gate. Cloudflare API connector was unavailable; no changes were made in Cloudflare. The worker has workers_dev:false and no routes; deployment is intentionally prevented without a new explicit route. + +Run: node --test test/*.test.mjs + +Primary source: data/reference/verified_manufacturer_codes.csv from PR #186. Target branch stacks on PR #188. +Cloudflare docs: https://developers.cloudflare.com/workers/wrangler/configuration/ diff --git a/deploy/cloudflare/bearings-codebook/data/verified_codes.json b/deploy/cloudflare/bearings-codebook/data/verified_codes.json new file mode 100644 index 0000000..934cd47 --- /dev/null +++ b/deploy/cloudflare/bearings-codebook/data/verified_codes.json @@ -0,0 +1,772 @@ +[ + { + "manufacturer": "SKF", + "code": "2Z", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "two", + "meaning_ru": "Две металлические защитные шайбы", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://evolution.skf.com/en/added-versatility-as-use-of-rsh-heavy-duty-seals-is-extended/", + "source_locator": "SKF Evolution — sealing solutions", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "Z", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "one", + "meaning_ru": "Одна металлическая защитная шайба", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://cdn.skfmediahub.skf.com/api/public/0901d196802809de/pdf_preview_medium/0901d196802809de_pdf_preview_medium.pdf", + "source_locator": "SKF Deep Groove Ball Bearings — Designation system, p. 258", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "2RZ", + "component": "suffix", + "feature": "seal", + "contact_type": "noncontact", + "sides": "two", + "meaning_ru": "Два бесконтактных уплотнения", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://evolution.skf.com/en/added-versatility-as-use-of-rsh-heavy-duty-seals-is-extended/", + "source_locator": "SKF Evolution — sealing solutions", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "RZ", + "component": "suffix", + "feature": "seal", + "contact_type": "noncontact", + "sides": "one", + "meaning_ru": "Одно бесконтактное уплотнение", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://cdn.skfmediahub.skf.com/api/public/0901d196802809de/pdf_preview_medium/0901d196802809de_pdf_preview_medium.pdf", + "source_locator": "SKF Deep Groove Ball Bearings — Designation system, p. 258", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "2RS1", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "two", + "meaning_ru": "Два контактных уплотнения", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://evolution.skf.com/en/added-versatility-as-use-of-rsh-heavy-duty-seals-is-extended/", + "source_locator": "SKF Evolution — sealing solutions", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "RS1", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "one", + "meaning_ru": "Одно контактное уплотнение", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://cdn.skfmediahub.skf.com/api/public/0901d196802809de/pdf_preview_medium/0901d196802809de_pdf_preview_medium.pdf", + "source_locator": "SKF Deep Groove Ball Bearings — Designation system, p. 258", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "2RSH", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "two", + "meaning_ru": "Два контактных уплотнения RSH", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://evolution.skf.com/en/added-versatility-as-use-of-rsh-heavy-duty-seals-is-extended/", + "source_locator": "SKF Evolution — sealing solutions", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "RSH", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "one", + "meaning_ru": "Одно контактное уплотнение RSH", + "bearing_scope": "радиальные шариковые подшипники SKF", + "source_url": "https://cdn.skfmediahub.skf.com/api/public/0901d196802809de/pdf_preview_medium/0901d196802809de_pdf_preview_medium.pdf", + "source_locator": "SKF Deep Groove Ball Bearings — Designation system, p. 258", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "C2", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор меньше нормального", + "bearing_scope": "подшипники SKF; сверить применимость для типа", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — internal clearance", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "C3", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор больше нормального", + "bearing_scope": "подшипники SKF; сверить применимость для типа", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — internal clearance", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "C4", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор больше C3", + "bearing_scope": "подшипники SKF; сверить применимость для типа", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — internal clearance", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "P6", + "component": "suffix", + "feature": "precision", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Класс точности P6", + "bearing_scope": "подшипники SKF", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — common suffixes", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "W33", + "component": "suffix", + "feature": "lubrication", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Канавка и три отверстия для смазки наружного кольца", + "bearing_scope": "сферические роликовые SKF", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — common suffixes", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "K", + "component": "suffix", + "feature": "bore", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Коническое отверстие 1:12", + "bearing_scope": "сферические роликовые SKF", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — common suffixes", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "M", + "component": "suffix", + "feature": "cage", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Массивный латунный сепаратор", + "bearing_scope": "подшипники SKF, тип уточнить", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — common suffixes", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "NU", + "component": "basic_family", + "feature": "cylindrical_roller_type", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "NU — конструктивное исполнение цилиндрического роликового подшипника, часть базового обозначения", + "bearing_scope": "цилиндрические роликовые SKF", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — bearing type", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "NJ", + "component": "basic_family", + "feature": "cylindrical_roller_type", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "NJ — конструктивное исполнение цилиндрического роликового подшипника, часть базового обозначения", + "bearing_scope": "цилиндрические роликовые SKF", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — bearing type", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "SKF", + "code": "NUP", + "component": "basic_family", + "feature": "cylindrical_roller_type", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "NUP — конструктивное исполнение цилиндрического роликового подшипника, часть базового обозначения", + "bearing_scope": "цилиндрические роликовые SKF", + "source_url": "https://benelux.promo.skf.com/acton/attachment/21304/f-55e38212-9419-4532-a361-8c1a9aab6720/0/-/-/-/file.pdf?sid=TV2%3AFx2eJqRHy", + "source_locator": "SKF Designations — bearing type", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "Z", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "one", + "meaning_ru": "Одна защитная металлическая шайба", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "ZZ", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "two", + "meaning_ru": "Две защитные металлические шайбы", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "V", + "component": "suffix", + "feature": "seal", + "contact_type": "noncontact", + "sides": "one", + "meaning_ru": "Одно бесконтактное резиновое уплотнение", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "VV", + "component": "suffix", + "feature": "seal", + "contact_type": "noncontact", + "sides": "two", + "meaning_ru": "Два бесконтактных резиновых уплотнения", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "DW", + "component": "suffix", + "feature": "seal", + "contact_type": "light_contact", + "sides": "one", + "meaning_ru": "Одно слабоконтактное резиновое уплотнение", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "DDW", + "component": "suffix", + "feature": "seal", + "contact_type": "light_contact", + "sides": "two", + "meaning_ru": "Два слабоконтактных резиновых уплотнения", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "DU", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "one", + "meaning_ru": "Одно контактное резиновое уплотнение", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "DDU", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "two", + "meaning_ru": "Два контактных резиновых уплотнения", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 7, 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "C2", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор меньше нормального", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "CN", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Нормальный радиальный зазор", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "CM", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор для электродвигателей", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "C3", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор больше нормального", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "N", + "component": "suffix", + "feature": "retaining", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Канавка под стопорное кольцо на наружном кольце", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NSK", + "code": "NR", + "component": "suffix", + "feature": "retaining", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Канавка и стопорное кольцо на наружном кольце", + "bearing_scope": "однорядные радиальные шариковые NSK", + "source_url": "https://www.nsk.com/content/dam/nsk-marketing/projects-completed/literature/product-brochures/deep-grooves-bbs_product-brochure/en_deep-grooves-bbs_product-brochure/preview-pdf_deep-grooves-bbs_product-brochure_en/EN_Deep%20Grooves%20BBs_Product_Brochure_low-res.pdf", + "source_locator": "NSK Deep Groove Ball Bearings, p. 9", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "LB", + "component": "suffix", + "feature": "seal", + "contact_type": "noncontact", + "sides": "one", + "meaning_ru": "Одно бесконтактное резиновое уплотнение", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "LLB", + "component": "suffix", + "feature": "seal", + "contact_type": "noncontact", + "sides": "two", + "meaning_ru": "Два бесконтактных резиновых уплотнения", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "LU", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "one", + "meaning_ru": "Одно контактное резиновое уплотнение", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "LLU", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "two", + "meaning_ru": "Два контактных резиновых уплотнения", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "LH", + "component": "suffix", + "feature": "seal", + "contact_type": "light_contact", + "sides": "one", + "meaning_ru": "Одно слабоконтактное резиновое уплотнение", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "LLH", + "component": "suffix", + "feature": "seal", + "contact_type": "light_contact", + "sides": "two", + "meaning_ru": "Два слабоконтактных резиновых уплотнения", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "Z", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "one", + "meaning_ru": "Одна металлическая защитная шайба", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "ZZ", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "two", + "meaning_ru": "Две металлические защитные шайбы", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / seals & shields", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "C2", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор меньше нормального", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "C3", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор больше нормального", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "C4", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор больше C3", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "P5", + "component": "suffix", + "feature": "precision", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Класс точности ISO 5", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "P6", + "component": "suffix", + "feature": "precision", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Класс точности ISO 6", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "NR", + "component": "suffix", + "feature": "retaining", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Канавка и стопорное кольцо на наружном кольце", + "bearing_scope": "радиальные шариковые NTN", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "TS2", + "component": "prefix", + "feature": "heat_treatment", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Термически стабилизированное исполнение до 160°C", + "bearing_scope": "радиальные шариковые NTN; зависит от смазки/уплотнений", + "source_url": "https://ntnamericas.com/wp-content/uploads/2025/12/UPDATED-NTN-Catalog-Gen-NomenclatureQRG-A-22NTNQREF.pdf", + "source_locator": "NTN Quick Reference, p. 5 / Prefix", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "NTN", + "code": "4T-", + "component": "prefix", + "feature": "material", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Специальная цементируемая сталь для конических роликовых подшипников", + "bearing_scope": "конические роликовые NTN", + "source_url": "https://ntnamericas.com/technical-resources/faqs/", + "source_locator": "NTN FAQ — What is 4T- prefix", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "FAG", + "code": "RSR", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "one", + "meaning_ru": "Одно контактное уплотнение RSR", + "bearing_scope": "радиальные шариковые FAG; архивная публикация, проверить актуальное исполнение", + "source_url": "https://www.schaeffler.com/remotemedien/media/_shared_media/08_media_library/01_publications/schaeffler_2/publication/downloads_18/wl_43163_de_en.pdf", + "source_locator": "FAG Deep Groove Ball Bearings WL 43 163, pp. 2-3 (1997)", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "FAG", + "code": "2RSR", + "component": "suffix", + "feature": "seal", + "contact_type": "contact", + "sides": "two", + "meaning_ru": "Два контактных уплотнения RSR", + "bearing_scope": "радиальные шариковые FAG; архивная публикация, проверить актуальное исполнение", + "source_url": "https://www.schaeffler.com/remotemedien/media/_shared_media/08_media_library/01_publications/schaeffler_2/publication/downloads_18/wl_43163_de_en.pdf", + "source_locator": "FAG Deep Groove Ball Bearings WL 43 163, pp. 2-3 (1997)", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "FAG", + "code": "ZR", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "one", + "meaning_ru": "Одна защитная шайба ZR", + "bearing_scope": "радиальные шариковые FAG; архивная публикация, проверить актуальное исполнение", + "source_url": "https://www.schaeffler.com/remotemedien/media/_shared_media/08_media_library/01_publications/schaeffler_2/publication/downloads_18/wl_43163_de_en.pdf", + "source_locator": "FAG Deep Groove Ball Bearings WL 43 163, pp. 2-3 (1997)", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "FAG", + "code": "2ZR", + "component": "suffix", + "feature": "shield", + "contact_type": "shield", + "sides": "two", + "meaning_ru": "Две защитные шайбы ZR", + "bearing_scope": "радиальные шариковые FAG; архивная публикация, проверить актуальное исполнение", + "source_url": "https://www.schaeffler.com/remotemedien/media/_shared_media/08_media_library/01_publications/schaeffler_2/publication/downloads_18/wl_43163_de_en.pdf", + "source_locator": "FAG Deep Groove Ball Bearings WL 43 163, pp. 2-3 (1997)", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "FAG", + "code": "C3", + "component": "suffix", + "feature": "clearance", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Радиальный зазор больше нормального", + "bearing_scope": "радиальные шариковые FAG; архивная публикация, проверить актуальное исполнение", + "source_url": "https://www.schaeffler.com/remotemedien/media/_shared_media/08_media_library/01_publications/schaeffler_2/publication/downloads_18/wl_43163_de_en.pdf", + "source_locator": "FAG Deep Groove Ball Bearings WL 43 163, pp. 2-3 (1997)", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "FAG", + "code": "M", + "component": "suffix", + "feature": "cage", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Механически обработанный латунный сепаратор", + "bearing_scope": "радиальные шариковые FAG; архивная публикация, проверить актуальное исполнение", + "source_url": "https://www.schaeffler.com/remotemedien/media/_shared_media/08_media_library/01_publications/schaeffler_2/publication/downloads_18/wl_43163_de_en.pdf", + "source_locator": "FAG Deep Groove Ball Bearings WL 43 163, pp. 2-3 (1997)", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + }, + { + "manufacturer": "FAG", + "code": "W203B", + "component": "suffix", + "feature": "material", + "contact_type": "unspecified", + "sides": "unspecified", + "meaning_ru": "Исполнение из нержавеющей стали", + "bearing_scope": "радиальные шариковые FAG; архивная публикация, проверить актуальное исполнение", + "source_url": "https://www.schaeffler.com/remotemedien/media/_shared_media/08_media_library/01_publications/schaeffler_2/publication/downloads_18/wl_43163_de_en.pdf", + "source_locator": "FAG Deep Groove Ball Bearings WL 43 163, pp. 2-3 (1997)", + "verified_on": "2026-10-20", + "verification_status": "OFFICIAL_CODE_ONLY" + } +] diff --git a/deploy/cloudflare/bearings-codebook/package.json b/deploy/cloudflare/bearings-codebook/package.json new file mode 100644 index 0000000..88917e7 --- /dev/null +++ b/deploy/cloudflare/bearings-codebook/package.json @@ -0,0 +1,11 @@ +{ + "name": "everest-bearing-codebook-cloudflare", + "private": true, + "type": "module", + "scripts": { + "test": "node --test test/*.test.mjs" + }, + "engines": { + "node": ">=20" + } +} diff --git a/deploy/cloudflare/bearings-codebook/src/codebook.mjs b/deploy/cloudflare/bearings-codebook/src/codebook.mjs new file mode 100644 index 0000000..27ed0cc --- /dev/null +++ b/deploy/cloudflare/bearings-codebook/src/codebook.mjs @@ -0,0 +1,4 @@ +// Snapshot is generated from verified_manufacturer_codes.csv; code meaning != analogue approval. +import VERIFIED_CODES from '../data/verified_codes.json' with { type: 'json' }; +export { VERIFIED_CODES }; +export const KNOWN_BRANDS = ['SKF','NSK','NTN','FAG','INA']; diff --git a/deploy/cloudflare/bearings-codebook/src/index.mjs b/deploy/cloudflare/bearings-codebook/src/index.mjs new file mode 100644 index 0000000..bdd6867 --- /dev/null +++ b/deploy/cloudflare/bearings-codebook/src/index.mjs @@ -0,0 +1,175 @@ +import { VERIFIED_CODES, KNOWN_BRANDS } from './codebook.mjs'; + +const index = new Map(VERIFIED_CODES.map(c => [c.manufacturer+'|'+c.component+'|'+c.code,c])); +const headers = {'content-type':'application/json; charset=utf-8','cache-control':'no-store','x-content-type-options':'nosniff','referrer-policy':'no-referrer'}; +function json(value,status=200){return new Response(JSON.stringify(value),{status,headers})} +function invalid(message,status=400){return json({error:message,auto_replace_allowed:false},status)} +function brandOf(b){return typeof b==='string'?b.trim().toUpperCase():''} +function safe(s,limit=96){return typeof s==='string'&&s.length<=limit&&/^[\w.\-/\s]+$/u.test(s)} +export function lookup(brand,code,component='suffix'){ + return index.get(brandOf(brand)+'|'+component+'|'+String(code||'').trim().toUpperCase())??null; +} +export function decode(brand,suffix){ + const b=brandOf(brand), s=String(suffix||'').trim().toUpperCase(); + if(!KNOWN_BRANDS.includes(b))return {brand:b||null,original_suffix:s,matched:[],unknown_parts:s?[s]:[],status:'UNKNOWN_BRAND',auto_replace_allowed:false}; + const candidates=VERIFIED_CODES.filter(c=>c.manufacturer===b&&c.component==='suffix').sort((a,b)=>b.code.length-a.code.length); + let i=0;const matched=[],unknown_parts=[]; + while(is.startsWith(c.code,i)); + if(found){matched.push(found);i+=found.code.length;continue} + let j=i+1;while(jx.status==='VERIFIED_CODE_SCOPE_REVIEW'&&x.matched.length>0; + const shapes=x=>x.matched.map(c=>c.feature+':'+c.contact_type+':'+c.sides).sort(); + const code_relationship=!full(l)||!full(r)?'INSUFFICIENT_CODE_EVIDENCE': + JSON.stringify(shapes(l))===JSON.stringify(shapes(r))?'SAME_FEATURE_NOT_PROVEN_INTERCHANGEABLE':'DIFFERENT_TECHNICAL_FEATURE'; + return {left:l,right:r,code_relationship,product_equivalence:'NOT_ASSESSED',decision:'ENGINEER_REVIEW_REQUIRED',auto_replace_allowed:false, + reasons:['OEM_CODE_MEANING_NOT_PRODUCT_SPECIFICATION','NO_SCOPED_ENGINEERING_APPROVAL']}; +} +async function readSmallJSON(req){ + const length=Number(req.headers.get('content-length')); + if(length>2048)throw Error('PAYLOAD_TOO_LARGE'); + if(!(req.headers.get('content-type')||'').toLowerCase().startsWith('application/json'))throw Error('JSON_ONLY'); + const reader=req.body?.getReader(); + if(!reader)throw Error('INVALID_JSON'); + const chunks=[];let bytesRead=0; + while(true){ + const {done,value}=await reader.read();if(done)break; + bytesRead+=value.byteLength; + if(bytesRead>2048){await reader.cancel();throw Error('PAYLOAD_TOO_LARGE')} + chunks.push(value); + } + const buffer=new Uint8Array(bytesRead);let pos=0; + for(const chunk of chunks){buffer.set(chunk,pos);pos+=chunk.byteLength} + const body=new TextDecoder().decode(buffer); + let obj;try{obj=JSON.parse(body)}catch{throw Error('INVALID_JSON')} + if(!obj||typeof obj!=='object'||Array.isArray(obj))throw Error('OBJECT_REQUIRED'); + return obj; +} + +// Structural parsing only. ГОСТ↔ISO equivalence is never inferred from designation digits. +export function parseMarking(raw, declaredBrand='') { + const raw_designation = typeof raw==='string' ? raw : ''; + const issues=[]; + const empty=() => ({raw_designation,brand:null,prefix:'',basic_designation:'',suffix:'', + standard_hint:'UNKNOWN',parse_status:'INVALID',issues,source_codes:[], + product_equivalence:'NOT_ASSESSED',auto_replace_allowed:false}); + if (!raw_designation.trim()||raw_designation.length>160 || !/^[A-ZА-ЯЁ0-9.\/\-\s]+$/u.test(raw_designation.toUpperCase())) { + issues.push('INVALID_MARKING_INPUT');return empty(); + } + let value=raw_designation.trim().toUpperCase().replace(/\s+/g,' '); + value=value.replace(/^(?:ПОДШИПНИК|BEARING)\s+/, ''); + const detected=[]; + const atStart=KNOWN_BRANDS.find(b=>value.startsWith(b+' ')); + if(atStart){detected.push(atStart);value=value.slice(atStart.length+1).trim()} + const atEnd=KNOWN_BRANDS.find(b=>value.endsWith(' '+b)); + if(atEnd){detected.push(atEnd);value=value.slice(0,-atEnd.length-1).trim()} + const asserted=typeof declaredBrand==='string'?declaredBrand.trim().toUpperCase():''; + if(asserted&&!KNOWN_BRANDS.includes(asserted)) issues.push('UNKNOWN_DECLARED_BRAND'); + const distinct=new Set([...detected, ...(asserted?[asserted]:[])]); + if(distinct.size>1)issues.push('CONFLICTING_BRANDS'); + const brand=asserted||detected[0]||null; + if(!brand)issues.push('BRAND_UNKNOWN'); + let prefix='', prefix_origin='NONE', standard_hint='UNVERIFIED'; + if(brand){ + const documented=VERIFIED_CODES.filter(c=>c.manufacturer===brand&&c.component==='prefix') + .sort((a,b)=>b.code.length-a.code.length); + const hit=documented.find(c=>value.startsWith(c.code)); + if(hit){prefix=hit.code;prefix_origin='OFFICIAL_CODE_ONLY';value=value.slice(hit.code.length); + if(value.startsWith('-')){prefix+='-';value=value.slice(1)}value=value.trim();} + } + if(!prefix){const gost=/^(\d{1,2}-)(?=\d{3,7}(?:\D|$))/.exec(value); + if(gost){prefix=gost[1];prefix_origin='STRUCTURAL_ONLY';value=value.slice(prefix.length);standard_hint='GOST_CANDIDATE';}} + const genericFamilies=['NUP','RNA','NU','NJ','QJ','NA','HK','BK','UC','UK','N']; + const family=genericFamilies.find(f=>new RegExp('^'+f+'\\d{2,7}').test(value)); + const bodyMatch=family?new RegExp('^('+family+'\\d{2,7})(.*) + async fetch(req){ + try{ + const url=new URL(req.url),path=url.pathname; + if(req.method==='GET'&&path==='/health') + return json({service:'EVEREST BearingsInfo',status:'ok',mode:'read-only',code_count:VERIFIED_CODES.length,approved_product_analogues:0}); + if (path==='/v1/parse' && req.method==='POST') { + const obj=await readSmallJSON(req); + if (typeof obj.raw_designation!=='string'||obj.raw_designation.length>160|| + (obj.brand!==undefined&&typeof obj.brand!=='string'))return invalid('BAD_MARKING'); + return json(parseMarking(obj.raw_designation,obj.brand||'')); + } + if(req.method==='GET'&&path==='/v1/lookup'){ + const brand=brandOf(url.searchParams.get('brand')),code=url.searchParams.get('code'),component=url.searchParams.get('component')||'suffix'; + if(!KNOWN_BRANDS.includes(brand)||!safe(code)||!['suffix','prefix','basic_family'].includes(component))return invalid('BAD_LOOKUP'); + const entry=lookup(brand,code,component); + return json({entry,found:!!entry,status:entry?'OFFICIAL_CODE_ONLY':'NOT_FOUND',auto_replace_allowed:false}); + } + if(req.method==='POST'&&path==='/v1/decode'){ + const o=await readSmallJSON(req); + if(typeof o.brand!=='string'||o.brand.length>40||!safe(o.suffix,256))return invalid('BAD_DESIGNATION'); + return json(decode(o.brand,o.suffix)); + } + if(req.method==='POST'&&path==='/v1/compare'){ + const o=await readSmallJSON(req); + if(!o.left||!o.right||typeof o.left.brand!=='string'||typeof o.right.brand!=='string' + ||!safe(o.left.suffix,256)||!safe(o.right.suffix,256))return invalid('BAD_PAIR'); + return json(compare(o.left,o.right)); + } + if(path==='/v1/approve')return invalid('APPROVAL_ENDPOINT_NOT_AVAILABLE',403); + return invalid('NOT_FOUND',404); + }catch(e){ + if(['PAYLOAD_TOO_LARGE','JSON_ONLY','INVALID_JSON','OBJECT_REQUIRED'].includes(e?.message)) + return invalid(e.message,e.message==='PAYLOAD_TOO_LARGE'?413:400); + return invalid('INTERNAL_ERROR',500); + } + } +}; +).exec(value):/^(\d{3,7})(.*)$/.exec(value); + if(!bodyMatch){issues.push('BASIC_DESIGNATION_UNRECOGNIZED');return {...empty(),brand,prefix,standard_hint};} + const basic_designation=bodyMatch[1]; + const suffix=bodyMatch[2].trim(); + if(family && !VERIFIED_CODES.some(c=>c.manufacturer===brand && c.component==='basic_family' && c.code===family)) + issues.push('BASIC_FAMILY_NOT_OEM_VERIFIED'); + const decoded=decode(brand,suffix); + if(suffix && decoded.status!=='VERIFIED_CODE_SCOPE_REVIEW')issues.push('UNVERIFIED_SUFFIX'); + if(/[А-ЯЁ]/u.test(basic_designation+suffix)&&/[A-Z]/u.test(basic_designation+suffix))issues.push('MIXED_ALPHABETS'); + return {raw_designation,brand,prefix,prefix_origin,basic_designation,suffix,standard_hint, + source_codes:decoded.matched,unresolved_suffix_parts:decoded.unknown_parts, + parse_status:issues.length?'REVIEW':'PARSED_COMPONENTS',issues, + product_equivalence:'NOT_ASSESSED',auto_replace_allowed:false}; +} + +export default { + async fetch(req){ + try{ + const url=new URL(req.url),path=url.pathname; + if(req.method==='GET'&&path==='/health') + return json({service:'EVEREST BearingsInfo',status:'ok',mode:'read-only',code_count:VERIFIED_CODES.length,approved_product_analogues:0}); + if(req.method==='GET'&&path==='/v1/lookup'){ + const brand=brandOf(url.searchParams.get('brand')),code=url.searchParams.get('code'),component=url.searchParams.get('component')||'suffix'; + if(!KNOWN_BRANDS.includes(brand)||!safe(code)||!['suffix','prefix','basic_family'].includes(component))return invalid('BAD_LOOKUP'); + const entry=lookup(brand,code,component); + return json({entry,found:!!entry,status:entry?'OFFICIAL_CODE_ONLY':'NOT_FOUND',auto_replace_allowed:false}); + } + if(req.method==='POST'&&path==='/v1/decode'){ + const o=await readSmallJSON(req); + if(typeof o.brand!=='string'||o.brand.length>40||!safe(o.suffix,256))return invalid('BAD_DESIGNATION'); + return json(decode(o.brand,o.suffix)); + } + if(req.method==='POST'&&path==='/v1/compare'){ + const o=await readSmallJSON(req); + if(!o.left||!o.right||typeof o.left.brand!=='string'||typeof o.right.brand!=='string' + ||!safe(o.left.suffix,256)||!safe(o.right.suffix,256))return invalid('BAD_PAIR'); + return json(compare(o.left,o.right)); + } + if(path==='/v1/approve')return invalid('APPROVAL_ENDPOINT_NOT_AVAILABLE',403); + return invalid('NOT_FOUND',404); + }catch(e){ + if(['PAYLOAD_TOO_LARGE','JSON_ONLY','INVALID_JSON','OBJECT_REQUIRED'].includes(e?.message)) + return invalid(e.message,e.message==='PAYLOAD_TOO_LARGE'?413:400); + return invalid('INTERNAL_ERROR',500); + } + } +}; diff --git a/deploy/cloudflare/bearings-codebook/test/api.test.mjs b/deploy/cloudflare/bearings-codebook/test/api.test.mjs new file mode 100644 index 0000000..a366a0b --- /dev/null +++ b/deploy/cloudflare/bearings-codebook/test/api.test.mjs @@ -0,0 +1,15 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import api,{decode,lookup,compare} from '../src/index.mjs'; +const req=(p,method='GET',data)=>new Request('https://example.invalid'+p,{method,headers:{'content-type':'application/json'},body:data?JSON.stringify(data):undefined}); +const call=async (r)=>{const x=await api.fetch(r);return [x.status,await x.json()]}; +test('fifty five official codes in source snapshot',async()=>{const [s,r]=await call(req('/health'));assert.equal(s,200);assert.equal(r.code_count,55);assert.equal(r.approved_product_analogues,0)}); +test('manufacturer-specific semantics retained',()=>{assert.equal(lookup('NSK','DDU').contact_type,'contact');assert.equal(lookup('NTN','LLB').contact_type,'noncontact')}); +test('compound suffix decodes',()=>{const r=decode('SKF','-2RSH/C3');assert.deepEqual(r.matched.map(x=>x.code),['2RSH','C3']);assert.equal(r.auto_replace_allowed,false)}); +test('unknown part not silently discarded',()=>{const r=decode('NSK','DDUXYZCM');assert.deepEqual(r.unknown_parts,['XYZCM']);assert.equal(r.status,'REVIEW_UNKNOWN_CODE')}); +test('FAG code not inherited by INA',()=>{assert.equal(lookup('INA','2RSR'),null);assert.equal(decode('INA','2RSR').status,'REVIEW_UNKNOWN_CODE')}); +test('functional similarity never equals product equivalence',()=>{const r=compare({brand:'NSK',suffix:'DDU'},{brand:'NTN',suffix:'LLU'});assert.equal(r.code_relationship,'SAME_FEATURE_NOT_PROVEN_INTERCHANGEABLE');assert.equal(r.auto_replace_allowed,false)}); +test('contact versus noncontact difference is reported',()=>{const r=compare({brand:'NSK',suffix:'VV'},{brand:'NTN',suffix:'LLU'});assert.equal(r.code_relationship,'DIFFERENT_TECHNICAL_FEATURE')}); +test('approval routes rejected',async()=>{const [s,r]=await call(req('/v1/approve','POST',{}));assert.equal(s,403);assert.equal(r.auto_replace_allowed,false)}); +test('overlong suffix rejected',async()=>{const [s]=await call(req('/v1/decode','POST',{brand:'SKF',suffix:'X'.repeat(300)}));assert.equal(s,400)}); +test('lookup route works',async()=>{const [s,r]=await call(req('/v1/lookup?brand=SKF&code=2RSH'));assert.equal(s,200);assert.equal(r.entry.code,'2RSH');assert.equal(r.auto_replace_allowed,false)}); diff --git a/deploy/cloudflare/bearings-codebook/wrangler.jsonc b/deploy/cloudflare/bearings-codebook/wrangler.jsonc new file mode 100644 index 0000000..cc09c25 --- /dev/null +++ b/deploy/cloudflare/bearings-codebook/wrangler.jsonc @@ -0,0 +1,13 @@ +{ + "name": "everest-bearings-codebook-staging", + "main": "src/index.mjs", + "compatibility_date": "2026-10-21", + "compatibility_flags": [ + "nodejs_compat" + ], + "workers_dev": false, + "observability": { + "enabled": true, + "head_sampling_rate": 0.1 + } +}